51 07/04/2026 8 min

Scelta architetturale su Debian 12

Nginx Proxy Manager (NPM) conviene installarlo come stack Docker su Debian 12: separi bene i componenti, semplifichi aggiornamenti e rollback, e tieni sotto controllo i file di configurazione. L’approccio più pulito è usare Docker Engine e Docker Compose, con volumi persistenti per configurazione, certificati e database.

Lo scenario tipico è questo: Debian 12 come host, NPM esposto su porte 80/443 per i reverse proxy pubblici, e la web UI amministrativa limitata a rete fidata o almeno protetta da accesso ristretto. Se hai già un web server sulla macchina, devi decidere prima chi prende 80/443: NPM oppure il servizio esistente. Non vanno condivise alla cieca.

Obiettivo di sicurezza minimo: ridurre la superficie esposta, proteggere l’accesso admin, mantenere i dati persistenti separati dal container, aggiornare senza rompere il servizio e avere un rollback semplice.

Prerequisiti minimi

  • Debian 12 aggiornato.
  • Accesso root o sudo.
  • Una macchina con IP pubblico o raggiungibile dal reverse proxy che userai.
  • DNS già pronto per i domini che passeranno da NPM.
  • Porte 80 e 443 libere se NPM deve gestire il traffico HTTPS pubblico.

Se la macchina ospita già Apache, Nginx, Caddy o un altro servizio su 80/443, fermalo o spostalo prima di procedere. Verifica con:

sudo ss -ltnp | egrep ':(80|443)'

Atteso: nessun altro processo deve occupare le porte che assegnerai a NPM. Se trovi un listener, identifica il servizio prima di modificare nulla.

Installazione base di Docker su Debian 12

Usa i pacchetti ufficiali di Docker per evitare versioni vecchie o incoerenti nei repository Debian. La sequenza sotto installa prerequisiti, repository e motore Docker.

sudo apt update
sudo apt install -y ca-certificates curl gnupg
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

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Verifica subito che il servizio sia attivo:

sudo systemctl status docker --no-pager

Atteso: active (running). Se non lo è, controlla i log con journalctl -u docker -n 50 --no-pager prima di andare avanti.

Creazione directory persistenti

Metti i dati di NPM in una directory dedicata, ad esempio /opt/npm. Questo ti aiuta con backup e rollback.

sudo mkdir -p /opt/npm/{data,letsencrypt}
sudo chown -R root:root /opt/npm
sudo chmod 0755 /opt/npm /opt/npm/data /opt/npm/letsencrypt

Se vuoi tenere il file di Compose separato, crea anche una cartella di lavoro:

sudo mkdir -p /opt/npm-stack

Con questa struttura puoi fare snapshot o backup del contenuto in modo semplice, senza toccare l’immagine container.

Docker Compose per Nginx Proxy Manager

Per installare NPM in modo ripetibile, crea un file docker-compose.yml dedicato. Usa una password iniziale robusta e non lasciare valori deboli nei file condivisi.

cd /opt/npm-stack
sudo nano docker-compose.yml

Contenuto consigliato:

services:
  app:
    image: jc21/nginx-proxy-manager:latest
    container_name: npm
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "127.0.0.1:81:81"
    environment:
      DB_SQLITE_FILE: "/data/database.sqlite"
    volumes:
      - /opt/npm/data:/data
      - /opt/npm/letsencrypt:/etc/letsencrypt

Questa configurazione usa SQLite, che è la scelta più semplice per installazioni singole o piccole. Se prevedi alta disponibilità o più istanze, valuta MySQL/MariaDB esterno, ma per la maggior parte dei casi su Debian 12 SQLite basta e riduce complessità.

Nota importante: la porta admin 81 è legata a 127.0.0.1, quindi non è esposta su tutte le interfacce. È una misura di hardening minima e pratica.

Avvio del servizio

Avvia lo stack e verifica che il container sia su:

cd /opt/npm-stack
sudo docker compose up -d
sudo docker ps --filter name=npm

Atteso: il container npm deve risultare Up. Se si ferma subito, guarda i log:

sudo docker logs --tail 100 npm

Per il primo accesso apri la UI da localhost o tramite tunnel SSH se sei remoto:

ssh -L 8181:127.0.0.1:81 user@server

Poi visita http://127.0.0.1:8181. In alternativa, se hai deciso di esporre la porta admin su rete, fallo solo dietro firewall e rete fidata.

Credenziali iniziali e primo hardening

Al primo login, cambia immediatamente l’account amministrativo predefinito. La UI iniziale di NPM usa credenziali note e non va lasciata così.

Subito dopo il primo accesso:

  • cambia email e password dell’admin;
  • abilita l’autenticazione a due fattori se disponibile nella tua versione;
  • limita l’accesso alla UI admin a IP di gestione o VPN;
  • non pubblicare la porta 81 su Internet.

Se usi un firewall host-based, consenti solo ciò che serve.

Firewall su Debian 12

Se usi nftables o ufw, apri solo le porte necessarie. Esempio con UFW, se è il tuo standard operativo:

sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 127.0.0.1 to any port 81 proto tcp
sudo ufw enable
sudo ufw status verbose

