A simple and efficient Go-based HTTP service that provides geolocation information for IP addresses using the MaxMind GeoLite2-City database.
- Go: Version 1.21 or higher.
- GeoLite2-City Database: You need to download the
GeoLite2-City.mmdbfile from MaxMind. This service expects the database file to be present.
-
Clone the repository:
git clone https://github.com/ali-issa/ip-lookup cd ip-lookup -
Download the GeoLite2-City Database: Obtain the
GeoLite2-City.mmdbfile from MaxMind and place it in a directory accessible by the application. By default, the application looks for it at/app/data/GeoLite2-City.mmdb(common in containerized environments) or a path specified by theGEOIP_DB_PATHenvironment variable. -
Build the application:
go build -o ip-lookup-service main.go
Pre-compiled binaries for various operating systems and architectures are available on the GitHub Releases page. You can download the appropriate binary for your system instead of building from source.
The service is configured using environment variables:
GEOIP_DB_PATH: (Required unless default path is used) The absolute path to yourGeoLite2-City.mmdbfile.- If not set, the application will attempt to load the database from
/app/data/GeoLite2-City.mmdb. - Example:
export GEOIP_DB_PATH="/path/to/your/GeoLite2-City.mmdb"
- If not set, the application will attempt to load the database from
PORT: (Optional) The port on which the server should listen.- Defaults to
8080. - Example:
export PORT="9000"
- Defaults to
ALLOWED_CORS_ORIGINS: (Optional) A comma-separated list of origins that are allowed to make cross-origin requests.- If not set, or if the request's
Originheader doesn't match any in the list, CORS headers will not be added, and browsers may block cross-origin requests. - To allow all origins (use with caution, especially in production), set it to
*. - Example for specific origins:
export ALLOWED_CORS_ORIGINS="http://localhost:3000,https://yourfrontend.com" - Example to allow all:
export ALLOWED_CORS_ORIGINS="*"
- If not set, or if the request's
Once built and configured, you can run the service:
./ip-lookup-serviceExample with environment variables:
export GEOIP_DB_PATH="/opt/geoip/GeoLite2-City.mmdb"
export PORT="8080"
./ip-lookup-serviceThe server will start, and log messages will indicate if the GeoIP database was loaded successfully and the address it's listening on.
A pre-built Docker image is available on Docker Hub: issaali/ip-lookup.
The image is based on Alpine Linux and uses the binary from the GitHub releases.
The ip-lookup Docker container expects the GeoLite2 database to be available at /geoipdb/GeoLite2-City.mmdb by default. This path is configurable via the GEOIP_DB_PATH environment variable if needed.
The recommended way to run this service with Docker is by using docker-compose along with MaxMind's official geoipupdate container. This automates the download and periodic refresh of the GeoLite2 database, which the ip-lookup service will then use.
Here’s how to set it up:
-
Create a
docker-compose.ymlfile:version: "3.8" services: geoipupdate: container_name: geoipupdate image: ghcr.io/maxmind/geoipupdate restart: unless-stopped environment: # Replace with your actual MaxMind account ID and license key - GEOIPUPDATE_ACCOUNT_ID=YOUR_ACCOUNT_ID - GEOIPUPDATE_LICENSE_KEY=YOUR_LICENSE_KEY - GEOIPUPDATE_EDITION_IDS=GeoLite2-City # We only need the City database - GEOIPUPDATE_FREQUENCY=72 # How often to check for updates (in hours) volumes: - geoip_data:/usr/share/GeoIP # geoipupdate writes here ip-lookup: container_name: ip-lookup image: issaali/ip-lookup:latest # Or a specific version restart: unless-stopped depends_on: - geoipupdate ports: - "8080:8080" # Map host port 8080 to container port 8080 volumes: - geoip_data:/geoipdb # ip-lookup reads from here environment: # GEOIP_DB_PATH is already set to /geoipdb/GeoLite2-City.mmdb in the Dockerfile # PORT can be overridden here if needed, defaults to 8080 PORT: 8080 # ALLOWED_CORS_ORIGINS can be set here to configure allowed origins for CORS # Example: - ALLOWED_CORS_ORIGINS=http://localhost:3000,https://your.frontend.app # Example to allow all: - ALLOWED_CORS_ORIGINS=* # Add healthcheck if desired # healthcheck: # test: ["CMD", "curl", "-f", "http://localhost:8080/healthz"] # interval: 30s # timeout: 10s # retries: 3 volumes: geoip_data: # This named volume is shared between the two services driver: local
-
Sign up for a MaxMind Account: You need a MaxMind account and a license key to use
geoipupdate. You can typically get these from the MaxMind website. The free GeoLite2 databases require account signup. -
Configure Environment Variables: Replace
YOUR_ACCOUNT_IDandYOUR_LICENSE_KEYin thedocker-compose.ymlfile with your actual MaxMind credentials. Alternatively, you can use a.envfile in the same directory as yourdocker-compose.yml:GEOIPUPDATE_ACCOUNT_ID=YOUR_ACCOUNT_ID GEOIPUPDATE_LICENSE_KEY=YOUR_LICENSE_KEY
And then reference them in
docker-compose.yml:# ... inside geoipupdate service environment: - GEOIPUPDATE_ACCOUNT_ID=${GEOIPUPDATE_ACCOUNT_ID} - GEOIPUPDATE_LICENSE_KEY=${GEOIPUPDATE_LICENSE_KEY} # ...
-
Run Docker Compose:
docker-compose up -d
This will start both services. The
geoipupdateservice will download theGeoLite2-City.mmdbinto the sharedgeoip_datavolume, andip-lookupwill read it from there.
- Endpoint:
/lookup/{ip_address} - Method:
GET - Description: Retrieves geolocation data for the specified IP address.
- Example:
curl http://localhost:8080/lookup/8.8.8.8
- Success Response (200 OK):
{ "ip": "8.8.8.8", "city": "Mountain View", "country_code": "US", "country_name": "United States", "continent": "North America", "latitude": 37.422, "longitude": -122.084, "time_zone": "America/Los_Angeles", "postal_code": "94043", "subdivision_name": "California" // Present if available } - Error Responses:
400 Bad Request: If the IP address format is invalid.{ "message": "Invalid IP address format: X.X.X.X", "code": 400 }404 Not Found: If GeoIP data is not found for the IP.{ "message": "GeoIP data not found for IP: X.X.X.X", "code": 404 }
- Endpoint:
/lookup/or/lookup - Method:
GET - Description: Retrieves geolocation data for the IP address of the client making the request.
- Example:
curl http://localhost:8080/lookup/
- Success Response (200 OK): Same format as
/lookup/{ip_address}. - Error Responses:
400 Bad Request: If the client's IP could not be determined.
- Endpoint:
/healthz - Method:
GET - Description: Checks the health of the service, primarily if the GeoIP database is loaded.
- Example:
curl http://localhost:8080/healthz
- Success Response (200 OK):
{ "status": "ok" } - Error Response (500 Internal Server Error): If the GeoIP database is not loaded.
{ "message": "GeoIP database not loaded", "code": 500 }
Contributions are welcome! Please feel free to submit a Pull Request or open an issue for bugs, feature requests, or improvements.
- Fork the repository.
- Create your feature branch (
git checkout -b feature/AmazingFeature). - Commit your changes (
git commit -m 'Add some AmazingFeature'). - Push to the branch (
git push origin feature/AmazingFeature). - Open a Pull Request.
This project is licensed under the MIT License. See the LICENSE file for details.