Block Some Countries from visiting my website

October 16, 2014 8.1k views

I'm currently using NginX on my Server and i want to block some countries from visiting my website. Can anyone help me please?

1 comment
  • If your nginx compiled with http_geoip_module (you can check executing /usr/local/nginx/sbin/nginx -V or where ever you have binary) then:

    1. Install geoip database. That package provide you also monthly update of database

    sudo apt-get install geoip-database-contrib -y

    1. Include into your http block following:
        geoip_country /usr/share/GeoIP/GeoIP.dat;
        map $geoip_country_code $allowed_country {
            default yes;
            RU no;
        }
        geo $exclusions {
            default 0;
            10.8.0.0/24 1;
        }
    
    1. Include in your server block following:
            if ($allowed_country = yes) {
                    set $exclusions 1;
            }
            if ($exclusions = "0") {
                    return 444;
            }
    

    That's it

3 Answers

With Nginx, this can be accomplished using the GeoIP module. First, you'll need to make sure that you have the GeoIP database installed:

sudo apt-get install geoip-database libgeoip1

Then in your Nginx configuration, you can add the list of countries to block using the two letter country code:

        geoip_country /usr/share/GeoIP/GeoIP.dat;
        map $geoip_country_code $allow_visit {
           default yes;
           US no;
        }

This must be outside of a server block, usually in /etc/nginx/nginx.conf. Next, you need to specify what should happen to the blocked countries. This is done inside of your server block, usually /etc/nginx/sites-enabled/default :

        if ($allow_visit = no) {
            return 403;
        }

This example gives them a 403 error, but you can create a custom error page or redirect them off site as well using standard Nginx directives.

  • I apologize for the stupid question, but I'm trying to do your final step by adding to "/etc/nginx/sites-enabled/default", but it's showing "default" to be a shortcut/folder and not an editable file. What am I missing?

    Also, in the snippet above that, you have "US no". This would block US traffic, correct? If I wanted to block China, for example, I would simply change this to "CN no", correct?

  • @daniel5e2386056 The file /etc/nginx/sites-enabled/default is usually symlinked from /etc/nginx/sites-available/default

    In the example, I am blocking the US. You could use any other country code there.

  • I carefully followed your directions and ran this first:

    sudo apt-get install geoip-database libgeoip1
    

    Then added this to my /etc/nginx/nginx.conf file within the http block:

    ##
    # exclude non-english # 
    ## 
    
    geoip_country /usr/share/GeoIP/GeoIP.dat;
    map $geoip_country_code $allow_visit { 
    default no; 
    UK yes;
    US yes;
    UM yes;
    VG yes;
    VI yes;
    ES yes;
    PT yes;
    NZ yes;
    IE yes;
    GB yes;
    CA yes;
    AU yes;
    BZ yes;
    BM yes;
    DE yes;
    MX yes;
    AS yes;
    }
    
    

    When I tried restarting nginx I got this:

    sudo service nginx restart

    • Restarting nginx nginx nginx: [emerg] unknown directive "geoip_country" in /etc/nginx/nginx.conf:83 nginx: configuration file /etc/nginx/nginx.conf test failed

    Do I need an include or something to enable this directive?

    • I ran a list nginx command: (--with-httpgeoipmodule=dynamic is included)

      nginx version: nginx/1.9.15                                                                                                                                                             
      built by gcc 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.1)                                                                                                                                      
      built with OpenSSL 1.0.1f 6 Jan 2014                                                                                                                                                    
      TLS SNI support enabled                                                                                                                                                                 
      configure arguments: --prefix=/etc/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=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=
      /var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp -
      -user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_
      mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_reque
      st_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_geoip_module=dynamic --with-http_perl_module=dynamic --add-dynamic-module=debian/extra/njs
      -1c50334fbea6/nginx --with-threads --with-stream --with-stream_ssl_module --with-http_slice_module --with-mail --with-mail_ssl_module --with-file-aio --with-ipv6 --with-http_v2_module 
      --with-cc-opt='-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,--a
      s-needed' 
      
      • The line in the nginx -V result shows the "--with-httpgeoipmodule" value but includes the appendage: "=dynamic":

        --with-http_geoip_module=dynamic
        

        Does this need to be in the configure arguments as

        --with-http_geoip_module
        

        instead? Would it help to make this change and recompile nginx?

        I added these to the nginx.conf within the http block--

        ### SET FASTCGI Variables ###
        fastcgiparam GEOIPCOUNTRYCODE $geoipcountrycode;
        fastcgi
        param GEOIPCOUNTRYCODE3 $geoipcountrycode3;
        fastcgiparam GEOIPCOUNTRYNAME $geoipcountry_name;

        Didn't help.

        The nginx docs show that the geoipcountry is the correct syntax and I have the latest GeoIP.dat file and the nginx -V command shows that I have the configure argument: --with-httpgeoipmodule=dynamic installed. nginx still refuses to recognize the geoipcountry directive.

        No matter what I have tried I get this when I try to restart nginx--

        nginx: [emerg] unknown directive "geoip_country" in /etc/nginx/nginx.conf
        
        • What version of Nginx are you using and how did you install it? If you have dynamic modules, it sounds like you are probably using version 1.9.11 or higher. In these versions, there is the ability to load modules dynamically at run time rather than when compiling (see this blog post for more info).

          In that case, you'll need to load it in your Nginx configuration like so:

          load_module "modules/ngx_http_geoip_module.so";
          
          • Hello asb and thanks for responding!
            where do I put the load module line?

            I put it in my /etc/nginx/nginx.conf in the http block and it returned

            nginx: [emerg] "load_module" directive is not allowed here in /etc/nginx/nginx.conf:12     
            

            Here are my nginx ubuntu versions---

            nginx version: nginx/1.9.15                                                                                                                                                             
            built by gcc 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.1)                                                                                                                                      
            built with OpenSSL 1.0.1f 6 Jan 2014  
            

            I don't have a /nginx/module/ directory and a locate search for "ngxhttpgeoip_module.so" didn't return anything. It would seem that my nginx install was incomplete or this directory has been moved or renamed.

          • @infof3ce3f99958 According to the Nginx docs, the context is "main." So that would mean outside of any blocks, usually just at the top of the main configuration file.

          • I put the load module line at the top of the nginx.conf file....got the same error.

            I don't have a /nginx/module/ directory and a locate search for "ngxhttpgeoip_module.so" didn't return anything. It would seem that my nginx install was incomplete or this directory has been moved or renamed.

          • Apparently the /etc/nginx/module is a symbiotic link, so maybe I do have the ngxhttpgeoip_module.so file somewhere but I don't see it and the locate command doesn't find it.

          • @infof3ce3f99958 After some further investigation, it looks like the upstream Nginx "mainline" repository packages things a bit different than when using Ubuntu's. You'll also need to run: sudo apt-get install nginx-module-geoip

          • Thanks asb, this was the secret sauce--

            sudo apt-get install nginx-module-geoip
            

            after this ran everything started working! The exclude countries function works perfectly.

Have another answer? Share your knowledge.