A veces queremos restringir el acceso a una web o una carpeta sólo a ciertas ips, pero nos encontramos con el problema de que esas ips son de conexiones a internet con ips dinámicas como la típica que podemos tener en casa o en el móvil.

Lo primero que hay que hacer es asociar esas ips a un servicio de dns dinámico como el que da dyndns, noip, duckdns o freedns

Una vez que ya tenemos el servicio de dns dinámico instalado en el ordenador o conexión a internet que vamos a usar tenemos que crear un script en el servidor para sacar esa ip. algo así:

vim /scripts/ips_dinamicas_nginx.sh
#!/bin/bash
echo "Allow "$(dig +short rastreador.duckdns.org)";" > /etc/nginx/sites-available/ips_dynamicas.conf

De esta forma cada vez que se ejecute este scrip nos guardará en /etc/nginx/sites-available/ips_dynamicas.conf «Allow nuestra_ip;»

La asignamos permisos de ejecución:

chmod 755 /scripts/ips_dinamicas_nginx.sh

Añadimos este script al cron para que se ejecute cada 5 minutos

*/5 * * * * /scripts/ips_dinamicas_nginx.sh

Y sólo nos queda añadir el fichero donde damos acceso a nuestra ip al location correspondiente

location / {
        include /etc/nginx/sites-available/ips_dynamicas.conf; 
        deny all; #denegamos el acceso al resto de ips
}

Hace poco se dio el caso de que necesité tener bajo un mismo dominio 2 entornos: uno para el público en general y otro para que los programadores pudieran probar la nueva web sobre el mismo dominio.

La forma mas sencilla es tener las dos webs en dos rutas diferentes y asignar el root en función de una variable.

set $ruta_root  "/ruta_de/midominio.com/httpdocs";
 
if ($remote_addr ~* "xx.xx.xx.xx|yy.yy.yy.yy") {
  set $ruta_root  "/ruta_de/midominio.com/httpdocs_desarrollo";
}
root $ruta_root;

Esto mismo se puede hacer en otros muchos casos, por ejemplo si queremos que todas las visitas de un bot muestren otra web:

set $ruta_root  "/ruta_de/midominio.com/httpdocs";
if ($http_user_agent ~ "Indy Library") {
  set $ruta_root  "/ruta_de/midominio.com/httpdocs_desarrollo";
}
root $ruta_root;

O también mostrar otra web a los visitantes de un país o zona geográfica con el módulo de geopip.

set $ruta_root  "/ruta_de/midominio.com/httpdocs";
if ($geoip_city_country_code = "RU") {
  set $ruta_root  "/ruta_de/midominio.com/httpdocs_desarrollo";
}
root $ruta_root;

Andrey_Photos / Pixabay

Nginx tiene un módulo llamado geoip que geolocaliza las ips de los visitantes de la web y asigna a unas variables los valores de la geolocalización, desde lo mas básico como el país hasta la ciudad, el código postal o incluso la latitud y longitud asignadas a esa ip.

Hay que remarcar que para geolocalizar las ips usa las bases de datos de maxmind, concretamente la versión GeoIP1. Desgraciadamente maxmind ya no tiene disponible gratuitamente esa versión de la base de datos, sólo tienen gratis las versiones nuevas que usan el formato GeoIP2 que no es compatible con el módulo que viene por defecto con nginx.

Desde maxmind avisan de que si deseas usar la versión GeoIP1 la puedes descargar con la versión de pago aunque no la van a mantener eternamente.

Probablemente lo más lógico sea usar la nueva versión pero eso implica recompilar nginx y no siempre es posible o recomendable. En kenkogeek.com tenéis una guía estupenda de como hacerlo, también tienes información mas concreta en la página del módulo geoip2. Si usáis nginx plus podéis añadir este módulo de forma dinámica

Si optáis por usar la versión antigua de la base de datos o si simplemente queréis actualizar la base de datos que ya estáis utilizando se puede pasar del formato GeoIP1 a GeopIP2 muy fácilmente con el script GeoIP_convert-v2-v1

Los pasos son muy sencillos:

git clone https://github.com/emphazer/GeoIP_convert-v2-v1
cd GeoIP_convert-v2-v1
chmod +x geoip_convert-v2-v1.sh
 
./geoip_convert-v2-v1.sh CustomName

Este script al final te genera el fichero GeoIP.dat que ya puedes usar directamente desde nginx. Te recomiendo echarle un ojo al script porque instala un par de programas para hacer la conversión.

