community italiana di domotica personale
 
Installare e configurare Caddy con Docker su Raspberry Pi OS

Installare e configurare Caddy con Docker su Raspberry Pi OS

12 minuti di lettura
SCOPI DELLA GUIDA:
  • Installare e configurare un servizio reverse proxy per la propria rete domestica basato su Caddy, usando Docker su sistema operativo Raspberry Pi OS
  • Livello di difficoltà: medio
CONCETTI AFFRONTATI:
  • installazione e configurazione software
COMPONENTI SOFTWARE UTILIZZATE:
PREREQUISITI:
DISPOSITIVI FISICI UTILIZZATI:
GUIDA DEDICATA A SISTEMI:

Raspbian

Note e disclaimer
  • qualsiasi eventuale modifica agli impianti domestici dev'essere progettata ed realizzata SOLO da personale qualificato;
  • qualsiasi modifica attuata in proprio è a propria responsabilità personale nonché a proprio rischio e pericolo (i contenuti della presenta pagina hanno puro scopo didattico);
  • qualsiasi modifica attuata in proprio a un dispositivo ne fa decadere garanzia, omologazioni e certificazioni di qualità.
Revisione guida: 2.1

Caddy - Docker

Abstract

Con un Raspberry Pi installato con sistema operativo Raspberry Pi OS è relativamente facile dotarsi di un servizio reverse proxy per la propria rete domestica.

L’adozione di un software gratuito come Caddy, per esempio, consente di realizzare tale funzionalità di rete in pochi e semplici passi; tale strumento può poi essere configurato e utilizzato per le sue tipiche funzioni di reindirizzamento delle chiamate da Internet verso servizi presenti sulla propria rete interna nonché l’ottenimento automatico degli eventuali certificati crittografici utili alla navigazione sicura verso tali servizi.

N.b. Sebbene non si tratti di scienza missilistica, l’implementazione di questa guida prevede un minimo di cultura sul networking nonché sul funzionamento del reverse proxy. Inutile e deleterio tentare di configurare su Caddy senza conoscere l’abc su questi temi.

ATTENZIONE: Per funzionare, questa guida dev’essere letta con particolare attenzione e calma. Pena, il probabile fallimento della configurazione del servizio.

Si parte

Assunti

Questa guida è dedicata a chi abbia già un Raspberry in uso con sistema operativo Raspberry Pi OS (aka Raspberry Pi OS). Per coloro che non abbiano ancora provveduto e si trovino ad avere un Raspberry nuovo, magari acquistato appositamente per realizzare la propria domotica, allora questo passo della guida va smarcato seguendo prima un’altra guida, che spiega passo passo come configurare il sistema operativo Raspberry Pi OS.

La guida da seguire:

Una volta terminata la configurazione di Raspberry Pi OS (inclusa la possibilità di collegarvisi tramite SSH) è possibile procedere nella presente guida.

Si assume infine che l’host ospitante Caddy possegga un indirizzo IP fisso assegnato automaticamente dal router domestico.

Installare Docker

Installare Docker su Raspberry Pi dotato di sistema operativo Raspberry Pi OS è piuttosto semplice, esiste una procedura completamente automatica e una manuale. Entrambe le procedure sono illustrate in dettaglio in questa breve guida.

Se si ha già provveduto all’installazione di Docker, va da sé che questo passaggio possa essere saltato.

ATTENZIONE: affinché i comandi a seguire funzionino, è necessario aver aggiunto Docker al gruppo sudoers, come spiegato in guida.

Dominio

N.b. Se si possiede un dominio proprio o comunque una gestione DDNS diversa da DuckDNS, si può saltare direttamente alla sezione “Port forwarding“.

Affinché sia raggiungibile dall’esterno in modo semplificato, il punto di accesso alla rete domestica (ovvero interfaccia WAN del modem) deve esser rappresentato da un nome univoco (chiamato FQDN) il quale veda l’IP ad esso associato aggiornarsi automaticamente ad ogni variazione, dato che quello assegnato al vostro modem/router cambia ciclicamente. Per fare questo interviene il servizio Dynamic DNS (o DDNS), ovvero un servizio che tenga traccia dell’ultima variazione e risponda, ai sistemi che chiedano la risoluzione (traduzione) del nome DNS, l’ultimo IP conosciuto, ovvero quello in uso.

