Un sito senza HTTPS oggi viene segnalato come “non sicuro” da ogni browser, perde posizioni su Google e rischia il blocco di API e webhook che richiedono una connessione cifrata. La buona notizia è che ottenere un certificato SSL valido non costa più nulla e non richiede competenze da amministratore di sistema esperto. Con Let’s Encrypt e Certbot si passa da un dominio in chiaro a una configurazione TLS 1.3 completa, con rinnovo automatico, in meno di un’ora.

In questa guida configuriamo un certificato SSL gratuito con Let’s Encrypt, lo installiamo su Nginx, attiviamo TLS 1.3, HSTS e OCSP stapling, e automatizziamo il rinnovo così da non doverci pensare più. Copriamo anche i certificati wildcard, l’hardening avanzato delle cipher suite, la protezione della chiave privata e gli errori più comuni che fanno fallire la validazione proprio all’ultimo passaggio. Il procedimento è pensato per un server Ubuntu con Nginx, ma le stesse logiche valgono per Apache o per un reverse proxy dietro Docker.

Il problema non è solo estetico. Chrome e Firefox mostrano un avviso esplicito “Non sicuro” nella barra degli indirizzi per ogni pagina HTTP che raccoglie dati, i form di login o pagamento su siti senza HTTPS vengono bloccati o segnalati in modo ancora più aggressivo, e Google usa HTTPS come segnale di ranking da anni. Se gestisci anche solo un piccolo sito aziendale, un blog o un’API interna, il certificato SSL non è più un dettaglio tecnico opzionale: è la base minima perché il sito venga considerato affidabile, sia dai browser che dai motori di ricerca.

Perché Let’s Encrypt e Certbot restano la scelta giusta nel 2026

Let’s Encrypt è una Certificate Authority non profit gestita dall’Internet Security Research Group, nata per rendere HTTPS lo standard di fatto del web. Il progetto emette certificati tramite il protocollo ACME, lo stesso standard che oggi usano quasi tutti i tool di automazione: Certbot, acme.sh, Caddy, Traefik. Non serve inserire una carta di credito né rinnovare manualmente ogni anno: il certificato dura 90 giorni e si rinnova con un comando, o automaticamente, prima della scadenza.

Let’s Encrypt non è l’unica Certificate Authority gratuita sul mercato: se vuoi confrontarla con alternative come ZeroSSL o Buypass prima di scegliere, abbiamo già messo a confronto le tre CA gratuite più usate. In questa guida restiamo su Let’s Encrypt perché è quella con il supporto più ampio tra i tool di automazione, Certbot incluso.

Due novità rendono il 2026 un anno di svolta per chi gestisce certificati SSL. Dal 15 gennaio 2026 Let’s Encrypt ha reso generalmente disponibili i certificati short-lived da 160 ore, poco più di sei giorni, pensati per chi vuole ridurre la finestra di rischio in caso di compromissione della chiave privata, e i certificati per indirizzi IP, sia IPv4 che IPv6, utili per servizi che non hanno ancora un nome di dominio stabile. Nessuno dei due formati è obbligatorio: il certificato standard da 90 giorni resta la configurazione predefinita e quella che useremo in questa guida.

Sul lato client, Certbot resta il tool di riferimento per Linux: è mantenuto dalla Electronic Frontier Foundation, ha un plugin dedicato per Nginx e Apache che scrive la configurazione TLS per noi, e con la versione 4.0 ha anche cambiato la logica di rinnovo, passando da un rinnovo fisso a 30 giorni dalla scadenza a un rinnovo dinamico quando resta un terzo della vita del certificato, o metà se il certificato dura meno di 10 giorni, come nel caso dei nuovi certificati short-lived.

Il protocollo alla base di tutto si chiama ACME, Automatic Certificate Management Environment, uno standard aperto definito dalla IETF. ACME definisce come un client (Certbot, nel nostro caso) dialoga con il server della Certificate Authority per dimostrare il controllo su un dominio e ottenere un certificato, senza intervento umano diretto durante lo scambio. È proprio questa automazione end-to-end, dalla richiesta alla validazione fino al rinnovo, a rendere possibile gestire centinaia di domini con un singolo cron job, qualcosa che con le autorità di certificazione tradizionali, basate su validazione manuale via email o documenti, sarebbe semplicemente impensabile alla stessa scala.

Prerequisiti: cosa serve prima di iniziare

