SSD Nodes Learn 🎉 VPS da $5.50/mese
Guide Matt ConnorDi Matt Connor · Aggiornato 2026-08-13

firewalld su Rocky e AlmaLinux: guida per VPS

Apri SSH, abilita una porta web, chiudine un’altra e mantieni le regole dopo il riavvio. Guida a zone, configurazione attiva e trappola di --permanent.

Che cos’è firewalld e perché Rocky e AlmaLinux lo includono

firewalld è il gestore del firewall installato per impostazione predefinita su Rocky Linux, AlmaLinux e sulle altre ricostruzioni di Red Hat Enterprise Linux (RHEL). Non analizza direttamente i pacchetti. Mantiene una configurazione salvata e la converte in regole nftables. Il comando firewall-cmd modifica questa configurazione mentre il server resta online.

Se sai già come funziona ufw su un VPS Ubuntu, conosci già il principio. firewalld aggiunge due concetti che ufw non prevede. Il primo sono le zone: criteri denominati in cui vengono classificati i pacchetti. Il secondo è la separazione tra regole attive e regole salvate. Questa separazione è controllata dal flag --permanent ed è la principale fonte di confusione nell’uso di questo strumento.

Tutto ciò che segue consiste in comandi da eseguire sul tuo server. Verifica ogni modifica da una seconda macchina, perché una regola che sembra corretta sul server può comunque essere errata dal punto di vista di Internet.

Apri SSH prima di fare qualsiasi altra cosa

Nella maggior parte delle installazioni Rocky e AlmaLinux, firewalld è già presente e in esecuzione, e la configurazione fornita consente SSH. Alcune immagini cloud minimali lo rimuovono. Verificalo invece di dare per scontato che sia presente.

sudo dnf install -y firewalld
sudo systemctl enable --now firewalld
sudo firewall-cmd --state

firewall-cmd --state restituisce running. Se il servizio è arrestato, ogni altra chiamata firewall-cmd restituisce FirewallD is not running e termina con un codice diverso da zero. È il primo controllo da eseguire quando un comando sembra non fare assolutamente nulla.

Ora verifica ciò che è attualmente consentito.

sudo firewall-cmd --list-all

L'output effettivo contiene alcune righe in più. Queste sono quelle importanti:

public (active)
  target: default
  interfaces: eth0
  sources:
  services: cockpit dhcpv6-client ssh
  ports:
  rich rules:

ssh nella riga services: è il motivo per cui la sessione è ancora attiva. Se manca, aggiungilo prima di modificare qualsiasi altra cosa, perché avviare un firewall senza una regola per SSH termina la sessione e impedisce di accedere nuovamente al server.

sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload

target: default indica che un pacchetto che non corrisponde ad alcuna regola viene rifiutato con una risposta ICMP (internet control message protocol) host-prohibited, quindi un client che accede a una porta chiusa riceve subito No route to host. Impostando la destinazione su DROP, il server resta invece silenzioso e gli scanner attendono quindi il timeout.

sudo firewall-cmd --permanent --zone=public --set-target=DROP
sudo firewall-cmd --reload

Prima di eseguire il comando, considera questa conseguenza: DROP impedisce anche al server di rispondere a ping, quindi anche il tuo monitoraggio smette di ricevere dati.

Perché la regola è scomparsa? Il flag --permanent

firewalld mantiene contemporaneamente due configurazioni. La configurazione runtime è quella applicata dal kernel in questo momento. La configurazione permanente è quella salvata in /etc/firewalld/zones/public.xml e ripristinata dopo un reload o un riavvio.

Un comando senza --permanent modifica soltanto la configurazione runtime. Diventa effettivo subito, ma viene perso al reload o al successivo avvio. Un comando con --permanent scrive il file senza modificare ciò che è attualmente in esecuzione, quindi la porta resta chiusa finché non si esegue un reload. Nessuno dei due comportamenti è un bug. Entrambi confondono gli utenti, perché il comando restituisce success in ogni caso.

Scrivere sempre entrambe le opzioni.

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload

È possibile leggere entrambe le configurazioni. È il modo più rapido per capire quale dei due errori è stato commesso.

sudo firewall-cmd --list-services
sudo firewall-cmd --permanent --list-services

