Qualche tempo fa - non è chiaro quanto tempo, ma almeno diversi mesi - i rinnovi di Let’s Encrypt hanno iniziato a fallire sul mio forum Discourse, dopo aver funzionato bene per anni. Quando l’ho notato per la prima volta qualche giorno fa, il certificato era scaduto nell’agosto 2021. Dopo aver provato alcuni rinnovi manuali e riavvii di nginx, ho scoperto che il certificato era stato aggiornato a scadere solo pochi giorni fa. Ovviamente, non è ancora un certificato attuale. L’esecuzione manuale di acme.sh per forzare un rinnovo (all’interno del container di Discourse) restituisce questo errore (dove [site] è ovviamente l’indirizzo del mio sito):
[site]:Verify error:Fetching http://[site]/.well-known/acme-challenge/[long alpha challenge string]: Error getting validation data
Devo notare che il sito richiede l’accesso per tutti gli utenti, ma questo non è stato un problema per i rinnovi dei certificati SSL durante gli anni di funzionamento precedente.
Qualche idea? Grazie mille!
AGGIORNAMENTO: Il test di verifica tramite wget restituisce un 404. Tuttavia, non so dove questi dati siano configurati in nginx per Discourse in un container e come si relazionino al relativo nginx che fa da proxy all’esterno del container.
Ciao. Non dovrebbe essere correlato, perché quel problema causerebbe il rifiuto dei certificati da parte del browser con errori diversi, non errori di scadenza come nel mio caso. Sembra che Let’s Encrypt non riesca improvvisamente ad autenticarsi con Discourse per fornire nuovi certificati. Grazie.
Ciao. Questi non sembrano applicarsi. Vedo un errore 404, non gli altri errori, le build sono state aggiornate finora e quel modello da GitHub è effettivamente la versione già installata nella mia installazione. Grazie!
Non avendo familiarità con il processo, potrebbe aspettarsi che il container si trovi in uno stato che non è quello quando si esegue solo quello script? Ad esempio, forse si aspetta che si verifichi prima un altro processo cron che prepara nginx per consentire l’accesso a tale URL.
Hai provato a ricostruire? (Che tenterà di ottenere un nuovo certificato nel processo.)
Menzioni che è ospitato localmente. Riesci ad accedere all’istanza dall’esterno della tua rete utilizzando il nome di dominio?
Ciao, sì ricostruzioni multiple. Nessun cambiamento. Uso Let’s Encrypt su un sacco di siti non-Discourse e si rinnovano tutti senza problemi. Sì, posso accedere da un sito esterno e ho testato usando wget, il risultato è 404. Domanda: Esattamente dove si trova l’albero html di nginx in questo caso, la parte che conterrebbe (o dovrebbe contenere) la directory .well-known? Non sono riuscito a trovarla. Grazie.
Non sono riuscito a trovare un cron job, solo uno script di runlevel in /etc/runit/1.d/letsencrypt. Sembra che quello script avvii una nuova istanza di nginx con una configurazione che include questo:
Penso che ciò significhi che il percorso finirebbe per essere /var/www/discourse/public/acme-challenge, anche se potrebbe essere creato prima della sfida, quindi rimosso in seguito.
Se quello è lo script che hai provato a eseguire manualmente, hai prima fermato nginx? L’istanza che lo script tenta di avviare tenterà di ascoltare sulla porta 80, quindi sospetto che fallirebbe se nginx fosse già in esecuzione per Discourse.
Penso di aver individuato il problema. Ma non so come risolverlo. Sembra che tutti i tentativi di accedere al forum sulla porta https 80 vengano (come previsto) reindirizzati alla porta https 443. Giusto. Ma questo significa che quando Let’s Encrypt tenta di convalidare per il rinnovo, fallisce, perché il certificato corrente è scaduto. Posso vedere il reindirizzamento con wget. Quindi la domanda è: come disabilito temporaneamente il reindirizzamento in modo che Let’s Encrypt possa convalidare e ottenere un nuovo certificato non scaduto? Un’ulteriore possibile complicazione è che il reindirizzamento sia un 301 permanente. Grazie.
Questa ridefinizione si trova in /etc/nginx/conf.d/discourse.conf e non verrà utilizzata quando nginx viene arrestato, quindi avviato con la configurazione menzionata nel mio post precedente.
Temo di non avere molta familiarità con il funzionamento dell’aggiornamento automatico, quindi non sono sicuro di quale sia il metodo appropriato per rinnovare mentre il container è in esecuzione. In teoria, arrestare e avviare il container dovrebbe comportare il rinnovo, ma poiché hai detto che una ricompilazione non lo ha fatto, probabilmente nemmeno questo funzionerà.
acme.sh ha opzioni come --renew-all, ma non sono sicuro di quali altre opzioni siano necessarie affinché faccia la cosa giusta qui. Quanto segue potrebbe essere tutto ciò di cui hai bisogno, ma non posso dirlo con certezza.
E in effetti questo consente a Let’s Encrypt di accedere senza il reindirizzamento, ma apparentemente il file che sta cercando non esiste, quindi in definitiva lo stesso errore di verifica.
Ora lo sto usando per provare a ottenere con successo il certificato. Sembra che il token di convalida venga recuperato da curl, ma acme.sh dichiara comunque un fallimento della convalida ogni volta! Quindi ancora giù.
Con molti client ACME (come acme.sh) quando nginx è specificato come metodo di autenticazione, il file della sfida http-01 viene creato in una directory specifica basata su un’eccezione/reindirizzamento nella configurazione del server nginx piuttosto che direttamente nella struttura della directory .well-known/acme-challenge nella directory webroot. Spesso questo reindirizzamento esiste solo temporaneamente per la durata della verifica della sfida, così come i file di sfida stessi.
Quindi:
Una considerazione saggia. Uno script di rinnovo scritto correttamente dovrebbe rendere non necessario fermare nginx. Tipicamente, nginx viene utilizzato per servire i file di sfida, quindi qualcosa di simile a nginx -s reload viene utilizzato per ricaricare in modo fluido il web server/proxy una volta che il nuovo certificato è stato acquisito.
La nostra implementazione della sfida HTTP-01 segue i reindirizzamenti, fino a 10 reindirizzamenti di profondità. Accetta solo reindirizzamenti a “http:” o “https:”, e solo alle porte 80 o 443. Non accetta reindirizzamenti a indirizzi IP. Quando reindirizzato a un URL HTTPS, non convalida i certificati (poiché questa sfida è intesa a fornire certificati validi, potrebbe incontrare certificati auto-firmati o scaduti lungo il percorso).
Tipicamente, quando vediamo problemi come questo, uno dei seguenti è solitamente il colpevole:
Un firewall non consente il traffico verso il web server/proxy che serve i file di sfida.
Un router/proxy è mappato/configurato in modo errato tale che la richiesta di verifica della sfida da parte di Boulder (il server CA di Let’s Encrypt) tenta di recuperare i file da un web server o da una directory errata.
Un qualche tipo di riscrittura/reindirizzamento (ad esempio, file .htaccess in Apache) interferisce con la capacità del web server/proxy di servire i file di sfida dalla posizione corretta.
Utilizzo di porte non standard, solitamente con mappatura errata.
Il container che esegue il client ACME crea i file di sfida in un luogo da cui il web server/proxy (ad esempio, nginx) non li serve. Quando Docker è coinvolto, questo è quasi sempre il problema.
Ciao. Quindi, tra i vari elementi che hai elencato, diversi chiaramente non si applicano nel mio caso. Non è un problema di firewall: posso accedere manualmente al token con wget o curl da 1) all’interno dell’app Docker Discourse, 2) dall’esterno del container Docker sul sistema host e 3) da un sistema correlato.
Per questi casi manuali, OTTENGO il contenuto del token dalla posizione prevista, supponendo che venga specificato --ignore o -k per superare il certificato scaduto quando Discourse reindirizza automaticamente a https.
Non ho modificato alcun aspetto della configurazione di nginx creata da Discourse, né all’interno né all’esterno del container Docker di Discourse. Non eseguo copie di nginx e Apache vive su porte completamente diverse solo per uso locale. Notando che tutto questo ha funzionato bene per oltre due anni, con rinnovi di certificati di routine e nessun’altra modifica all’app: è una macchina molto stabile.
Nessuna porta insolita.
Poiché posso ottenere manualmente il contenuto del token, non vedo come possano essere coinvolte posizioni errate. TRANNE…
Non stavo fermando manualmente nginx per i miei test. Ora l’ho fatto e non c’è stata alcuna differenza significativa: gli stessi errori da acme.sh (attualmente di nuovo errore 56). Quando nginx viene fermato dall’interno del container, vedo un’istanza runsv nginx sull’host, ma non ha processi worker o cache. Quando riavvio nginx nel container, i processi worker e cache riappaiono sull’host insieme al runsv nginx che era rimasto. I comandi sv start/stop nginx all’interno del container danno le conferme previste di tali azioni.
Ma c’è qualcos’altro menzionato sopra che potrebbe essere motivo di preoccupazione. E non capisco perché questo dovrebbe improvvisamente essere un problema dato quanto tempo le cose hanno funzionato fino ad ora.
L’indirizzo IP statico del forum utilizzato dall’esterno delle mie reti locali non è utilizzabile da quella macchina per connettersi ai servizi della propria macchina, a causa delle complessità nel modo in cui gli indirizzi IP statici sono forniti dall’ISP. Ho usato regolarmente voci in /etc/hosts per fornire indirizzi IP di rete locale per quei nomi. Quindi, quando testo con curl sulla stessa macchina (sia all’interno che all’esterno del container, entrambi hanno l’aggiunta /etc/hosts per il forum), il test utilizza un indirizzo IP diverso (e locale) rispetto a quello che sarebbe utilizzato da un sito esterno che lo cerca tramite DNS. C’è qualche modo in cui questo potrebbe essere rilevante? Grazie.