Série Nginx #5: Trabalhando com Geolocalização por IP
Tags: nginx, devops, sysadmin, geoip
Published: 2021-09-23 20:00:51

Opa!!! Vamos aprender a configurar nosso primeiro módulo externo. 🤓🤓

Aprenderemos como realizar bloqueio e balancear requisições conforme a região do usuário.

Para realizar o bloqueio por cidade ou país, utilizaremos o módulo [`GeoIP`](https://github.com/leev/ngx_http_geoip2_module).

Caso você não saiba instalar um módulo, acesse o capítulo [Série Nginx #4: Instalando módulos de terceiros](https://dev.to/valdeirpsr/serie-nginx-4-instalando-modulos-de-terceiros-hjh).

> Após instalar o módulo, carregue-o no arquivo de configuração do Nginx.

```bash
echo "load_module modules-available/ngx_http_geoip2_module.so;" \
    | sudo tee -a /etc/nginx/modules-enabled/geoip2.conf
```

------------

## GeoIP2 Databases

Agora é necessário baixar os arquivos `.mmdb`. Eles possuem as configurações e regras necessárias para o módulo. Para isso, acesse o site https://dev.maxmind.com/geoip/geolite2-free-geolocation-data e realize o download. Após baixá-los, extraia em uma pasta como `/etc/nginx/GeoIP2`, por exemplo.

------------

## Configurando o módulo

Para configurar é simples. Iremos carregar o arquivo baixado e criar nossas variáveis que terão os valores de código de país, cidade e/ou continente.

```
http {
    ...

    # Cria variáveis relacionadas ao país de acesso
    #
    geoip2 GeoIP2/GeoLite2-Country.mmdb {
        $geoip2_data_continent_code   default="NU" continent code;
        $geoip2_data_country_iso_code country iso_code;
        $geoip2_metadata_country_build metadata build_epoch;
    }

    # Cria variáveis relacionadas à cidade de acesso
    #
    geoip2 GeoIP2/GeoLite2-City.mmdb {
        $geoip2_data_city_name   city names en;
        $geoip2_data_postal_code postal code;
        $geoip2_data_latitude    location latitude;
        $geoip2_data_longitude   location longitude;
        $geoip2_data_state_name  subdivisions 0 names en;
        $geoip2_data_state_code  subdivisions 0 iso_code;
    }
}
```

Ainda no bloco `http`, criaremos uma variável com a diretiva `map` para definir quais países terão permissão ou não de acesso.

```
http {
    ...

    # Permite apenas países lusófonos
    #
    map $geoip2_data_country_code $country_blocked {
        default 1;

        AO 0;
        BR 0;
        CV 0;
        GW 0;
        MZ 0;
        PT 0;
        ST 0;
        TL 0;
        GQ 0;
    }
}
```

> Permite todos os países que possua o valor "0" tenham permissão de acesso.

No contexto `server`, definiremos nossa condição.

```
server {
    server_name valdeir.dev;

    if ($country_blocked) {
        return 403;
    }
}
```

Reincie o Nginx e faça o teste.

```
nginx -s reload
```

------------

## Load Balancer

Além de bloqueios, podemos usar o módulo de *GeoIP2* para criar um *load balancer* por país ou continente, por exemplo.

```
upstream all {
    server default1.valdeir.dev:8080;
    server default2.valdeir.dev:8080;
}

upstream eu {
    server eu1.example.com:8080;
    server eu2.example.com:8080;
}

upstream as {
    server as1.example.com:8080;
    server as2.example.com:8080;
}

http {
    geoip2 GeoIP2/GeoLite2-Country.mmdb {
        $geoip2_data_continent_code continent code;
    }

    map $geoip2_data_continent_code $nearest_server {
        default all;

        EU      eu;
        AS      as;
    }

    server {
        listen 80;
        proxy_pass http://$nearest_server;
    }
}
```

------------

## Conclusão

Parabéns! Concluímos mais uma etapa. Caso tenha dúvidas ou sugestões, só deixar nos comentários.