firewalld su VPS Rocky o AlmaLinux: guida base
Apri SSH, abilita una porta web, chiudine un'altra e mantieni tutto dopo il riavvio. Guida a zone e opzione --permanent su Rocky e AlmaLinux.
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). Entrambe le distribuzioni hanno ereditato questa impostazione predefinita, invece di sceglierla autonomamente. Il motivo è più chiaro se si conosce come Rocky e AlmaLinux hanno ricostruito il lavoro di Red Hat dopo il cambio di direzione di CentOS. firewalld non analizza direttamente i pacchetti. Mantiene una configurazione salvata e la converte in regole nftables. Un comando, firewall-cmd, modifica la configurazione mentre il server resta operativo. Nulla di questa guida cambia tra le due distribuzioni, perché ciò che distingue realmente Rocky da AlmaLinux riguarda la promessa di compatibilità e l’insieme di CPU ancora supportate, non il firewall.
Se si sa già come funziona ufw su un VPS Ubuntu, si conosce già lo scopo dello strumento. firewalld aggiunge due concetti che ufw non prevede. Il primo sono le zone: una policy denominata a cui vengono assegnati 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 proprio server. Testare ogni modifica da una seconda macchina, perché una regola che sembra corretta sul server può comunque essere errata quando viene verificata da Internet.
Aprire SSH prima di eseguire qualsiasi altra operazione
Nella maggior parte delle installazioni Rocky e AlmaLinux, firewalld è già presente e in esecuzione. La configurazione fornita consente le connessioni SSH. Alcune immagini cloud minimali lo rimuovono. Verificare invece di dare questo per scontato.
sudo dnf install -y firewalld
sudo systemctl enable --now firewalld
sudo firewall-cmd --statefirewall-cmd --state stampa 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 verificare quali regole sono attualmente consentite.
sudo firewall-cmd --list-allL'output reale contiene alcune righe in più. Quelle importanti sono:
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, aggiungerlo prima di modificare qualsiasi altra impostazione: l'avvio di un firewall senza una regola per SSH chiude la sessione e impedisce di accedere nuovamente al server.
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reloadtarget: default indica che un pacchetto che non corrisponde ad alcuna regola viene rifiutato con una risposta ICMP (Internet Control Message Protocol) host-prohibited; di conseguenza, un client che raggiunge una porta chiusa riceve subito No route to host. Impostando la destinazione su DROP, il server rimane invece silenzioso e gli scanner attendono il timeout.
sudo firewall-cmd --permanent --zone=public --set-target=DROP
sudo firewall-cmd --reloadValutare le conseguenze prima di eseguire questo comando: DROP impedisce al server di rispondere anche a ping, quindi anche il proprio monitoraggio smette di ricevere risposte.
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 solo la configurazione runtime. Ha effetto immediato e viene perso al reload o al successivo avvio. Un comando con --permanent scrive il file, ma non modifica ciò che è in esecuzione; la porta resta quindi chiusa finché non si esegue un reload. Nessuno dei due comportamenti è un bug. Entrambi possono creare confusione, perché in ogni caso il comando stampa success.
Scrivi sempre entrambe le opzioni.
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reloadPuoi leggere entrambe le configurazioni. È il modo più rapido per capire quale dei due errori hai commesso.
sudo firewall-cmd --list-services
sudo firewall-cmd --permanent --list-servicesIl primo comando stampa l'insieme attivo. Il secondo stampa quello salvato. Se l'insieme attivo contiene un servizio che non è presente in quello salvato, la regola scompare al reload successivo. Se invece l'insieme salvato contiene una regola che non è presente in quello attivo, hai dimenticato il reload. sudo firewall-cmd --runtime-to-permanent copia tutto l'insieme 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 quello stato. In genere questo termina tutte le connessioni aperte, inclusa la tua. Usa il reload normale.
È disponibile anche una rete di sicurezza integrata. Una regola runtime può scadere automaticamente.
sudo firewall-cmd --add-service=http --timeout=5mQuesta regola viene rimossa dopo cinque minuti. Non può essere combinata con --permanent, ed è proprio questo lo scopo: puoi usarla per testare una modifica che non sei certo di voler mantenere. La rete di sicurezza più collaudata è ancora migliore. Mantieni aperta una seconda sessione SSH mentre modifichi le regole e non chiuderla finché un nuovo accesso non conferma 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 attendibilità. firewalld assegna ogni pacchetto in ingresso a una sola zona. Prima confronta l'indirizzo sorgente del pacchetto con l'elenco sources: di ogni zona. Se non trova corrispondenze, usa la zona a cui è associata l'interfaccia di 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-zonesSu un VPS con una sola interfaccia di rete, la prima risposta è quasi sempre public, ed è l'unica zona che userai. firewall-cmd senza l'argomento --zone= opera sulla zona predefinita. Per questo tutti i comandi brevi di questa guida funzionano senza specificare una zona.
Ecco il problema che può farti perdere un pomeriggio. Se l'interfaccia è associata a un'altra zona, le tue regole vengono inserite in public, mentre il traffico viene gestito altrove. Di conseguenza, le nuove regole non hanno alcun effetto e non viene visualizzato alcun avviso. --get-active-zones mostra l'associazione:
public
interfaces: eth0Se l'interfaccia compare sotto un nome di zona diverso, inserisci le regole in quella zona usando --zone= oppure sposta l'interfaccia.
sudo firewall-cmd --permanent --zone=public --change-interface=eth0
sudo firewall-cmd --reloadNetworkManager gestisce le interfacce su Rocky e AlmaLinux e ripristina la zona quando la connessione viene attivata. Imposta l'associazione anche in NetworkManager, così un riavvio non annulla le modifiche. Ricava il nome della connessione dal primo comando, perché raramente coincide con il nome del dispositivo.
sudo nmcli connection show
sudo nmcli connection modify "System eth0" connection.zone publicLa corrispondenza sull'origine ha la precedenza su quella sull'interfaccia. In questo modo un indirizzo può avere una policy diversa. La zona predefinita trusted accetta tutto.
sudo firewall-cmd --permanent --zone=trusted --add-source=203.0.113.10/32
sudo firewall-cmd --reloadUsala con cautela. Apre tutte le porte del server per quell'indirizzo, incluso il database che ritenevi privato. Usa una rich rule quando vuoi autorizzare una sola porta, 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/tcpUsa il nome quando disponibile. Sei mesi dopo, il risultato è più chiaro in --list-all, e pacchetti come Cockpit installano un proprio file di servizio. Usa --add-port per tutto ciò che non dispone di una definizione.
Il punto da controllare è il seguente: il servizio ssh indica 22/tcp e nient'altro. Se hai spostato SSH su un'altra porta durante la messa in sicurezza 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 --reloadIn una nuova installazione RHEL esiste un secondo controllo su quella porta. SELinux (security-enhanced Linux) assegna etichette ai numeri di porta e sshd non può associarsi a 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 l'etichetta alla porta.
sudo dnf install -y policycoreutils-python-utils
sudo semanage port -a -t ssh_port_t -p tcp 2222Come 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 40I primi due comandi mostrano ciò che firewalld considera attivo. Il terzo legge le regole effettivamente presenti nel 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 443Non eseguire il test sul server stesso. firewalld accetta tutto il traffico ricevuto sull'interfaccia di loopback, quindi curl http://localhost:8080 ha esito positivo indipendentemente dalle regole configurate. Questo test indica che il servizio è attivo. Non fornisce alcuna informazione sul firewall.
Consenti 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-servicesL'ultimo comando dovrebbe ora elencare http https insieme agli elementi già presenti. Se il sito continua a non rispondere, il firewall potrebbe non essere la causa. Una regola consente il passaggio di un pacchetto. Per accettarlo, deve comunque esserci un processo in ascolto.
sudo ss -tlnpUn 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 soltanto sull'interfaccia di loopback; nessuna regola del firewall lo renderà raggiungibile dall'esterno. Porte e socket in ascolto su Linux illustra questa differenza in maggiore dettaglio.
Come richiudere una porta?
sudo firewall-cmd --permanent --remove-service=http
sudo firewall-cmd --reloadAnche in questo caso si applica la regola --permanent, ma in questa direzione gli effetti sono più insidiosi. Rimuovi un servizio solo dalla configurazione runtime e la porta risulta chiusa; al successivo reload o riavvio, però, viene riaperta dal 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 visualizza Warning: NOT_ENABLED: http e restituisce comunque il codice di uscita 0. L'aggiunta dello stesso elemento due volte visualizza Warning: ALREADY_ENABLED: http. Entrambi i casi sono sicuri. Un nome scritto in modo errato è diverso: Error: INVALID_SERVICE significa che firewalld non contiene alcuna definizione con quel nome e che non è stata apportata alcuna modifica.
Se --list-all visualizza cockpit e non usi la console web Cockpit sulla porta 9090, rimuovilo. Ogni porta aperta corrisponde a un servizio che devi mantenere aggiornato. Per i servizi che decidi di mantenere, dnf-automatic può installare gli aggiornamenti di sicurezza in base a una pianificazione, così questa attività non dipende dal fatto che tu te ne ricordi. Installare una patch, però, non equivale a riavviare il servizio, e needs-restarting mostra quali servizi utilizzano ancora le librerie precedenti dopo l'installazione degli aggiornamenti.
Limita una porta a un unico indirizzo sorgente
Le rich rules sono la forma estesa, utile quando un semplice nome di servizio non consente di esprimere ciò che serve. Per limitare SSH a un unico indirizzo dell'ufficio servono due comandi, e 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 --reloadUna zone è un insieme di autorizzazioni, non un elenco numerato che si interrompe alla prima corrispondenza. La rich rule aggiunge un'operazione 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 cambiamento misurabile. Rimuovi l'elemento generale, altrimenti quello specifico è solo decorativo.
Per una porta senza 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 proveniente da una rete rumorosa e mantenere una registrazione, inserisci l'elemento di log prima dell'azione, nell'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-dropIl valore limit impedisce a un flusso elevato di pacchetti di riempire il journal. Prima di limitare SSH a un unico indirizzo, verifica che l'indirizzo sia stabile. Una connessione domestica con un indirizzo IP variabile può impedirti l'accesso dal giorno in cui cambia. Verifica quindi prima che l'accesso alla console del provider sia disponibile e funzionante.
comandi ufw e relativi equivalenti firewall-cmd
Stesso obiettivo, strumento diverso. Ogni riga --permanent richiede una riga sudo firewall-cmd --reload, cosa che un elenco di questo tipo non può mostrare.
sudo ufw enablediventasudo systemctl enable --now firewalldsudo ufw disablediventasudo systemctl disable --now firewalldsudo ufw status verbosediventasudo firewall-cmd --list-allsudo ufw allow OpenSSHdiventasudo firewall-cmd --permanent --add-service=sshsudo ufw allow 443/tcpdiventasudo firewall-cmd --permanent --add-port=443/tcpsudo ufw delete allow 443/tcpdiventasudo firewall-cmd --permanent --remove-port=443/tcpsudo ufw allow from 203.0.113.10 to any port 22diventa la rich rule mostrata soprasudo ufw reloaddiventasudo firewall-cmd --reloadsudo ufw default deny incomingè già il comportamento della zonapublice--set-target=DROPne è la versione silenziosasudo ufw logging ondiventasudo 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 assegna numeri alle regole, quindi qui l'istruzione «metti questa regola per prima» non ha significato. Quando due voci di firewalld sembrano contraddirsi, prevale l'accettazione più ampia, perché nel set non è presente alcuna regola di negazione. La voce più ampia deve essere rimossa manualmente.
Perché il mio container Docker è raggiungibile anche se il firewall sembra chiuso?
Perché una porta pubblicata dal container non attraversa mai la 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 inoltrato al container, quindi viene inoltrato anziché consegnato all'host. Le righe services: e ports: della zona gestiscono i pacchetti consegnati all'host. Le regole di Docker gestiscono il percorso di inoltro e li accettano.
Il risultato è un server in cui sudo firewall-cmd --list-all non mostra la porta 8080, mentre nc -zv 203.0.113.20 8080 da un'altra macchina riesce comunque a connettersi. Verificate cosa ha installato Docker:
sudo iptables -t nat -L DOCKER -nLa correzione consiste nel flag di pubblicazione. Associate la porta all'interfaccia loopback e anteponete un reverse proxy.
docker run -d -p 127.0.0.1:8080:80 nginxOra il container risponde a curl http://127.0.0.1:8080 sul server, ma non è raggiungibile dall'esterno. Gli utenti Ubuntu incontrano lo stesso problema, descritto in perché i container Docker pubblicano le porte direttamente oltre ufw. Podman rootful, incluso da Rocky e AlmaLinux nei repository di base, pubblica le porte usando lo stesso approccio NAT. Eseguite quindi il test da un'altra macchina invece di fidarvi dell'elenco della zona. Questa sovrapposizione spiega anche perché installare Docker Engine su queste distribuzioni richiede alcuni passaggi che una guida per Ubuntu non menziona mai, a partire dal fatto che Podman possiede già il comando docker.
Rendere la configurazione persistente dopo un riavvio e gestire gli errori più comuni
sudo systemctl is-enabled firewalld
sudo systemctl status firewalldenabled e active (running) sono i risultati attesi. Un firewall in esecuzione ma non abilitato protegge il server fino al primo riavvio. Questo controllo va incluso nell'elenco delle verifiche da eseguire nei primi dieci minuti su un nuovo VPS, insieme alle chiavi SSH e agli aggiornamenti.
I comandi nftables eseguiti direttamente non sono compatibili con firewalld. firewalld gestisce una tabella chiamata inet firewalld. sudo nft flush ruleset la elimina e il server rimane quindi aperto a tutto. Tuttavia firewall-cmd --list-all continua a mostrare la configurazione prevista, perché firewalld riporta ciò che ritiene configurato, non ciò che è effettivamente presente nel kernel. sudo firewall-cmd --reload reinstalla le regole. Scrivere le regole con firewall-cmd permette di ripristinarle dopo un reload.
Due gestori firewall sullo stesso server. Installare ufw o iptables-services insieme a firewalld significa avere due programmi che scrivono regole senza conoscersi. 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 hanno un firewall di rete separato. Se --list-all mostra una porta aperta ma una connessione dall'esterno continua a non funzionare, controlla il pannello prima di modificare il server. Vale anche il contrario: una regola aperta nel pannello non serve a nulla se firewalld rifiuta il pacchetto.
Eseguire firewall-cmd senza sudo. Ogni modifica richiede root. Senza sudo, la richiesta viene rifiutata da un controllo di autorizzazione e non viene modificato nulla. A una prima lettura, può sembrare che il comando sia stato ignorato.
Sei comandi coprono la maggior parte delle operazioni quotidiane: --list-all per leggere lo stato, --permanent --add-service o --add-port per aprire una porta o un servizio, --permanent --remove-service per chiuderlo, --reload per applicare il file salvato e --runtime-to-permanent dopo una serie di prove. La zona è public, il flag è --permanent e l'unica verifica attendibile viene eseguita 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 viene eliminata al successivo reload o riavvio, perché la configurazione salvata in /etc/firewalld/zones/public.xml non è mai stata modificata. Aggiungi --permanent, quindi esegui sudo firewall-cmd --reload. Per mantenere le regole già aggiunte manualmente, esegui sudo firewall-cmd --runtime-to-permanent: il comando copia l'insieme attivo nel file salvato.
Perché non cambia nulla dopo avere 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 non è presente nell'elenco attivo, manca il reload.
Devo usare --add-service o --add-port?
Usa --add-service quando esiste un nome per il servizio che esegui. In questo modo dichiari l'intento e sudo firewall-cmd --info-service=https mostra esattamente quali porte comprende quel nome. Usa --add-port quando nessuna definizione corrisponde al servizio oppure quando il servizio è in ascolto su una porta non standard. Il servizio ssh significa solo 22/tcp; quindi, se SSH è stato spostato sulla porta 2222, servono --add-port=2222/tcp e un'etichetta SELinux per quella porta.
Perché il 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 riguardano solo i pacchetti consegnati all'host. Il container risponde da Internet anche se --list-all non mostra nulla. Pubblica invece la porta sull'interfaccia di loopback con docker run -d -p 127.0.0.1:8080:80 nginx e posiziona un reverse proxy davanti al container.
Posso installare ufw su Rocky Linux invece di firewalld?
Due gestori firewall sullo stesso server scrivono regole senza conoscersi tra loro, e l'insieme di regole che 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. È sufficiente conoscere la zona predefinita e il flag --permanent per gestire l'intero strumento.