SSD Nodes Learn Hosting plans →
Guide Matt ConnorDi Matt Connor

Installare Certbot per Apache su Ubuntu 24.04

Installa un certificato Let's Encrypt con un solo comando: Ubuntu 24.04 include Certbot 2.9.0 via apt. Evita l'errore ServerName che blocca l'emissione.

Cosa stai configurando

Un sito Apache su Ubuntu 24.04 raggiungibile tramite HTTPS, con un certificato Let's Encrypt gratuito e riconosciuto dai browser, emesso da Certbot e rinnovato automaticamente da un timer systemd a cui non dovrai più prestare attenzione. Il comando che esegue l'operazione è una sola riga. Tutti gli errori si verificano prima di quella riga: un vhost senza ServerName, la porta 80 bloccata dal firewall del provider, il DNS ancora configurato per puntare al vecchio server. Per questo motivo, la maggior parte della guida è dedicata ai prerequisiti e riporta la stringa di errore esatta generata da ogni errore di configurazione.

Due precisazioni sull'ambito. Se il tuo web server è nginx, il flusso è simile, ma il plugin e le configurazioni sono diversi: usa invece la versione di questa guida per nginx. Se il servizio da proteggere è accessibile soltanto internamente, ad esempio un pannello di amministrazione su un indirizzo privato o un server di staging che nessun altro utilizza, non ti serve affatto una certification authority; un certificato autofirmato richiede meno componenti e funziona anche offline.

Prerequisiti e i tre motivi per cui la procedura fallisce prima ancora dell'esecuzione di Certbot

  • Apache sta già servendo il sito tramite HTTP semplice. Il plugin Apache di Certbot modifica un sito esistente; non ne crea uno da zero. Se stai partendo da una VPS vuota, configura prima lo stack LAMP su Ubuntu 24.04 e poi torna qui: questa guida è il capitolo mancante sulla gestione TLS.
  • Un dominio pubblico con un record A che punta all'indirizzo della tua VPS. La sfida HTTP-01 di Let's Encrypt richiede che i loro server di validazione si connettano alla tua macchina da Internet: non sono ammessi lab domestici dietro NAT senza port forwarding, né nomi .local. HTTP-01 può validare un indirizzo IP nudo, ma Let's Encrypt emette certificati per IP solo sul profilo opzionale shortlived (con durata di 160 ore), e la versione 2.9.0 di Certbot presente in apt non può richiedere né profili ACME né indirizzi IP; pertanto, questa guida richiede un nome di dominio. Il record dig +short example.com deve restituire l'indirizzo della tua VPS; se hai modificato il DNS nell'ultima ora, attendi la scadenza del TTL del vecchio record prima di procedere con l'emissione.
  • Se esiste un record AAAA, deve essere corretto. Let's Encrypt tenta sempre la connessione tramite IPv6 se è presente un record AAAA. Se la connessione va in timeout, riprova tramite IPv4, ma nessun altro errore concede questa seconda possibilità: un record AAAA che punta a un indirizzo che rifiuta le connessioni, o a un server attivo diverso da quello in uso, causa il fallimento della validazione anche se il comando curl dal tuo laptop, probabilmente su IPv4, funziona correttamente. Pubblica un record AAAA corretto oppure non pubblicarne alcuno.

Le porte 80 e 443 devono essere aperte sia in ufw che nel firewall di rete del tuo provider; la maggior parte dei pannelli di hosting dispone di un secondo firewall che il sistema operativo non vede. La sfida HTTP-01 esegue la validazione specificamente sulla porta 80; non è possibile eseguire questa procedura utilizzando solo la porta 443.

sudo ufw allow "Apache Full"
sudo ufw status

Con questi requisiti soddisfatti, l'intera operazione richiede quindici minuti, dieci dei quali dedicati alla lettura.

Snap o apt Certbot? Su 24.04, apt è finalmente una scelta valida

Certbot è passato alla distribuzione tramite snap anni fa per un buon motivo: i pacchetti delle distribuzioni erano rimasti obsoleti. Ubuntu 20.04 includeva Certbot 0.40 e non lo ha mai aggiornato, mentre il progetto si è stancato di eseguire il debug di problemi vecchi di cinque anni. Su 24.04 questo motivo non sussiste più: l'archivio include Certbot 2.9.0, una versione rilasciata a febbraio 2024 appartenente alla moderna serie 2.x, e unattended-upgrades installa tutti gli aggiornamenti di sicurezza pubblicati da Ubuntu. Nel frattempo il progetto upstream è passato alla serie 5.x, ma questa guida non richiede nulla di quella versione. Per questo sistema operativo consiglio di usare apt. Non è necessario eseguire il demone snapd, il plugin Apache viene installato nella stessa transazione e il timer di rinnovo si integra con systemd secondo il normale approccio Debian.

