Reindirizzare HTTP a HTTPS in Nginx: Best Practices
Configura un reindirizzamento affidabile da HTTP a HTTPS in Nginx utilizzando un blocco dedicato sulla porta 80, evita loop di reindirizzamento, scegli il codice di reindirizzamento corretto e aggiungi HSTS quando sei pronto.
Reindirizzare HTTP a HTTPS in Nginx: Best Practices
Reindirizzare HTTP a HTTPS in Nginx garantisce che i visitatori utilizzino la versione crittografata del tuo sito, anche se digitano il vecchio URL http:// o seguono un link obsoleto. Una configurazione di reindirizzamento pulita migliora la sicurezza, evita URL duplicati e offre agli utenti un punto di ingresso coerente.
L'approccio migliore è solitamente semplice: tieni la porta 80 aperta solo il tempo necessario per reindirizzare il traffico e servi il sito reale sulla porta 443 con un certificato TLS valido.
I dettagli contano perché i reindirizzamenti sono facili da realizzare quasi correttamente. Un reindirizzamento che perde il percorso rompe i segnalibri. Un reindirizzamento che preserva il nome host sbagliato può creare URL canonici duplicati. Un reindirizzamento dietro un bilanciatore di carico può andare in loop per sempre se Nginx non capisce dove termina TLS.
Pensa al reindirizzamento come parte della tua API pubblica. Le persone incollano link nelle chat, i motori di ricerca li scansionano, i sistemi di monitoraggio li colpiscono e le vecchie email li mantengono vivi per anni. Se il reindirizzamento è stabile, nessuno se ne accorge. Se è sciatto, gli utenti vedono avvisi di certificato, percorsi interrotti o errori di troppi reindirizzamenti prima ancora che la tua applicazione riceva una richiesta.
Perché i reindirizzamenti HTTPS sono importanti
HTTPS protegge il traffico tra il browser e il tuo server utilizzando la crittografia TLS. Senza di essa, i dati possono essere ispezionati o modificati dalle reti tra l'utente e il tuo sito. Questo è importante per login, moduli, cookie, aree di amministrazione, API e persino per la navigazione ordinaria.
I reindirizzamenti aiutano anche con la coerenza. I motori di ricerca e gli utenti non dovrebbero vedere http://example.com/pagina e https://example.com/pagina come due destinazioni separate. Un reindirizzamento permanente dice ai client che HTTPS è la versione preferita.
Il pattern standard di Nginx è un blocco server dedicato sulla porta 80:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
Poi il tuo blocco server HTTPS gestisce il sito reale:
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /var/www/example.com;
index index.html;
}
La direttiva return 301 è efficiente e chiara. Dice a Nginx di inviare un reindirizzamento permanente senza eseguire elaborazioni aggiuntive sulla posizione. $request_uri preserva il percorso e la stringa di query, quindi /docs?page=2 diventa https://example.com/docs?page=2.
Per una configurazione TLS completa, vedi proteggere Nginx con HTTPS.
Per la maggior parte dei siti, evita di mettere logica applicativa nel blocco della porta 80. Non dovrebbe servire file statici, fare da proxy all'app o contenere un grande insieme di posizioni. Mantienilo semplice:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
Quel piccolo blocco è più facile da controllare e meno incline a discostarsi dalla configurazione HTTPS.
Scegliere tra reindirizzamenti 301 e 302
Usa 301 per un reindirizzamento permanente da HTTP a HTTPS su un sito di produzione. I browser e i motori di ricerca capiscono che l'URL HTTPS dovrebbe sostituire l'URL HTTP.
Usa 302 o 307 solo quando il reindirizzamento è temporaneo. Ad esempio, potresti usare un reindirizzamento temporaneo durante i test prima che i certificati e i nomi host siano definitivi. Una volta che il sito HTTPS è pronto, passa a un reindirizzamento permanente.
Fai attenzione durante la configurazione iniziale. I browser possono memorizzare nella cache i reindirizzamenti 301 in modo aggressivo. Se accidentalmente reindirizzi al nome host sbagliato, il browser potrebbe continuare a usare il reindirizzamento errato anche dopo aver corretto Nginx. Testa con curl, finestre del browser in incognito e nomi host non di produzione quando possibile.
Un flusso di distribuzione pratico è il seguente:
- Conferma che il blocco server HTTPS funzioni direttamente.
- Conferma che il certificato corrisponda a ogni nome host.
- Aggiungi il blocco server di reindirizzamento HTTP.
- Testa diversi percorsi e stringhe di query.
- Cambia i reindirizzamenti temporanei in permanenti solo quando il comportamento è corretto.
Dovresti anche decidere il nome host canonico. Se sia example.com che www.example.com funzionano, scegline uno come nome host pubblico preferito. Altrimenti, gli utenti potrebbero rimbalzare tra nomi host o i motori di ricerca potrebbero indicizzare entrambi.
Ad esempio, per reindirizzare tutto il traffico HTTP al nome host HTTPS non www:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
Questo è diverso da https://$host$request_uri, che preserva il nome host richiesto dall'utente.
Puoi anche separare i reindirizzamenti del nome host dai reindirizzamenti dello schema se vuoi che il comportamento sia esplicito:
server {
listen 80;
server_name www.example.com;
return 301 https://example.com$request_uri;
}
server {
listen 80;
server_name example.com;
return 301 https://example.com$request_uri;
}
Questo è più verboso, ma rende ovvia la destinazione finale. Su un sito piccolo, entrambi gli stili vanno bene. Su un sito più grande con molti alias, blocchi server espliciti possono ridurre la confusione durante le modifiche successive.
Evitare loop di reindirizzamento e problemi di certificato
I loop di reindirizzamento si verificano quando Nginx, un bilanciatore di carico o un'applicazione continuano a inviare una richiesta a un URL che attiva un altro reindirizzamento. Questo è comune quando TLS termina prima di Nginx, ad esempio su un bilanciatore di carico cloud o una CDN.
In una configurazione semplice a server singolo, Nginx riceve HTTPS direttamente, quindi il reindirizzamento è semplice. In una catena di proxy, Nginx potrebbe ricevere HTTP semplice dal bilanciatore di carico anche se l'utente si è connesso con HTTPS. Se la tua applicazione cerca quindi di forzare HTTPS in base allo schema di connessione locale, potrebbe causare un loop.
La soluzione dipende dalla tua architettura. Di solito, il bilanciatore di carico dovrebbe passare intestazioni come X-Forwarded-Proto, e l'applicazione o la configurazione di Nginx dovrebbero fidarsi di esse solo da indirizzi proxy noti.
Ad esempio, se Nginx si trova dietro un bilanciatore di carico fidato e riceve solo HTTP interno, potresti non volere che Nginx reindirizzi ogni richiesta HTTP locale. Invece, il bilanciatore di carico può gestire il reindirizzamento pubblico da HTTP a HTTPS, mentre Nginx serve il traffico dalla rete privata. Se Nginx deve prendere la decisione, ha bisogno di informazioni affidabili sul protocollo inoltrato dal proxy davanti a sé. Non fidarti di X-Forwarded-Proto da client internet arbitrari.
Assicurati anche che i certificati coprano ogni nome host reindirizzato. Se un utente visita http://www.example.com e lo reindirizzi a https://www.example.com, il certificato deve essere valido per www.example.com. Se reindirizzi tutto a https://example.com, il certificato per il sito finale deve coprire example.com.
Testa con:
curl -I http://example.com/some/path?x=1
Cerca:
HTTP/1.1 301 Moved Permanently
Location: https://example.com/some/path?x=1
Poi testa l'URL HTTPS:
curl -I https://example.com/some/path?x=1
La risposta HTTPS dovrebbe restituire lo stato effettivo della pagina, non un altro reindirizzamento a HTTP.
Testa anche entrambi i nomi host se esistono entrambi:
curl -I http://www.example.com/
curl -I https://www.example.com/
curl -I http://example.com/
curl -I https://example.com/
Stai cercando una catena breve e prevedibile. Un reindirizzamento da HTTP all'URL HTTPS canonico è buono. Salti multipli, come HTTP non www a HTTPS non www a HTTPS www e viceversa, sono un segno che Nginx, l'app, le regole CDN o il forwarding a livello DNS stanno combattendo tra loro.
Puoi ispezionare l'intera catena con:
curl -IL http://www.example.com/some/path
Il flag -L segue i reindirizzamenti. In una configurazione pulita, l'output dovrebbe mostrare la risposta HTTP iniziale e poi la risposta HTTPS finale. Se vedi tre o quattro intestazioni Location, semplifica le regole finché non c'è una rotta chiara verso l'URL canonico.
HSTS e altre best practice
Dopo che la tua configurazione HTTPS è stabile, puoi considerare HTTP Strict Transport Security, solitamente chiamato HSTS. HSTS dice ai browser di usare automaticamente HTTPS per le visite future.
Un'intestazione comune è simile a questa:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Non aggiungerla con leggerezza. Se includi i sottodomini, ogni sottodominio deve supportare HTTPS. Se in seguito rompi HTTPS, i browser che hanno visto l'intestazione HSTS potrebbero rifiutarsi di accedere alla versione HTTP. Inizia con un max-age più breve durante i test, poi aumentalo quando sei sicuro.
Altre best practice:
- Mantieni il blocco della porta 80 semplice.
- Preserva percorsi e stringhe di query a meno che tu non abbia un motivo per non farlo.
- Scegli un nome host canonico.
- Testa i reindirizzamenti con
curl, non solo con un browser. - Rinnova i certificati automaticamente e monitora i fallimenti di rinnovo.
- Mantieni la logica di reindirizzamento in Nginx quando possibile invece di duplicarla nell'app.
Regole di reindirizzamento semplici sono più facili da comprendere e meno soggette a rompersi durante le modifiche successive al sito.
Errori comuni
L'errore più comune è usare rewrite per un semplice reindirizzamento:
rewrite ^ https://example.com$request_uri permanent;
Questo può funzionare, ma return 301 ... è più chiaro ed evita elaborazioni di riscrittura aggiuntive. Usa rewrite quando hai veramente bisogno di pattern matching, non per un reindirizzamento di schema di base.
Un altro errore è reindirizzare a $server_name senza capire cosa contiene. $host proviene dall'intestazione host della richiesta, mentre $server_name si basa sul nome server Nginx corrispondente. Per reindirizzamenti canonici, un nome host letterale è spesso l'opzione meno sorprendente:
return 301 https://example.com$request_uri;
Dovresti anche evitare di reindirizzare i percorsi della sfida ACME HTTP se i tuoi strumenti per certificati ne hanno bisogno sulla porta 80. Molte configurazioni di Let's Encrypt gestiscono questo automaticamente, ma le configurazioni personalizzate potrebbero aver bisogno di un'eccezione:
location /.well-known/acme-challenge/ {
root /var/www/letsencrypt;
}
location / {
return 301 https://example.com$request_uri;
}
Aggiungi quell'eccezione solo se il tuo client per certificati la usa. Se i tuoi certificati si rinnovano tramite validazione DNS o un server temporaneo gestito dallo strumento, mantieni il blocco di reindirizzamento semplice.
Un pattern di rollout sicuro
Per un sito di produzione, apporta la modifica per fasi:
- Conferma che il blocco server HTTPS serva il sito correttamente.
- Conferma che il rinnovo del certificato funzioni o sia monitorato.
- Aggiungi un reindirizzamento temporaneo sulla porta 80 se stai ancora testando i nomi host.
- Testa gli URL comuni con
curl -Iecurl -IL. - Passa a
301una volta che la destinazione del reindirizzamento è definitiva. - Aspetta prima di abilitare HSTS a lungo termine.
Quel periodo di attesa è utile. Ti dà il tempo di individuare sottodomini dimenticati, vecchi URL di webhook, link http:// hardcoded o una regola CDN che non era visibile dal tuo primo computer di test.
Tieni anche a mente il monitoraggio. Se il tuo controllo di uptime punta ancora a http://example.com, decidi se dovrebbe aspettarsi un 301 o seguire i reindirizzamenti e controllare la pagina HTTPS finale. Entrambi possono essere validi, ma il monitor dovrebbe corrispondere al comportamento che desideri effettivamente.
Esempio: Sito statico e proxy inverso
Per un sito statico, il blocco HTTPS può essere solo una root di documenti:
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /var/www/example.com;
index index.html;
}
Per un'applicazione dietro Nginx, il blocco di reindirizzamento rimane lo stesso, ma il blocco HTTPS fa da proxy al traffico:
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Il punto importante è la separazione. La porta 80 decide dove deve andare il browser. La porta 443 serve il sito. Mescolare questi compiti rende più difficile comprendere il comportamento del reindirizzamento, specialmente quando viene aggiunto un altro proxy o CDN in seguito.
Dopo la modifica, esegui sempre:
sudo nginx -t
sudo systemctl reload nginx
Se il test fallisce, non ricaricare. Correggi prima l'errore di sintassi, poi testa di nuovo.
Un ultimo controllo vale la pena farlo dall'esterno del server, non solo tramite SSH sull'host. Un firewall, una CDN o un bilanciatore di carico possono cambiare ciò che vedono gli utenti reali. Esegui gli stessi controlli curl -I dal tuo laptop, da una posizione di monitoraggio o da un'istanza cloud temporanea. Se il risultato esterno differisce da localhost, il problema di reindirizzamento è probabilmente nel livello di rete davanti a Nginx, non nel blocco server stesso. Controllalo prima di riscrivere una configurazione funzionante.
Quando chiedere aiuto
Chiedi aiuto a un ingegnere DevOps se il tuo sito si trova dietro una CDN, un bilanciatore di carico cloud, un ingress Kubernetes o più proxy inversi. I reindirizzamenti HTTPS in infrastrutture a strati dipendono da dove termina TLS e da quali intestazioni sono considerate affidabili.
Dovresti anche chiedere aiuto prima di abilitare HSTS a lungo termine su molti sottodomini. Un'impostazione sbagliata può bloccare gli utenti da servizi che non sono pronti per HTTPS.
Reindirizzare HTTP a HTTPS in Nginx è una piccola modifica di configurazione con un grande impatto sulla sicurezza. Usa un blocco di reindirizzamento dedicato sulla porta 80, preserva l'URI della richiesta, verifica i certificati e testa per loop prima di dichiarare completato.