Lynx supports optional visitor IP analytics with geolocation capabilities. This feature is designed to be high-performance and does not affect the core URL redirection latency when disabled.
- GeoIP Lookup: Resolve visitor IP addresses to geographic locations (country, region, city)
- Privacy-Focused: Optional IP anonymization
- Flexible Trust Models: Support for direct connections, standard proxies (X-Forwarded-For/RFC 7239), and CDN-specific headers (Cloudflare)
- High Performance: Memory-mapped MaxMind database with in-memory aggregation
- Non-Blocking: GeoIP lookups don't block redirects
- IPv4/IPv6 Support: Unified handling of both IP versions
The analytics feature is optional and must be enabled at compile time:
cargo build --release --features analyticsDownload the MaxMind GeoLite2 or GeoIP2 database (free or paid):
- Sign up for a free account at https://www.maxmind.com/en/geolite2/signup
- Download the GeoLite2 City or Country database in MMDB format
- Place the
.mmdbfile in a location accessible to Lynx
Recommended: GeoLite2-City.mmdb for full geographic resolution including cities.
Alternative: GeoLite2-Country.mmdb for smaller footprint with country-level data only.
Add the following to your .env file or environment:
# Enable analytics
ANALYTICS_ENABLED=true
# Path to GeoIP database
ANALYTICS_GEOIP_DB_PATH=/path/to/GeoLite2-City.mmdb
# Optional: Enable IP anonymization (truncate to network prefix)
ANALYTICS_IP_ANONYMIZATION=false
# Trusted proxy mode: none, standard, or cloudflare
ANALYTICS_TRUSTED_PROXY_MODE=none
# Optional: Trusted proxy CIDR ranges (for standard mode)
# ANALYTICS_TRUSTED_PROXIES=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
# Optional: Number of trusted proxies to skip from right in X-Forwarded-For
# ANALYTICS_NUM_TRUSTED_PROXIES=1
# Optional: Analytics flush interval in seconds (default: 60)
ANALYTICS_FLUSH_INTERVAL_SECS=60Use the direct socket remote address only. Ignore all proxy headers.
ANALYTICS_TRUSTED_PROXY_MODE=noneUse case: Direct connections without reverse proxies.
Trust RFC 7239 Forwarded and X-Forwarded-For headers with validation.
ANALYTICS_TRUSTED_PROXY_MODE=standardConfiguration options:
-
CIDR-based trust (recommended for security):
ANALYTICS_TRUSTED_PROXIES=10.0.0.0/8,172.16.0.0/12
-
Count-based trust (simpler but less secure):
ANALYTICS_NUM_TRUSTED_PROXIES=1
Use case: Behind nginx, HAProxy, or other standard reverse proxies.
Trust only the Cloudflare-specific CF-Connecting-IP header.
ANALYTICS_TRUSTED_PROXY_MODE=cloudflareUse case: Traffic exclusively routed through Cloudflare.
Security Note: Only use this mode if ALL traffic is guaranteed to pass through Cloudflare and direct origin access is blocked.
When enabled, IP addresses are truncated to network prefixes before storage:
- IPv4:
/24network (e.g.,192.168.1.100→192.168.1.0) - IPv6:
/48network (e.g.,2001:db8::1234→2001:db8::)
Enable anonymization:
ANALYTICS_IP_ANONYMIZATION=truePrivacy Note: When anonymization is enabled, the raw IP address is not stored in analytics records.
The GeoIP database should be updated periodically to maintain accuracy:
- Manual updates: Download new databases from MaxMind quarterly
- Automated updates: Use geoipupdate tool
Example cron job for weekly updates:
0 3 * * 0 /usr/local/bin/geoipupdate- Lookup Latency: ~1-10 microseconds per IP with memory-mapped database
- Memory Usage: Database size (~70MB for City, ~5MB for Country) + in-memory aggregates
- Redirect Impact: Minimal (non-blocking, asynchronous aggregation)
- Client makes request → Redirect handler
- Extract client IP based on trust configuration
- Perform GeoIP lookup (non-blocking)
- Record in memory aggregator
- Return redirect response immediately
- Background task flushes aggregates periodically
Analytics are aggregated in-memory by:
- Short code
- Time bucket (hourly)
- Country
- Region
- City
- ASN
- IP version
This reduces database write load and improves performance.
Risk: Clients can inject fake X-Forwarded-For or X-Real-IP headers.
Mitigation:
- Use
ANALYTICS_TRUSTED_PROXY_MODE=nonefor direct connections - Configure reverse proxy to overwrite (not append) client headers
- Use CIDR-based trust lists to validate proxy sources
- Consider vendor-specific modes (Cloudflare) when applicable
- Enable
ANALYTICS_IP_ANONYMIZATIONfor privacy compliance - Consider legal requirements (GDPR, CCPA) for IP storage
- Document IP handling in your privacy policy
- Restrict file permissions on
.mmdbfiles - Ensure GeoIP data is from trusted sources only
- Verify database integrity after downloads
-
Check feature is enabled:
cargo build --release --features analytics
-
Verify configuration:
ANALYTICS_ENABLED=true
-
Check GeoIP database path:
ls -lh /path/to/GeoLite2-City.mmdb
-
Review logs for GeoIP initialization messages:
Analytics enabled - GeoIP database loaded from: /path/to/GeoLite2-City.mmdb
- Symptom: IPs resolving to wrong locations
- Cause: Outdated GeoIP database
- Solution: Download latest database from MaxMind
- Symptom: All IPs show as server IP
- Cause: Incorrect trust configuration
- Solution:
- Check
ANALYTICS_TRUSTED_PROXY_MODE - Verify proxy headers are being sent
- Ensure proxy is in
ANALYTICS_TRUSTED_PROXIES
- Check
ANALYTICS_ENABLED=true
ANALYTICS_GEOIP_DB_PATH=/var/lib/geoip/GeoLite2-City.mmdb
ANALYTICS_TRUSTED_PROXY_MODE=none
ANALYTICS_IP_ANONYMIZATION=falseANALYTICS_ENABLED=true
ANALYTICS_GEOIP_DB_PATH=/var/lib/geoip/GeoLite2-City.mmdb
ANALYTICS_TRUSTED_PROXY_MODE=standard
ANALYTICS_TRUSTED_PROXIES=10.0.1.0/24
ANALYTICS_IP_ANONYMIZATION=falseNginx configuration:
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://lynx:3000;
}ANALYTICS_ENABLED=true
ANALYTICS_GEOIP_DB_PATH=/var/lib/geoip/GeoLite2-City.mmdb
ANALYTICS_TRUSTED_PROXY_MODE=cloudflare
ANALYTICS_IP_ANONYMIZATION=falseImportant: Ensure origin is only accessible via Cloudflare IPs.
ANALYTICS_ENABLED=true
ANALYTICS_GEOIP_DB_PATH=/var/lib/geoip/GeoLite2-Country.mmdb
ANALYTICS_TRUSTED_PROXY_MODE=standard
ANALYTICS_NUM_TRUSTED_PROXIES=1
ANALYTICS_IP_ANONYMIZATION=true- Database storage for analytics aggregates
- API endpoints for querying analytics data
- Dashboard visualizations
- ASN enrichment
- Time-series analytics