# Nginx GeoIP Not Working
GeoIP should block countries, route based on location, or show region-specific content. Instead, $geoip_country_code is empty, country blocks don't work, or all requests come from the same detected country. GeoIP functionality depends on module availability, database configuration, and correct usage.
Introduction
This article covers troubleshooting steps and solutions for How to Fix Nginx GeoIP Not Working. The error typically occurs in production environments and can cause service disruptions if not addressed promptly.
Symptoms
Common error messages include:
nginx -V 2>&1 | grep -o geoip
# Should show: --with-http_geoip_module```bash # Check if module is compiled nginx -V 2>&1 | grep geoip
# Check installed modules (some distributions use dynamic modules) ls /etc/nginx/modules/ ls /usr/lib/nginx/modules/
# Check if module is loaded grep -r "load_module" /etc/nginx/nginx.conf ```
# In nginx.conf main context
load_module modules/ngx_http_geoip_module.so;Common Causes
- Configuration misconfiguration
- Missing or incorrect credentials
- Network connectivity issues
- Version compatibility problems
- Resource exhaustion or limits
- Permission or access denied
Step-by-Step Fix
- 1.Check logs for specific error messages
- 2.Verify configuration settings
- 3.Test network connectivity
- 4.Review recent changes
- 5.Apply corrective action
- 6.Verify the fix
Understanding Nginx GeoIP
- 1.Nginx GeoIP requires:
- 2.GeoIP module compiled into Nginx (
ngx_http_geoip_module) - 3.MaxMind GeoIP database files
- 4.
geoip_countryorgeoip_citydirective - 5.Variables like
$geoip_country_code
Check module availability:
``bash
nginx -V 2>&1 | grep -o geoip
# Should show: --with-http_geoip_module
If missing, you need to recompile Nginx with the module or install the package version that includes it.
Common Cause 1: Module Not Compiled/Installed
The GeoIP module isn't available in your Nginx build.
Diagnosis: ```bash # Check if module is compiled nginx -V 2>&1 | grep geoip
# Check installed modules (some distributions use dynamic modules) ls /etc/nginx/modules/ ls /usr/lib/nginx/modules/
# Check if module is loaded grep -r "load_module" /etc/nginx/nginx.conf ```
Solution:
For dynamic modules:
``nginx
# In nginx.conf main context
load_module modules/ngx_http_geoip_module.so;
For missing module: ```bash # Ubuntu/Debian - install extra modules sudo apt install libnginx-mod-http-geoip
# Or install full nginx sudo apt install nginx-full
# CentOS/RHEL sudo yum install nginx-module-geoip ```
For source compilation:
``bash
./configure --with-http_geoip_module
make
sudo make install
Common Cause 2: GeoIP Database Not Configured
The database path isn't set or the database file doesn't exist.
Problematic config:
``nginx
http {
geoip_country GeoIP.dat; # Where is this file?
}
Diagnosis: ```bash # Check if database exists ls -la /usr/share/GeoIP/
# Common locations ls -la /var/lib/GeoIP/ ls -la /usr/local/share/GeoIP/
# Check Nginx config for database path grep -r "geoip" /etc/nginx/ ```
Solution: Specify full path: ```nginx http { geoip_country /usr/share/GeoIP/GeoIP.dat;
# For city data geoip_city /usr/share/GeoIP/GeoLiteCity.dat; } ```
Common Cause 3: GeoIP Database Missing or Outdated
The database files don't exist or are too old.
Diagnosis: ```bash # Check database files ls -la /usr/share/GeoIP/
# Check database age stat /usr/share/GeoIP/GeoIP.dat
# Test database with geoiplookup geoiplookup 8.8.8.8 ```
Solution: Install GeoIP database: ```bash # Ubuntu/Debian sudo apt install geoip-bin geoip-database
# CentOS/RHEL sudo yum install geoip geoip-data
# Download from MaxMind (GeoLite2 requires free account) wget https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.tar.gz tar xzf GeoLite2-Country.tar.gz sudo mv GeoLite2-Country.mmdb /usr/share/GeoIP/ ```
Note: GeoIP Legacy is deprecated. Use GeoIP2 for current data.
Common Cause 4: Using GeoIP2 with Legacy Module
The GeoIP module only supports legacy database format, not GeoIP2/MMDB.
Problem:
``nginx
# Legacy module
geoip_country /usr/share/GeoIP/GeoLite2-Country.mmdb;
# This won't work - .mmdb format requires different module
Solution: Use GeoIP2 module: ```bash # Install geoip2 module sudo apt install libnginx-mod-http-geoip2
# Or compile with geoip2 ./configure --add-dynamic-module=/path/to/ngx_http_geoip2_module ```
```nginx # Load module load_module modules/ngx_http_geoip2_module.so;
http { geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb { $geoip2_country_code country iso_code; $geoip2_country_name country names en; } } ```
Common Cause 5: GeoIP Variables Empty
Variables like $geoip_country_code return empty values.
Diagnosis: ```bash # Add header to see value curl -H "X-Forwarded-For: 8.8.8.8" http://localhost/test | grep Country
# Or in Nginx config add_header X-Country $geoip_country_code; ```
Common causes:
- 1.Database not loaded:
- 2.```bash
- 3.sudo nginx -t
- 4.# Should not show "geoip_country" errors
- 5.
` - 6.IP is private (not in database):
- 7.Private IPs (192.168.x.x, 10.x.x.x) have no country.
# Log to see detected IP
add_header X-Detected-IP $remote_addr;- 1.Behind proxy, real IP not detected:
- 2.```nginx
- 3.# Use real IP from header
- 4.set_real_ip_from 10.0.0.0/8;
- 5.real_ip_header X-Forwarded-For;
geoip_country /usr/share/GeoIP/GeoIP.dat; ```
- 1.Module variables changed:
- 2.GeoIP2 uses different variable names:
- 3.```nginx
- 4.geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
- 5.$geoip_country_code country iso_code; # Not $geoip_country_code
- 6.}
- 7.
`
Common Cause 6: Country Blocking Not Working
Country-based blocks don't apply.
Problematic config: ```nginx http { geoip_country GeoIP.dat;
# Block specific countries if ($geoip_country_code = CN) { return 403; } } ```
Problems:
- if directive issues in Nginx
- Variable might be empty
- Country code format (CN vs cn)
Solution: Use geo/map for blocking: ```nginx http { geoip_country /usr/share/GeoIP/GeoIP.dat;
# Define blocked countries geo $blocked_country { default 0; CN 1; RU 1; KP 1; }
map $geoip_country_code $block_request { default 0; CN 1; RU 1; KP 1; }
server { location / { if ($block_request) { return 403; }
add_header X-Country $geoip_country_code always; } } } ```
Better approach using map: ```nginx http { geoip_country /usr/share/GeoIP/GeoIP.dat;
map $geoip_country_code $allowed { default yes; CN no; RU no; }
server { location / { if ($allowed = no) { return 403 "Country blocked"; } } } } ```
Common Cause 7: GeoIP City Not Working
City-level detection returns empty values.
Diagnosis: ```nginx http { geoip_city /usr/share/GeoIP/GeoLiteCity.dat;
server { location /test { add_header X-City $geoip_city; add_header X-Region $geoip_region; add_header X-Country $geoip_city_country_code; return 200; } } } ```
curl -H "X-Forwarded-For: 8.8.8.8" -I http://localhost/test- 1.Causes:
- 2.Database file doesn't exist
- 3.Using country database instead of city database
- 4.IP doesn't have city-level resolution
- 5.GeoIP2 uses different variable mapping
GeoIP2 city configuration:
``nginx
geoip2 /usr/share/GeoIP/GeoLite2-City.mmdb {
$geoip2_city city names en;
$geoip2_region subdivisions 0 iso_code;
$geoip2_country country iso_code;
$geoip2_latitude location latitude;
$geoip2_longitude location longitude;
}
Common Cause 8: GeoIP Behind CDN/Proxy
All requests appear from same CDN IP.
Problem:
``nginx
geoip_country GeoIP.dat;
# $remote_addr is CDN IP, not user IP
Solution: Use real IP module: ```nginx # Set trusted proxies set_real_ip_from 103.21.244.0/22; # Cloudflare set_real_ip_from 103.22.200.0/22; set_real_ip_from 173.245.48.0/20; # Add all CDN/proxy IPs
real_ip_header CF-Connecting-IP; # Cloudflare # or real_ip_header X-Forwarded-For;
real_ip_recursive on;
geoip_country /usr/share/GeoIP/GeoIP.dat; ```
Now $remote_addr contains the user's real IP.
Verification
- 1.Check module:
- 2.```bash
- 3.nginx -V 2>&1 | grep geoip
- 4.
` - 5.Check database:
- 6.```bash
- 7.ls -la /usr/share/GeoIP/
- 8.
` - 9.Test GeoIP lookup:
- 10.```nginx
- 11.location /geoip-test {
- 12.add_header X-Country $geoip_country_code;
- 13.return 200;
- 14.}
- 15.
`
```bash curl -H "X-Forwarded-For: 8.8.8.8" -I http://localhost/geoip-test # Should show X-Country: US
curl -H "X-Forwarded-For: 1.1.1.1" -I http://localhost/geoip-test # Should show X-Country: AU ```
- 1.Check Nginx configuration:
- 2.```bash
- 3.sudo nginx -t
- 4.
` - 5.Monitor logs:
- 6.```nginx
- 7.log_format geo '$remote_addr - $geoip_country_code [$time_local]';
- 8.access_log /var/log/nginx/geo.log geo;
- 9.
`
Complete Working Configuration
```nginx load_module modules/ngx_http_geoip2_module.so;
http { geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb { $geoip_country_code country iso_code; $geoip_country_name country names en; }
geoip2 /usr/share/GeoIP/GeoLite2-City.mmdb { $geoip_city city names en; $geoip_region subdivisions 0 names en; $geoip_latitude location latitude; $geoip_longitude location longitude; }
# Trust CDN/proxy IPs set_real_ip_from 10.0.0.0/8; set_real_ip_from 172.16.0.0/12; set_real_ip_from 192.168.0.0/16; real_ip_header X-Forwarded-For; real_ip_recursive on;
# Country blocking map $geoip_country_code $blocked { default 0; CN 1; RU 1; }
# Geographic routing map $geoip_country_code $backend { default backend-eu; US backend-us; CA backend-us; GB backend-eu; DE backend-eu; }
upstream backend-eu { server eu.example.com; }
upstream backend-us { server us.example.com; }
server { location / { if ($blocked) { return 403 "Country blocked"; }
add_header X-Country $geoip_country_code always; proxy_pass http://$backend; } } } ```
Verification
| Issue | Cause | Fix |
|---|---|---|
| Variables empty | Module not loaded | Install/load module |
| Variables empty | Database missing | Install GeoIP database |
| Wrong country | Behind proxy | Configure real_ip_header |
| City not detected | City database missing | Install city database |
| mmdb not working | Legacy module | Use geoip2 module |
| Block not working | Empty variable | Use map for blocking |
| All same country | Private IPs only | Test with public IP |
GeoIP requires module, database, and correct configuration chain. Start by verifying the module is loaded and database exists, then test with known public IPs.
Related Articles
- [Nginx troubleshooting: Fix Lambda Permission Denied - Complete ](fix-lambda-permission-denied)
- [Nginx web server troubleshooting: Fix Client Max Body Size Large Upload Nginx Issue ](client-max-body-size-large-upload-nginx)
- [Fix Apache 502 Proxy Error](fix-apache-502-proxy-error)
- [Fix Apache LogLevel Core Debug Configuration](fix-apache-loglevel-core-debug)
- [Fix Cloudflare 502 Bad Gateway Error](fix-cloudflare-502-bad-gateway)
<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "TechArticle", "headline": "How to Fix Nginx GeoIP Not Working", "description": "Troubleshoot Nginx GeoIP module issues. Fix GeoIP database loading, country blocking, and geographic routing configuration.", "url": "https://www.fixwikihub.com/fix-nginx-geoip-not-working", "publisher": { "@type": "Organization", "name": "FixWikiHub", "url": "https://www.fixwikihub.com" }, "author": { "@type": "Person", "name": "FixWikiHub Editorial Team" }, "datePublished": "2025-11-28T01:07:47.474Z", "dateModified": "2025-11-28T01:07:47.474Z" } </script>