If you’re a web developer, you probably already know what Nginx is. For those who don’t know what it is, Nginx is an open-source web server. Since 2004, developers have been using Nginx for hosting high performance and scalable web applications. Today, millions of websites use Nginx, including websites of companies like Netflix, Dropbox, Airbnb, Box, Tumble, etc.
Nginx is my personal favorite web server, I’ve deployed 100s of web applications in it. Recently, in one of the web applications I built, the client wanted to restrict access to the application based on geography. That is, only grant access to a user if they are from a specific list of countries. And there I stumbled upon a problem with Nginx’s geography-based access restriction feature.
Nginx supported a pretty decent functionality for restricting user access based on geographic locations. It used the GeoIP module, which offers identification of the location of internet users. However, with the recent update of GeoIP module, databases are discontinued and the current version of Nginx doesn’t support it. Even though the current version of Nginx comes with a default GeoIP module, the server cannot access the geolocation data from the module since the updated GeoIP version (GeoIP2) is not prebuilt in it. The module is not available in official Ubuntu repos or their official PPA. So my only option was to build Nginx from source by adding the GeoIP2 module source. It was kinda a long process so I thought to prepare a simple tutorial for it so that the other fellow developers out there who want to do the same can get it done faster.
Backup old Nginx configs
sudo cp /etc/nginx/ /home/ubuntu
Remove old Nginx installation
sudo apt-get remove --purge nginx nginx-common
Download Nginx
wget http://nginx.org/download/nginx-1.16.1.tar.gz
Unzip Nginx Source
tar xvfz nginx-1.16.1.tar.gz
Download GeoIP2 Nginx Module
git clone https://github.com/leev/ngx_http_geoip2_module.git
Install new Geoip mmdb extension support
sudo add-apt-repository ppa:maxmind/ppa sudo apt update sudo apt install libmaxminddb0 libmaxminddb-dev mmdb-bin
Install Dependencies for Building Nginx
sudo apt-get install libpcre3 sudo apt-get install libpcre3-dev sudo apt-get install zlib1g zlib1g-dev libssl-dev sudo apt-get install build-essential
Download Other modules for building Nginx
PCRE version 4.4 – 8.40
wget https://ftp.pcre.org/pub/pcre/pcre-8.40.tar.gz && tar xzvf pcre-8.40.tar.gz
zlib version 1.1.3 – 1.2.11
wget http://www.zlib.net/zlib-1.2.11.tar.gz && tar xzvf zlib-1.2.11.tar.gz
OpenSSL version 1.0.2 – 1.1.0
wget https://www.openssl.org/source/openssl-1.1.0f.tar.gz && tar xzvf openssl-1.1.0f.tar.gz
Install Nginx
cd nginx-1.16.1 ./configure --prefix=/usr/share/nginx \ --sbin-path=/usr/sbin/nginx \ --modules-path=/usr/lib/nginx/modules \ --conf-path=/etc/nginx/nginx.conf \ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log \ --pid-path=/run/nginx.pid \ --lock-path=/var/lock/nginx.lock \ --user=www-data \ --group=www-data \ --build=Ubuntu \ --http-client-body-temp-path=/var/lib/nginx/body \ --http-fastcgi-temp-path=/var/lib/nginx/fastcgi \ --http-proxy-temp-path=/var/lib/nginx/proxy \ --http-scgi-temp-path=/var/lib/nginx/scgi \ --http-uwsgi-temp-path=/var/lib/nginx/uwsgi \ --with-openssl=../openssl-1.1.0f \ --with-openssl-opt=enable-ec_nistp_64_gcc_128 \ --with-openssl-opt=no-nextprotoneg \ --with-openssl-opt=no-weak-ssl-ciphers \ --with-openssl-opt=no-ssl3 \ --with-pcre=../pcre-8.40 \ --with-pcre-opt='-g -Ofast -fPIC -m64 -march=native -fstack-protector-strong -D_FORTIFY_SOURCE=2' \ --with-zlib-opt='-g -Ofast -fPIC -m64 -march=native -fstack-protector-strong -D_FORTIFY_SOURCE=2' \ --with-ld-opt='-lpcre -Wl' \ --with-pcre-jit \ --with-zlib=../zlib-1.2.11 \ --with-compat \ --with-file-aio \ --with-threads \ --with-http_addition_module \ --with-http_auth_request_module \ --with-http_dav_module \ --with-http_flv_module \ --with-http_gunzip_module \ --with-http_gzip_static_module \ --with-http_mp4_module \ --with-http_random_index_module \ --with-http_realip_module \ --with-http_slice_module \ --with-http_ssl_module \ --with-http_sub_module \ --with-http_stub_status_module \ --with-http_v2_module \ --with-http_secure_link_module \ --with-mail \ --with-mail_ssl_module \ --with-stream \ --with-stream_realip_module \ --with-stream_ssl_module \ --with-stream_ssl_preread_module \ --with-debug \ --add-dynamic-module=/home/arun/ngx_http_geoip2_module \ --with-cc-opt='-g -O2 -fPIC -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' \ --with-ld-opt='-Wl,-Bsymbolic-functions -fPIC -pie -Wl,-z,relro -Wl,-z,now'
Note : replace the paths in the configure command, check all lines eg : –add-dynamic-module=/home/arun/ngx_http_geoip2_module \
make make install
Copy the GeoIP2 ” .so ” files from the source directory to
/usr/share/nginx/modules
, here the source dir is home/arun/ngx_http_geoip2_module
Check Installation
sudo nginx -v && sudo nginx -V
check /var/lib/nginx
directory is present if not create one by sudo mkdir /var/lib/nginx
Check syntax and potential errors
sudo nginx -t
Create service file for Nginx
sudo nano /etc/systemd/system/nginx.service
copy – paste the content
[Unit] Description=A high performance web server and a reverse proxy server After=network.target [Service] Type=forking PIDFile=/run/nginx.pid ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;' ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;' ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid TimeoutStopSc=5 KillMode=mixed [Install] WantedBy=multi-user.target
Start the service
sudo systemctl start nginx.service && sudo systemctl enable nginx.service
If sites-available and site enabled directory are missing in /etc/nginx create these directories.
Edit nginx.conf in /etc/nginx and remove the server block code and add include /etc/nginx/sites-enabled/*;
at the very beginning of http block
create a file in sites-available
and make a link of the file to sites-enabled
and check its working
GeoIp2 Config
Edit nginx.conf sudo nano /etc/nginx/nginx.conf
add the content to the very beginning of nginx.conf
file
load_module modules/ngx_http_geoip2_module.so; load_module modules/ngx_stream_geoip2_module.so;
add the content and end of the http
block
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb { auto_reload 60m; $geoip2_metadata_country_build metadata build_epoch; $geoip2_data_country_code country iso_code; $geoip2_data_country_name country names en; } map $geoip2_data_country_code $allowed_country { default yes; US no; ID no; CU no; IQ no; SY no; SO no; KP no; VE no; } geoip2 /usr/share/GeoIP/GeoLite2-City.mmdb { auto_reload 60m; $geoip2_metadata_city_build metadata build_epoch; $geoip2_data_city_name city names en; }
In the Vhost file add the country headers in response headers, this will be helpful in debugging.
to add headers edit vhost file and add the content in the server block.
add_header X-GeoCountry $geoip2_data_country_name; add_header X-GeoCode $geoip2_data_country_code; add_header X-GeoCity $geoip2_data_city_name;
To block the access, add the content in the server block of the Vhost file.
if ($allowed_country = no) { return 406; }
To send a new page instead of error code, add
error_page /blocked.html
Restart Nginx
sudo service nginx restart
For updating Geo IP database add a cron to run geoipupdate command
Install geoipupdate
sudo apt-get install -y geoipupdate
or
get DEB file from https://github.com/maxmind/geoipupdate/releases and install it