1 19/05/2026 10 min

Perché Docker qui ha senso

Su Debian 12, ChangeDetection.io si installa bene in container perché separa l’applicazione dalle dipendenze di sistema e riduce il rischio di sporcare l’host con librerie, runtime e aggiornamenti manuali. In pratica ottieni un servizio più semplice da spostare, aggiornare e ripristinare.

La scelta architetturale più pulita è questa: Docker gestisce l’applicazione, Nginx termina TLS e fa da reverse proxy, e il volume dati conserva configurazione, watch list e storico. Se qualcosa si rompe, il blast radius resta limitato al container o al proxy, non al sistema intero.

Assumo un’installazione esposta su un nome DNS dedicato, per esempio watch.example.com, e un server Debian 12 aggiornato. Se hai già un Nginx che serve altri siti, aggiungi solo un nuovo server block e non toccare il resto.

Prerequisiti minimi sull’host

Prima di installare il servizio, verifica tre cose: DNS corretto, porte 80 e 443 libere verso Nginx, e spazio disco sufficiente per il volume dati. ChangeDetection.io non è pesante, ma se lo usi per tanti siti e con snapshot frequenti, il volume cresce più di quanto sembri.

Controlli rapidi:

hostname -f
ss -ltnp | grep -E ':(80|443)\s'
df -h /
getent hosts watch.example.com

Se la risoluzione DNS non punta al server giusto, fermati qui: non ha senso installare il proxy prima di avere l’IP corretto. Se 80 o 443 sono già occupate da un altro servizio, va deciso subito chi deve gestire il vhost, altrimenti rischi conflitti difficili da leggere a freddo.

Installazione di Docker su Debian 12

Per evitare versioni vecchie nei repository di base, conviene usare il repository ufficiale Docker. È un cambio controllato e reversibile: se non ti piace, puoi rimuovere i pacchetti e tornare indietro senza toccare i dati applicativi.

  1. Aggiorna l’host e installa i prerequisiti.
sudo apt update
sudo apt install -y ca-certificates curl gnupg
  1. Aggiungi la chiave e il repository Docker.
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  1. Installa Docker Engine e Compose plugin.
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker

Verifica immediata:

docker version
docker compose version
sudo docker run --rm hello-world

Se il test con hello-world fallisce, il problema è nel runtime Docker, non in ChangeDetection.io. In quel caso non andare avanti: controlla journalctl -u docker --no-pager -n 100 e risolvi prima il layer base.

Directory, volume e file di compose

Io tengo il progetto in /opt/changedetection perché è un path chiaro, facile da documentare e semplice da backuppare. Il volume dati va separato dal file di composizione, così un aggiornamento del compose non tocca i contenuti.

sudo mkdir -p /opt/changedetection/{data,compose}

Crea il file /opt/changedetection/compose/docker-compose.yml con questa struttura di base:

services:
  changedetection:
    image: dgtlmoon/changedetection.io:latest
    container_name: changedetection
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Rome
      - BASE_URL=https://watch.example.com
    volumes:
      - /opt/changedetection/data:/datastore
    ports:
      - "127.0.0.1:5000:5000"
    healthcheck:
      test: ["CMD", "wget", "-qO", "-", "http://127.0.0.1:5000/"]
      interval: 30s
      timeout: 10s
      retries: 3

Due note pratiche. Primo: esporre il container solo su 127.0.0.1 evita di pubblicare direttamente la porta applicativa su Internet. Secondo: BASE_URL deve combaciare con l’URL pubblico, altrimenti alcuni link e callback si comportano male dietro reverse proxy.

Se l’immagine cambia naming o parametri in una release futura, il punto di verifica non è “sembra giusto”, ma la documentazione ufficiale dell’immagine e i log del container. Questo è il classico caso in cui una rottura di compatibilità si vede subito in avvio, non dopo ore.

Avvio del servizio e prima verifica

Avvia il container e controlla che resti su:

cd /opt/changedetection/compose
sudo docker compose up -d
sudo docker ps
sudo docker logs --tail=100 changedetection

Il risultato atteso è un container Up e un log senza errori di permessi sul datastore. Se trovi problemi di ownership, allinea UID e GID del volume a quelli configurati in compose:

sudo chown -R 1000:1000 /opt/changedetection/data

Questa correzione è reversibile e circoscritta al volume applicativo. Se non sai quale utente usare, non indovinare: verifica l’UID del tuo account o quello previsto dalla tua policy host/container, poi applicalo in modo coerente.

Nginx come reverse proxy davanti a ChangeDetection.io

Il proxy Nginx serve per tre motivi: TLS, controllo degli header e isolamento della porta applicativa. In più ti permette di applicare eventuali limiti di accesso, log separati e regole di caching disattivate dove non servono.

Crea un server block dedicato, per esempio /etc/nginx/sites-available/watch.example.com:

server {
    listen 80;
    server_name watch.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name watch.example.com;

    ssl_certificate /etc/letsencrypt/live/watch.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/watch.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:5000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-Host $host;
        proxy_read_timeout 300s;
        proxy_connect_timeout 30s;
        proxy_send_timeout 300s;
    }
}

Abilita il sito e verifica la sintassi:

sudo ln -s /etc/nginx/sites-available/watch.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Se nginx -t fallisce, fermati e correggi il file prima del reload. Il reload di una configurazione rotta è il modo più rapido per trasformare un problema locale in un disservizio vero.

TLS con Let’s Encrypt

Per il certificato, la via più semplice su Debian 12 è Certbot con plugin Nginx. È un passaggio standard e non cambia la logica del resto dello stack.

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d watch.example.com

Verifica immediata del certificato e del rinnovo automatico:

sudo certbot certificates
systemctl list-timers | grep certbot