sudo apt update
sudo apt install -y certbot python3-certbot-apache
certbot --version

Risultato corretto: certbot 2.9.0. Il pacchetto python3-certbot-apache è il plugin che legge e modifica le configurazioni di Apache; senza di esso, certbot --apache non riesce con The requested apache plugin does not appear to be installed.

Lo snap resta la scelta corretta in due casi: vuoi la versione più recente di Certbot il giorno stesso del rilascio, oppure ti serve un plugin DNS distribuito soltanto come snap (lo sono diversi plugin dei provider certbot-dns-*). Se scegli questa soluzione:

sudo apt remove -y certbot python3-certbot-apache
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Qualunque scelta tu faccia, non eseguire mai entrambe le installazioni. Due installazioni significano due pianificatori dei rinnovi in conflitto per /etc/letsencrypt, e il comando certbot che la shell trova in PATH potrebbe non essere quello che gestisce i tuoi certificati. La riga apt remove sopra non è un elemento decorativo facoltativo.

Il vhost che Certbot deve modificare deve già esistere: ServerName è il requisito fondamentale

certbot --apache individua il virtual host sulla porta 80 il cui ServerName o ServerAlias corrisponde a ciascun dominio -d passato, dimostra il controllo del dominio tramite quel virtual host e quindi crea una copia SSL dello stesso vhost. Se non esiste un ServerName corrispondente, non viene trovata alcuna corrispondenza. Inoltre, il 000-default.conf predefinito di Ubuntu viene distribuito con ServerName commentato. Quella singola riga commentata è il motivo più comune per cui il comando unico di questa guida non funziona.

Prima di usare Certbot, quindi, assegna al sito un vhost basato sul nome configurato correttamente. Crea /etc/apache2/sites-available/example.com.conf:

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com
    ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
    CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined
</VirtualHost>

Abilitalo e verifica che Apache lo analizzi correttamente e instradi il nome verso quel vhost:

sudo a2ensite example.com.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
sudo apache2ctl -S

configtest deve stampare Syntax OK. Se stampa anche AH00558: apache2: Could not reliably determine the server's fully qualified domain name, si tratta di un avviso relativo al parametro global ServerName, non al tuo vhost. In questo caso è innocuo e può essere soppresso con echo "ServerName $(hostname -f)" | sudo tee /etc/apache2/conf-available/servername.conf && sudo a2enconf servername && sudo systemctl reload apache2.

L'output di -S è il controllo importante. Deve comparire una riga come port 80 namevhost example.com (/etc/apache2/sites-enabled/example.com.conf:1) con alias www.example.com sotto di essa. Apache indica il symlink sites-enabled che ha effettivamente letto, non il file modificato in sites-available. Se example.com non è elencato sulla porta 80, neppure Certbot lo troverà.

Emettere il certificato: certbot --apache

sudo certbot --apache -d example.com -d www.example.com

La prima esecuzione richiede tre informazioni: un indirizzo email (Let's Encrypt non lo memorizza più insieme all'account ACME e non invia più avvisi sulla scadenza, quindi il monitoraggio dei rinnovi è a tuo carico), l'accettazione dei termini di Let's Encrypt e la scelta se condividere l'indirizzo email con la EFF. Non viene più chiesto se configurare il redirect: da Certbot 1.0 l'installer Apache reindirizza per impostazione predefinita HTTP verso HTTPS (la domanda è stata rimossa nella versione 1.4), che è il comportamento desiderato. Usa --no-redirect solo se hai realmente bisogno che HTTP continui a fornire contenuti senza cifratura.

Il risultato corretto è simile al seguente. Leggilo con attenzione invece di limitarti a scorrerlo:

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/example.com/privkey.pem
This certificate expires on 2027-01-09.

Deploying certificate
Successfully deployed certificate for example.com to /etc/apache2/sites-available/example.com-le-ssl.conf
Successfully deployed certificate for www.example.com to /etc/apache2/sites-available/example.com-le-ssl.conf
Congratulations! You have successfully enabled HTTPS on https://example.com and https://www.example.com

