Permite criptografar com um proxy reverso nginx


45

Introdução

Eu tenho um servidor de desenvolvimento (atualmente executando o Ubuntu 14.04 LTS), que venho usando há algum tempo para hospedar várias ferramentas de desenvolvimento em portas diferentes. Como as portas podem ser difíceis de lembrar, decidi usar a porta 80 para todos os meus serviços e fazer o encaminhamento de portas internamente, com base no nome do host.

Em vez de escrever domain.com:5432, eu posso simplesmente acessá-lo através de sub.domain.com

Por exemplo, o aplicativo X, que está usando a porta 7547 e está sendo executado no sub.domínio.com, tem a seguinte configuração 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 "";
    }
}

A questão

Dada a estrutura de configuração atual, que eu escolhi, é possível usar o letsencrypt e executar os diferentes serviços em https?


Respostas:


81

Sim, você pode ter solicitações de proxy nginx para servidores HTTP e, em seguida, responder aos clientes por HTTPS. Ao fazer isso, você deve ter certeza de que é improvável que o nginx <-> proxy connect seja detectado por quem quer que seja o invasor esperado. As abordagens suficientemente seguras podem incluir:

  • proxy no mesmo host (como você faz)
  • proxy para outros hosts atrás do seu firewall

É improvável que o proxy para outro host na Internet pública seja suficientemente seguro.

Aqui estão as instruções para obter um certificado Let's Encrypt usando o mesmo servidor da web que você está usando como proxy.

Solicitando seu certificado inicial do Let's Encrypt

Modifique sua servercláusula para permitir que o subdiretório .well-knownseja atendido a partir de um diretório local, por exemplo:

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 é onde os servidores do Let's Encrypt procurarão as respostas para os desafios que apresentam.

Em seguida, você pode usar o cliente certbot para solicitar um certificado do Let's Encrypt usando o plugin webroot (como root):

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

Sua chave, certificado e cadeia de certificados agora serão instalados no /etc/letsencrypt/live/sub.domain.com/

Configurando o nginx para usar seu certificado

Primeiro, crie uma nova 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
        […]
    }
}

Recarregar nginx:

service nginx reload

Verifique se o HTTPS agora funciona visitando https://sub.domain.come https://www.sub.domain.comno seu navegador (e em qualquer outro navegador que você deseja oferecer suporte especificamente) e verificando se eles não reportam erros de certificado.

Recomendado: verifique também raymii.org: forte segurança SSL no nginx e teste sua configuração no SSL Labs .

(Recomendado) Redirecionar solicitações HTTP para HTTPS

Depois de confirmar que seu site funciona com a https://versão do URL, em vez de alguns usuários exibirem conteúdo inseguro porque eles foram http://sub.domain.com, redirecione-os para a versão HTTPS do site.

Substitua toda a servercláusula da porta 80 por:

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

Agora você também deve descomentar esta linha na configuração da porta 443, para que os navegadores lembrem-se de nem tentar a versão HTTP do site:

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

Renovar automaticamente seu certificado

Você pode usar este comando (como root) para renovar todos os certificados conhecidos pelo certbot e recarregar o nginx usando o novo certificado (que terá o mesmo caminho que o seu certificado existente):

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

O certbot apenas tentará renovar os certificados com mais de 60 dias, portanto, é seguro (e recomendado!) executar este comando com muita regularidade e automaticamente, se possível. Por exemplo, você pode colocar o seguinte comando em /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"

Você pode testar renovações com uma execução a seco, que entrará em contato com os servidores de teste Let's Encrypt para fazer um teste real de contato com seu domínio, mas não armazenará os certificados resultantes:

certbot --dry-run renew

Ou você pode forçar uma renovação antecipada com:

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

Nota: você pode executar a seco quantas vezes quiser, mas as renovações reais estão sujeitas aos limites da taxa Let's Encrypt .


Seu solução parece não funcionar para mim. Eu tenho basicamente a mesma configuração. Funciona para o goopen.tk, mas não no www.goopen.tk
Alko

3
@Alko, as instruções da resposta estão corretas e cobrem esse problema. Ao usar certbotou qualquer outra ferramenta, você não pode esquecer de especificar seu domínio no formato www e não www para funcionar.
Paulo Coghi - Restabelece Monica 15/16

Abaixo location /.well-known, você precisa deixar de .well-knownfora o caminho. Use alias /var/www/sub.domain.com, nãoalias /var/www/sub.domain.com/.well-known
gldraphael

1
Alguém pode me explicar por que você gostaria de usar "reescrever ^ https: // $ host $ request_uri? Permanente;" aqui em vez de "retornar 301 https: // $ server_name $ request_uri;"
ZaxLofful

Descobri que precisava de aspas ao redor do caminho no local. location '/.well-known' {. Não tenho certeza se isso é uma versão ou apenas a minha configuração, mas no caso de alguém estar preso.
Frank V

2

Sim, você pode usar nginxcomo ponto final de https e cooperar com os back-end via http. Por exemplo, minha configuração:

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/;
        }
...
}

Mas como eu sei, com vamos criptografar, você precisa apontar todos os subdomínios ao obter o certificado e, se isso for um problema, você escolhe o URL em https://host/servicevez dehttps://service.host

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.