Il primo comando stampa l'insieme attivo. Il secondo stampa l'insieme salvato. Se l'insieme attivo contiene un servizio che non è presente in quello salvato, la regola viene persa al successivo reload. Se l'insieme salvato contiene una regola che non è presente in quello attivo, è stato dimenticato il reload. sudo firewall-cmd --runtime-to-permanent copia tutto il contenuto attivo nel file salvato. È utile dopo una sessione di prove.

--reload mantiene lo stato del connection tracking, quindi la sessione SSH resta attiva. --complete-reload ricarica anche i moduli del kernel e perde questo stato. Di conseguenza, in genere termina tutte le connessioni aperte, inclusa quella corrente. Usare il reload semplice.

È disponibile anche una protezione automatica. Una regola runtime può scadere autonomamente.

sudo firewall-cmd --add-service=http --timeout=5m

Questa regola viene rimossa dopo cinque minuti. Non può essere combinata con --permanent, ed è proprio questo lo scopo: consente di testare una modifica quando non si è certi del risultato. La protezione precedente è più efficace. Tenere aperta una seconda sessione SSH durante la modifica delle regole e chiuderla solo dopo aver verificato, con un nuovo accesso, che le nuove regole funzionano.

Zone e perché su un VPS conta solo la zona predefinita

Una zona è un insieme denominato di autorizzazioni associato a un livello di affidabilità. firewalld assegna ogni pacchetto in ingresso a una sola zona. Prima confronta l'indirizzo di origine del pacchetto con l'elenco sources: di ogni zona. Se non trova corrispondenze, usa la zona a cui è associata l'interfaccia in ingresso. Se l'interfaccia non è associata ad alcuna zona, il pacchetto viene assegnato alla zona predefinita.

sudo firewall-cmd --get-default-zone
sudo firewall-cmd --get-active-zones

Su un VPS con una sola interfaccia di rete, la prima risposta è quasi sempre public, ed è l'unica zona che utilizzerai. firewall-cmd senza l'argomento --zone= agisce sulla zona predefinita. Per questo tutti i comandi brevi di questa guida funzionano senza specificare una zona.

Questo è l'errore che può farti perdere un pomeriggio. Se l'interfaccia è associata a un'altra zona, le regole vengono aggiunte a public mentre il traffico viene gestito altrove. Di conseguenza, nessuna regola aggiunta ha effetto e non viene mostrato alcun avviso. --get-active-zones mostra l'associazione:

public
  interfaces: eth0

Se l'interfaccia compare sotto un nome di zona diverso, puoi scrivere le regole in quella zona usando --zone= oppure spostare l'interfaccia.

sudo firewall-cmd --permanent --zone=public --change-interface=eth0
sudo firewall-cmd --reload

NetworkManager gestisce le interfacce su Rocky e AlmaLinux e ripristina la zona quando la connessione viene attivata. Impostala anche in NetworkManager, così un riavvio non annulla la configurazione. Usa il nome della connessione mostrato dal primo comando, perché raramente coincide con il nome del dispositivo.

sudo nmcli connection show
sudo nmcli connection modify "System eth0" connection.zone public

La corrispondenza sull'origine ha precedenza su quella sull'interfaccia. In questo modo puoi applicare una policy diversa a un singolo indirizzo. La zona predefinita trusted accetta tutto.

sudo firewall-cmd --permanent --zone=trusted --add-source=203.0.113.10/32
sudo firewall-cmd --reload

Presta attenzione a questa zona. Apre tutte le porte del server a quell'indirizzo, compresa la porta del database che ritenevi privata. Usa una rich rule quando vuoi autorizzare una sola porta e non un intero host.

Che cos’è un servizio firewalld?

Un servizio è un insieme denominato di porte, distribuito come file XML. --add-service=https apre 443/tcp perché /usr/lib/firewalld/services/https.xml definisce il significato di https.

sudo firewall-cmd --get-services
sudo firewall-cmd --info-service=https

--info-service mostra le porte associate al nome:

https
  ports: 443/tcp

Usa il nome quando disponibile. In --list-all sarà più leggibile anche tra sei mesi, e pacchetti come Cockpit installano un proprio file di servizio. Usa --add-port per tutto ciò che non ha una definizione.

Il punto da controllare è questo: il servizio ssh indica 22/tcp e nessun’altra porta. Se hai spostato SSH su un’altra porta durante l’irrobustimento dell’accesso SSH al server, --add-service=ssh non apre la porta effettivamente utilizzata.

sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload

In una nuova installazione RHEL c’è un secondo vincolo. SELinux (security-enhanced Linux) assegna etichette ai numeri di porta e sshd non può mettersi in ascolto su una porta che non rientra nelle etichette consentite. Di conseguenza non si avvia e il log riporta error: Bind to port 2222 on 0.0.0.0 failed: Permission denied. Assegna prima un’etichetta alla porta.

sudo dnf install -y policycoreutils-python-utils
sudo semanage port -a -t ssh_port_t -p tcp 2222

Come posso vedere cosa è aperto in questo momento?

sudo firewall-cmd --list-all
sudo firewall-cmd --list-rich-rules
sudo nft list table inet firewalld | head -n 40

I primi due comandi mostrano ciò che firewalld considera attivo. Il terzo legge le regole effettivamente caricate dal kernel nella tabella gestita da firewalld. I risultati dovrebbero coincidere.

Nessuno di questi controlli costituisce una prova. Esegui il test da un'altra macchina:

nc -zv 203.0.113.20 443

Non eseguire il test sul server stesso. firewalld accetta tutto il traffico proveniente dall'interfaccia loopback, quindi curl http://localhost:8080 riesce indipendentemente dalle regole configurate. Questo test conferma che il servizio è attivo. Non fornisce alcuna informazione sul firewall.

Consenti l’accesso a una porta Web

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-services

L’ultimo comando dovrebbe ora elencare http https insieme a quanto era già presente. Se il sito continua a non rispondere, il firewall potrebbe non essere la causa. Una regola autorizza un pacchetto. Deve comunque esserci un processo in ascolto per riceverlo.

sudo ss -tlnp

Un socket indicato come 0.0.0.0:443 o *:443 accetta connessioni da qualsiasi indirizzo. Un socket indicato come 127.0.0.1:443 risponde solo sull’interfaccia di loopback e nessuna regola del firewall lo renderà raggiungibile dall’esterno. Porte e socket in ascolto su Linux illustra questa differenza in modo più dettagliato.

Come chiudere nuovamente una porta?

sudo firewall-cmd --permanent --remove-service=http
sudo firewall-cmd --reload

Anche in questo caso si applica la regola --permanent, e in questa direzione le conseguenze sono più gravi. Rimuovi un servizio solo dalla configurazione runtime e la porta sembra chiusa, ma il successivo reload o riavvio la riapre leggendo il file salvato. È una vulnerabilità che non noterai, perché il controllo eseguito ha avuto esito positivo.

La rimozione di un elemento che non era mai presente restituisce Warning: NOT_ENABLED: http, ma termina comunque con codice 0. L'aggiunta dello stesso elemento due volte restituisce Warning: ALREADY_ENABLED: http. Entrambi i casi sono sicuri. Un nome scritto in modo errato è diverso: Error: INVALID_SERVICE indica che firewalld non ha alcuna definizione con quel nome e che non è stata apportata alcuna modifica.

Se --list-all mostra cockpit e non utilizzi la console web Cockpit sulla porta 9090, rimuovilo. Ogni porta aperta corrisponde a un servizio che devi mantenere aggiornato con le patch.

Limitare una porta a un solo indirizzo sorgente

Le rich rules sono la forma estesa da usare quando un semplice nome di servizio non esprime ciò che serve. Limitare SSH a un solo indirizzo dell'ufficio richiede due comandi. Il secondo è quello che spesso viene dimenticato.

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.10/32" service name="ssh" accept'
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --reload

Una zone è un insieme di autorizzazioni, non un elenco numerato che si interrompe alla prima corrispondenza. La rich rule aggiunge un'azione di accettazione per un indirizzo. Non nega l'accesso a nessuno. Finché ssh resta nella riga services:, l'intera Internet continua a raggiungere la porta 22 e la rich rule non produce alcun effetto osservabile. Rimuovi la voce generale. In caso contrario, quella specifica è solo decorativa.

Per una porta che non dispone di un nome di servizio, specifica direttamente la porta.

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.10/32" port port="5432" protocol="tcp" accept'