Una vez que tienes el fichero GeoIP.dat solo tienes que copiarlo a un directorio y configurar el nginx para que lo use. Sólo hay que añadir la siguiente línea al fichero nginx.conf:

geoip_country /etc/nginx/geoip/GeoIP.dat;

Este fichero te proporciona las siguientes variables que puedes usar en la configuración de los dominios:

  • $geoip_country_code – Código de dos letras con país: RU, ES, US, etc.
  • $geoip_country_code3 – Código de tres letras del país: RUS, ESP, USA, etc.
  • $geoip_country_name – El nombre completo del pais: Russian Federation, Spain, United States, etc.

 

Si quieres comprobar que la instalación es correcta puedes añadir las variables a las cabeceras de la petición:

add_header  X-geoip_country_code $geoip_country_code always;
add_header  X-geoip_country_code3 $geoip_country_code3 always;
add_header  X-geoip_country_name $geoip_country_name always;

y con un curl -I https://dominio.com podrás verlos.

 

Si has dejado de usar AMP desactivando el plugin de wordpress es muy probable que te aumenten en número de páginas con 404 en Google Search Console por todas las urls que tenías indexadas acabadas en /amp/

La forma mas cómoda de solucionarlo es hacer una redirección 301 en el nginx:

    # Redirigir las páginas de AMP a normales
    rewrite ^/(.*)/amp $scheme://$http_host/$1/ permanent;

Si necesitamos proteger una web o un directorio de una web con nginx sólo hay que seguir estos 2 pasos:

 

Generar un fichero con el usuario y clave

Si ya tenemos un fichero de usuarios clave de apache lo podemos reutilizar en nginx, pero si lo tenemos que crear hay dos formas de hacerlo:

En el ejemplo crearemos el fichero de claves en /etc/nginx/.htpasswd

Usando el comando de apache2-utils htpasswd

sudo htpasswd -c /etc/nginx/.htpasswd usuario

con openssl

echo -n "usuario:" >> /etc/nginx/.htpasswd
openssl passwd -apr1 >> /etc/nginx/.htpasswd

de esta forma nos quedará algo así en el fichero

test2:$apr1$o4Lmm4.x$joXl8SfzA2tYPVtRQPTtF0

Configurar nginx

Sólo tenemos añadir al location que queremos proteger dos líneas:
auth_basic «acceso prohibido»; para indicar que vamos a usar usuario y contraseña para ese location
auth_basic_user_file /etc/nginx/.htpasswd; para decirle donde está el fichero con el usuario y contraseña

Por ejemplo para proteger el acceso a un wordpress:

location / {
	auth_basic "acceso prohibido";
	auth_basic_user_file /etc/nginx/.htpasswd;
 
	try_files $uri $uri/ /index.php?q=$uri&$args;
}

Hace un tiempo tuvimos que cambiar la estructura de permalinks de wordpress del formato http://dominio/año/mes/contenido a http://dominio/contenido y decidimos hacer que el nginx hiciera un 301 del formato viejo al nuevo.

Es algo tan sencillo como esto:

rewrite "^/[\d]{4}/[\d]{2}/(.*)\/$" /$1/ permanent;

Espero que os sea útil.

nginx
Acabo de ver esta entrada «evitar hotlinking mediante nginx» en el blog de systemadmin.es y me ha recordado una anécdota similar con la que tuve que lidiar hace un tiempo.

Revisando los logs de un un acortador de urls con yourls me encontré una barbaridad de enlaces desde un foro que redirigían a imágenes con contenido porno, y la verdad es que ni ese era el objetivo del acortador ni me apetecía regalar ancho de banda (por poco que sea) a esas cosas, así que aprovechando la versatilidad que da nginx hice que todas las peticiones de ese foro se redirigieran a otra foto un pelín diferente.

if ($http_referer ~* (foro_malo_malo)) {
        #return 403;
        return 301 http://www.photogallery.va/content/dam/photogallery/franciscus/06612_19052013.jpg/_jcr_content/renditions/cq5dam.web.800.800.jpeg;
}

La verdad es que me estuve riendo un buen rato pensando en la cara que le quedaría al chaval que esperaba encontrarse una alegre moza con poca ropa y que de pronto se encuentra a este buen señor con esa cara de cachondeo. 🙂

Al principio había puesto un «return 403;» pero noté que la gente veía el error, recargaba la url del acortador y ya le redirigía a la página de destino correctamente.