Permite cifrar con un proxy inverso nginx

45

Introducción

Tengo un servidor de desarrollo (que actualmente ejecuta Ubuntu 14.04 LTS), que he estado usando durante un tiempo para alojar varias herramientas de desarrollo en diferentes puertos. Debido a que los puertos pueden ser difíciles de recordar, he decidido usar el puerto 80 para todos mis servicios y hacer el reenvío de puertos internamente, basado en el nombre de host.

En lugar de escribir domain.com:5432, simplemente puedo acceder a él a través de sub.domain.com

Por ejemplo, la aplicación X, que usa el puerto 7547 y se ejecuta en sub.domain.com tiene la siguiente configuración nginx:

upstream sub {
    server 127.0.0.1:7547;
}

server {
    listen 80;
    server_name sub.domain.com www.sub.domain.com;
    access_log /var/log/nginx/sub.log combined;
    location / {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://127.0.0.1:7547;
            proxy_set_header Authorization "";
    }
}

La pregunta

Dada la estructura de configuración actual, que he elegido, ¿es posible usar letsencrypt y ejecutar los diferentes servicios en https?

0x450
fuente
3
Escribí una publicación de blog sobre este tema: tom.busby.ninja/letsecnrypt-nginx-reverse-proxy-no-downtime
Tom Busby

Respuestas:

81

Sí, puede tener solicitudes de proxy nginx para servidores HTTP y luego responder a los clientes a través de HTTPS. Al hacer esto, querrás asegurarte de que el nginx <-> proxy connect no sea rastreado por quien sea tu atacante esperado. Los enfoques suficientemente seguros pueden incluir:

  • proxy al mismo host (como tú)
  • proxy a otros hosts detrás de su firewall

Proxing a otro host en Internet público es poco probable que sea lo suficientemente seguro.

Aquí hay instrucciones para obtener un certificado Let's Encrypt utilizando el mismo servidor web que está utilizando como proxy.

Solicitando su certificado inicial de Let's Encrypt

Modifique su servercláusula para permitir que el subdirectorio .well-knownse sirva desde un directorio local, por ejemplo:

server {
    listen 80;
    server_name sub.domain.com www.sub.domain.com;
    […]
    location /.well-known {
            alias /var/www/sub.domain.com/.well-known;
    }

    location / {
        # proxy commands go here
        […]
    }
}

http://sub.domain.com/.well-known es donde los servidores Let's Encrypt buscarán las respuestas a los desafíos que plantea.

Luego puede usar el cliente certbot para solicitar un certificado de Let's Encrypt usando el complemento webroot (como root):

certbot certonly --webroot -w /var/www/sub.domain.com/ -d sub.domain.com -d www.sub.domain.com

Su clave, certificado y cadena de certificados ahora se instalarán en /etc/letsencrypt/live/sub.domain.com/

Configurando nginx para usar su certificado

Primero cree una nueva cláusula de servidor como esta:

server {
    listen 443 ssl;

    # if you wish, you can use the below line for listen instead
    # which enables HTTP/2
    # requires nginx version >= 1.9.5
    # listen 443 ssl http2;

    server_name sub.domain.com www.sub.domain.com;

    ssl_certificate /etc/letsencrypt/live/sub.domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sub.domain.com/privkey.pem;

    # Turn on OCSP stapling as recommended at 
    # https://community.letsencrypt.org/t/integration-guide/13123 
    # requires nginx version >= 1.3.7
    ssl_stapling on;
    ssl_stapling_verify on;

    # Uncomment this line only after testing in browsers,
    # as it commits you to continuing to serve your site over HTTPS
    # in future
    # add_header Strict-Transport-Security "max-age=31536000";

    access_log /var/log/nginx/sub.log combined;

    # maintain the .well-known directory alias for renewals
    location /.well-known {
        alias /var/www/sub.domain.com/.well-known;
    }

    location / {
        # proxy commands go here as in your port 80 configuration
        […]
    }
}

