Cambiare la porta SSH con SELinux e firewalld
Su Rocky Linux e AlmaLinux, cambia la porta SSH senza perdere l'accesso: configura firewalld, l'etichetta SELinux e sshd_config nell'ordine corretto.
Perché qui cambiare la porta SSH richiede tre passaggi
Per cambiare la porta SSH su Rocky Linux, AlmaLinux, CentOS Stream o Fedora, una sola modifica non è sufficiente. Tre sistemi distinti determinano se una connessione sulla nuova porta può funzionare. firewalld decide se il pacchetto può raggiungere la macchina. SELinux decide se sshd può eseguire il bind su quel numero di porta. sshd_config decide quale porta il demone deve usare. Se si salta il passaggio SELinux, il demone non si avvia. Se si salta il passaggio firewalld, il demone si avvia e resta in ascolto, ma nessuno può raggiungerlo.
Su Ubuntu la stessa operazione richiede una sola modifica e un riavvio, perché Ubuntu usa AppArmor anziché SELinux e non include alcun profilo che limiti le porte su cui sshd può eseguire il bind. Se ufw è in esecuzione, è necessario aggiungere una regola. Questa è l'unica differenza. Nella famiglia RHEL, firewalld è in esecuzione e SELinux è in modalità enforcing dopo una nuova installazione; entrambi considerano i numeri di porta.
Eseguire le operazioni in questo ordine mantiene attiva la sessione corrente durante tutti i passaggi:
- Aprire la nuova porta in firewalld, lasciando aperta per il momento la porta 22.
- Aggiungere l'etichetta SELinux per la nuova porta con
semanage. - Impostare la porta nella configurazione di sshd.
- Riavviare
sshd, quindi accedere sulla nuova porta da un secondo terminale prima di chiudere il primo.
Individuare la console web del provider (VNC o seriale) prima di iniziare e verificare di potervi accedere. Questa console consente di ripristinare l'accesso se la modifica causa problemi. Il cambio di porta è uno dei motivi più comuni per cui un tenant rimane senza accesso a un server appena acquistato.
Prima di tutto, installare semanage
semanage è lo strumento che modifica le impostazioni delle policy SELinux. Un'installazione minima di Rocky Linux o AlmaLinux non lo include. Il file si trova in policycoreutils-python-utils.
sudo dnf install -y policycoreutils-python-utilsL'esecuzione del comando prima di installare quel pacchetto restituisce sudo: semanage: command not found. È a questo punto che molti lettori concludono che SELinux non sia installato e saltano il passaggio. SELinux è installato. Manca soltanto lo strumento di gestione. Se la sintassi dnf è nuova, gli equivalenti dei comandi dnf e apt permettono di ricondurla a ciò che già si conosce.
Scegliere una porta e verificare che non sia già utilizzata
Va bene qualsiasi porta TCP libera compresa tra 1024 e 65535. Eseguire questi due controlli prima di sceglierne una:
sudo ss -tlnp | grep -w 2222
sudo semanage port -l | grep -w 2222Il primo comando mostra se un processo è già in ascolto su quel numero. Il secondo mostra se la policy SELinux lo assegna già a un altro tipo di servizio. Una porta libera non restituisce alcun risultato in entrambi i casi. Se la policy la utilizza già, il semanage port -a nel passaggio 2 non riesce con ValueError: Port tcp/2222 already defined. In questo caso, scegliere un altro numero.
In questa guida viene usata 2222 come esempio. È anche la prima porta che uno scanner prova dopo la 22. Su un server reale, scegliere quindi un numero meno prevedibile.
Passaggio 1: aprire la porta in firewalld
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --list-ports--permanent scrive la regola nel file della zona su disco, ma non modifica il firewall in esecuzione. --reload carica la configurazione presente su disco nel firewall in esecuzione. Se si salta il reload, la regola viene creata ma non ha effetto fino al successivo riavvio di firewalld. Questo è uno dei motivi più comuni per cui l'intera procedura sembra non funzionare senza una causa evidente.
Per ora, lascia invariata la voce del servizio ssh. Questa voce mantiene aperta la porta 22 e costituisce il fallback durante i test.
Controlla anche il pannello di controllo del provider. Molti host eseguono un firewall di rete davanti al VPS, esterno al sistema operativo. Di conseguenza, una porta aperta in firewalld può essere comunque bloccata a monte. La guida di base a firewalld per un VPS descrive le zone e la differenza tra configurazione runtime e permanente, se questo modello non ti è familiare.
Passaggio 2: applicare l'etichetta SELinux alla porta
sudo semanage port -a -t ssh_port_t -p tcp 2222
sudo semanage port -l | grep ssh_port_t-a aggiunge una nuova assegnazione di porta. -t ssh_port_t è il tipo associato alle porte SSH. Il secondo comando elenca tutte le porte ora coperte da ssh_port_t, così puoi verificare che il numero sia stato aggiunto prima di modificare il demone.
Perché SELinux blocca la porta
SELinux (security-enhanced Linux) assegna un'etichetta a ogni oggetto del sistema, incluse le porte TCP. Il demone SSH viene eseguito confinato in un dominio chiamato sshd_t. La policy consente a sshd_t di associarsi alle porte TCP con etichetta ssh_port_t e, nella configurazione predefinita, l'unica porta con questa etichetta è la 22. Se si chiede al demone di associarsi alla porta 2222, il kernel controlla l'etichetta, rileva il tipo generico assegnato dalla policy a quel numero e rifiuta il permesso name_bind sul socket.
Per questo l'errore non assomiglia a un problema del firewall. Il kernel rifiuta l'operazione prima che esista un socket in ascolto, quindi sshd segnala l'errore e termina. Nel caso di un problema del firewall, il comportamento è opposto: il demone è in esecuzione e funziona correttamente, ma i pacchetti vengono scartati durante il percorso in ingresso.
getenforce indica la modalità attiva sul sistema. In Permissive una negazione viene registrata ma non applicata, quindi la modifica della porta sembra funzionare e poi smette di funzionare quando qualcuno esegue setenforce 1 oppure quando il sistema si riavvia in modalità enforcing. Etichettare la porta in ogni caso. La guida di base a SELinux per un server descrive correttamente modalità, contesti e booleani. Le porte non sono gli unici oggetti interessati: la stessa policy impedisce a un container di leggere una directory dell'host montata finché il relativo percorso non viene rietichettato. Per questo l'installazione di Docker su Rocky Linux o AlmaLinux include un passaggio dedicato a SELinux che nelle guide per Ubuntu non viene mai menzionato.
Passaggio 3: impostare la porta nella configurazione di sshd
Su Rocky Linux 9 e 10, AlmaLinux 9 e 10 e nelle versioni correnti di Fedora, /etc/ssh/sshd_config inizia con una direttiva include. Il punto corretto per la modifica è quindi un file drop-in. Gli aggiornamenti dei pacchetti non sovrascriveranno mai la modifica.
grep -n '^Include' /etc/ssh/sshd_config
echo 'Port 2222' | sudo tee /etc/ssh/sshd_config.d/10-port.conf
sudo sshd -tSe grep non trova alcuna direttiva Include, come accade in Rocky Linux 8 e in altre immagini meno recenti, inserire direttamente Port 2222 in /etc/ssh/sshd_config. sshd -t analizza l'intera configurazione, inclusi i file drop-in, e segnala gli errori di sintassi. Correggere tutti gli errori segnalati prima del riavvio. Una configurazione che non può essere analizzata impedisce al demone di riavviarsi.
Port può comparire più volte e sshd resta in ascolto su tutte le porte elencate. Mantenere Port 22 insieme a Port 2222 per il primo giorno è una semplice misura di sicurezza, purché ci si ricordi di rimuoverlo.
Il servizio sshd viene avviato da una socket unit?
Alcune immagini avviano SSH tramite l'attivazione socket di systemd invece di eseguirlo come servizio a esecuzione prolungata. In questo caso, systemd gestisce la socket in ascolto e passa le connessioni a sshd; quindi la riga Port in sshd_config viene completamente ignorata. Verifica prima di riavviare qualsiasi componente:
systemctl is-enabled sshd.socketUna risposta enabled indica che la porta è impostata nella socket unit, non in sshd_config:
sudo systemctl edit sshd.socket[Socket]
ListenStream=
ListenStream=2222Il ListenStream= senza argomenti è obbligatorio. I valori si accumulano tra i drop-in. Senza un'assegnazione vuota che azzeri prima l'elenco, la socket continua ad ascoltare sulla porta 22 oltre che sulla 2222. Applica la modifica con sudo systemctl daemon-reload e poi con sudo systemctl restart sshd.socket. Se l'unità è disabilitata o non è presente sul server, questa sezione non si applica al tuo caso.
Passaggio 4: riavviare, quindi verificare da un secondo terminale
sudo systemctl restart sshd
systemctl status sshd
sudo ss -tlnp | grep sshdMantieni aperto questo terminale. Non eseguire il logout. Apri un secondo terminale sul tuo computer e connettiti alla nuova porta:
ssh -p 2222 youruser@203.0.113.10Chiudi la prima sessione solo dopo che il secondo accesso è riuscito. Se il collegamento non funziona, hai ancora una shell da cui puoi annullare tutte le modifiche. Questa semplice procedura può fare la differenza tra una modifica di cinque minuti e un pomeriggio trascorso nella console del provider.
Blocco del firewall o rifiuto SELinux? Come distinguerli
Dal laptop i due errori sembrano quasi identici. Sul server, invece, sono completamente diversi.
- Se
systemctl status sshdindica che l'unità è in errore, il demone non ha mai ottenuto il socket. Si tratta di un errore di configurazione o di un rifiuto SELinux. - Se l'unità è attiva e
ss -tlnpmostra che sshd è in ascolto sulla nuova porta, il demone funziona e il problema riguarda il percorso di rete: firewalld, il firewall separato del provider oppure l'indirizzo e la porta utilizzati per la connessione.
Nel caso di SELinux, leggere il record di audit invece di fare ipotesi:
sudo ausearch -m AVC -ts recent
sudo journalctl -u sshd -n 50 --no-pagerUn rifiuto name_bind sulla classe tcp_socket indica il processo in comm="sshd", il numero di porta in src= e l'etichetta effettivamente associata alla porta in tcontext=. Quest'ultimo campo fornisce la risposta. Un valore diverso da ssh_port_t significa che il passaggio 2 non è stato applicato alla porta in uso, in genere a causa di un numero errato o del protocollo sbagliato. Installare setroubleshoot-server se si preferisce che sealert trasformi il record in una frase.
Il messaggio scritto direttamente da sshd quando il kernel rifiuta il bind è simile al seguente:
error: Bind to port 2222 on 0.0.0.0 failed: Permission denied.Permission denied su una porta superiore a 1024, per la quale non sono necessari privilegi root per eseguire il bind, è la firma di SELinux. Address already in use nella stessa riga indica un errore diverso: un altro processo sta utilizzando la porta. Dal lato client, la differenza tra connessione rifiutata e connessione scaduta consente di distinguere i due casi di rete: un rifiuto significa che il pacchetto ha raggiunto l'host e nessun processo era in ascolto, mentre un timeout significa che non ha risposto nulla.
Chiudere la porta 22 e aggiornare i client
Dopo aver verificato che diversi accessi sulla nuova porta funzionino, rimuovi la porta 22:
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --reload
sudo firewall-cmd --list-allLascia invariata l'etichetta SELinux sulla porta 22. Proviene dalla policy di base e non concede nulla quando il firewall non consente più l'ingresso dei pacchetti.
Poi aggiorna i client, perché ogni strumento che presupponeva la porta predefinita deve ora ricevere questa informazione. Inseriscila una volta in ~/.ssh/config sul computer locale, invece di dover digitare sempre -p:
Host myvps
HostName 203.0.113.10
Port 2222
User youruserscp, sftp, rsync e Ansible leggono quel file. I processi di backup, i controlli di monitoraggio e gli script cron che impostano direttamente la porta 22 non lo fanno. Individua questi casi finché la modifica è ancora recente.
Cosa comporta e cosa non comporta cambiare porta
Riduce il rumore nei log. Gli scanner automatizzati colpiscono continuamente la porta 22; spostare il servizio su un'altra porta elimina la maggior parte di queste righe dal journal e rende più facili da individuare gli eventi reali. Non è una misura di sicurezza. Qualsiasi scanner che analizzi l'intero intervallo delle porte trova il demone e legge comunque il banner con la relativa versione. Considera il cambio di porta un'attività di manutenzione e affida la protezione effettiva all'autenticazione basata esclusivamente su chiavi, disabilitando gli accessi con password. La guida al rafforzamento di SSH per un VPS illustra questa procedura passo dopo passo.
Tutto quanto descritto sopra funziona allo stesso modo su entrambe le principali ricompilazioni di RHEL, perché sono ottenute dagli stessi sorgenti. Se devi ancora scegliere tra le due, consulta il confronto tra Rocky Linux e AlmaLinux. Esistono due ricompilazioni quasi identiche tra cui scegliere perché CentOS ha smesso di esserlo nel 2020; la storia completa è raccontata in la storia da Red Hat a CentOS, fino a Rocky e AlmaLinux. Prima di seguire una guida precedente, verifica quale release ti è stata effettivamente fornita usando cat /etc/os-release. Le guide scritte per Rocky Linux 8 continuano a ottenere buoni risultati e i relativi passaggi semanage e firewall-cmd restano corretti, ma Rocky 8 non dispone della riga include sshd_config.d né di una socket unit da considerare. Per questo, la parte relativa a sshd di quelle guide non corrisponde a un sistema attuale.
fail2ban deve conoscere la nuova porta
fail2ban non è incluso nei repository di base. È disponibile tramite EPEL (Extra Packages for Enterprise Linux):
sudo dnf install -y epel-release
sudo dnf install -y fail2ban fail2ban-firewalldIl sottopacchetto fail2ban-firewalld fa sì che fail2ban applichi i ban tramite firewalld. È la scelta corretta su un sistema in cui firewalld gestisce il ruleset.
Il jail predefinito sshd imposta port = ssh. Questo nome viene risolto tramite /etc/services nella porta 22. Dopo la modifica, il jail monitora una porta che nessuno attacca. Di conseguenza non applica alcun ban, mentre i tentativi di accesso non riusciti si accumulano sulla porta 2222. Imposta la porta tramite il numero in /etc/fail2ban/jail.local:
[sshd]
enabled = true
port = 2222
backend = systemd
maxretry = 5
bantime = 3600backend = systemd legge i tentativi non riusciti dal journal invece che da /var/log/secure. È la scelta più sicura in un'installazione minimale, dove rsyslog potrebbe non essere presente. Avvialo con sudo systemctl enable --now fail2ban e verifica il jail con sudo fail2ban-client status sshd. La sintassi del jail è la stessa usata in la configurazione di fail2ban per SSH su Ubuntu 24.04. Cambiano soltanto la sorgente del pacchetto e l'azione di ban.
Le patch sono più importanti della porta
Un server con la porta SSH modificata e quattro mesi di aggiornamenti di sicurezza non applicati è in condizioni peggiori di un server che usa la porta 22 ma installa automaticamente le patch ogni notte. Nella stessa sessione, mentre hai già effettuato l'accesso come root, abilita gli aggiornamenti automatici: aggiornamenti automatici con dnf su Rocky Linux e AlmaLinux descrive il timer e la scelta tra scaricare gli aggiornamenti e applicarli. Un aggiornamento installato non riavvia i demoni che stanno ancora eseguendo il codice precedente. Per questo, quando nel batch viene aggiornato openssh-server o una libreria da cui dipende, vale la pena dedicare un minuto a verificare quali servizi richiedono ancora un riavvio o un reboot.
FAQ
Perché sshd non si avvia dopo aver modificato la porta su Rocky Linux?
Quasi sempre manca l'etichetta della porta SELinux. sshd viene eseguito nel dominio sshd_t, e la policy consente il binding solo sulle porte etichettate come ssh_port_t, che per impostazione predefinita include soltanto la porta 22. Il kernel rifiuta il binding, quindi il daemon termina invece di mettersi in ascolto, e journalctl -u sshd contiene una riga del tipo error: Bind to port 2222 on 0.0.0.0 failed: Permission denied.. Esegui sudo semanage port -a -t ssh_port_t -p tcp 2222 sostituendo il numero con quello della tua porta, quindi riavvia il servizio. Se semanage non è presente, installa prima policycoreutils-python-utils.
Devo usare semanage anche se SELinux è in modalità permissive?
Sì. In modalità permissive il diniego viene registrato, ma il binding viene comunque consentito, quindi sembra che la modifica abbia funzionato. L'etichetta continua a mancare. Non appena qualcuno esegue setenforce 1, oppure il server si avvia con SELINUX=enforcing in /etc/selinux/config, sshd smette di avviarsi su quella porta. Aggiungere l'etichetta richiede un solo comando ed elimina un errore che altrimenti potrebbe comparire settimane dopo senza una causa evidente.
La porta è etichettata e sshd è in esecuzione: perché la connessione va in timeout?
Un daemon in esecuzione indica che SELinux non sta bloccando il servizio, quindi il pacchetto viene scartato durante il percorso in ingresso. Controlla sudo firewall-cmd --list-ports per la tua porta e verifica di aver eseguito firewall-cmd --reload dopo la regola --permanent, perché una regola permanente, da sola, non modifica il firewall in esecuzione. Controlla poi il pannello di controllo del tuo host per verificare la presenza di un firewall di rete separato davanti al VPS. È il secondo punto in cui le connessioni vengono spesso bloccate e il sistema operativo non può mostrare nulla a riguardo.
Quale porta devo usare al posto della 22?
Qualsiasi porta TCP libera compresa tra 1024 e 65535. Su un server reale evita 2222 e 22222, perché gli scanner le provano subito dopo la 22. Verifica che il numero sia libero con sudo ss -tlnp, controlla che la policy SELinux non lo abbia già assegnato con sudo semanage port -l ed evita le porte assegnate a un servizio che potresti installare in seguito. Un numero alto e difficile da ricordare va bene, perché lo inserirai una volta in ~/.ssh/config e non dovrai più digitarlo.