Dietro quel messaggio, Certbot ha eseguito quattro operazioni: ha abilitato il modulo Apache ssl, se non era già abilitato; ha scritto example.com-le-ssl.conf, una copia del tuo vhost in *:443 con SSLEngine on e i percorsi dei certificati; lo ha abilitato; infine, ha aggiunto un blocco RewriteRule al vhost originale sulla porta 80, che reindirizza tutto verso HTTPS con un codice 301. Il file del vhost originale viene modificato, non sostituito, mentre il duplicato SSL si trova accanto a esso e consente di leggere ogni riga aggiunta.

Dove risiede realmente il certificato e perché non bisogna mai copiarlo

Tutto viene salvato in /etc/letsencrypt/live/example.com/: fullchain.pem (il certificato insieme alla catena degli intermedi, il file a cui i server devono puntare), privkey.pem (la chiave privata, leggibile solo da root), oltre a cert.pem e chain.pem per i software che richiedono i componenti separati. Questi file sono collegamenti simbolici a /etc/letsencrypt/archive/. Questo livello di indirezione gestisce il rinnovo: il rinnovo scrive i nuovi file in archive/ e aggiorna i collegamenti simbolici. Configura gli altri software affinché usino i percorsi live/: riceveranno automaticamente i certificati rinnovati. Se copi i file in un'altra posizione, provocherai un'interruzione del servizio dopo 90 giorni.

L'altro file importante è /etc/letsencrypt/renewal/example.com.conf. Registra come è stato emesso questo certificato, authenticator = apache, installer = apache e i domini. In questo modo il rinnovo può ripetere automaticamente la procedura, incluso il successivo ricaricamento di Apache.

Il rinnovo è già pianificato: verificalo, non ricrearlo

I certificati Let's Encrypt durano attualmente 90 giorni per impostazione predefinita e il pacchetto apt ha già installato i componenti necessari: un timer systemd che esegue Certbot due volte al giorno a orari casuali e rinnova i certificati che scadranno entro 30 giorni. Non aggiungere un cron job: un secondo scheduler non fa altro che aumentare il rumore nei log e l'esposizione ai rate limit. Let's Encrypt ha annunciato che, a partire dal 10 febbraio 2027, i nuovi certificati avranno una durata predefinita di 64 giorni. La finestra di 30 giorni continua a funzionare anche in questo caso: il rinnovo avverrà semplicemente intorno al giorno 34 invece che al giorno 60. Su questo server non è quindi necessario modificare nulla.

systemctl list-timers certbot.timer
sudo certbot renew --dry-run

Il primo comando mostra che il timer è attivo, con un orario NEXT nelle 24 ore successive. La pianificazione prevede due esecuzioni al giorno con un ritardo casuale, quindi l'orario esatto è deliberatamente imprevedibile (nell'installazione tramite snap, il timer è invece snap.certbot.renew.timer). La dry run esegue una simulazione completa del rinnovo nell'ambiente staging di Let's Encrypt, con una challenge reale ma senza emettere alcun certificato e senza consumare il rate limit. Un risultato corretto termina con:

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

Se la dry run non riesce, anche il rinnovo reale tra circa 60 giorni fallirà allo stesso modo. Risolvi il problema ora, mentre il certificato attuale ha ancora tutta la sua validità residua. La causa più comune è una regola del firewall aggiunta dopo l'emissione, che ha nuovamente chiuso la porta 80.

Verifica con curl e controlla cosa deve indicare il lucchetto

curl -sI http://example.com | head -n 3
curl -I https://example.com
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -issuer -dates

Il primo comando deve restituire HTTP/1.1 301 Moved Permanently con un'intestazione Location: https://example.com/: si tratta del reindirizzamento installato da Certbot. Il secondo deve restituire HTTP/1.1 200 OK senza errori TLS da parte di curl. Il terzo stampa l'emittente, una riga O = Let's Encrypt con un CN breve come YE1 o YE2 (chiavi ECDSA) oppure YR1 o YR2 (chiavi RSA), e notAfter con una scadenza tra circa 90 giorni. Un certificato emesso prima che Let's Encrypt ritirasse i suoi intermediari precedenti può ancora mostrare un CN come R12 o E7 fino al rinnovo successivo; non è un errore. Nel browser viene visualizzato il lucchetto e, facendo clic su di esso, viene mostrato lo stesso emittente. Se curl funziona ma il browser visualizza un avviso, quasi certamente stai visualizzando una pagina memorizzata nella cache oppure il nome host non è quello corretto, non si tratta di un problema del certificato.

Più siti: un certificato SAN o un certificato per sito