Per eliminare il traffico di rete indesiderato e conservare una registrazione, inserisci l'elemento di log prima dell'azione. Questo è l'ordine previsto dal linguaggio delle rich rule.

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="198.51.100.0/24" log prefix="fw-drop " level="info" limit value="3/m" drop'
sudo firewall-cmd --reload
sudo journalctl -k -g fw-drop

Il valore limit impedisce che un flusso di pacchetti riempia il journal. Prima di limitare SSH a un solo indirizzo, verifica che l'indirizzo sia stabile. Una connessione domestica con indirizzo IP dinamico ti impedirà l'accesso il giorno in cui l'indirizzo cambia. Verifica quindi prima che l'accesso alla console del provider sia disponibile e funzionante.

Comandi ufw e relativi equivalenti firewall-cmd

Stesse attività, strumento diverso. Ogni riga --permanent richiede un elemento sudo firewall-cmd --reload dopo di sé; è l’unica cosa che un elenco di questo tipo non può mostrare.

  • sudo ufw enable diventa sudo systemctl enable --now firewalld
  • sudo ufw disable diventa sudo systemctl disable --now firewalld
  • sudo ufw status verbose diventa sudo firewall-cmd --list-all
  • sudo ufw allow OpenSSH diventa sudo firewall-cmd --permanent --add-service=ssh
  • sudo ufw allow 443/tcp diventa sudo firewall-cmd --permanent --add-port=443/tcp
  • sudo ufw delete allow 443/tcp diventa sudo firewall-cmd --permanent --remove-port=443/tcp
  • sudo ufw allow from 203.0.113.10 to any port 22 diventa la rich rule mostrata sopra
  • sudo ufw reload diventa sudo firewall-cmd --reload
  • sudo ufw default deny incoming è già il comportamento della zona public, mentre --set-target=DROP ne è la versione silenziosa
  • sudo ufw logging on diventa sudo firewall-cmd --set-log-denied=all

È importante chiarire una differenza. ufw mantiene un elenco numerato e consente di inserire una regola alla posizione 1. firewalld non usa numeri di regola, quindi qui l’istruzione «inserisci questa regola per prima» non ha significato. Quando due voci di firewalld sembrano contraddirsi, prevale l’accettazione ampia, perché nell’insieme non esiste alcun rifiuto. La voce ampia deve essere rimossa manualmente.

Perché il mio container Docker è raggiungibile anche quando il firewall sembra chiuso?

Perché una porta pubblicata dal container non passa dalla parte del firewall controllata dalla zona. docker run -d -p 8080:80 nginx indica a Docker di scrivere le proprie regole NAT (network address translation) e di inoltro. Un pacchetto che arriva sulla porta 8080 viene riscritto e instradato verso il container. Viene quindi inoltrato, non consegnato all'host. Le righe services: e ports: della zona regolano i pacchetti consegnati all'host. Le regole di Docker regolano il percorso di inoltro e li accettano.

Il risultato è un server in cui sudo firewall-cmd --list-all non mostra la porta 8080, ma nc -zv 203.0.113.20 8080 da un altro computer stabilisce comunque la connessione. Verificate cosa ha installato Docker:

sudo iptables -t nat -L DOCKER -n

La correzione consiste nel flag di pubblicazione. Associate la porta all'interfaccia di loopback e mettete un reverse proxy davanti al container.

docker run -d -p 127.0.0.1:8080:80 nginx

Ora il container risponde a curl http://127.0.0.1:8080 sul server e non accetta connessioni dall'esterno. Gli utenti Ubuntu incontrano lo stesso problema, descritto in perché i container Docker pubblicano le porte aggirando direttamente ufw. Podman rootful, incluso nei repository di base di Rocky e AlmaLinux, pubblica le porte usando lo stesso approccio NAT. Eseguite quindi il test da un altro computer invece di affidarvi all'elenco della zona.

Rendere la configurazione persistente dopo un riavvio e gestire gli errori più comuni

sudo systemctl is-enabled firewalld
sudo systemctl status firewalld

enabled e active (running) sono le opzioni corrette. Un firewall in esecuzione ma non abilitato protegge il server fino al primo riavvio. Questo controllo deve rientrare nella procedura dei primi dieci minuti su un nuovo VPS, insieme alle chiavi SSH e agli aggiornamenti.

