Docker, Nginx e Letsencrypt

Docker, Nginx e Letsencrypt: Proxy reverso fácil e seguro

Introdução
Já tentou configurar algum tipo de servidor em casa? Ter que abrir uma nova porta para cada serviço? Tendo que se lembrar de qual porta vai para qual serviço, e lembrando do seu ip de casa? Isso é definitivamente algo que funciona, e as pessoas estão fazendo isso há muito tempo.

No entanto, não seria interessante digitar plex.example.com e ter acesso instantâneo ao seu servidor de mídia? Isso é exatamente o que um proxy reverso fará por você e, combinando-o ao Docker, é mais fácil do que nunca.

Pré-requisitos
Docker e Docker-Compose
Você deve ter o Docker versão 17.12.0+ e Compose versão 1.21.0+.

Domínio
Você deve ter um domínio configurado e ter um certificado SSL associado a ele. Se você não tiver um, siga o meu guia aqui, sobre como obter um gratuito com o LetsEncrypt.

O que esta capa de artigo
Acredito firmemente em entender o que você está fazendo. Houve um tempo em que eu seguiria os guias e não tenho nenhuma pista sobre como solucionar falhas. Se é assim que você quer fazer isso, aqui está um ótimo tutorial, que aborda como configurá-lo. Embora meus artigos sejam longos, você deve entender como tudo funciona.

O que você aprenderá aqui é o que é um proxy reverso, como configurá-lo e como você pode protegê-lo. Eu faço o meu melhor para dividir o assunto em seções, divididas por cabeçalhos, então fique à vontade para pular uma seção, se você quiser. Eu recomendo ler o artigo inteiro uma vez antes de começar a configurá-lo.

O que é um proxy reverso
Proxy Regular
Vamos começar com o conceito de um proxy regular. Embora esse seja um termo muito predominante na comunidade de tecnologia, não é o único lugar usado. Um proxy significa que a informação está passando por um terceiro, antes de chegar ao local.

Digamos que você não quer que um serviço conheça seu IP, você pode usar um proxy. Um proxy é um servidor que foi configurado especificamente para esse propósito. Se o servidor proxy que você está usando estiver localizado, por exemplo, em Amsterdã, o IP que será exibido para o mundo externo será o IP do servidor em Amsterdã. Os únicos que saberão o seu IP são aqueles que controlam o servidor proxy.

Procuração reversa
Para dividi-lo em termos simples, um proxy adicionará uma camada de mascaramento. É o mesmo conceito em um proxy reverso, exceto que em vez de mascarar conexões de saída (você acessando um servidor da Web), são as conexões de entrada (pessoas que acessam seu servidor da Web) que serão mascaradas. Você simplesmente fornece um URL como example.com, e sempre que as pessoas acessarem esse URL, seu proxy reverso cuidará de onde o pedido vai.

Digamos que você tenha dois servidores configurados em sua rede interna. O servidor1 está em 192.168.1.10 e o servidor2 está em 192.168.1.20. Neste momento, seu proxy reverso está enviando solicitações provenientes de example.com para o Server1. Um dia você tem algumas atualizações na página da web. Em vez de baixar o site para manutenção, basta fazer a nova configuração no Server2. Uma que você fez, simplesmente altere uma única linha em seu proxy reverso e agora as solicitações são enviadas para o Servidor2. Supondo que o proxy reverso esteja configurado corretamente, você não deve ter absolutamente nenhum tempo de inatividade.

Mas talvez a maior vantagem de ter um proxy reverso, é que você pode ter serviços em execução em uma infinidade de portas, mas você só tem que abrir as portas 80 e 443, HTTP e HTTPS, respectivamente. Todos os pedidos entrarão em sua rede nessas duas portas e o proxy reverso cuidará do resto. Tudo isso fará sentido quando começarmos a configurar o proxy.

Configurando o contêiner
O que fazer

Primeiro de tudo, você deve adicionar um novo serviço ao seu arquivo de composição do docker. Você pode chamar o que preferir, neste caso eu optei por reverter. Aqui, acabei de escolher o nginx como imagem, mas em um ambiente de produção, geralmente é uma boa ideia especificar uma versão, caso haja alguma alteração significativa em futuras atualizações.

Então você deve ligar o volume de duas pastas. / etc / nginx é onde todos os seus arquivos de configuração são armazenados, e / etc / ssl / private é onde seus certificados SSL são armazenados. É muito importante que sua pasta de configuração NÃO exista em seu host pela primeira vez em que você inicia o contêiner. Ao iniciar seu contêiner através do docker-compose, ele criará automaticamente a pasta e a preencherá com o conteúdo do contêiner. Se você criou uma pasta de configuração vazia em seu host, ela será montada e a pasta dentro do contêiner estará vazia.