Se il certificato non viene emesso, le cause tipiche sono DNS non propagato, porta 80 non raggiungibile dall’esterno o un server block che non corrisponde al nome host richiesto. Non forzare il problema con workaround strani: risolvi il layer di front door.

Hardening minimo utile

Non serve complicare la configurazione per avere un setup decente. Le misure minime sensate sono: container esposto solo in localhost, TLS obbligatorio, aggiornamenti del sistema regolari e attenzione ai permessi del datastore. Questo riduce parecchio la superficie d’attacco senza introdurre fragilità.

Se vuoi irrigidire un po’ di più il profilo, valuta un firewall host che consenta solo SSH, HTTP e HTTPS, e niente accesso diretto alla porta 5000. Con UFW, per esempio:

sudo apt install -y ufw
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

Qui il rischio operativo è basso, ma resta una modifica di rete: se lavori da remoto e hai SSH su una porta non standard o tramite VPN, verifica prima di attivare la policy. Il rollback è semplice: disabilitare UFW o rimuovere la regola che blocca il tuo accesso.

Controllo funzionale dell’applicazione

A questo punto la catena dovrebbe essere completa: DNS risolve, Nginx risponde, TLS è valido e il container serve l’interfaccia web. La verifica più utile è sempre un curl dal server e uno dal client esterno, perché ti dice se il problema è locale o di esposizione.

curl -I http://127.0.0.1:5000
curl -Ik https://watch.example.com

Il primo comando deve mostrare una risposta HTTP del container. Il secondo deve mostrare un 200 o un redirect coerente verso l’interfaccia pubblica, senza errori di certificato o loop infiniti. Se il browser mostra pagina bianca ma curl è corretto, vai a cercare errori JavaScript lato client o blocchi di estensioni/browser, non il server.

Quando l’interfaccia si apre, crea un primo monitor di prova su un URL che controlli davvero, non su un endpoint casuale. Il test migliore è una pagina che cambia contenuto in modo prevedibile, perché così verifichi sia la raccolta sia il confronto delle differenze.

Gestione degli aggiornamenti

Con Docker, l’aggiornamento è semplice ma va trattato come change controllato. Prima scarichi la nuova immagine, poi riavvii il container, poi verifichi log e UI. Non fare il contrario.

cd /opt/changedetection/compose
sudo docker compose pull
sudo docker compose up -d
sudo docker logs --tail=100 changedetection

Se vuoi ridurre il rischio, fissa una versione specifica dell’immagine invece di usare sempre latest. È una scelta più prevedibile in produzione, perché elimini le sorprese di un tag mobile. In cambio devi gestire tu il ciclo di upgrade, ma almeno sai cosa stai promuovendo.

Prima di un upgrade importante, salva sempre il volume dati. Il backup minimo è una copia coerente di /opt/changedetection/data, fatta a container fermo o con snapshot del filesystem se il tuo storage lo supporta. Se qualcosa va storto, il rollback consiste nel ripristinare il volume e rilanciare il compose con la versione precedente dell’immagine.

Osservabilità pratica: cosa guardare quando non va

Quando il servizio non risponde, non partire dalla reinstallazione. Parti dal layer che ha più probabilità di essere rotto e raccogli evidenze minime: stato del container, log, risposta HTTP e configurazione del proxy. Questo ti evita di confondere sintomi diversi.

Sequenza utile:

  1. sudo docker ps per vedere se il container è vivo.
  2. sudo docker logs --tail=100 changedetection per errori applicativi o di permessi.
  3. curl -Ik https://watch.example.com per distinguere problema Nginx/TLS da problema app.
  4. sudo tail -n 100 /var/log/nginx/error.log se il proxy restituisce 502 o 504.

Se il container è in crash loop, la causa più frequente è il datastore non scrivibile, una variabile d’ambiente errata o una versione immagine incompatibile. Se Nginx mostra 502 Bad Gateway, invece, il problema è quasi sempre a monte della UI: container non in ascolto, porta sbagliata o crash del processo interno.

Un caso che vale la pena ricordare: se il sito apre ma il login o alcune funzioni non persistono, controlla il volume /datastore. Un montaggio errato o temporaneo può far sembrare tutto funzionante finché non provi a salvare qualcosa.

Backup e rollback davvero utili

Il rollback deve essere banale. Se hai cambiato solo la configurazione del proxy, il ripristino è tornare al file Nginx precedente e ricaricare il servizio. Se hai cambiato l’immagine Docker, il rollback è riportare il tag precedente e riavviare il container. Se hai toccato il volume, serve un backup del datastore.

Procedura minima consigliata prima di ogni change rilevante:

sudo cp /opt/changedetection/compose/docker-compose.yml /opt/changedetection/compose/docker-compose.yml.bak
sudo tar -czf /root/changedetection-data-$(date +%F).tar.gz -C /opt/changedetection data

Se usi backup su filesystem con snapshot, ancora meglio: il restore è più rapido e meno soggetto a errori umani. In ogni caso, conserva anche una copia del file di compose e della configurazione Nginx, perché spesso il problema non è il dato ma la sua esposizione.

Conclusione operativa

Su Debian 12, ChangeDetection.io con Docker e Nginx è una combinazione solida se tieni separati i ruoli: container per l’app, Nginx per l’edge, volume per i dati. La parte che fa davvero la differenza non è l’installazione in sé, ma la disciplina sulle verifiche: prima DNS e porte, poi container, poi proxy, poi TLS, infine funzionalità applicativa.

Se rispetti questa sequenza, i guasti diventano leggibili e il ripristino resta rapido. Se la salti, finisci a inseguire sintomi in ordine sbagliato e a introdurre cambi non necessari. Qui la semplicità non è estetica: è operatività.