DuckDNS è il servizio che abbiamo scelto per questa funzione di fornitura di FQDN nonché di associazione dinamica dell’IP.

N.b. Caddy può serenamente gestire anche domini propri acquistati e gestiti sulla rete dai più diversi fornitori diversi da DuckDNS. Come vedremo a seguire, la “challenge” (ovvero la procedura di ottenimento automatica dei certificati) varia da fornitore a fornitore: impossibilitati a documentare qualsiasi casistica possibile, in questa guida analizzeremo le più comuni modalità di challenge tra i servizi più comunemente usati. Ciononostante, con i debiti accorgimenti la guida di massima è valida anche per gli altri casi.

Collegarsi quindi al servizio tramite l’indirizzo https://www.duckdns.org e, una volta registrati creare un proprio nome dominio che, univocamente, rappresenterà il vostro modem collegato ad Internet. Il suffisso è sempre lo stesso (“.duckdns.org“) mentre ciò che cambia e va scelto è il suffisso (per esempio “casamia“).

Per questa guida, daremo per assunto di aver creato il seguente FQDN:

casamia.duckdns.org

dove “duckdns.org” è la parte fissa mentre casamia è il nome di dominio da noi creato a mo’ di esempio.

All’interno della vostra sezione privata di DuckDNS troverete anche un campo importante chiamato “token“, il quale appare analogo a questo:

e3ff465f-c6d6-acb1-4416-44b2af152111

Appuntarselo da una parte, tornerà utile a breve.

Aggiornamento di DuckDNS

Prima di provvedere alla configurazione di Caddy è necessario assicurarsi che l’associazione del proprio FQDN con l’IP assegnato al modem dal nostro provider Internet sia garantita quasi in tempo reale. A fronte dell’eventuale cambiamento dell’IP Internet sull’interfaccia WAN del proprio modem/router, è necessario che tale variazione venga comunicata a DuckDNS, in modo da aggiornare la conseguente risoluzione dell’FQDN.

N.b. Questo paragrafo non va attuato se sulla propria rete c’è già qualche dispositivo che provveda a tale funzione di associazione dell’IP con il proprio FQDN, come per esempio un modem/router FRITZ!Box o altri modelli/marche in grado di effettuare da sé l’operazione. Se e quando un modem è in grado di provvedere a tale funzione, è sempre buona regola lasciare che sia lui ad aggiornare tale associazione, e non il Raspberry o altri host della propria rete.
N.b. Gli utenti che utilizzino già l’HUB Home Assistant possono alternativamente utilizzare questa guida che non prevede l’adozione di un container ad hoc su ContainerStation, cosa invece descritta nel presente paragrafo.

Istanzieremo dunque un container Docker ad hoc che contenga una mini-app concepita specificamente a tal scopo.
Per farlo, eseguire il seguente comando:

docker run -d --name=duckdns -e TZ=Europe/Rome -e SUBDOMAINS=NOME_DOMINIO -e TOKEN=MIO_TOKEN_DUCKDNS --restart always ghcr.io/linuxserver/duckdns

sostituendo nel comando le stringhe indicate come segue:

NOME_DOMINIO nome dominio definito sul servizio DuckDNS (inteso come terzo livello, quindi nel caso sopra solo “casamia“)
MIO_TOKEN_DUCKDNS toker fornito da DuckDNS

Eseguito il comando, il container verrà scaricato ed istanziato. Al termina, verificare tramite il comando:

docker logs duckdns

che i log riportino qualcosa tipo:

Your IP was updated at Thu Gen 1 00:00:00 CET 1980

il che indica un corretto avvio dell’applicazione container e dell’avvenuto aggiornamento dell’associazione IP/FQDN.
Diversamente, un errore tipo:

Something went wrong, please check your settings Thu Gen 1 00:00:00 CET 1980

indica che qualche errore è stato commesso nella formulazione del comando di cui sopra (verificare nome dominio e token).

In caso di errori, fermare e cancellare il container con:

docker container stop duckdns
docker container rm duckdns

e ritentare, correggendo gli errori, la sua creazione come spiegato sopra.


