← Back to desktop ← Return to Blog

Hardening server Linux: chiudere SSH, HestiaCP e Portainer

L’hardening di un server Linux serve a ridurre al minimo ciò che un attaccante può raggiungere da Internet. In concreto vuol dire: SSH solo con chiavi e senza root, pannelli di amministrazione come HestiaCP e Portainer non esposti a tutti, nessuna porta di database aperta, accessi dei fornitori nominali e revocabili, log consultabili. Non c’è nulla di esotico. Il problema è che spesso nessuno lo fa davvero, perché il server “funziona” e nessuno guarda quali porte risponde al mondo.

In questo articolo spiego come ragiono quando prendo in carico un server che ospita siti WordPress o web app come quelle che sviluppo e gestisco (apicco.app, indelio.eu, tandemops.app), e quali verifiche consiglio a qualsiasi PMI che abbia un server affidato a terzi.

Perché parlarne adesso: l’allerta ACN sugli accessi esterni

A novembre 2026 l’Agenzia per la Cybersicurezza Nazionale ha ripubblicato un bollettino del 13 ottobre chiedendo sei verifiche immediate: esposizione su Internet, reti OT, ditte di manutenzione con accesso da remoto, credenziali, temperature e dispositivi non più supportati. Il contesto erano gli attacchi a impianti di refrigerazione in Europa e casi segnalati anche in Italia, come riportato da Cybersecurity360. Il giorno prima, secondo AGI, il tema degli attacchi alla filiera era stato affrontato in una riunione governativa.

L’allerta riguarda soprattutto impianti industriali, ma il principio vale identico per i server web: ogni accesso di manutenzione è una porta. Il pannello hosting raggiungibile da qualsiasi IP, la console Docker pubblicata per comodità, l’utente SSH condiviso tra tre fornitori diversi: sono la versione “web” del frigorifero collegato a Internet con la password di fabbrica.

Primo passo: sapere cosa è esposto

Prima di toccare qualsiasi configurazione faccio un inventario. Due controlli bastano per partire:

  • Dall’interno: ss -tulpn mostra quali processi sono in ascolto e su quale indirizzo. Un servizio legato a 0.0.0.0 ascolta su tutte le interfacce, quindi potenzialmente anche su quella pubblica.
  • Dall’esterno: una scansione delle porte del proprio IP pubblico (ad esempio con nmap, da una macchina fuori dalla rete) dice cosa vede davvero un attaccante. È l’unico controllo che conta, perché tiene conto di firewall e regole del provider.

Il risultato ideale per un server web è corto: 80 e 443 aperte, SSH aperto solo se serve e possibilmente filtrato, tutto il resto chiuso. Se compaiono 3306 (MySQL/MariaDB), 5432 (PostgreSQL), 6379 (Redis), 9000/9443 (Portainer) o la porta del pannello, c’è lavoro da fare.

SSH: chiavi, niente root, niente utenti condivisi

SSH è la porta di amministrazione principale e va trattata come tale. Le regole che applico:

  1. Solo autenticazione a chiave: PasswordAuthentication no in sshd_config. Con le password, un attacco a dizionario è solo questione di tempo e di log intasati.
  2. Login di root disabilitato: PermitRootLogin no. Si entra con un utente nominale e si eleva con sudo, così resta traccia di chi ha fatto cosa.
  3. Un utente, una persona: se un’altra ditta deve intervenire, riceve un proprio utente con la propria chiave. A fine intervento la chiave si rimuove da authorized_keys. Le chiavi condivise sono impossibili da revocare senza bloccare tutti.
  4. Limitazione dei tentativi: fail2ban o equivalente per bannare gli IP che insistono. Cambiare la porta di SSH riduce il rumore nei log, ma non è una misura di sicurezza.
  5. Filtro per IP, quando possibile: se gli amministratori lavorano da indirizzi noti o tramite VPN, SSH può essere aperto solo a quelli.

Su come impostare l’accesso remoto per l’intera azienda, non solo per i server, rimando all’approfondimento su VPN e Zero Trust per l’accesso remoto.

HestiaCP: il pannello non deve parlare con tutti

HestiaCP è il pannello che uso per gestire hosting, domini, email e certificati dei clienti, e ne ho parlato in dettaglio in come gestisco l’hosting con HestiaCP. Il pannello ascolta di default sulla porta 8083 e, se non si interviene, è raggiungibile da qualunque IP.

Le misure pratiche:

  • Restringere la porta del pannello agli IP degli amministratori o alla VPN, usando il firewall integrato di HestiaCP. Il cliente finale che deve solo leggere le email non ha bisogno di vedere il pannello.
  • Autenticazione a due fattori sugli account amministrativi. HestiaCP la supporta: va attivata, non basta che esista.
  • Account separati per ogni cliente e per ogni persona, senza riutilizzare l’utente admin per il lavoro quotidiano.
  • Aggiornamenti regolari del pannello e del sistema operativo, con verifica dopo l’update che i servizi siano ripartiti.