Prima di lanciare il primo comando, verifica di avere questi elementi pronti. La tabella seguente riassume versioni e requisiti minimi testati per questa guida.

ComponenteVersione consigliataNote
Sistema operativoUbuntu 24.04 LTS o 26.04 LTSLe istruzioni valgono anche su Debian 12/13 con comandi apt equivalenti
Nginx1.24 o superiore (mainline 1.31.6)Serve il modulo ngx_http_ssl_module, incluso di default
Certbot5.8.0 (ultima stabile)Installato via snap, non via pip, per evitare conflitti di dipendenze
OpenSSL3.0.x minimo, ideale 3.6.5Richiesto per TLS 1.3 e le cipher suite moderne
Accesso al serverUtente con sudo o rootCertbot deve scrivere in /etc/letsencrypt e riavviare Nginx
DNS del dominioRecord A/AAAA già propagatoDeve puntare all’IP pubblico del server prima della validazione
Porte firewall80/TCP e 443/TCP aperteLa porta 80 serve anche solo per la validazione HTTP-01

Non ti serve altro: niente carta di credito, niente account a pagamento, niente verifica via email con scadenza. L’unico vincolo reale è che il dominio risolva correttamente verso il server prima di chiedere il certificato, altrimenti la validazione fallisce. Torniamo su questo errore più avanti, nella sezione dedicata al troubleshooting. Se lavori su un server condiviso con un pannello come cPanel o Plesk, controlla anche se il pannello gestisce già i certificati per conto tuo: in quel caso rischi di avere due client ACME che si contendono lo stesso dominio, con risultati imprevedibili sul rinnovo.

Passo 1: scegliere il metodo di validazione, HTTP-01 o DNS-01

Prima di installare qualsiasi cosa, decidi come Let’s Encrypt verificherà che tu controlli davvero il dominio. Esistono due metodi principali supportati da Certbot, e la scelta cambia il resto della procedura.

MetodoCome funzionaQuando usarlo
HTTP-01Certbot pubblica un file temporaneo su /.well-known/acme-challenge/ che Let’s Encrypt scarica via porta 80Server singolo con porta 80 pubblica, nessun certificato wildcard necessario
DNS-01Certbot crea un record TXT temporaneo sul DNS del dominio, verificato via query DNSCertificati wildcard, server dietro NAT o firewall senza porta 80 esposta, provider DNS con API

Per un singolo sito su un singolo server, HTTP-01 è più semplice e non richiede nessuna configurazione extra: lo useremo nei primi passaggi. Quando arriveremo ai certificati wildcard, passeremo a DNS-01, perché Let’s Encrypt non emette certificati wildcard con la validazione HTTP-01.

Passo 2: installare Certbot e il plugin per Nginx

Il modo più affidabile per installare Certbot su Ubuntu e Debian è tramite snap, come raccomandato dalla stessa documentazione EFF: i pacchetti delle distribuzioni spesso restano indietro rispetto alle release ufficiali e possono creare conflitti di dipendenze con la libreria ACME.

sudo apt update
sudo apt install -y snapd
sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -sf /snap/bin/certbot /usr/bin/certbot
certbot --version

Se preferisci evitare snap, in alternativa puoi installare il pacchetto python3-certbot-nginx tramite apt, ma verifica sempre la versione con certbot –version: su alcune distribuzioni stabili può essere più vecchia di diverse minor release rispetto all’ultima pubblicata su GitHub. A questo punto apri anche le porte necessarie sul firewall, se non lo hai già fatto:

Plugin automatico o solo richiesta del certificato?

Certbot offre due modalità operative distinte, ed è utile sapere quale userai prima di procedere. Il comando certbot –nginx (o –apache) usa il plugin dedicato al web server: ottiene il certificato e modifica automaticamente i file di configurazione per attivarlo, inclusi i redirect da HTTP a HTTPS. Il comando certbot certonly, invece, scarica solo il certificato nelle cartelle /etc/letsencrypt/live, senza toccare la configurazione del web server: è la scelta giusta quando usi un reverse proxy non supportato nativamente, un bilanciatore di carico, o quando vuoi gestire tu stesso i blocchi server con un controllo più fine, come faremo più avanti per i certificati wildcard.

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw status

Verifica anche che il DNS del tuo dominio punti già al server, con un comando rapido come dig tuodominio.it A oppure nslookup tuodominio.it. Se il record non è ancora propagato, aspetta prima di procedere: una richiesta fallita per DNS non propagato conta comunque ai fini dei rate limit settimanali di Let’s Encrypt.

