- Complete unit, integration, and E2E test coverage (189 test cases) - Enhanced CI/CD pipeline with race detection and quality checks - Comprehensive godoc documentation for all packages - Updated README with API docs, examples, and deployment guides
GeoIP API
A high-performance HTTP service that provides MaxMind GeoIP data for IP geolocation lookups. Designed to run as a lightweight daemon within Kubernetes clusters to serve geolocation data to other services.
Features
- Fast HTTP API for IP geolocation lookups
- Multiple response formats: country codes and full JSON data
- OpenTelemetry tracing with standard Traceparent headers
- Automatic database discovery in standard system paths
- Health check endpoint with actual database verification
- Go client library for easy integration
- Comprehensive test coverage with unit, integration, and E2E tests
API Endpoints
Country Lookup
GET /api/country?ip=192.0.2.1
Returns the lowercase ISO country code (e.g., us
, gb
)
Full JSON Data
GET /api/json?ip=192.0.2.1
Returns complete MaxMind GeoIP data in JSON format including:
- Country, city, and region information
- Latitude/longitude coordinates
- ISP and organization data (if available)
- Time zone information
Health Check
GET /healthz
Performs an actual GeoIP lookup to verify database connectivity and returns the country code for a test IP.
Installation
From Source
go build -o geoipapi
./geoipapi
Using Docker
docker build -t geoipapi .
docker run -p 8009:8009 geoipapi
Database Setup
The service automatically searches for MaxMind databases in standard locations:
/usr/share/GeoIP/
(Linux default)/usr/local/share/GeoIP/
(FreeBSD)/opt/local/share/GeoIP/
(MacPorts)/opt/homebrew/var/GeoIP/
(Homebrew)
Supported Database Files
- Country databases:
GeoIP2-Country.mmdb
,GeoLite2-Country.mmdb
- City databases:
GeoIP2-City.mmdb
,GeoLite2-City.mmdb
- ISP databases:
GeoIP2-ISP.mmdb
Installing GeoLite2 Databases (Free)
- Create a free MaxMind account at https://www.maxmind.com/en/geolite2/signup
- Download the databases manually, or
- Use the built-in MaxMind package for automatic downloads:
import "go.ntppool.org/geoipapi/maxmind"
maxmind.LicenseKey = "your_license_key_here"
maxmind.EditionIDs = "GeoLite2-City,GeoLite2-Country"
maxmind.Path = "/usr/share/GeoIP/"
err := maxmind.DownloadGeoLite2DB()
Configuration
Environment Variables
- OpenTelemetry: Standard OTel environment variables are supported
OTEL_EXPORTER_OTLP_ENDPOINT
OTEL_SERVICE_NAME
OTEL_RESOURCE_ATTRIBUTES
Server Configuration
The server runs on port 8009 by default with the following timeouts:
- Read timeout: 1 second
- Write timeout: 10 seconds
OpenTelemetry Support
The service includes comprehensive OpenTelemetry instrumentation:
- HTTP requests are automatically traced
- Database lookups are instrumented with spans
- Health checks are filtered from tracing to reduce noise
- Custom attributes include IP addresses and operation details
Tracing works seamlessly with the OpenTelemetry Collector and common observability platforms.
Go Client Library
Use the provided Go client for easy integration:
package main
import (
"context"
"fmt"
"log"
"net/netip"
"os"
"go.ntppool.org/geoipapi/client/geoipapi"
)
func main() {
// Set the service endpoint
os.Setenv("geoip_service", "geoip-service:8009")
ctx := context.Background()
ip := netip.MustParseAddr("8.8.8.8")
city, err := geoipapi.GetCity(ctx, ip)
if err != nil {
log.Fatal(err)
}
fmt.Printf("IP: %s\n", ip)
fmt.Printf("Country: %s\n", city.Country.IsoCode)
fmt.Printf("City: %s\n", city.City.Names["en"])
fmt.Printf("Location: %f, %f\n", city.Location.Latitude, city.Location.Longitude)
}
Client Configuration
Set the geoip_service
environment variable to point to your GeoIP API service:
export geoip_service="geoip-service.default.svc.cluster.local:8009"
Command Line Usage
The service can also be used as a command-line tool for IP lookups:
./geoipapi 8.8.8.8 1.1.1.1 192.168.1.1
Output:
8.8.8.8: us
1.1.1.1: us
192.168.1.1:
Development
Running Tests
The project includes comprehensive test coverage:
# Run all tests
go test ./...
# Run tests with race detection
go test -race ./...
# Run only fast tests
go test -short ./...
# Run with coverage
go test -cover ./...
Test Types
- Unit tests: Test individual functions and components
- Integration tests: Test HTTP API endpoints with a running server
- End-to-end tests: Test complete client-server workflows
- Race condition tests: Verify thread safety under concurrent load
Code Quality
# Format code
gofumpt -w .
# Lint code
go vet ./...
# Verify dependencies
go mod verify
Architecture
Core Components
- HTTP Server (
geoipapi.go
): Main API server with endpoint handlers - MaxMind Package (
maxmind/
): Database download and management utilities - Client Library (
client/geoipapi/
): Go client for consuming the HTTP API
Database Discovery
The service automatically discovers MaxMind databases by:
- Searching standard system paths
- Looking for supported database filenames
- Opening the first available database for each type
- Gracefully handling missing databases
Error Handling
- Invalid IP addresses return HTTP 500 with "data error"
- Missing databases are detected during health checks
- Network errors in the client include proper context
- Tracing errors are recorded in spans for debugging
Deployment
Kubernetes
Example Kubernetes deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: geoipapi
spec:
replicas: 3
selector:
matchLabels:
app: geoipapi
template:
metadata:
labels:
app: geoipapi
spec:
containers:
- name: geoipapi
image: your-registry/geoipapi:latest
ports:
- containerPort: 8009
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "http://otel-collector:4317"
- name: OTEL_SERVICE_NAME
value: "geoipapi"
volumeMounts:
- name: geoip-data
mountPath: /usr/share/GeoIP
readinessProbe:
httpGet:
path: /healthz
port: 8009
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8009
initialDelaySeconds: 15
periodSeconds: 20
volumes:
- name: geoip-data
configMap:
name: geoip-databases
---
apiVersion: v1
kind: Service
metadata:
name: geoipapi
spec:
selector:
app: geoipapi
ports:
- port: 8009
targetPort: 8009
Performance Considerations
- Database caching: MaxMind databases are loaded once on startup
- Connection pooling: HTTP client uses connection pooling for better performance
- Concurrent requests: Server handles multiple concurrent requests efficiently
- Memory usage: Minimal memory footprint suitable for container environments
Contributing
- Fork the repository
- Create a feature branch
- Make your changes with tests
- Run the full test suite:
go test ./...
- Format code:
gofumpt -w .
- Submit a pull request
CI/CD
The project uses Drone CI with the following pipeline:
- Dependencies: Download Go modules
- Testing: Run unit, integration, and race tests
- Code Quality: Run
go vet
,gofumpt
, andgo mod verify
- Build: Compile the binary
- Docker: Build and push container image
License
This project is licensed under the terms specified in the LICENSE file.
Support
For issues and questions:
- Bug reports: Create an issue in the GitHub repository
- Feature requests: Submit a feature request with use case details
- Documentation: Check the Go docs:
go doc go.ntppool.org/geoipapi
Related Projects
- MaxMind GeoIP2: https://www.maxmind.com/en/geoip2-services-and-databases
- OpenTelemetry Go: https://github.com/open-telemetry/opentelemetry-go
- Kubernetes ingress-nginx: https://github.com/kubernetes/ingress-nginx (inspiration for MaxMind handling)