Entrambe le opzioni funzionano e si rinnovano nello stesso modo. Per siti distinti sullo stesso server, esegui il comando di emissione una volta per sito. Ogni sito ottiene una propria directory in live/ e una propria configurazione di rinnovo. Un problema relativo a un dominio non impedisce mai il rinnovo degli altri. Questa è la mia impostazione predefinita.

Per un solo sito con più nomi, inseriscili in un unico certificato SAN. Un singolo certificato può contenere fino a 100 nomi. Hai già utilizzato questa configurazione sopra con example.com e www.example.com. Per aggiungere in seguito un nome a un certificato esistente, emetti nuovamente il certificato specificando il nome del certificato e l'elenco completo aggiornato:

sudo certbot --apache --cert-name example.com -d example.com -d www.example.com -d blog.example.com

Certbot rileva la modifica dell'insieme di domini, chiede di confermare l'estensione e sostituisce il certificato in loco, mantenendo lo stesso percorso live/. Non è quindi necessario modificare altro. L'elenco sostituisce quello precedente, non lo estende: se ometti www da quel comando, il nuovo certificato lo esclude senza ulteriore avviso.

I certificati wildcard richiedono DNS-01 e, nella maggior parte dei casi, non sono necessari

HTTP-01 non può emettere *.example.com: pubblicare un file su un server web dimostra il controllo di un solo hostname, non di un intero namespace. I certificati wildcard richiedono la challenge DNS-01. Certbot imposta un record TXT su _acme-challenge.example.com. In pratica, questo richiede un plugin certbot-dns-* con credenziali API per il provider DNS oppure la modifica manuale dei record TXT a ogni rinnovo con --manual (una procedura impraticabile, da non usare come soluzione). La procedura completa, dalla gestione dei record TXT al plugin che esegue il rinnovo senza intervento, è disponibile in certificati wildcard con Certbot tramite DNS-01. Un consiglio pratico: se conosci già quattro sottodomini, un certificato SAN che li elenca tutti è più semplice di un certificato wildcard e non richiede chiavi API DNS archiviate sul server.

Modalità di errore e stringhe corrispondenti

Certbot si rifiuta di avviarsi perché la configurazione di Apache è danneggiata.

The apache plugin is not working; there may be problems with your existing configuration.
The error was: MisconfigurationError('Error while running apache2ctl configtest.\n\nAction \'configtest\' failed.\nThe Apache error log may have more information.\n\nAH00526: Syntax error on line 12 of /etc/apache2/sites-enabled/example.com.conf')

Il plugin esegue configtest prima di qualsiasi operazione e si interrompe se Apache rileva anomalie; i \n sono letterali perché Certbot stampa il repr dell'eccezione. Esegui personalmente sudo apache2ctl configtest: il comando indica il file e la riga, solitamente a causa di un errore di battitura dovuto a modifiche manuali, un SSLCertificateFile che punta a un percorso inesistente o un modulo referenziato ma non abilitato. Correggi finché il comando non restituisce Syntax OK, quindi riesegui Certbot.

Nessun vhost corrisponde al dominio.

Unable to find a virtual host listening on port 80 which is currently the only challenge port.

Si tratta del fallimento per ServerName mancante menzionato in precedenza, rilevato al momento dell'emissione. Certbot ha analizzato ogni vhost attivo sulla porta 80 alla ricerca di un ServerName/ServerAlias corrispondente al tuo -d senza trovarlo. sudo apache2ctl -S mostra come Apache instrada effettivamente il traffico; aggiungi la direttiva ServerName al vhost corretto, ricarica e riprova. Un caso simile si verifica quando la validazione raggiunge il vhost sbagliato e la risposta alla sfida restituisce Invalid response ... 404 perché un altro sito ha intercettato la richiesta. Diagnosi e strumento sono identici: apache2ctl -S.

Timeout durante la validazione.

Certbot failed to authenticate some domains (authenticator: apache).
...
Detail: ...: Timeout during connect (likely firewall problem)

Let's Encrypt non è riuscito ad aprire una connessione TCP sulla porta 80 all'indirizzo indicato dal tuo DNS. In ordine di probabilità: il firewall di rete del provider (separato da ufw, configurato nel pannello di hosting), regole ufw che consentono solo la porta 443 o solo SSH, oppure il DNS che punta ancora a un server precedente. Un record AAAA non aggiornato di solito non causa questo problema, poiché se il tentativo IPv6 va in timeout, Let's Encrypt riprova via IPv4; i problemi con AAAA tendono a manifestarsi come Connection refused o Invalid response dal server errato. Esegui un test dall'esterno della VPS: curl -I http://example.com dal tuo laptop riproduce ciò che vede il loro validatore.