Recargar nginx:

service nginx reload

Verifique que HTTPS ahora funcione visitando https://sub.domain.comy https://www.sub.domain.comen su navegador (y cualquier otro navegador que desee admitir específicamente) y verificando que no reporten errores de certificado.

Recomendado: también revise raymii.org: Seguridad SSL fuerte en nginx y pruebe su configuración en SSL Labs .

(Recomendado) Redirigir solicitudes HTTP a HTTPS

Una vez que haya confirmado que su sitio funciona con la https://versión de la URL, en lugar de que algunos usuarios hayan servido contenido inseguro porque fueron http://sub.domain.com, rediríjalos a la versión HTTPS del sitio.

Reemplace toda su servercláusula port 80 con:

server {
    listen 80;
    server_name sub.domain.com www.sub.domain.com;
    rewrite     ^   https://$host$request_uri? permanent;
}

Ahora también debería descomentar esta línea en la configuración del puerto 443, para que los navegadores recuerden ni siquiera probar la versión HTTP del sitio:

add_header Strict-Transport-Security "max-age=31536000";

Renovar automáticamente su certificado

Puede usar este comando (como root) para renovar todos los certificados conocidos por certbot y volver a cargar nginx usando el nuevo certificado (que tendrá la misma ruta que su certificado existente):

certbot renew --renew-hook "service nginx reload"

certbot solo intentará renovar los certificados que tengan más de 60 días de antigüedad, por lo que es seguro (¡y recomendado!) ejecutar este comando de manera muy regular y automática si es posible. Por ejemplo, podría poner el siguiente comando en /etc/crontab:

# at 4:47am/pm, renew all Let's Encrypt certificates over 60 days old
47 4,16   * * *   root   certbot renew --quiet --renew-hook "service nginx reload"

Puede probar las renovaciones con una ejecución en seco, que se pondrá en contacto con los servidores de ensayo Let's Encrypt para hacer una prueba real de contactar su dominio, pero no almacenará los certificados resultantes:

certbot --dry-run renew

O puede forzar una renovación anticipada con:

certbot renew --force-renew --renew-hook "service nginx reload"

Nota: puede ejecutar en seco tantas veces como desee, pero las renovaciones reales están sujetas a los límites de velocidad de Let's Encrypt .

perplejidad
fuente
Tu solución no parece funcionar para mí. Básicamente tengo la misma configuración. Funciona para goopen.tk, pero no www.goopen.tk
Alko
3
@Alko, las instrucciones de la respuesta son correctas y cubren este problema. Al usar certboto cualquier otra herramienta, no puede olvidar especificar su dominio en formato www y no www para que funcione.
Paulo Coghi - Restablece a Monica el
Debajo location /.well-known, debes dejarlo .well-knownen el camino. Uso alias /var/www/sub.domain.com, noalias /var/www/sub.domain.com/.well-known
gldraphael
1
¿Alguien puede explicarme por qué desea utilizar "rewrite ^ https: // $ host $ request_uri? Permanent;" aquí en lugar de "return 301 https: // $ server_name $ request_uri;"
ZaxLofful
Descubrí que necesitaba citas alrededor de la ruta en la ubicación. location '/.well-known' {. No estoy seguro si esto es una versión o solo mi configuración, pero en caso de que alguien más esté atascado.
Frank V
2

Sí, puede usar nginxcomo punto final de https y cooperar con backends a través de http. Por ejemplo mi config:

server {
        server_name host;
        listen 443 ssl;
...
 location /svn/ {
            auth_ldap off;

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_pass http://localhost:1080/svn/;
            proxy_redirect http://localhost:1080/ https://host/;
        }
...
}

Pero como sé, con el cifrado, debe apuntar todos los subdominios cuando obtenga el certificado, y si esto es un problema, entonces elige url en https://host/servicelugar dehttps://service.host

fghj
fuente