Atteso: 22, 80 e 443 devono essere aperte; 81 deve restare accessibile solo da loopback se la UI è bindata su 127.0.0.1. Se gestisci la macchina via VPN, puoi restringere ancora di più la porta SSH.

Se preferisci nftables, mantieni la stessa logica: consenti solo gestione, HTTP e HTTPS, e non esporre la dashboard amministrativa.

Primo proxy host e certificato TLS

La funzione principale di NPM è creare reverse proxy verso servizi interni. Dopo il login, crea un Proxy Host puntando a un backend interno, ad esempio un’app su 127.0.0.1:3000 o su IP privato.

Configurazione tipica:

  • Domain Names: il dominio pubblico.
  • Scheme: http o https a seconda del backend.
  • Forward Hostname / IP: indirizzo del servizio origin.
  • Forward Port: porta dell’app.
  • Websockets Support: attiva se il backend lo richiede.
  • Block Common Exploits: attiva.

Per il TLS, usa Let’s Encrypt solo dopo aver verificato che il DNS punti correttamente alla macchina e che le porte 80/443 siano raggiungibili dall’esterno. Se la validazione fallisce, controlla prima:

curl -I http://tuodominio.tld

Atteso: risposta HTTP raggiungibile dalla rete pubblica. Se ottieni timeout o NXDOMAIN, il problema non è NPM ma DNS o routing.

Hardening della superficie esposta

Qui si fa la differenza tra “funziona” e “è esposto male”. Le misure minime sono poche e concrete.

  • Non esporre la porta 81 su WAN.
  • Usa password forte e 2FA sull’account admin.
  • Limita SSH a chi serve davvero.
  • Tieni aggiornato Docker e l’immagine NPM.
  • Evita volumi con permessi troppo larghi.

Controlla i permessi dei volumi:

sudo ls -ld /opt/npm /opt/npm/data /opt/npm/letsencrypt

Atteso: ownership chiara e permessi non world-writable. Se trovi permessi anomali, correggili prima di procedere con l’esposizione pubblica.

Se usi SELinux o AppArmor in modalità restrittiva, verifica che non blocchino Docker o i bind mount. Su Debian 12 il caso più comune resta però il firewall e la gestione dei listener.

Aggiornamento controllato e rollback

Con Docker, l’aggiornamento è semplice ma va fatto con disciplina. Prima di aggiornare, salva lo stato e verifica lo spazio disco.

df -h
sudo docker compose pull
sudo docker compose up -d

Prima di cambiare versione, fai una copia dei dati persistenti:

sudo tar -czf /root/npm-backup-$(date +%F).tar.gz -C /opt npm

Se qualcosa va storto, il rollback tipico è rimettere il tag immagine precedente nel file di Compose e rilanciare docker compose up -d. Se usi latest, il rollback è meno preciso: meglio fissare una versione nota quando passi in produzione.

Rollback operativo:

  1. ferma lo stack: sudo docker compose down;
  2. ripristina il file docker-compose.yml dalla copia di backup;
  3. riavvia: sudo docker compose up -d;
  4. verifica log e accesso UI.

Controlli finali di sicurezza e funzionamento

Dopo l’installazione, fai questi controlli minimi:

  1. Servizio attivo: sudo docker ps --filter name=npm deve mostrare il container in esecuzione.
  2. Listener corretti: sudo ss -ltnp | egrep ':(80|443|81)' deve mostrare 81 solo su loopback se hai applicato il binding locale.
  3. UI raggiungibile: accesso su http://127.0.0.1:8181 via tunnel o sulla rete di gestione autorizzata.
  4. Certificato valido: dal browser o con curl -I https://tuodominio.tld verifica che il certificato sia emesso correttamente.
  5. Log puliti: sudo docker logs --tail 50 npm non deve mostrare errori ripetuti su database, bind o permessi.

Se vuoi un controllo più sintetico della reachability pubblica, usa:

curl -sI https://tuodominio.tld | head

Atteso: risposta 200, 301 o 302 coerente con la tua configurazione. Errori 502 o 504 indicano che NPM è su ma il backend proxyato non risponde.

Problemi comuni da evitare

  • Lasciare la porta 81 esposta su Internet.
  • Usare credenziali predefinite oltre il primo accesso.
  • Mettere NPM su 80/443 senza verificare conflitti con altri servizi.
  • Ignorare il backup dei volumi prima degli upgrade.
  • Confondere problemi DNS con problemi di NPM.

Se il certificato Let’s Encrypt non viene emesso, la causa più frequente è una combinazione di DNS errato, porta 80 non raggiungibile o proxy/CDN davanti che blocca la challenge. In quel caso, prima di cambiare configurazioni a caso, verifica il layer di rete e la raggiungibilità esterna.

Conclusione operativa

Su Debian 12, Nginx Proxy Manager si installa bene in Docker se tieni separati i dati persistenti, limiti la dashboard admin, apri solo le porte necessarie e fai controlli dopo ogni modifica. La regola pratica è semplice: prima osservi, poi cambi una cosa sola, poi verifichi. Così eviti di trasformare un proxy utile in un punto unico di fallimento.

Assunzione: macchina Debian 12 singola, uso standard di Docker Compose, UI admin non esposta pubblicamente, e dominio già delegato correttamente verso l’host.