Hai raggiunto un limite di frequenza (rate limit) a forza di riprovare.

Error creating new order :: too many failed authorizations (5) for "example.com" in the last 1h0m0s, retry after ... UTC: see https://letsencrypt.org/docs/rate-limits/...

Let's Encrypt consente 5 validazioni fallite per hostname, per account, ogni ora. È un sistema a "secchio" che recupera circa un tentativo ogni 12 minuti; insistere con i tentativi mentre il firewall è bloccato esaurisce rapidamente il credito. Attendere risolve il problema, ma la soluzione corretta è comportamentale: dopo ogni fallimento, esegui il debug nell'ambiente di staging finché non ha successo.

sudo certbot certonly --apache --dry-run -d example.com -d www.example.com

Nota il certonly: --dry-run è accettato solo dai sottocomandi certonly e renew, mentre la forma base certbot --apache --dry-run si rifiuta di essere eseguita, restituendo --dry-run currently only works with the 'certonly' or 'renew' subcommands. Il dry run effettua la validazione contro lo staging, che ha limiti generosi e non emette certificati reali, permettendoti di fallire per tutto il pomeriggio. Riesegui il comando reale solo dopo che lo staging ha avuto successo. Gli altri limiti, 50 certificati per dominio registrato a settimana e 5 duplicati dello stesso set di nomi a settimana, si incontrano solo se uno script sta richiedendo certificati in un ciclo infinito.

Una volta attivo HTTPS, ricorda che il certificato protegge il trasporto, non il server: la porta 22 continua a ricevere tentativi di accesso forzato. Abbinare questa configurazione a Fail2ban su Ubuntu 24.04 è il naturale passo successivo da compiere nei trenta minuti seguenti.

FAQ

È meglio installare Certbot tramite snap o apt per Apache su Ubuntu 24.04?

Usa apt. Ubuntu 24.04 rilascia Certbot 2.9.0, una versione sufficientemente aggiornata per tutto ciò che è descritto in questa guida, che riceve gli aggiornamenti di sicurezza pubblicati da Ubuntu tramite unattended-upgrades e non richiede snapd. Scegli snap solo se hai bisogno immediato della release più recente o di un plugin DNS distribuito esclusivamente come snap; se effettui il passaggio, esegui prima apt remove certbot python3-certbot-apache affinché due pianificatori di rinnovo non coesistano mai.

Perché Certbot restituisce "Unable to find a virtual host listening on port 80"?

Perché nessun vhost attivo sulla porta 80 possiede una direttiva ServerName o ServerAlias corrispondente al dominio indicato con -d; il vhost predefinito di Ubuntu viene fornito con ServerName commentato. Esegui sudo apache2ctl -S, individua (o crea) il vhost che deve gestire il nome, aggiungi ServerName example.com, ricarica Apache e riesegui Certbot.

Come risolvo l'errore "Timeout during connect (likely firewall problem)"?

Let's Encrypt non è riuscito a raggiungere la porta 80 all'indirizzo pubblicato dal tuo DNS. Controlla il firewall di rete a livello di pannello del provider e ufw, verifica che dig +short example.com restituisca questo VPS e correggi o elimina eventuali record AAAA obsoleti, poiché la validazione tenta prima IPv6 e passa a IPv4 solo dopo un timeout. Conferma la risoluzione dall'esterno del server con curl -I http://example.com, quindi esegui una prova con sudo certbot certonly --apache --dry-run -d example.com prima dell'emissione reale.

Certbot rinnova i certificati automaticamente su Ubuntu 24.04?

Sì. Il pacchetto apt installa certbot.timer, un timer di systemd che viene eseguito due volte al giorno e rinnova ogni certificato entro 30 giorni dalla scadenza, ricaricando Apache al termine; la versione snap utilizza snap.certbot.renew.timer per lo stesso compito. Verifica con systemctl list-timers certbot.timer ed effettua una prova con sudo certbot renew --dry-run; non aggiungere un tuo cron job aggiuntivo.

Come ottengo un certificato wildcard con Certbot e Apache?

I certificati wildcard richiedono la sfida DNS-01: Certbot deve inserire un record TXT presso _acme-challenge.example.com, il che implica l'uso di un plugin certbot-dns-* con credenziali API per il tuo provider DNS (l'alternativa --manual richiede la modifica manuale dei record TXT a ogni rinnovo). Se hai solo pochi sottodomini noti, un certificato SAN che li elenchi esplicitamente è più semplice e mantiene le chiavi API del DNS fuori dal server.