Una volta attuata correttamente tale configurazione, DuckDNS conoscerà in tempo (quasi) reale l’IP del vostro modem/router, e con lui, voi e chi interrogherà tale FQDN.

Configurazione Docker Compose

Per coloro che utilizzino, per la gestione dei container, l’utile tool Docker Compose, la configurazione è la seguente:

  duckdns:
    container_name: duckdns
    image: ghcr.io/linuxserver/duckdns
    environment:
    - "TZ=Europe/Rome"
    - "SUBDOMAINS=NOME_DOMINIO"
    - "TOKEN=MIO_TOKEN_DUCKDNS"
    restart: always

Prestare attenzione, ovviamente, alle personalizzazoni dei campi SUBDOMAINS e TOKEN come da indicazioni precedenti.

Port forwarding

Per far sì che Caddy possa autonomamente provvedere all’ottenimento di eventuali certificati SSL per il proprio FQDN nonché accettare le connessioni esterna da girare – in quanto reverse proxy – è necessario configurare delle regole di port forwarding sul modem/router. Il cosiddetto “aprire le porte”.

Prima di proseguire oltre – se non si ha già dimestichezza col port forwarding – si consiglia la lettura di questo articolo.

IMPORTANTE.

Le regole di port forwarding variano in base alle porte che si vogliano esporre verso Internet rispetto a quelle aperte (e da raggiungere) internamente. Questo non è oggetto della presente guida, in quanto qualsiasi guida presente su inDomus che referenzi la presente e che utilizzi Caddy come reverse proxy spiegherà questo aspetto nello specifico del servizio.

Ciò che viene spiegato in questa occasione – ovvero alla prima installazione e configurazione di Caddy – è relativo alle porte (eventualmente) da aprire in caso si voglia far provvedere a Caddy all’ottenimento di eventuali certificati SSL per la securizzazione delle comunicazioni dentro-fuori.

I certificati crittografici, per essere considerati validi, devono essere rilasciati da una Certification Authority riconosciuta: nel caso della presente guida utilizzeremo il servizio gratuito Let’s Encrypt. Questo processo viene automatizzato sfruttando uno specifico protocollo (chiamato ACME Protocol) il quale prevede tre modalità diverse, dette anche challenge, per appurare la propria “identità” al gestore del servizio e ottenere quindi i certificati richiesti. Tali modalità sono:

  • HTTP Challenge
  • TLS-ALPN Challenge
  • DNS Challenge

Su Caddy le prime due challenge vengono utilizzate di default, la terza invece va eventualmente abilitata in configurazione (il che disabilita le prime due).

  • TLS-ALPN Challenge: Questa è la prima challenge che viene tentata di default da Caddy. Tecnicamente, viene effettuata una DNS lookup verso il proprio FQDN per il quale viene richiesto il certificato e viene eseguita una specifica request sulla porta TCP 443. Se alla CA viene restituito il risultato atteso, avviene il rilascio del certificato. Per questa challenge è necessaria l’apertura della porta TCP 443 verso l’host che ospita Caddy.
  • HTTP Challenge: Si tratta della seconda challenge che viene tentata di default da Caddy. Anche qui viene effettuata una DNS lookup verso il proprio FQDN per il quale viene richiesto il certificato e viene effettuata una specifica request sulla porta TCP 80. Se alla CA viene restituito il risultato atteso, avviene il rilascio del certificato. Com’è facile intuire, questa challenge necessità dell’apertura della porta TCP 80 verso l’host che ospita Caddy.
  • DNS challenge: Questa challenge non viene tentata in automatico ma, come detto prima, va eventualmente configurata (disabilitando di conseguenza le precedenti due). Diversamente dalle altre non necessita di apertura porte ma richiede una specifica configurazione: caddy deve poter accedere al provider DNS del proprio dominio per impostare i cosidetti TXT record in modo tale che, quando viene effettuata l’authoritative DNS lookup verso il provider DNS per la ricerca del TXT record, venga effettivamente restituito il valore atteso.

Dunque, quali porte vanno “aperte” tramite port forwarding e girate verso l’host che ospita Caddy? La TCP 80, la 443 o nessuna?