Passo 3: richiedere il primo certificato SSL

Con Certbot installato e Nginx già attivo sulla porta 80 con il tuo sito, il comando più semplice è certbot –nginx, che si occupa sia di ottenere il certificato che di modificare automaticamente la configurazione di Nginx per usarlo.

sudo certbot --nginx -d tuodominio.it -d www.tuodominio.it \
  --email [email protected] --agree-tos --no-eff-email

Certbot chiederà se vuoi reindirizzare automaticamente il traffico HTTP verso HTTPS: rispondi sì, perché è esattamente il comportamento che vogliamo per un sito in produzione. L’indirizzo email richiesto dal comando non è decorativo: Let’s Encrypt lo usa per avvisarti se un certificato sta per scadere senza essersi rinnovato correttamente, e per comunicazioni importanti legate alla sicurezza del tuo account ACME, quindi usa un indirizzo che controlli davvero, non uno temporaneo. Un output tipico, in caso di successo, è questo:

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/tuodominio.it/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/tuodominio.it/privkey.pem
This certificate expires on 2027-01-06.
These files will be updated when the certificate renews.
Deploying certificate
Successfully deployed certificate for tuodominio.it and www.tuodominio.it
    to /etc/nginx/sites-enabled/tuodominio.it.conf
Congratulations! You have successfully enabled HTTPS

Prima di lanciare il comando reale su un dominio di produzione con poco margine di errore, è buona prassi testare con il flag –dry-run o aggiungendo –staging, che usa l’ambiente di test di Let’s Encrypt senza consumare la tua quota di rate limit reale.

Passo 4: configurare Nginx per TLS 1.3

Il plugin Nginx di Certbot genera una configurazione funzionante, ma spesso lascia attivo anche TLS 1.2 per compatibilità massima. TLS 1.3, standardizzato nella RFC 8446, elimina diversi algoritmi deprecati e riduce l’handshake a un solo giro di andata e ritorno nella maggior parte dei casi. Se il tuo pubblico usa browser recenti, puoi stringere la configurazione e forzare principalmente TLS 1.3, più rapido da negoziare e privo delle cipher suite più vecchie e deboli.

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name tuodominio.it www.tuodominio.it;

    ssl_certificate     /etc/letsencrypt/live/tuodominio.it/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/tuodominio.it/privkey.pem;

    ssl_protocols TLSv1.3 TLSv1.2;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
}

Lasciare anche TLSv1.2 nella lista è una scelta prudente: alcuni client legacy, bot di monitoraggio e vecchie librerie HTTP non parlano ancora TLS 1.3. Se gestisci un’API interna e controlli tutti i client, puoi limitarti a ssl_protocols TLSv1.3; per un sito pubblico, la combinazione TLS 1.3 più TLS 1.2 resta il compromesso più sicuro dal punto di vista della compatibilità, in linea con il profilo intermedio del generatore di configurazioni di Mozilla.

Ricordati anche il blocco sulla porta 80: deve restare attivo solo per completare la validazione HTTP-01 e per reindirizzare ogni visitatore verso la versione HTTPS, non per servire contenuti in chiaro.