I comandi nftables diretti e firewalld non devono essere usati insieme. firewalld gestisce una tabella chiamata inet firewalld. sudo nft flush ruleset la elimina; il server resta quindi aperto a tutto, mentre firewall-cmd --list-all continua a mostrare la configurazione prevista, perché firewalld visualizza ciò che ritiene configurato e non ciò che è effettivamente presente nel kernel. sudo firewall-cmd --reload reinstalla le regole. Configura le regole con firewall-cmd, in modo che vengano ripristinate dopo un reload.

Due gestori del firewall sullo stesso server. Installare ufw o iptables-services insieme a firewalld significa avere due programmi che scrivono le regole senza coordinarsi. Il risultato dipende da quale servizio viene avviato per ultimo. Scegline uno. Su Rocky e AlmaLinux, firewalld è il gestore supportato dalla distribuzione.

Il firewall del provider davanti al server. Molti pannelli VPS includono un firewall di rete separato. Se --list-all mostra una porta aperta ma una connessione dall'esterno continua a fallire, controlla il pannello prima di modificare il server. Vale anche il contrario: una regola aperta nel pannello non serve se firewalld rifiuta il pacchetto.

Eseguire firewall-cmd senza sudo. Ogni modifica richiede root. Senza questo privilegio, la richiesta viene rifiutata dal controllo di autorizzazione e non viene modificato nulla. A una prima verifica può sembrare che il comando sia stato ignorato.

Sei comandi coprono la maggior parte delle attività quotidiane: --list-all per leggere lo stato, --permanent --add-service o --add-port per aprire una porta o un servizio, --permanent --remove-service per chiuderli, --reload per applicare il file salvato e --runtime-to-permanent dopo una serie di prove. La zone è public, il flag è --permanent e l'unico controllo affidabile deve essere eseguito da un'altra macchina.

FAQ

Perché la regola di firewalld è scomparsa dopo un riavvio?

La regola è stata aggiunta solo alla configurazione runtime. sudo firewall-cmd --add-service=http la applica immediatamente, ma la regola viene eliminata al successivo reload o avvio perché la configurazione salvata in /etc/firewalld/zones/public.xml non è mai stata modificata. Aggiungi --permanent, quindi esegui sudo firewall-cmd --reload. Per conservare le regole già aggiunte manualmente, esegui sudo firewall-cmd --runtime-to-permanent, che copia l'insieme attivo nel file salvato.

Perché non cambia nulla dopo aver aggiunto una regola con --permanent?

Perché --permanent scrive il file e non modifica il firewall in esecuzione. La porta resta chiusa finché sudo firewall-cmd --reload non carica la configurazione salvata nel kernel. Confronta sudo firewall-cmd --list-services con sudo firewall-cmd --permanent --list-services: se l'elenco salvato contiene una voce che manca nell'elenco attivo, devi eseguire il reload.

Devo usare --add-service o --add-port?

Usa --add-service quando esiste un nome per il servizio che esegui. Esprime l'intento e sudo firewall-cmd --info-service=https mostra esattamente quali porte copre quel nome. Usa --add-port quando non esiste una definizione per il servizio o quando il servizio è in ascolto su una porta non standard. Il servizio ssh indica soltanto 22/tcp, quindi, se SSH è stato spostato sulla porta 2222, servono --add-port=2222/tcp e un'etichetta SELinux per quella porta.

Perché il mio container Docker è raggiungibile quando firewall-cmd mostra la porta chiusa?

Una porta pubblicata viene riscritta dalle regole NAT di Docker e inoltrata al container. Il pacchetto non viene quindi consegnato all'host, mentre gli elenchi di servizi e porte di una zona si applicano soltanto ai pacchetti consegnati all'host. Il container risponde da Internet anche se --list-all non mostra nulla. Pubblica invece la porta sull'interfaccia loopback con docker run -d -p 127.0.0.1:8080:80 nginx e configura un reverse proxy davanti al container.

Posso installare ufw su Rocky Linux invece di firewalld?

Due gestori firewall sullo stesso server scrivono regole senza conoscere le modifiche dell'altro. Quale insieme di regole resta attivo dipende dal servizio avviato per ultimo. firewalld è lo strumento supportato su Rocky Linux e AlmaLinux, è già installato e usa lo stesso backend nftables che userebbe ufw. Impara una volta la zona predefinita e il flag --permanent: sono sufficienti per gestire l'intero strumento.