La scelta ovviamente è soggettiva e dipende da diversi fattori. Dipende in primis dal DNS provider, in base se esso consenta o meno la scrittura dei TXT record. Dipende anche dal proprio modem: non tutti permettono l’apertura delle porte 80 e 443. Dipende dalla volontà o meno di voler esporre il proprio server sulle porte 80 e 443. Per fare qualche esempio:

  • se abbiamo un comune modem che consente il port forwarding della porta TCP 443 o della TCP 80 e utilizziamo DucKDNS, ci basta HTTP-Challenge;
  • se abbiamo un vecchio modem Fastweb che non permette il port forwarding della porta TCP 80 e non abbiamo un provider DNS che permetta l’impostazione dei TXT record (magari perché non previsto dal servizio gratuito), possiamo pensare di sfruttare la TLS-ALPN inoltrando il traffico sulla 443 verso Caddy;
  • se invece abbiamo acquistato un dominio possiamo ad esempio farlo gestire a Cloudflare e sfruttare la DNS Challenge;
  • se abbiamo registrato un dominio su noip.com e facciamo l’upgrade a pagamento, possiamo impostare i TXT record e scegliere di usufruire della DNS Challenge evitando di esporre altre porte.

e altro.

In questa guida assumeremo di utilizzare la casistica più classica, ovvero il primo esempio qui sopra spiegato, ovvero quello che utilizza port forwarding della porta TCP 443 o TCP 80 nonché – come vedremo – la corretta challenge prevista per DuckDNS (la TLS-ALPN).

La configurazione per il port forwarding sul modem da noi consigliata è:

  • IP destinazione: IP statico del Raspberry Pi (assegnato in precedenza);
  • Porta esterna: TCP 443
  • Porta interna: TCP 443

oppure

  • IP destinazione: IP statico del Raspberry Pi (assegnato in precedenza);
  • Porta esterna: TCP 80
  • Porta interna: TCP 80

Punto della situazione

Arrivati a questo punto della guida abbiamo:

  • un FQDN rappresentante il nostro punto di ingresso alla rete locale;
  • un sistema di aggiornamento automatico dell’FQDN;
  • un port forwarding su porta TCP 80 o 443 (o nessuno, se si usa la DNS Challenge).

Ora non manca che installare Caddy e far sì che nella sua configurazione ci sia l’ottenimento automatico dei certificati da parte di Let’s Encrypt per il nostro FQDN.

Installare Caddy su Docker

Una volta dotati di un proprio FQDN è dunque il momento di installare (o meglio, “istanziarvi sopra”) Caddy. Prima di procedere, però, è necessario creare una cartella la quale conterrà la sua configurazione.

Una volta collegati via SSH al Raspberry Pi tramite utenza “pi“, provvedere a creare a cartella:

mkdir -p /home/pi/caddy/data

Creare poi un file il file di configurazione (detto – e chiamato – “Caddyfile“):

nano /home/pi/caddy/Caddyfile

all’interno copiare il seguente codice:

#  When your config is ok comment block below to disable use of AMCE staging server
{
    acme_ca https://acme-staging-v02.api.letsencrypt.org/directory 
}

https://casamia.duckdns.org { 
  respond "Saluti dal Crew inDomus.it"
  file_server
}

Dove ovviamente “casamia.duckdns.org” andrà personalizzato col proprio FQDN.
Una volta completata la modifica, usciamo dall’editor salvando il file (CTRL+x, y, invio).