server {
    listen 80;
    listen [::]:80;
    server_name tuodominio.it www.tuodominio.it;

    location /.well-known/acme-challenge/ {
        root /var/www/html;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

Il plugin –nginx di Certbot scrive automaticamente un blocco molto simile a questo quando accetti il redirect durante la richiesta del certificato. Se invece hai usato certonly, devi aggiungerlo tu a mano: senza questo blocco, i visitatori che digitano il dominio senza https:// restano bloccati su una connessione non cifrata finché non intervieni anche sulla porta 80.

Passo 5: attivare HSTS e gli header di sicurezza

Un certificato valido non basta se un utente può ancora digitare l’URL senza https:// e restare esposto a un attacco di downgrade. HTTP Strict Transport Security, HSTS, dice al browser di non tentare mai più una connessione in chiaro verso il tuo dominio, nemmeno se un link punta a http://.

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Il valore max-age=31536000 corrisponde a un anno: una volta che il browser ha visto questo header, ricorderà di usare sempre HTTPS per quella durata. Proprio per questo è fondamentale testare la configurazione con un valore di max-age basso, ad esempio 300 secondi, nei primi giorni, prima di alzarlo a un anno. Un errore di configurazione con HSTS già attivo a lungo termine non si corregge disattivando semplicemente l’header, perché il browser ha già memorizzato la regola.

Puoi consultare la guida ufficiale OWASP Transport Layer Protection Cheat Sheet per la lista completa degli header di sicurezza consigliati insieme a HSTS, inclusi quelli per Content-Security-Policy, che richiede un’analisi separata del tuo sito prima di essere attivato senza rischi. Se vuoi affrontare la sicurezza del sito in modo più ampio, oltre al solo livello di trasporto, la nostra guida alla remediation OWASP Top 10 copre le altre categorie di rischio da chiudere dopo aver messo in sicurezza il traffico.

Per chi vuole fare un passo oltre, esiste anche la HSTS preload list, una lista mantenuta a livello di browser (Chrome, Firefox e Safari la consultano) che forza HTTPS fin dalla primissima visita, prima ancora che il browser abbia ricevuto l’header dal tuo server. L’iscrizione si fa dal sito ufficiale della preload list e richiede che il dominio e tutti i suoi sottodomini servano già HTTPS in modo stabile: una volta dentro la lista, uscirne richiede settimane, perché la rimozione si propaga solo con i successivi aggiornamenti dei browser. Valutala solo dopo aver verificato con calma la configurazione, non come primo passo.

Passo 6: abilitare l’OCSP stapling

L’OCSP stapling permette al server, e non al browser del visitatore, di interrogare periodicamente l’autorità di certificazione per verificare che il certificato non sia stato revocato, e di allegare quella risposta firmata direttamente alla connessione TLS. Il risultato è una negoziazione più veloce e meno richieste in uscita dal browser dell’utente verso i server di Let’s Encrypt.

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/tuodominio.it/chain.pem;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;

La direttiva resolver è quella che più spesso viene dimenticata: senza un resolver DNS esplicito, Nginx non riesce a contattare il server OCSP dell’autorità di certificazione e lo stapling resta silenziosamente disattivato, senza generare errori evidenti nei log. Dopo aver applicato la configurazione, riavvia Nginx e verifica con il comando OpenSSL che vedremo nel passo dedicato alla verifica finale.

Passo 7: automatizzare il rinnovo del certificato

Il certificato dura 90 giorni, e nessuno vuole ricordarsi di rinnovarlo manualmente ogni tre mesi. Da Certbot 4.0 in poi, il rinnovo automatico non scatta più fisso a 30 giorni dalla scadenza, ma quando resta un terzo della vita residua del certificato: per un certificato standard da 90 giorni significa circa 30 giorni prima, ma per i nuovi certificati short-lived da 160 ore il rinnovo scatta molto più spesso, dato che la soglia minima è metà della durata per certificati più corti di 10 giorni.

L’installazione via snap crea già un timer systemd che gestisce il rinnovo automaticamente due volte al giorno. Puoi verificarlo così:

systemctl list-timers | grep certbot
sudo certbot renew --dry-run

Il comando certbot renew –dry-run simula il rinnovo di tutti i certificati configurati senza modificare nulla sul disco: è il test da lanciare ogni volta che cambi qualcosa nella configurazione di Nginx o nel firewall, per essere certo che il rinnovo automatico continuerà a funzionare quando scatterà davvero. Un output positivo si chiude con una riga simile a questa:

Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/tuodominio.it/fullchain.pem (success)

Se invece di snap usi il pacchetto apt, aggiungi tu stesso un job in /etc/cron.d/certbot, con un piccolo ritardo casuale per non colpire i server di Let’s Encrypt sempre allo stesso minuto insieme a migliaia di altri server:

0 3,15 * * * root sleep $((RANDOM % 3600)) && certbot renew --quiet --deploy-hook "systemctl reload nginx"

Il flag –deploy-hook è importante: senza di esso, Certbot scrive i nuovi file del certificato su disco, ma Nginx continua a usare in memoria quello vecchio finché non viene ricaricato manualmente. Usare –deploy-hook invece di un reload separato garantisce che Nginx venga ricaricato solo dopo un rinnovo effettivamente riuscito, e non ogni volta che il cron esegue il comando.

Passo 8: certificati wildcard con la sfida DNS-01

Se gestisci decine di sottodomini, come blog.tuodominio.it, app.tuodominio.it o api.tuodominio.it, e non vuoi richiedere un certificato per ciascuno, un certificato wildcard *.tuodominio.it coprirà tutti i sottodomini di primo livello con un’unica richiesta. Come accennato, Let’s Encrypt richiede la validazione DNS-01 per i wildcard, quindi serve un plugin DNS specifico per il tuo provider: Cloudflare, Route 53 e DigitalOcean, tra gli altri, hanno un plugin ufficiale.

sudo snap install certbot-dns-cloudflare
sudo certbot certonly --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
  -d "tuodominio.it" -d "*.tuodominio.it"

Il file cloudflare.ini contiene il token API con permessi limitati alla sola modifica dei record DNS del dominio in questione: non usare mai un token con privilegi account completi solo per questo scopo. Con il plugin DNS, Certbot crea il record TXT, aspetta che si propaghi, lo verifica, e lo rimuove automaticamente: tutto il processo richiede qualche secondo o decina di secondi in più rispetto a HTTP-01, a seconda della velocità di propagazione del tuo provider.

Una volta ottenuto il certificato wildcard con certonly, devi comunque aggiornare a mano il blocco server di Nginx perché punti ai nuovi file in /etc/letsencrypt/live, dato che il comando certonly, a differenza del plugin –nginx, non tocca la configurazione del web server. Ricordati anche che un certificato wildcard copre solo un livello di sottodominio: *.tuodominio.it protegge blog.tuodominio.it ma non copre api.blog.tuodominio.it, che richiederebbe un secondo wildcard dedicato a quel livello. Se il sottodominio in questione espone delle API, vale la pena anche impostare le intestazioni CORS corrette: ne parliamo nella guida dedicata a CORS in Node.js.

Passo 9: verificare tutto con SSL Labs e OpenSSL

Una volta applicata la configurazione, non fidarti solo del fatto che il lucchetto compaia nel browser: usa due strumenti indipendenti per controllare protocollo, catena di certificazione e header.

openssl s_client -connect tuodominio.it:443 -tls1_3 -status | grep -E "Protocol|OCSP"
curl -sI https://tuodominio.it | grep -i strict-transport

Un output corretto mostra Protocol: TLSv1.3 e una risposta OCSP Response Status: successful, con l’header Strict-Transport-Security presente nella seconda chiamata. Per un test più completo e un punteggio pubblico, usa il SSL Labs Server Test di Qualys: analizza la configurazione da remoto, segnala catene di certificazione incomplete, protocolli deprecati ancora attivi e problemi di compatibilità che da un singolo browser locale non noteresti.

Il test restituisce un voto da A+ a F. Un voto A o A+ indica TLS 1.3 attivo, HSTS correttamente configurato e nessuna cipher suite debole in ascolto. Un voto B o più basso segnala quasi sempre uno di questi tre problemi: TLS 1.0 o 1.1 ancora abilitati, catena di certificazione incompleta, oppure assenza di HSTS. Ripeti il test dopo ogni modifica significativa alla configurazione, perché anche un singolo parametro sbagliato (ad esempio un ordine delle cipher suite non ottimale) può far scendere il voto di una lettera intera.

Passo 10: hardening avanzato, cipher suite e scambio di chiavi

Per chi vuole andare oltre la configurazione di base, ci sono alcune leve aggiuntive. La prima è generare le configurazioni Nginx partendo dal Mozilla SSL Configuration Generator, uno strumento ancora attivamente mantenuto che produce file pronti per Nginx, Apache e altri server web a partire da tre profili: moderno, solo TLS 1.3 e massima sicurezza con compatibilità più bassa; intermedio, il più usato in produzione con TLS 1.2 e 1.3; e vecchio, da evitare salvo casi molto specifici.

ProfiloProtocolliDurata massima certificatoCompatibilità client
ModernoSolo TLS 1.390 giorniBrowser e client aggiornati negli ultimi 2-3 anni
IntermedioTLS 1.2 e TLS 1.390 giorniCompatibilità ampia, scelta predefinita per siti pubblici

ECDSA o RSA: quale chiave scegliere

La seconda leva riguarda il tipo di chiave: una chiave ECDSA, ad esempio su curva prime256v1, produce handshake più leggeri rispetto a una chiave RSA a parità di sicurezza stimata, utile se servi molto traffico TLS da un singolo server o da un dispositivo con poca CPU disponibile, come un piccolo VPS. Certbot genera chiavi RSA per impostazione predefinita, ma puoi richiedere una chiave ECDSA aggiungendo –key-type ecdsa al comando di richiesta del certificato. Se non sei sicuro, resta su RSA: è la scelta più compatibile e il risparmio di prestazioni di ECDSA si nota soprattutto su server con un volume di connessioni TLS molto alto.

Post-quantum: cosa aspettarsi nei prossimi mesi

La terza leva, più sperimentale, riguarda i meccanismi di scambio di chiavi ibridi resistenti al calcolo quantistico. I browser più recenti e le ultime versioni delle librerie TLS stanno iniziando a offrirli, ma l’adozione lato server è ancora agli inizi e va trattata come un’opzione da monitorare nei prossimi mesi, non come requisito per un sito in produzione oggi. Quando deciderai di attivarla, basterà aggiornare OpenSSL e Nginx alle versioni che la supportano: non servirà cambiare autorità di certificazione né il flusso di richiesta visto in questa guida, perché riguarda solo la fase di negoziazione della connessione, non il certificato in sé. TLS protegge il canale, ma non filtra le richieste malevole che arrivano comunque cifrate: se il prossimo passo della tua infrastruttura è un livello di filtro applicativo, il nostro confronto tra Cloudflare, AWS e ModSecurity come WAF è un buon punto di partenza.

Passo 11: proteggere la chiave privata e pianificare il backup

Un certificato SSL vale quanto la sicurezza della chiave privata che lo accompagna: se quella chiave finisce nelle mani sbagliate, chiunque può impersonare il tuo dominio fino alla revoca del certificato. Certbot imposta già permessi restrittivi di default, ma vale la pena verificarli dopo ogni installazione, soprattutto se il server è condiviso con altri processi o utenti.

Permessi corretti sui file del certificato

sudo ls -l /etc/letsencrypt/live/tuodominio.it/
sudo chmod 600 /etc/letsencrypt/archive/tuodominio.it/privkey*.pem
sudo chown root:root /etc/letsencrypt/archive/tuodominio.it/privkey*.pem

Il file privkey.pem deve essere leggibile solo da root, o dall’utente con cui gira Nginx se la tua distribuzione usa un gruppo dedicato. Se un’applicazione di terze parti (un CMS, un pannello di hosting) richiede accesso diretto al certificato, valuta di copiarlo in una posizione separata con permessi ridotti al minimo indispensabile, invece di allargare i permessi della cartella originale di Certbot. Il certificato che abbiamo configurato qui autentica il server verso il client: se il tuo caso d’uso richiede anche il contrario, cioè autenticare i client verso il server con un certificato individuale, quello è un meccanismo diverso chiamato mTLS, che abbiamo trattato nella guida su mTLS e certificati client in Node.js.

Backup e migrazione su un nuovo server

Tutto quello che serve per spostare la configurazione ACME su un altro server si trova in due cartelle: /etc/letsencrypt (certificati, chiavi, account ACME e configurazione dei rinnovi) e, se usi il plugin Nginx, i file di configurazione in /etc/nginx/sites-available. Includi entrambe nel tuo backup regolare del server. Se invece devi revocare un certificato perché sospetti che la chiave privata sia stata compromessa, il comando è certbot revoke –cert-path /etc/letsencrypt/live/tuodominio.it/cert.pem, seguito da una nuova richiesta per generare una coppia di chiavi completamente nuova.

Gli errori più comuni da evitare

  • Chiedere il certificato prima che il DNS sia propagato. Se il record A non punta ancora al server, la validazione HTTP-01 fallisce e il tentativo conta comunque verso i rate limit settimanali.
  • Lasciare la porta 80 bloccata sul firewall. Molti pensano che basti aprire la 443 perché il sito è su HTTPS, ma la validazione HTTP-01 e i redirect iniziali passano dalla porta 80.
  • Ignorare i rate limit e colpire l’ambiente di produzione per ogni test. Let’s Encrypt limita il numero di certificati per dominio registrato a settimana: per sperimentare la configurazione usa sempre il flag –staging o –dry-run.
  • Attivare HSTS con max-age a un anno senza aver testato prima. Un errore di configurazione TLS con HSTS già memorizzato dal browser può rendere il sito irraggiungibile per i visitatori già passati di lì, per tutta la durata del max-age.
  • Modificare a mano i file generati da Certbot dentro /etc/letsencrypt/live. Quei percorsi sono link simbolici che puntano alla versione corrente del certificato: vanno lasciati intatti, le personalizzazioni vanno fatte nei blocchi server di Nginx.
  • Dimenticare il –deploy-hook nel rinnovo via cron. Senza reload automatico di Nginx dopo il rinnovo, il server continua a servire il certificato vecchio fino al prossimo riavvio manuale.
  • Gestire decine di domini senza un piano di rinnovo centralizzato. Su server con molti siti, un singolo comando certbot renew rinnova tutto in sequenza: se uno dei domini ha il DNS rotto, l’errore su quel singolo dominio non deve bloccare il rinnovo degli altri, verifica sempre i log dopo l’esecuzione pianificata.

Risoluzione dei problemi: le domande più frequenti in produzione

Anche con una configurazione corretta, capita di incontrare errori specifici, spesso legati più all’ambiente circostante (DNS, firewall del provider cloud, orario di sistema) che a un problema reale di Certbot o Nginx. Ecco i più frequenti e come risolverli, nell’ordine in cui vale la pena controllarli.

  • “Certbot failed to authenticate some domains”. Quasi sempre è DNS non propagato o porta 80 bloccata da un firewall esterno, ad esempio quello del provider cloud e non solo quello del sistema operativo. Verifica con dig e con un curl diretto a http://tuodominio.it/.well-known/acme-challenge/test.
  • “Too many certificates already issued for this exact set of domains”. Hai superato il rate limit settimanale. Aspetta il reset, una settimana dalla prima richiesta, oppure usa –staging per continuare a testare la configurazione.
  • Il browser mostra ancora il certificato vecchio dopo il rinnovo. Nginx non è stato ricaricato. Esegui sudo systemctl reload nginx manualmente e verifica che il –deploy-hook sia presente nel comando di rinnovo automatico.
  • “NET::ERR_CERT_AUTHORITY_INVALID” su alcuni dispositivi più vecchi. La configurazione deve usare fullchain.pem, cioè certificato più catena intermedia, e non solo cert.pem. Controlla che ssl_certificate punti al file corretto.
  • L’OCSP stapling non si attiva, anche se la direttiva è presente. Manca la direttiva resolver con un DNS pubblico raggiungibile, oppure ssl_trusted_certificate punta al file sbagliato. Verifica con openssl s_client -status.
  • Il rinnovo wildcard via DNS-01 va in timeout. Il provider DNS impiega più tempo del previsto a propagare il record TXT. Molti plugin DNS di Certbot accettano un parametro per aumentare il tempo di attesa della propagazione.
  • “Connection refused” quando testi la porta 443 da remoto. Nginx non è in ascolto su quella porta, oppure il firewall del provider cloud, non quello locale, blocca ancora il traffico in ingresso.
  • HSTS blocca l’accesso a un sottodominio che gira ancora solo in HTTP. Se hai usato includeSubDomains, ogni sottodominio deve avere HTTPS funzionante. Rimuovi includeSubDomains finché tutti i sottodomini non sono pronti.
  • Certbot renew non rinnova nulla, anche vicino alla scadenza. Controlla con systemctl status certbot.timer che il timer sia attivo: alcune installazioni manuali o container Docker non lo abilitano di default.
  • “Server.internal” o errori 500 dal server ACME durante la validazione. Può capitare un’interruzione temporanea lato Let’s Encrypt, non del tuo server: controlla la pagina di stato ufficiale e riprova dopo qualche minuto prima di modificare la tua configurazione, per non introdurre un problema che non esisteva.

Il progetto completo: script di deploy end-to-end

Per chiudere il cerchio, ecco uno script che riunisce i passaggi principali: installazione di Certbot, richiesta del certificato, verifica del rinnovo automatico e test finale. Puoi adattarlo come base per un playbook Ansible o per un primo deploy manuale su un nuovo server.

#!/bin/bash
set -euo pipefail

DOMAIN="tuodominio.it"
EMAIL="[email protected]"

# 1. Installazione Certbot via snap
sudo apt update
sudo apt install -y snapd
sudo snap install core && sudo snap refresh core
sudo snap install --classic certbot
sudo ln -sf /snap/bin/certbot /usr/bin/certbot

# 2. Apertura firewall
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# 3. Richiesta certificato con plugin Nginx
sudo certbot --nginx -d "$DOMAIN" -d "www.$DOMAIN" \
  --email "$EMAIL" --agree-tos --no-eff-email --redirect

# 4. Verifica rinnovo automatico (dry-run)
sudo certbot renew --dry-run

# 5. Test finale protocollo e header
echo "--- Verifica TLS 1.3 ---"
openssl s_client -connect "$DOMAIN:443" -tls1_3 -status < /dev/null 2>/dev/null | grep -E "Protocol|OCSP Response Status"
echo "--- Verifica HSTS ---"
curl -sI "https://$DOMAIN" | grep -i strict-transport || echo "HSTS non trovato, controlla la configurazione Nginx"

echo "Setup completato. Controlla anche https://www.ssllabs.com/ssltest/ per il punteggio finale."

Questo script copre il caso più comune, un singolo dominio con www su Nginx. Per i wildcard via DNS-01, sostituisci il passo 3 con il comando certonly –dns-provider visto nel passo dedicato, e aggiungi manualmente i blocchi server in Nginx, dato che il plugin certonly non modifica la configurazione del web server. Prima di eseguirlo su un dominio reale, lancialo una volta con –staging aggiunto al comando certbot, per verificare che tutti i passaggi funzionino senza consumare la quota di certificati reali.

Se preferisci automatizzare l’intero processo su più server contemporaneamente, questo stesso script può diventare la base di un playbook Ansible: basta parametrizzare DOMAIN ed EMAIL come variabili, spostare i passaggi 1 e 2 in un task idempotente eseguito una sola volta per server, e lasciare il passaggio 3 come task ripetibile per ogni nuovo dominio da proteggere. Lo stesso approccio funziona anche dentro un container Docker, con l’avvertenza che il timer systemd per il rinnovo automatico non è disponibile all’interno del container: in quel caso va eseguito certbot renew da un cron esterno all’host, oppure da un secondo container dedicato solo al rinnovo.

Domande frequenti

Let’s Encrypt è davvero gratuito, senza costi nascosti?
Sì. Let’s Encrypt è un servizio no-profit dell’Internet Security Research Group e non richiede carta di credito né abbonamenti. I costi a cui devi pensare sono quelli del tuo server e, se scegli DNS-01, eventualmente del provider DNS, ma il certificato in sé resta gratuito.

Quanto dura un certificato Let’s Encrypt e devo rinnovarlo a mano?
Il certificato standard dura 90 giorni. Con Certbot configurato come mostrato in questa guida, il rinnovo è automatico e non richiede intervento manuale, a patto che il timer systemd o il job cron siano attivi e che il comando certbot renew –dry-run continui a dare esito positivo.

Posso usare Certbot con Apache invece di Nginx?
Sì, Certbot ha un plugin dedicato anche per Apache, certbot –apache, con la stessa logica di richiesta e installazione automatica del certificato. I passaggi di validazione del dominio sono identici, cambia solo la sintassi dei file di configurazione generati.

Cosa succede se il sito è dietro Cloudflare o un altro CDN?
Se usi Cloudflare in modalità proxy, nuvoletta arancione, il traffico tra il visitatore e Cloudflare è già cifrato dal certificato di Cloudflare stesso. Il certificato Let’s Encrypt sul tuo server serve a cifrare la tratta tra Cloudflare e il server di origine: va comunque configurato per evitare che quella seconda tratta resti in chiaro.

Perché devo attivare HSTS se il certificato SSL è già valido?
Un certificato valido protegge la connessione una volta stabilita, ma non impedisce a un utente di digitare http:// o di cliccare un vecchio link non sicuro. HSTS costringe il browser a usare sempre HTTPS per quel dominio, chiudendo quella finestra di rischio.

Cosa sono i certificati short-lived da sei giorni, li devo usare subito?
Sono certificati validi circa 160 ore, generalmente disponibili da Let’s Encrypt dal 15 gennaio 2026, pensati per chi vuole ridurre al minimo i danni in caso di furto della chiave privata grazie a un rinnovo molto più frequente. Per la maggior parte dei siti il certificato standard da 90 giorni resta la scelta più semplice da gestire.

Come installo un solo certificato valido per più domini diversi?
Aggiungi più flag -d al comando certbot, uno per ciascun dominio o sottodominio che vuoi includere nel certificato. Per interi sottodomini sotto lo stesso nome con numero variabile nel tempo, valuta invece un certificato wildcard con validazione DNS-01.

Devo pagare per avere un voto A+ su SSL Labs?
No. Il voto A+ dipende solo dalla configurazione del server, non dal tipo di certificato. Un certificato gratuito di Let’s Encrypt configurato correttamente, con TLS 1.3, HSTS e OCSP stapling attivi come mostrato in questa guida, ottiene lo stesso voto massimo di un certificato a pagamento con lo stesso livello di configurazione.