Restricting Access by Geographical Location
Introduction
NGINX and NGINX Plus can differentiate users based on their geographical location. For example, you can have different website content for different countries, or you can restrict content distribution to a particular country or city.
NGINX uses third-party MaxMind databases to match the IP address of the user and its location. As soon as the geoposition is known, it is then possible to use geoip-based variables in the map or the split_clients module.
Restricting by geographical location works both for HTTP and TCP/UDP protocols.
Prerequisites
- NGINX Plus, or open source NGINX with the http geoip and/or stream geoip modules
- Geolite Legacy databases from MaxMind
Configuring GeoIP in NGINX and NGINX Plus
For NGINX Plus:
Install the GeoIP dynamic module for NGINX Plus:
$ apt-get install nginx-plus-module-geoip
Enable the GeoIP dynamic module in the NGINX Plus configuration file with the
load_module
directive specified on themain
configuration level:load_module modules/ngx_http_geoip_module.so; load_module modules/ngx_stream_geoip_module.so;
For open source NGINX:
Make sure your open source NGINX is compiled with the
--with-http_geoip_module
and/or--with-stream_geoip_module
configuration flag:$ nginx -V 2>&1 | grep -- 'http_geoip_module' $ nginx -V 2>&1 | grep -- 'stream_geoip_module'
or make sure that the module is linked dynamically.
Download and unzip legacy Geo Country and City databases from the MaxMind download page:
$ wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz $ wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz $ gunzip GeoIP.dat.gz $ gunzip GeoLiteCity.dat.gz
Add the paths to the databases to the NGINX configuration with the
geoip_country
andgeoip_city
directives for HTTP, TCP/UDP, or both:http { #... geoip_country GeoIP/GeoIP.dat; geoip_city GeoIP/GeoLiteCity.dat; #... } stream { #... geoip_country GeoIP/GeoIP.dat; geoip_city GeoIP/GeoLiteCity.dat; #... }
Use the standard variables from the GeoIP module (HTTP or TCP/UDP) to pass data to the
map
orsplit_clients
directive.For example, using the
$geoip_city_continent_code
variable of thegeoip_city
directive, and themap
module, you can create another variable whose value will be the closest server basing on a continent location:#... map $geoip_city_continent_code $nearest_server { default default {}; EU eu; NA na; AS as; AF af; #...
Then you can choose an upstream server basing on the value passed in the
$nearest_server
variable:#... server { listen 12346; proxy_pass $nearest_server; } upstream eu { server eu1.example.com:12345; server eu2.example.com:12345; } upstream na { server na1.example.com:12345; server na2.example.com:12345; } #...
If the continent is Europe, then the value of the
$nearest_server
will beeu
, and the connection will be passed to theeu
upstream via theproxy_pass
directive.
Complete Example
This example can be applied in both the http
and stream
contexts.
# can be either "http {" or "stream {"
#...
geoip_country GeoIP/GeoIP.dat;
geoip_city GeoIP/GeoLiteCity.dat;
map $geoip_city_continent_code $nearest_server {
default default {};
EU eu;
NA na;
AS as;
AF af;
server {
listen 12346;
proxy_pass $nearest_server;
}
upstream eu {
server eu1.example.com:12345;
server eu2.example.com:12345;
}
upstream na {
server na1.example.com:12345;
server na2.example.com:12345;
}
}
In this example, the IP address will be checked in the GeoLiteCity.dat
database, the result will be written to the $geoip_city_continent_code
variable. NGINX will match the value of the variable against values in the map
directive and white the result in the custom variable, in our example $nearest_server
. Basing on the value of the $nearest_server
, the proxy_pass
directive will choose a corresponding upstream server.