Il router ha una web interface, un’API, magari un VPN: tutta roba che gira in HTTPS. Ma con quale certificato? Di fabbrica RouterOS ne usa uno auto-firmato, e il browser protesta ad ogni accesso. In questo articolo ci facciamo dare da Let’s Encrypt un certificato vero, riconosciuto da tutti i browser, gratis e automatico, usando il client ACME integrato in RouterOS 7. Lo facciamo per davvero in laboratorio: apriamo la porta giusta, guardiamo a pacchetto cosa succede sul filo, ci sbattiamo contro due fallimenti istruttivi, e alla fine sezioniamo il certificato ottenuto fino alla radice della sua catena di fiducia.
Riferimento concettuale: Certificati, CA e la catena di fiducia — cos’è una CA, cosa vuol dire “catena”, DV vs OV/EV, OCSP/CRL, Certificate Transparency e CAA. Qui diamo per capiti quei termini.
Passo 1: cosa otteniamo, e cosa serve davvero
ACME (Automatic Certificate Management Environment, RFC 8555) è il protocollo con cui un server chiede a una Certificate Authority un certificato dimostrando di controllare il dominio, senza interventi manuali. Let’s Encrypt è la CA gratuita più usata al mondo e parla ACME. RouterOS 7 ha il client ACME dentro: nessun software esterno.
C’è però un prezzo onesto da mettere in chiaro subito, perché è il cuore di tutto l’articolo. Per darti il certificato, Let’s Encrypt deve verificare che quel nome sia tuo. Il metodo che useremo (la sfida http-01) funziona così: Let’s Encrypt si collega al tuo nome sulla porta 80 e si aspetta di trovare lì un file che solo tu puoi aver messo. Quindi servono due cose:
- un nome DNS pubblico che punta al router (un dominio tuo, oppure il nome di IP Cloud del MikroTik);
- la porta 80 raggiungibile da Internet verso il router — direttamente, o con un port forwarding (DST-NAT) sul router di bordo.
Aprire la 80 al mondo non è gratis in termini di rischio: lo vedremo letteralmente nello sniffer al Passo 5. Per questo la apriamo solo per la finestra dell’emissione e la richiudiamo dopo (Passo 9).
Passo 2: il comando
Su RouterOS 7 moderno (qui una 7.25 stable) il comando è add-acme. Una riga sola:
/certificate/add-acme \
directory-url=https://acme-v02.api.letsencrypt.org/directory \
domain-names=chr01test.mikrotikdojo.com
Il directory-url è il punto d’ingresso dell’API di Let’s Encrypt (da lì il router scopre tutti gli altri endpoint). domain-names è il nome (o i nomi) per cui vogliamo il certificato. Esiste anche un vecchio comando enable-ssl-certificate, legato a IP Cloud: funziona, ma add-acme è quello attuale e gestisce il rinnovo automatico da solo.
Perché vada a buon fine, il servizio www del router dev’essere acceso sulla porta 80: è lui che risponderà alla sfida.
Passo 3: la sfida http-01, raccontata
Quando lanci il comando, dietro le quinte si svolge una piccola cerimonia. Il router bussa all’API di Let’s Encrypt e dice: «vorrei un certificato per chr01test.mikrotikdojo.com». Let’s Encrypt risponde con un gettone — una stringa casuale, il token — e un compito: «mettilo a disposizione all’indirizzo http://chr01test.mikrotikdojo.com/.well-known/acme-challenge/<token>, poi avvisami».
Qui entra in scena il servizio www del router. Non deve fare nulla di speciale: il client ACME gli affida il gettone, e il www lo tiene pronto a quel preciso indirizzo come un portinaio che custodisce una busta col tuo nome. Quando Let’s Encrypt verrà a bussare sulla porta 80 e chiederà proprio quella busta, il portinaio gliela porgerà. Il gettone che il router consegna non è il token nudo: è token.impronta-della-chiave — la risposta è legata matematicamente alla chiave privata del router, così nessun altro, pur conoscendo il token, potrebbe fabbricare la risposta giusta. Let’s Encrypt la confronta con quello che si aspetta; se combacia, è convinto che quel nome è davvero tuo, e firma il certificato.
Tutto questo scambio — il bussare, il gettone, la busta sulla 80 — avviene in HTTP in chiaro. Ed è esattamente perché è in chiaro che possiamo guardarlo a pacchetto.
Passo 4: al microscopio — e il primo fallimento (dietro NAT)
Mettiamo uno sniffer sull’interfaccia del router rivolta a Internet e lanciamo il comando. Il primo tentativo finisce così:
/certificate print detail
0 Ea acme-status="http-01 challenge validation failed,
urn:ietf:params:acme:error:connection - Fetching
http://chr01test.mikrotikdojo.com/.well-known/acme-challenge/0WwwuU4...PGwU:
Error getting validation data"
Guardiamo i pacchetti, non le parole. Il verso in uscita funziona: il router raggiunge l’API di Let’s Encrypt sulla 443 (172.65.32.248), apre il dialogo, crea l’account e ottiene il token.
# router → API di Let's Encrypt (443): connessione aperta
router.33768 > 172.65.32.248.443: Flags [S] # SYN verso l'API
172.65.32.248.443 > router.33768: Flags [S.] # SYN-ACK: handshake
Il problema è il verso in entrata. E nello sniffer si vede addirittura un validatore di Let’s Encrypt (51.178.174.226) provarci — e non riuscirci: 320 tentativi di connessione sulla porta 80, nessuno che vada a buon fine, e zero GET della challenge completati.
# un nodo di validazione di Let's Encrypt bussa sulla :80... a vuoto
51.178.174.226.51xxx > router.80: Flags [S] # SYN \
51.178.174.226.51xxx > router.80: Flags [S] # SYN } 320 SYN, mai un handshake completo
51.178.174.226.51xxx > router.80: Flags [S] # SYN /
# GET /.well-known/acme-challenge/... ricevuti e serviti: 0
Ecco spiegato Error getting validation data: la busta non è stata consegnata perché l’inoltro della porta 80 dall’esterno non stava ancora recapitando (il SYN arriva, ma la risposta del router non torna indietro → l’handshake non si chiude). Lezione uno: la sfida ha due versi — in uscita verso l’API (basta il NAT normale) e in entrata sulla 80 (serve il port forwarding, fatto bene). Lo sistemiamo e riproviamo.
Passo 5: apri la 80… e il mondo se ne accorge in pochi secondi
Inoltrata la porta 80, rilanciamo. E qui succede una cosa che da sola vale l’articolo. Guardiamo chi bussa sulla 80 appena diventa pubblica:
# SYN in arrivo sulla porta 80, conteggiati per IP sorgente (dallo sniffer)
1474 40.160.24.53 <-- un solo IP: 1474 tentativi di connessione
14 44.252.14.108
7 47.129.199.229
7 13.60.43.228
7 13.51.178.31
Gli IP che fanno 6–14 tentativi e completano la connessione sono i nodi di validazione di Let’s Encrypt (torniamo tra un attimo sul perché sono tanti). Ma quel primo — 1474 SYN da un indirizzo solo — non è Let’s Encrypt: è uno scanner. Appena una porta 80 si affaccia su Internet, i bot che perlustrano la rete la trovano in secondi e cominciano a martellarla. Non è teoria: è successo in diretta, nel nostro lab, la prima volta che abbiamo aperto.
E il martellamento ha un effetto collaterale che fa fallire l’emissione. Il servizio www di RouterOS ha un tetto di sessioni contemporanee (max-sessions, di fabbrica 20). Il diluvio dello scanner lo satura; oltre il tetto il router rifiuta le connessioni in eccesso con un RST. E tra le vittime del rifiuto finisce una delle prospettive di validazione di Let’s Encrypt. Risultato:
acme-status="http-01 challenge validation failed,
... During secondary validation: ...
Timeout during connect (likely firewall problem)"
E lo si vede, pacchetto per pacchetto — è HTTP in chiaro, header e corpo. Un vero nodo di Let’s Encrypt chiede la challenge, e il router gli serve il gettone:
# la challenge richiesta da un nodo LE
23.178.112.104 > router:80
GET /.well-known/acme-challenge/GBjyI0nclef5ifJguzhLO56dde_AMz8PDukkBYRiR3Q HTTP/1.1
Host: chr01test.mikrotikdojo.com
User-Agent: Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)
Accept: */*
# il router risponde, e nel CORPO c'è il gettone (token . impronta-della-chiave)
router:80 > 23.178.112.104
HTTP/1.1 200 OK
Content-Length: 87
GBjyI0nclef5ifJguzhLO56dde_AMz8PDukkBYRiR3Q.NGo2y4WTCYleqL9xJ957-d1OkuWVBem0EJqYT4SGOqs
\_________ token _________________________/ \________ impronta della chiave __________/
Ma i conteggi sulla porta 80 raccontano la calca — e perché una prospettiva resta tagliata fuori:
SYN in ingresso : 1539 (di cui 1474 da un solo scanner, 40.160.24.53)
SYN-ACK : 736
RST dal router : 796 <-- connessioni stroncate oltre max-sessions=20
Il portinaio funziona (il 200 OK lo serve a chi riesce a parlargli); non è un errore di configurazione, è la calca alla porta a impedirgli di servire tutti — e tra i non serviti finisce una prospettiva di validazione di Let’s Encrypt.
Perché Let’s Encrypt valida da più punti: MPIC
Qui va spiegato il «secondary validation». Fino a qualche anno fa una CA validava da un solo punto della rete. Era un punto debole enorme. Internet instrada i pacchetti con BGP, un protocollo che funziona a fiducia: una rete annuncia «il blocco di indirizzi X si raggiunge da me» e le altre le credono. Una rete malevola può annunciare il prefisso di una vittima — è il dirottamento BGP (BGP hijack) — e per qualche minuto attirare a sé quel traffico. Se lo fa durante la validazione, il validatore della CA finisce sul server dell’attaccante, che risponde alla sfida e si porta a casa un certificato vero e fidato per un dominio che non è suo.
La contromisura è la MPIC (Multi-Perspective Issuance Corroboration), adottata da Let’s Encrypt tra il 2024 e il 2025 e oggi richiesta dal CA/Browser Forum. Let’s Encrypt non valida da un posto solo: lo fa da più prospettive sparse su reti, cloud e regioni diverse (ecco perché nello sniffer vediamo tanti IP che bussano). Un dirottamento BGP di solito è locale: si propaga a una parte di Internet, non a tutta. Le prospettive «lontane», che raggiungono ancora il server vero, sono in disaccordo con quella dirottata → niente quorum → la CA rifiuta. Per battere MPIC servirebbe un dirottamento quasi globale: enorme e rumorosissimo.
La chicca: è proprio questo scudo ad averci fatto fallire sopra. Una prospettiva non riusciva a connettersi (colpa nostra, il www saturo) e la logica anti-dirottamento, non avendo corroborazione piena, ha detto no. Il meccanismo che ferma gli attaccanti ha fermato anche la nostra porta intasata.
Passo 6: la tentazione sbagliata, e due difese vere
La reazione istintiva è: «allora accetto sulla 80 solo gli IP di Let’s Encrypt». Non si può, ed è voluto. Let’s Encrypt non pubblica l’elenco degli IP da cui valida, proprio per la MPIC: le prospettive cambiano senza preavviso e sono distribuite apposta. Una address-list = "Let's Encrypt" si romperebbe al primo cambio — e scoraggiano esplicitamente di farla.
La difesa giusta non filtra per sorgente, ma per comportamento: chi apre troppe connessioni contemporanee alla 80 è, con ogni probabilità, uno scanner; i nodi di Let’s Encrypt ne aprono poche ciascuno. Una regola mette chi floda in una lista dinamica e lo scarta, senza toccare la validazione:
/ip firewall filter add chain=input protocol=tcp dst-port=80 \
connection-state=new connection-limit=20,32 \
action=add-src-to-address-list address-list=port80-flood \
address-list-timeout=10m
/ip firewall filter add chain=input protocol=tcp dst-port=80 \
src-address-list=port80-flood action=drop
Chi supera 20 connessioni nuove concorrenti dallo stesso indirizzo (il ,32 conta per /32, cioè per singolo IP) finisce nella lista port80-flood ed è scartato per 10 minuti. L’abbiamo messa alla prova in laboratorio con un flood vero, e aggancia:
/ip firewall address-list print where list=port80-flood
# LIST ADDRESS TIMEOUT
0 D port80-flood 198.51.100.7 8m24s <-- listato per comportamento, non per IP noto
/ip firewall filter print stats
# CHAIN ACTION PACKETS
0 input add-src-to-address-list 80
1 input drop 475 <-- flood scartato
In alternativa (o in aggiunta), il tampone più semplice è alzare il tetto delle sessioni contemporanee del www, così anche il rumore residuo non soffoca i nodi LE:
/ip service set www max-sessions=100
Rilanciamo l’emissione. Stavolta tutte le prospettive passano e nel log compare la riga che aspettavamo:
certificate,info acme cert 'acme_cert_chr01test.mikrotikdojo.com' imported,
next update scheduled at 2027-01-10T...Z
Fatto: certificato emesso e importato, con il rinnovo già schedulato da solo. (La via per evitare del tutto la porta aperta esiste — la sfida DNS-01, un record TXT invece della 80 — e la trattiamo nella KB.)
Passo 7: il certificato, sezionato
Ora il pezzo interessante: cosa ci ha dato davvero Let’s Encrypt. Tiriamo fuori i campi del certificato (qui letti con openssl, ma li mostra anche RouterOS):
subject CN = chr01test.mikrotikdojo.com
issuer C = US, O = Let's Encrypt, CN = YR1
validità 89 giorni (Not Before ... Not After, ~3 mesi)
chiave RSA 2048 bit · firma sha256WithRSAEncryption
X509v3 Subject Alternative Name: DNS:chr01test.mikrotikdojo.com
X509v3 Key Usage (critical): Digital Signature, Key Encipherment
X509v3 Extended Key Usage: TLS Web Server Authentication
X509v3 Basic Constraints (critical): CA:FALSE
X509v3 Certificate Policies: 2.23.140.1.2.1
Authority Information Access: CA Issuers - URI:http://yr1.i.lencr.org/
X509v3 CRL Distribution Points: http://yr1.c.lencr.org/5.crl
CT Precertificate SCTs: (2 Signed Certificate Timestamp)
Cinque cose da leggere con attenzione, tutte attualissime:
- Validità ~90 giorni. Breve apposta: meno tempo vive un certificato, meno danno fa se la chiave viene rubata. Ecco perché il rinnovo deve essere automatico.
- Identità solo via SAN. Il nome valido è nel Subject Alternative Name, non nel vecchio Common Name: è così che i browser moderni leggono i certificati.
- Policy
2.23.140.1.2.1. È l’OID del CA/Browser Forum per Domain Validated (DV): Let’s Encrypt certifica che controlli il dominio, non chi sei. Niente identità d’azienda (è il suo limite, ne parla la KB). - Niente OCSP, solo CRL. L’Authority Information Access ha solo «CA Issuers», nessuna URL OCSP: Let’s Encrypt ha dismesso l’OCSP nel 2025 e punta su CRL e certificati a vita breve. Dettaglio recentissimo che in rete trovi ancora spiegato al contrario.
- Due SCT di Certificate Transparency. Incorporati nel certificato: provano che è stato registrato in log pubblici prima dell’emissione. È il motivo per cui una mis-issuance non resta nascosta — chiunque può monitorare i log CT del proprio dominio.
Nota pratica: il nostro chr01test.mikrotikdojo.com è finito, da questo momento, nei log CT pubblici per sempre. Non è un segreto (è un sottodominio nostro), ma va saputo: ogni certificato che emetti è un fatto pubblico e permanente.
Vai a verificarlo: cercalo nei log pubblici
Quelle due SCT non sono un vanto teorico: puoi controllarle tu. Un motore che aggrega i log di Certificate Transparency è crt.sh. Cerca il nome dal browser, oppure interroga la sua API in JSON:
# tutti i certificati emessi per il nome (o per % = tutti i sottodomini)
curl 'https://crt.sh/?q=chr01test.mikrotikdojo.com&output=json' | jq .
curl 'https://crt.sh/?q=%25.mikrotikdojo.com&output=json' | jq .
La risposta, per ogni certificato trovato, ha questa forma:
{
"id": 1......, <-- id nel registro CT
"issuer_name": "C=US, O=Let's Encrypt, CN=YR1",
"name_value": "chr01test.mikrotikdojo.com",
"not_before": "2026-10-30T16:37:38",
"not_after": "2027-01-28T16:37:37"
}
Due usi, uno curioso e uno serio. Curioso: è la prova che il nostro esperimento è ora un fatto pubblico e permanente. Serio: interrogando %25.tuodominio vedi tutti i certificati mai emessi per il tuo dominio — e se ne spunta uno che non hai chiesto tu, hai scoperto una mis-issuance. È così che Certificate Transparency trasforma un attacco silenzioso in un fatto visibile. (Un certificato appena emesso può metterci da qualche minuto a qualche ora a comparire negli aggregatori.)
Passo 8: la catena di fiducia, fino alla radice
Un certificato non vive da solo: si incatena fino a una radice di cui il tuo dispositivo già si fida. Seguiamo la catena scaricando ogni anello (l’indirizzo da cui prenderlo è nel campo CA Issuers di ciascun certificato):
chr01test.mikrotikdojo.com (foglia · DV · 90 giorni · CA:FALSE)
└─ emessa da YR1 (intermedia · 2025→2028 · CA:TRUE pathlen:0 · EKU=solo TLS server)
└─ emessa da ISRG Root YR (radice · 2026→2032)
└─ CROSS-FIRMATA da ISRG Root X1 (la radice storica, in tutti i dispositivi)
C’è una sorpresa in fondo, ed è la lezione più bella. La radice non è la celebre ISRG Root X1, ma una radice nuova, «ISRG Root YR» (comparsa nel 2026). Come fa un dispositivo vecchio, che non la conosce, a fidarsi? Perché ISRG Root YR è cross-firmata da ISRG Root X1, che è dentro ogni browser e sistema operativo da anni. Il dispositivo che non riconosce «Root YR» risale un altro gradino e arriva a «Root X1», che conosce — e si fida. È esattamente così che una CA introduce una radice nuova senza aspettare che milioni di dispositivi la ricevano: la fa firmare da una radice già fidata. L’abbiamo visto sul campo, non raccontato a memoria.
Noti anche che l’intermedia YR1 ha EKU = solo TLS Web Server e pathlen:0: anche l’anello di mezzo è limitato a ciò che deve fare — non può firmare altre CA, né certificati per usi diversi dal TLS server. La catena di fiducia è anche una catena di poteri ristretti.
Passo 9: metterlo in uso, e richiudere
Il certificato c’è: ora lo si usa dove serve. Per avere il Webfig in HTTPS vero, lo si assegna al servizio www-ssl:
/ip service set www-ssl certificate=acme_cert_chr01test.mikrotikdojo.com disabled=no
Il rinnovo è automatico (RouterOS lo rifà prima della scadenza), ma attenzione: al rinnovo serve di nuovo la sfida, quindi la porta 80 dovrà essere di nuovo raggiungibile in quel momento. Se l’avevi aperta solo per l’emissione, pianifica la finestra del rinnovo — oppure passa alla sfida DNS-01 (vedi KB), che non apre porte.
E adesso richiudi la 80: tolto il port forwarding, sparisce anche tutto il traffico degli scanner che abbiamo visto al Passo 5. La superficie esposta si riduce a zero. La 80 si riapre solo quando serve, per il tempo che serve.
Domande frequenti
Posso usarlo senza un mio dominio, con il nome di IP Cloud del MikroTik?
Sì: il nome ...sn.mynetname.net di IP Cloud risolve verso il router e vale come nome pubblico per la sfida. Tieni però presente che quel nome contiene il numero di serie del dispositivo in chiaro, e che il certificato (quindi quel nome) finirà nei log CT pubblici per sempre. Un dominio tuo è più pulito.
Devo per forza aprire la porta 80? Non è un rischio?
Per la sfida http-01 sì, serve la 80 in entrata — e il rischio l’abbiamo mostrato (gli scanner arrivano in secondi). Mitighi tenendola aperta solo nella finestra di emissione/rinnovo e limitando i flood per ritmo, non per IP. Per non aprire nessuna porta esiste la sfida DNS-01 (un record TXT nel DNS): la trattiamo nella KB sui certificati.
Perché non basta accettare solo gli IP di Let’s Encrypt sulla 80?
Perché Let’s Encrypt non li pubblica, di proposito: valida da molte prospettive che cambiano senza preavviso (è la MPIC anti-dirottamento). Una allow-list si romperebbe, ed è sconsigliata dalla CA stessa.
Il certificato dura 90 giorni: devo ricordarmi di rinnovarlo?
No: add-acme schedula il rinnovo da solo. Il tuo compito è assicurarti che, nel momento del rinnovo, la condizione della sfida sia di nuovo soddisfatta (porta 80 raggiungibile, o DNS-01 configurato).
Posso avere un certificato ECDSA invece di RSA?
Sì, Let’s Encrypt emette anche su chiavi a curva ellittica; nel comando si sceglie il tipo di chiave. Qui abbiamo lasciato il default (RSA 2048) per leggibilità, ma ECDSA dà chiavi più piccole a parità di robustezza — comoda su un router. La differenza tra le due famiglie è spiegata nella KB sui certificati.
Provato in laboratorio su CHR RouterOS 7.25 (stable), con uno sniffer sull’interfaccia rivolta a Internet. Emissione reale da Let’s Encrypt (directory di produzione) per un sottodominio di prova, via /certificate/add-acme con sfida http-01 e il servizio www sulla porta 80 (inoltrata dal bordo). Catturati i tre esiti: fallimento «Error getting validation data» (80 non raggiungibile in entrata), fallimento «During secondary validation … Timeout during connect» (il www con max-sessions=20 saturato dal diluvio di SYN di uno scanner — 1474 tentativi da un solo IP in pochi secondi dall’apertura — che stronca una prospettiva di validazione MPIC di Let’s Encrypt), e successo dopo www max-sessions=100 con importazione del certificato e rinnovo auto-schedulato. Il certificato ottenuto è stato sezionato con openssl: DV (policy 2.23.140.1.2.1), validità ~90 giorni, identità solo-SAN, EKU solo TLS-server, nessuna URL OCSP (solo CRL), due SCT di Certificate Transparency; catena ricostruita scaricando gli anelli — foglia → intermedia YR1 → ISRG Root YR (2026) cross-firmata da ISRG Root X1; presenza del certificato nei log di Certificate Transparency verificabile su crt.sh. Il sottodominio chr01test.mikrotikdojo.com è reale (già nei log CT); gli IP e i percorsi interni del laboratorio sono omessi.