Docker e Portainer: attenzione alle porte che il firewall non vede

Qui c’è la trappola più frequente che trovo nei server altrui. Quando un container pubblica una porta con -p 9443:9443, Docker scrive direttamente le proprie regole iptables. Il risultato è che la porta può essere raggiungibile da Internet anche se UFW la dà per bloccata. Molti pensano di essere protetti dal firewall e invece hanno Portainer, un database o un pannello di amministrazione aperti al mondo.

Come lo gestisco:

  • Bind su localhost: i servizi interni si pubblicano come 127.0.0.1:9443:9443, così ascoltano solo sulla macchina stessa.
  • Reverse proxy davanti: Nginx espone solo ciò che deve essere pubblico, con HTTPS e, per le interfacce di amministrazione, una restrizione per IP o un’autenticazione aggiuntiva.
  • Database mai pubblicati: i container dell’app parlano con il database su una rete Docker interna. Nessuna porta mappata verso l’host.
  • Portainer solo per chi amministra: dà controllo completo sui container, quindi su tutto ciò che girano. Va trattato come un accesso root, non come una dashboard qualsiasi.

Per la parte di configurazione generale di container e stack rimando a Docker e Portainer per l’infrastruttura web.

Accessi dei fornitori: il punto che l’ACN mette in evidenza

Un server di una PMI raramente ha un solo amministratore nel corso degli anni. C’è chi ha sviluppato il sito, chi ha fatto la migrazione, il consulente che ha installato un plugin. Ognuno lascia un utente, una chiave o una password. La verifica che consiglio è semplice da descrivere e noiosa da fare:

  1. Elencare tutti gli accessi: utenti di sistema, chiavi SSH, account del pannello, utenti FTP/SFTP, amministratori WordPress, token API.
  2. Associare ogni accesso a una persona e a un motivo. Se nessuno sa di chi è, si disabilita.
  3. Cambiare le credenziali condivise o passate per email o messaggi.
  4. Definire per iscritto come si chiede, si concede e si revoca un accesso. Anche mezza pagina è meglio di niente.

Le credenziali delle applicazioni (chiavi API, password del database, token di pagamento) non devono stare nel codice o in file accessibili via web: sono variabili d’ambiente o secret gestiti separatamente.

Log e manutenzione: l’hardening non è un evento

Un server messo in sicurezza oggi si degrada in pochi mesi se nessuno lo segue: arrivano nuovi container, qualcuno apre una porta “solo per una prova”, un pacchetto esce dal supporto. Per questo lo tratto come parte della gestione ordinaria:

  • Aggiornamenti di sicurezza automatici per il sistema operativo, aggiornamenti controllati per pannello, container e applicazioni.
  • Log consultati, non solo conservati: auth.log o journalctl per gli accessi, i log di fail2ban per i ban, i log del reverse proxy per richieste anomale.
  • Ripetere la scansione esterna dopo ogni modifica rilevante e periodicamente, per accorgersi di porte aperte per errore.
  • Sistemi fuori supporto pianificati per la migrazione, coerentemente con quanto chiede l’ACN sui dispositivi non più supportati.

FAQ

Cambiare la porta di SSH è sufficiente?

No. Riduce i tentativi automatici e quindi il rumore nei log, ma chi scansiona tutte le porte trova SSH comunque. La protezione vera viene da chiavi, disattivazione delle password e del login di root, limitazione dei tentativi e, se possibile, filtro per IP.

Se ho UFW attivo, le porte dei container Docker sono bloccate?

Non necessariamente. Docker gestisce iptables per conto proprio e una porta pubblicata può essere raggiungibile anche se UFW sembra bloccarla. La verifica affidabile è la scansione dall’esterno e il bind dei servizi interni su 127.0.0.1.

Il pannello HestiaCP deve essere raggiungibile dal cliente?

Dipende da cosa fa il cliente. Se usa solo email e sito, non gli serve. Se gestisce in autonomia caselle o domini, si può aprire il pannello ai suoi IP o tramite VPN, con 2FA attiva.

Ogni quanto va ripetuto il controllo?

Dopo ogni modifica all’infrastruttura (nuovo container, nuovo servizio, cambio di fornitore) e comunque a intervalli regolari. L’inventario degli accessi va rivisto ogni volta che finisce una collaborazione.

Server e applicazioni gestiti end-to-end

Quando sviluppo una web app o un sito, il lavoro non finisce al deploy: il server su cui gira, gli accessi, gli aggiornamenti e i log fanno parte del prodotto. È così che gestisco i miei progetti e quelli dei clienti. Se hai un’applicazione da costruire, o un server che nessuno ha mai davvero controllato, contattami per parlare di sviluppo web e app: partiamo da cosa è esposto oggi e da cosa serve davvero.

Cornel Caba — signature