N.b. Si noti come in alto nel file di configurazione sia stato esplicitamente (e volutamente) indicato il server ACME di test di Let’s Encrypt (https://acme-staging-v02.api.letsencrypt.org/directory). Questa scelta è voluta: consente di effettuare una prima prova, altrimenti utilizzando direttamente quello di esercizio si rischierebbe, in caso di problemi, di rimanere impossibilitati a fare nuove richieste per diversi giorni. Superata questa la prima fase, correggeremo il file di configurazione in modo appropriato a tempo debito.

Istanziamo dunque Caddy su Docker tramite il comando specifico al quale passeremo i seguenti argomenti:

  • nome del container: caddy;
  • il file di configurazione “Caddyfile” da utilizzare;
  • la directory “data” nella quale verranno salvati i certificati;
  • la porte da esporre (443 o 80).

Eseguire quindi il comando:

docker run --init -d --name="caddy" -e "TZ=Europe/Rome" -v /home/pi/caddy/Caddyfile:/etc/caddy/Caddyfile -v /home/pi/caddy/data:/data --restart always -p 443:443 -p 80:80 caddy:latest

Al termine, verifichiamo che tutto sia andato per il verso giusto:

docker logs caddy

in fondo al log dovremmo trovare qualcosa come:

{"level":"info","ts":1610093092.9648476,"logger":"tls.issuance.acme.acme_client","msg":"validations succeeded; finalizing order","order":"https://acme-staging-v02.api.letsencrypt.org/acme/order/yyyyyy/zzzzzz"} 
{"level":"info","ts":1610093093.8919973,"logger":"tls.issuance.acme.acme_client","msg":"successfully downloaded available certificate chains","count":2,"first_url":"https://acme-staging-v02.api.letsencrypt.org/acme/cert/xxxxxxxxxxxxxxxxxxxxxxxxxxx"} 
{"level":"info","ts":1610093093.8923566,"logger":"tls.obtain","msg":"certificate obtained successfully","identifier":"casamia.duckdns.org"}

il che confermerà il funzionamento del tutto.
Andremo anche verificare la generazione fisica dei certificati portandoci sotto la directory appena creata: noteremo che sarà presente un’alberatura nuova nella quale troveremo i file dei certificati:

ls -latr /home/pi/caddy/data/caddy/certificates/acme-staging-v02.api.letsencrypt.org-directory/casamia.duckdns.org

questo l’output:

total 20
-rw------- 1 pi pi  227 gen  1 00:00 casamia.duckdns.org.key
-rw------- 1 pi pi  171 gen  1 00:00 casamia.duckdns.org.json
-rw------- 1 pi pi 3299 gen  1 00:00 casamia.duckdns.org.crt
drwx------ 3 pi pi 4096 gen  1 00:00 ..
drwx------ 2 pi pi 4096 gen  1 00:00 .

In caso di problemi, ripetere i passi precedenti, portando particolare attenzione alla configurazione di port forwarding sul modem/router.


Come spiegato sopra, questi non sono i certificati definitivi: dovremo quindi fermare il container Docker di Caddy, modificare il file di configurazione e riavviarlo.

nano /home/pi/caddy/Caddyfile

Cancelliamo le prime quattro righe; il contenuto del file di configurazione diventerà quindi:

https://casamia.duckdns.org { 
  respond "Saluti dal Crew inDomus.it"
  file_server
}

Dove ovviamente “casamia.duckdns.org” andrà personalizzato col proprio FQDN.
Una volta completata la modifica, usciamo dall’editor salvando il file (CTRL+x, y, invio).

Riavviamo dunque il container:

docker restart caddy

dopo il riavvio, verifichiamo i log:

docker logs caddy

anche in questo caso dovremmo trovare:

{"level":"info","ts":1610092585.0720239,"logger":"tls.issuance.acme.acme_client","msg":"validations succeeded; finalizing order","order":"https://acme-v02.api.letsencrypt.org/acme/order/yyyyyy/zzzzzz"}
{"level":"info","ts":1610092586.0094872,"logger":"tls.issuance.acme.acme_client","msg":"successfully downloaded available certificate chains","count":2,"first_url":"https://acme-v02.api.letsencrypt.org/acme/cert/xxxxxxxxxxxxxxxxxxxxxxxxxxx"} 
{"level":"info","ts":1610092586.0111442,"logger":"tls.obtain","msg":"certificate obtained successfully","identifier":"casamia.duckdns.org"}

il che confermerà il funzionamento definitivo del tutto.
Andremo anche verificare la generazione fisica dei certificati portandoci sotto la directory appena creata: noteremo che sarà presente un’alberatura nuova nella quale troveremo i file dei certificati:

ls -latr /home/pi/caddy/data/caddy/certificates/acme-v02.api.letsencrypt.org-directory/casamia.duckdns.org

questo l’output:

total 20
-rw------- 1 pi pi  227 gen  1 00:00 casamia.duckdns.org.key
-rw------- 1 pi pi  171 gen  1 00:00 casamia.duckdns.org.json
-rw------- 1 pi pi 3299 gen  1 00:00 casamia.duckdns.org.crt
drwx------ 3 pi pi 4096 gen  1 00:00 ..
drwx------ 2 pi pi 4096 gen  1 00:00 .

A questo punto come verifica finale possiamo puntare al dominio configurato nel Caddyfile

https://casamia.duckdns.org

Congratulazioni: Caddy è ora operativo.

Configurazione Docker Compose

Per coloro che utilizzino, per la gestione dei container, l’utile tool Docker Compose, la configurazione è la seguente:

  caddy:
    container_name: caddy
    image: caddy:latest
    volumes:
    - "/home/pi/caddy/Caddyfile:/etc/caddy/Caddyfile"
    - "/home/pi/caddy/data:/data"
    environment:
    - "TZ=Europe/Rome"
    restart: always
    ports:
    - "80:80"
    - "443:443"

Abbiamo finito?

In realtà, nì.

Caddy, di per sé ora è operativo ma, in buona sostanza, non sta facendo nulla se non ottenere automaticamente gli aggiornamenti dei certificati per il nostro FQDN. Va da sé che per utilizzarlo per ciò che è concepito, ovvero la funzione di reverse proxy, sarà necessario indicare in configurazione (nel “Caddyfile”) quali regole implementare e riavviare coerentemente il container, oltre a implementare le relative regole di port forwarding sul modem/router.

Un esempio

Ipotizziamo di voler gestire il traffico esterno per un’istanza di Home Assistant presente sulla rete interna in modo da farlo raggiungere dall’esterno su porta 9000 (e in modo sicuro con certificati SSL) per controllare la propria domotica in remoto.

Le cose da fare sono:

  • modificare coerentemente il “Caddyfile”;
  • configurare il port forwarding;
  • riavviare il container Docker di Caddy.
MODIFICA AL CADDYFILE

Modificheremo il Caddyfile come segue:

(https_header) {
  header {
    Strict-Transport-Security "max-age=31536000; includeSubdomains"
    X-XSS-Protection "1; mode=block"
    X-Content-Type-Options "nosniff"
    X-Frame-Options "SAMEORIGIN"
    Referrer-Policy "same-origin"
  }
}

https://casamia.duckdns.org { 
  respond "Saluti dal Crew inDomus"
  file_server
}
https://casamia.duckdns.org:9000 { 
  import https_header
  reverse_proxy http://IP_DELLA_ISTANZA_HOME_ASSISTANT:8123
}

Come si nota, la regola indica che tutte le richieste https verso casamia.duckdns.org:9000 vengano reindirizzate verso l’indirizzo interno http://IP_DELLA_ISTANZA_HOME_ASSISTANT:8123.

CONFIGURARE IL PORT FORWARDING

Sul modem/router, definire una regola di port forwarding così modellata:

  • IP destinazione: IP statico del Raspberry Pi che ospita Caddy
  • Porta esterna: TCP 9000
  • Porta interna: TCP 9000
RICONFIGURARE CADDY
docker container stop caddy
docker container rm caddy
docker run --init -d --name="caddy" -e "TZ=Europe/Rome" -v /home/pi/caddy/Caddyfile:/etc/caddy/Caddyfile -v /home/pi/caddy/data:/data --restart always -p 443:443 -p 9000:9000 caddy:latest

Si noti come in fondo al secondo comando sia stato aggiunto -p 9000:9000, ovvero l’associazione della nuova porta d’ingresso ora gestita, la 9000. Terminata questa configurazione, Home Assistant sarà raggiungibile dall’esterno, via https, presso il proprio FQDN alla porta 9000.

Questo ovviamente è solo un esempio illustrativo: per tutte le possibili configurazioni (non documentate da inDomus) si consiglia di far riferimento direttamente alla documentazione Caddy.

RICONFIGURARE HOME ASSISTANT

Dato che abbiamo portato l’esempio di Home Assistant, dopo la configurazione di Caddy ricordarsi anche di effettuare un’ultima modifica, ma stavolta lato Home Assistant.

   
Telegram News Channel