Por que funciona
Não há muito a esta parte. Principalmente, é como iniciar qualquer outro contêiner com o docker-compose. O que você deve notar aqui é que você está ligando as portas 80 e 443. É onde todas as solicitações chegam e são encaminhadas para qualquer serviço que você especificar.

Configurando o Nginx
O que fazer
Agora você deve ter uma pasta de configuração no seu host. Mudando para esse diretório, você deve ver um monte de arquivos diferentes, e uma pasta chamada conf.d. É dentro conf.d que todos os seus arquivos de configuração serão colocados. No momento, há um único arquivo default.conf, você pode excluir isso.

Ainda dentro conf.d, crie duas pastas: sites disponíveis e sites habilitados. Navegue até os sites disponíveis e crie seu primeiro arquivo de configuração. Aqui, vamos configurar uma entrada para o Plex, mas fique à vontade para usar outro serviço que você configurou, se quiser. Não importa qual o nome do arquivo, no entanto, prefiro nomear como plex.conf.

Agora abra o arquivo e digite o seguinte:

Vá para o diretório habilitado para sites e insira o seguinte comando:

ln -s ../sites-available/plex.conf.
Isto irá criar um link simbólico para o arquivo na outra pasta. Agora resta apenas uma coisa, que é alterar o arquivo nginx.conf na pasta de configuração. Se você abrir o arquivo, deverá ver o seguinte como a última linha:

