A aplicação atrás de um proxy: os cabeçalhos que faltam
A aplicação corre em localhost:3000, o Nginx trata do domínio e do certificado, e tudo parece bem — até ao dia em que os endereços que ela gera saem com http://0.0.0.0:3000, e todos os visitantes ficam com o mesmo IP no registo.
O motivo é sempre o mesmo: a aplicação vê o proxy, não vê quem visita.
1. O que o proxy tem de contar
location / {
proxy_pass http://127.0.0.1:3000;
# O domínio que a pessoa escreveu
proxy_set_header Host $host;
# Quem é, do outro lado
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# http ou https — sem isto a aplicação julga-se em http
proxy_set_header X-Forwarded-Proto $scheme;
}2. E a aplicação tem de acreditar
Nenhuma framework confia nesses cabeçalhos por omissão, e faz bem: qualquer pessoa os pode inventar num pedido direto. É preciso dizer explicitamente que há um proxy à frente.
// Express
app.set('trust proxy', 1); // 1 = um proxy à frente, e é o único em quem confioSe confiar sem ter proxy nenhum, dá a qualquer visitante a possibilidade de dizer qual é o seu IP — e com isso furar limites de pedidos e falsificar registos.
3. Sockets e ligações longas
# Sem isto, WebSockets e Server-Sent Events não passam
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# E o proxy corta a ligação ao fim de 60 segundos por omissão
proxy_read_timeout 3600s;4. Quando os endereços saem errados na mesma
Há aplicações que constroem endereços absolutos — redirecionamentos de autenticação, links em emails. Quando o cabeçalho não chega como elas esperam, caem para o que o processo conhece: o endereço onde ele escuta dentro do contentor.
A solução não é adivinhar: é dizer-lhe qual é o endereço público.
AUTH_URL=https://exemplo.pt
PUBLIC_URL=https://exemplo.ptÉ uma variável que parece redundante enquanto tudo funciona — e é a primeira a verificar quando um redirecionamento sai com o endereço interno.