inclua /etc/nginx/conf.d/*.conf;
Altere isso para:

inclua /etc/nginx/conf.d/sites-enabled/*.conf;
Para que o proxy reverso funcione, precisamos recarregar o serviço nginx dentro do contêiner. No host, execute o docker exec <nome do contêiner> nginx -t. Isto irá executar um verificador de sintaxe contra seus arquivos de configuração. Isso deve resultar que a sintaxe está ok. Agora execute o docker exec <nome do contêiner> nginx -s reload. Isso enviará um sinal para o processo nginx que deve ser recarregado e parabéns! Agora você tem um proxy reverso em execução e deve poder acessar seu servidor em plex.example.com (supondo que você tenha encaminhado a porta 80 para seu host em seu roteador).

Mesmo que seu proxy reverso esteja funcionando, você está executando em HTTP, que não fornece nenhuma criptografia. A próxima parte será como proteger seu proxy e obter uma pontuação perfeita no SSL Labs.

Por que funciona
O arquivo de configuração

Como você pode ver, o arquivo plex.conf consiste em duas partes. Uma parte upstream e uma parte do servidor. Vamos começar com a parte do servidor. É aqui que você está definindo a porta que recebe as solicitações recebidas, qual domínio essa configuração deve corresponder e para onde ela deve ser enviada.

A maneira como este servidor está sendo configurado, você deve criar um arquivo para cada serviço para o qual deseja fazer solicitações de proxy, portanto, obviamente, você precisa distinguir qual arquivo receberá cada solicitação. Isso é o que a diretiva server-name faz. Abaixo disso, temos a diretiva de localização.

No nosso caso, precisamos apenas de um local, mas você pode ter quantas diretivas de local desejar. Imagine que você tenha um site com um frontend e um backend. Dependendo da infraestrutura que você está usando, você terá o frontend como um contêiner e o back-end como outro contêiner. Você pode então ter a localização / {} que enviará solicitações ao frontend e a localização / api / {} que enviará solicitações para o back-end. De repente, você tem vários serviços em execução em um único domínio memorável.

Quanto à parte a montante, isso pode ser usado para balanceamento de carga. Se você tiver interesse em saber mais sobre como isso funciona, consulte os documentos oficiais aqui. Para nosso caso simples, basta definir o nome do host ou endereço IP do serviço para o qual você deseja fazer proxy e a que porta deve-se fazer o proxy e, em seguida, consultar o nome do upstream na diretiva location.

Nome do host vs. Endereço de IP

Para entender o que é um nome de host, vamos fazer um exemplo. Digamos que você esteja na sua rede doméstica 192.168.1.0. Em seguida, você configura um servidor no 192.168.1.10 e executa o Plex nele. Agora você pode acessar o Plex em 192.168.1.10:32400, contanto que você ainda esteja na mesma rede. Outra possibilidade é dar ao servidor um nome de host. Nesse caso, forneceremos o nome do host plex. Agora você pode acessar o Plex inserindo o plex: 32400 no seu navegador!

Esse mesmo conceito foi introduzido no componente de janela de encaixe na versão 3. Se você observar o documento de composição do docker neste artigo, perceberá que dei a ele um nome de host: reverse directive. Agora todos os outros contêineres podem acessar meu proxy reverso por seu nome de host. Uma coisa que é muito importante notar é que o nome do serviço tem que ser o mesmo que o nome do host. Isso é algo que os criadores do docker-compose decidiram impor.

Outra coisa importante a lembrar é que, por padrão, os contêineres do docker são colocados em sua própria rede. Isso significa que você não poderá acessar seu contêiner pelo nome do host, se estiver sentado em seu laptop em sua rede host. São apenas os contêineres que podem acessar um ao outro por meio de seu nome de host.

Então, para resumir e deixar bem claro. Em seu arquivo de composição do docker, inclua a diretiva hostname em seus serviços. Na maioria das vezes, seus contêineres receberão um novo IP toda vez que você reiniciar o contêiner. Portanto, fazer referência a ele por meio do nome do host significa que não importa qual IP seu contêiner está obtendo.

Sites disponíveis e sites habilitados

Por que estamos criando os diretórios disponíveis para sites e habilitados para sites? Isso não é algo da minha criação. Se você instalar o Nginx em um servidor, verá que ele vem com essas pastas. No entanto, como o Docker é construído com microservices em mente, em que um contêiner deve fazer apenas uma coisa, essas pastas são omitidas no contêiner. Estamos recriando-os novamente, porque estamos usando o contêiner.

E sim, você poderia definitivamente apenas criar uma pasta habilitada para sites ou hospedar diretamente seus arquivos de configuração em conf.d. Fazendo desta forma, permite que você tenha configuração passiva por aí. Digamos que você está fazendo manutenção e não deseja que o serviço esteja ativo. basta remover o link simbólico e colocá-lo novamente quando quiser que o serviço seja ativado novamente.

Links Simbólicos

Os links simbólicos são um recurso muito poderoso do sistema operacional. Eu pessoalmente nunca os usei antes de configurar um servidor Nginx, mas desde então eu os tenho usado em todos os lugares que posso. Digamos que você esteja trabalhando em 5 projetos diferentes, mas todos esses projetos usam o mesmo arquivo de alguma forma. Você pode copiar o arquivo em cada projeto e consultá-lo diretamente, ou pode colocar o arquivo em um lugar e nesses 5 projetos criar links simbólicos para esse arquivo.

Isso dá duas vantagens: você ocupa 4 vezes menos espaço do que teria, e então o mais poderoso de todos; mude o arquivo em um lugar, e ele muda em todos os 5 projetos de uma só vez! Isso foi um pouco estranho, mas acho que vale a pena mencionar.

Protegendo o proxy Nginx
O que fazer
Vá para a sua pasta de configuração e crie 3 arquivos: ssl.conf common.conf common_location.conf. Preencha com a seguinte entrada:

Agora abra o arquivo plex.conf e altere-o para o seguinte (observe as linhas 2, 6, 9, 10 e 14):

Agora volte para a raiz da pasta de configuração e execute o seguinte comando:

openssl dhparam -out dhparams.pem 4096
Isso levará muito tempo para ser concluído; até uma hora em alguns casos.

Se você seguiu meu artigo sobre como obter um certificado SSL do LetsEncrypt, seus certificados devem estar localizados em </ path / to / your / letsencrypt / config> / etc / letsencrypt / live / <domain> /. Quando ajudei um amigo a configurar isso em seu sistema, tivemos alguns problemas em que não pudemos abrir os arquivos quando eles estavam localizados nesse diretório. Provavelmente a causa de alguns problemas de permissão. As soluções fáceis para isso são criar um diretório SSL, como </ path / to / your / nginx / config> / certs, e montá-lo na pasta / etc / ssl / private do contêiner Nginx. Na pasta recém-criada, você deve criar links simbólicos para os certificados na pasta de configuração do LetsEncrypt.

Quando o comando openssl for executado, você deverá executar o docker exec <nome do contêiner> nginx -t para certificar-se de que toda a sintaxe esteja correta e, em seguida, recarregá-la executando o docker exec <nome do contêiner> nginx -s reload. Neste ponto tudo deve estar rodando, e agora você tem um proxy reverso funcional e perfeitamente seguro!

Por que funciona
Olhando no arquivo plex.conf, há apenas uma alteração importante, e é a porta na qual o proxy reverso está escutando e informando que é uma conexão ssl. Então, há três lugares em que estamos incluindo os outros três arquivos que fizemos. Embora o SSL obviamente seja seguro por si só, esses outros arquivos o tornam ainda mais seguro. No entanto, se por algum motivo você não quiser incluir esses arquivos, será necessário mover o certificado ssl e a chave ssl-certificate dentro do arquivo .conf. Eles precisam ter, para que uma conexão HTTPS funcione.

Common.conf

Olhando no arquivo common.conf, adicionamos 4 cabeçalhos diferentes. Cabeçalhos são algo que o servidor envia ao navegador em todas as respostas. Esses cabeçalhos dizem ao navegador para agir de uma determinada maneira, e cabe então ao navegador impor esses cabeçalhos.

Estrito-Transporte-Segurança (HSTS)

Este cabeçalho informa ao navegador que as conexões devem ser feitas via HTTPS. Quando esse cabeçalho é adicionado, o navegador não permite que você estabeleça uma conexão HTTP simples com o servidor, garantindo que toda a comunicação seja segura.

Opções X-Frame

Ao especificar este cabeçalho, você está especificando se outros sites podem ou não incorporar seu conteúdo em seus sites. Isso pode ajudar a evitar ataques de clickjacking.

X-Content-Type-Options

Digamos que você tenha um site onde os usuários possam fazer upload de arquivos. Não há validação suficiente nos arquivos, portanto, um usuário carrega com êxito um arquivo php no servidor, no qual o servidor espera que uma imagem seja carregada. O atacante pode então acessar o arquivo enviado. Agora, o servidor responde com uma imagem, no entanto, o tipo MIME do arquivo é text / plain. O navegador “farejará” o arquivo e, em seguida, renderizará o script php, permitindo que o invasor execute o RCE (Execução Remota de Código).

Com esse cabeçalho definido como “nosniff”, o navegador não examinará o arquivo e simplesmente o processará como o que o servidor informar ao navegador.

Proteção X-XSS

Embora esse cabeçalho fosse mais necessário em navegadores mais antigos, é tão fácil adicionar que você também pode. Alguns ataques XSS (Cross-site Scripting) podem ser muito inteligentes, alguns são muito rudimentares. Este cabeçalho dirá aos navegadores para procurar as vulnerabilidades simples e bloqueá-las.

Common_location.conf

X-Real-IP

Como seus servidores estão atrás de um proxy reverso, se você tentar observar o IP solicitante, sempre verá o IP do proxy reverso. Este cabeçalho é adicionado para que você possa ver qual IP está realmente solicitando seu serviço.

X-Forwarded-For

Às vezes, uma solicitação de usuários passa por vários clientes antes de chegar ao seu servidor. Este cabeçalho inclui uma matriz de todos esses clientes.

X-Forwarded-Proto

Este cabeçalho mostrará qual protocolo está sendo usado entre o cliente e o servidor.

Hospedeiro

Isso garante que seja possível fazer uma pesquisa reversa de DNS no nome do domínio. É usado quando a diretiva server_name é diferente da que você está usando como proxy.

Host X-encaminhado

Mostra qual é o host real da solicitação em vez do proxy reverso.

X-Forwarded-Port

Ajuda a identificar em qual porta o cliente solicitou o servidor.

Ssl.conf

SSL é um tópico enorme por si só, e grande demais para começar a explicar neste artigo. Há muitos ótimos tutoriais sobre como os handshakes SSL funcionam e assim por diante. Se você quiser olhar para este arquivo específico, sugiro que veja os protocolos e cifras que estão sendo usados ​​e que diferença eles fazem.

Redirecionando HTTP para HTTPS
Os observantes talvez tenham notado que estamos apenas ouvindo na porta 443 nesta versão segura. Isso significaria que qualquer pessoa que tentasse acessar o site por meio de https: // * conseguiria, mas tentar se conectar por meio de http: // * seria apenas um erro. Felizmente, há uma solução realmente fácil para isso. Faça um arquivo com o seguinte conteúdo:

Agora, certifique-se de que apareça em sua pasta habilitada para sites e, ao recarregar o processo Nginx no contêiner, todas as solicitações para a porta 80 serão redirecionadas para a porta 443 (HTTPS).

Pensamentos finais
Agora que seu site está em funcionamento, você pode acessar o SSL Labs e executar um teste para ver a segurança do seu site. No momento de escrever isso, você deve obter uma pontuação perfeita. No entanto, há uma grande coisa a notar sobre isso.

Sempre haverá um equilíbrio entre segurança e conveniência. Neste caso, os pesos estão fortemente do lado da segurança. Se você realizar o teste no SSL Labs e rolar para baixo, verá que há vários dispositivos que não podem se conectar ao seu site, porque eles não são compatíveis com o novo padrão.

Então, tenha isso em mente quando você estiver configurando isso. No momento, estou apenas executando um servidor em casa, onde não preciso me preocupar com o fato de muitas pessoas poderem acessá-lo, mas se você fizer uma varredura no Facebook, verá que elas não terão um ótimo desempenho. pontuação, no entanto o seu site pode ser acessado por mais dispositivos.