Configurare un nuovo server root: checklist per i primi 30 minuti
I primi 30 minuti su un nuovo server root decidono tutto il resto. Nove passaggi nell'ordine giusto, comprese le trappole di Debian 13 e Ubuntu 24.04 che nella maggior parte delle guide mancano.
Un nuovo server root è raggiungibile dal primo secondo e viene scansionato dal primo minuto. I tentativi di accesso automatizzati sulla porta 22 iniziano, per esperienza, prima ancora che tu abbia fatto il tuo primo login. Questa lista porta un server appena consegnato, in circa mezz'ora, in uno stato in cui puoi lasciarlo lavorare con tranquillità.
Tutti i comandi presuppongono che tu stia lavorando come root, esattamente come subito dopo il provisioning. Non appena sei collegato con il tuo nuovo utente, anteponi sudo a ogni comando. La sequenza è verificata su Debian 13 (trixie), Debian 12 (bookworm), Ubuntu 24.04 LTS e Ubuntu 22.04 LTS. Dove i quattro sistemi si comportano in modo diverso, lo trovi indicato.
Passo 0: assicurati la via di ritorno prima di cambiare qualcosa
L'unico errore di questa lista che non puoi riparare via SSH è proprio quello che ti toglie SSH. Per i prossimi 30 minuti vale quindi una sola regola ferrea: apri una seconda finestra di terminale con una connessione SSH attiva e non chiuderla. Una sessione SSH già aperta sopravvive sia al riavvio del servizio SSH sia all'attivazione del firewall. Se dopo una modifica una nuova connessione non funziona più, annulla la modifica dalla sessione ancora aperta.
Vale anche la pena sapere dove si trova l'accesso alla console del tuo server prima di averne bisogno. Da KernelHost lo raggiungi nell'area clienti, indipendentemente da SSH e indipendentemente dal firewall. Chi comincia a cercarlo solo quando è già chiuso fuori perde tempo.
Questi messaggi di errore conviene saperli distinguere, perché indicano cause completamente diverse:
ssh: connect to host 203.0.113.10 port 22: Connection refusedsignifica che il pacchetto è arrivato, ma sulla porta non ascolta nessuno. Il servizio SSH non è in esecuzione oppure ascolta su un'altra porta.ssh: connect to host 203.0.113.10 port 22: Connection timed outsignifica che il pacchetto è stato scartato. Nella quasi totalità dei casi si tratta del firewall.Permission denied (publickey)significa che il servizio è attivo e il firewall ti lascia passare, semplicemente la tua chiave non va bene.
Passo 1: aggiornare il sistema
Un'immagine appena installata è raramente aggiornata. Tra la creazione dell'immagine e il tuo ordine passano spesso settimane, e nel frattempo sono usciti aggiornamenti di sicurezza.
cat /etc/os-release
apt update
apt full-upgrade -y
full-upgrade al posto di upgrade è una scelta deliberata: su un sistema appena installato apt può rimuovere pacchetti se una dipendenza lo richiede. Su un sistema in produzione già avviato controlleresti prima che cosa verrebbe rimosso.
Su Ubuntu 22.04 e 24.04 needrestart è preinstallato e interrompe l'upgrade con una schermata colorata a tutto schermo che chiede quali servizi riavviare. Se non lo vuoi, per esempio dentro uno script:
NEEDRESTART_MODE=a DEBIAN_FRONTEND=noninteractive apt full-upgrade -y
Poi fai pulizia e verifica se serve un riavvio:
apt autoremove --purge -y
apt list --upgradable
test -f /var/run/reboot-required && echo "riavvio necessario" || echo "nessun riavvio necessario"
Differenze tra le distribuzioni: il file /var/run/reboot-required viene creato in modo affidabile solo da Ubuntu, arriva dal pacchetto update-notifier-common. Debian, di base, non segnala affatto un riavvio necessario. Su Debian installi a questo scopo needrestart, che al richiamo ti dice se è pronto un kernel nuovo. Debian 13 porta inoltre una generazione più recente di apt, con output colorato e formattato in colonne: non è un errore, è solo insolito.
Verifica: apt list --upgradable non stampa più nulla oltre alla riga iniziale Listing.... Se durante l'aggiornamento compare il messaggio Release file for ... is not valid yet, l'orologio del tuo server è sbagliato: salta al passo 5 e ripeti poi il passo 1.
Approfondimento, anche sulla gestione dei pacchetti trattenuti e delle repository di terze parti: Aggiornare un server Linux con apt.
Passo 2: creare un utente invece di lavorare come root
Come root non si lavora, perché ogni errore di battitura colpisce subito l'intero sistema e perché il nome utente root lo conosce già qualsiasi attaccante. Sulle immagini minimali di Debian sudo spesso non è nemmeno installato:
apt install -y sudo
adduser --disabled-password --gecos "" kernel
usermod -aG sudo kernel
L'opzione --disabled-password crea l'utente senza password, che è esattamente ciò che serve per un accesso basato solo su chiave. Se vuoi impostare comunque una password, per esempio per usare sudo dalla console, lo fai con passwd kernel.
Differenze tra le distribuzioni: su Debian e Ubuntu il gruppo degli amministratori si chiama sudo. Solo se arrivi da un sistema di tipo RHEL cerchi wheel, che qui non esiste.
Adesso la chiave pubblica. Crea la directory con i permessi corretti, perché i permessi sbagliati sono la causa più frequente di un accesso a chiave rifiutato:
mkdir -p /home/kernel/.ssh
chmod 700 /home/kernel/.ssh
touch /home/kernel/.ssh/authorized_keys
chmod 600 /home/kernel/.ssh/authorized_keys
chown -R kernel:kernel /home/kernel/.ssh
Il contenuto della tua chiave pubblica va inserito in authorized_keys, ma dal tuo computer è più comodo farlo con ssh-copy-id kernel@203.0.113.10.
Verifica, e da fare prima di toccare SSH:
id kernel
sudo -l -U kernel
La seconda riga deve contenere (ALL : ALL) ALL. Poi collegati in una terza finestra come kernel ed esegui una volta sudo -v. Solo quando questo funziona si prosegue. Dettagli: Creare un utente e configurare sudo e Creare e installare chiavi SSH.
Passo 3: mettere in sicurezza SSH
Sulle immagini Debian più essenziali il server SSH non è nemmeno installato, in quel caso lo aggiungi per prima cosa:
apt install -y openssh-server
Tutti e quattro i sistemi trattati qui leggono configurazione aggiuntiva da /etc/ssh/sshd_config.d/. Non modificare quindi il grande sshd_config, crea invece un file tuo. Quello sopravvive agli aggiornamenti dei pacchetti senza porti domande.
Un dettaglio che quasi tutte le guide sbagliano: nella configurazione SSH vince il primo valore trovato, non l'ultimo. Su Debian e Ubuntu la riga Include /etc/ssh/sshd_config.d/*.conf si trova proprio in cima, e i file in quella directory vengono letti in ordine alfabetico. Sulle immagini Ubuntu spesso c'è già 50-cloud-init.conf con PasswordAuthentication yes. Un file chiamato 99-... resterebbe quindi senza effetto. Guarda prima che cosa c'è già:
ls -l /etc/ssh/sshd_config.d/
cat > /etc/ssh/sshd_config.d/10-kernelhost.conf <<'EOF'
PermitRootLogin prohibit-password
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
X11Forwarding no
MaxAuthTries 3
EOF
prohibit-password al posto di no è una scelta consapevole: root può ancora accedere con la chiave, ma mai con la password. Ti salva quando qualcosa va storto con l'utente sudo. Chi vuole stringere di più imposta no, ma a quel punto deve avere davvero provato l'accesso alla console.
Prima di ogni riavvio del servizio, controlla la sintassi:
ssh-keygen -A
sshd -t && echo "configurazione ok"
sshd -T | grep -E "^(permitrootlogin|passwordauthentication|pubkeyauthentication|port) "
sshd -T mostra i valori realmente in vigore, dopo la risoluzione di tutti i file inclusi. È l'unica prova affidabile che la tua modifica sia arrivata a destinazione. Se il comando segnala sshd: no hostkeys available -- exiting, mancano le host key e ssh-keygen -A le genera. Se invece il controllo si interrompe con Missing privilege separation directory: /run/sshd, il servizio non è mai partito da quando il sistema è stato avviato e manca la directory di runtime. Un mkdir -p /run/sshd oppure un systemctl restart ssh la crea, dopodiché sshd -t torna a valutare la tua configurazione.
Un output crea regolarmente confusione: per PermitRootLogin prohibit-password il comando sshd -T stampa la riga permitrootlogin without-password. È lo stesso valore sotto il suo nome più vecchio e non indica affatto che la tua impostazione non sia arrivata.
Solo a questo punto:
systemctl restart ssh
La trappola del socket su Ubuntu 24.04 e Debian 13
Da Ubuntu 22.10, e quindi anche nella 24.04, SSH viene avviato tramite socket activation. La conseguenza: una riga Port nella configurazione di sshd viene ignorata, la porta arriva da ssh.socket. Chi vuole cambiare la porta ha bisogno di un overlay systemd:
systemctl edit ssh.socket
Al suo interno metti questo, dove la prima riga vuota cancella l'impostazione predefinita:
[Socket]
ListenStream=
ListenStream=0.0.0.0:2222
ListenStream=[::]:2222
Poi systemctl daemon-reload e systemctl restart ssh.socket. Ubuntu 22.04 non conosce ancora questo meccanismo, lì basta la riga Port nella configurazione.
Su Debian 13 si presenta una stranezza analoga. Alcune immagini nuove hanno ssh.socket attivo, i sistemi aggiornati da Debian 12 no. Se sono attivi entrambi contemporaneamente, un reload fallisce con fatal: Cannot bind any address., perché servizio e socket si contendono la porta 22. Controlla e, nel dubbio, decidi:
systemctl is-enabled ssh.socket
systemctl disable --now ssh.socket
systemctl enable --now ssh.service
Verifica: ss -tlnp | grep ssh mostra la porta attesa e un nuovo tentativo di connessione da una finestra appena aperta va a buon fine. In dettaglio: Mettere in sicurezza SSH e disattivare il login di root e Cambiare la porta SSH.
Passo 4: attivare il firewall
Su Ubuntu ufw è installato, ma inattivo. Sulle immagini minimali di Debian manca del tutto. Qui l'ordine è vitale: prima consenti SSH, poi accendi.
apt install -y ufw
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
L'ultimo comando è il più importante di tutta la lista. Regole e policy predefinite da sole non filtrano niente, è ufw enable ad armare il firewall. Chi lo salta si ritrova alla fine con un firewall configurato in ogni dettaglio, ma privo di effetto.
All'attivazione ufw chiede: Command may disrupt existing ssh connections. Proceed with operation (y|n)?. L'avviso è serio, ma se la regola per la porta 22 (oppure per la porta che hai cambiato) viene prima, non succede nulla, e proprio per questo ufw allow 22/tcp compare nella lista sopra ufw enable. Se al passo 3 hai cambiato la porta, qui deve esserci ufw allow 2222/tcp, altrimenti ti chiudi fuori. In uno script o in una sessione non interattiva usa ufw --force enable, che salta la domanda.
Verifica:
ufw status verbose
Ti aspetti Status: active, sotto Default: deny (incoming), allow (outgoing) e nell'elenco delle regole una riga 22/tcp ALLOW IN per la tua porta SSH. Se lì compare ancora Status: inactive, manca ufw enable e non c'è niente di protetto, per quanto complete possano sembrare le regole. Apri poi una nuova finestra e connettiti prima di chiudere quella vecchia.
A completamento serve anche un meccanismo di blocco contro i tentativi di accesso:
apt install -y fail2ban python3-systemd
cat > /etc/fail2ban/jail.local <<'EOF'
[DEFAULT]
backend = systemd
bantime = 1h
findtime = 10m
maxretry = 5
[sshd]
enabled = true
EOF
Perché backend = systemd: dalla versione 12 Debian non installa più rsyslog, quindi non esiste alcun /var/log/auth.log. Il valore predefinito backend = auto cerca esattamente quel file e fail2ban non parte affatto, con il messaggio Failed during configuration: Have not found any log file for sshd jail. Il pacchetto python3-systemd è il presupposto perché l'accesso al journal funzioni. Su Ubuntu 22.04 e 24.04 il file esiste ancora grazie a rsyslog, ma anche lì la variante systemd funziona ed è la scelta a prova di futuro. Puoi controllare così:
test -f /var/log/auth.log && echo "auth.log presente" || echo "nessun auth.log, serve backend systemd"
fail2ban-client -t
Verifica: fail2ban-client status sshd mostra una riga Currently banned. Se invece arriva Sorry but the jail 'sshd' does not exist, la configurazione non è stata caricata. Altro in Configurare il firewall UFW e Configurare Fail2ban.
Passo 5: fuso orario e ora di sistema
Un orologio sbagliato rende i log inutilizzabili, fa fallire le verifiche dei certificati e può bloccare apt con Release file is not valid yet. Su un server vero:
timedatectl set-timezone Europe/Vienna
timedatectl status
Nell'output devono tornare queste righe: Time zone: Europe/Vienna, System clock synchronized: yes e NTP service: active. Se lì c'è NTP service: inactive, non è in funzione nessuna sincronizzazione oraria. Ubuntu porta con sé systemd-timesyncd di serie, le immagini minimali di Debian spesso no:
DEBIAN_FRONTEND=noninteractive apt install -y systemd-timesyncd tzdata
date
Molti operatori lasciano volutamente i server su UTC, così i log di sedi diverse restano confrontabili. Entrambe le scelte sono difendibili, decisivo è che tu sappia quale hai fatto. Se timedatectl non è disponibile in un ambiente container, funziona anche il metodo classico:
ln -sf /usr/share/zoneinfo/Europe/Vienna /etc/localtime
dpkg-reconfigure -f noninteractive tzdata
Approfondimento: Configurare fuso orario e sincronizzazione oraria.
Passo 6: impostare l'hostname
L'hostname compare nei log, nelle email in uscita e nei messaggi di monitoraggio. Impostalo presto, altrimenti più avanti tutti i tuoi server si chiameranno allo stesso modo.
hostnamectl set-hostname srv01.tuo-dominio.it
hostname -f
Subito dopo serve una voce corrispondente in /etc/hosts, altrimenti a ogni richiamo di sudo ti accoglie il messaggio sudo: unable to resolve host srv01: Name or service not known, con un ritardo ben percepibile. La riga suona più o meno così: 127.0.1.1 srv01.tuo-dominio.it srv01.
La trappola: sulle immagini con cloud-init, che su Ubuntu sono la regola, l'hostname viene riportato indietro al riavvio successivo. L'interruttore che lo impedisce:
command -v cloud-init || echo "cloud-init non installato"
mkdir -p /etc/cloud/cloud.cfg.d
printf 'preserve_hostname: true\n' > /etc/cloud/cloud.cfg.d/99_hostname.cfg
Verifica: dopo un riavvio hostnamectl restituisce ancora il tuo nome. Dettagli: Cambiare l'hostname su Linux in modo permanente.
Passo 7: aggiornamenti di sicurezza automatici
Il server più pericoloso è quello che nessuno tocca più. Gli aggiornamenti di sicurezza automatici sono il singolo passo più efficace di questa lista.
apt install -y unattended-upgrades
cat > /etc/apt/apt.conf.d/20auto-upgrades <<'EOF'
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
EOF
Installare il pacchetto da solo non basta ovunque, è questo file ad attivare davvero l'esecuzione quotidiana. Le regolazioni personali vanno in un file con un numero più alto di quello fornito con il pacchetto, 50unattended-upgrades, così vincono e non vengono sovrascritte a ogni aggiornamento:
cat > /etc/apt/apt.conf.d/52unattended-upgrades-local <<'EOF'
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::MinimalSteps "true";
EOF
Di serie lo strumento, su entrambe le distribuzioni, attinge solo alla repository di sicurezza e non agli aggiornamenti normali. È voluto ed è quasi sempre la scelta giusta per i sistemi in produzione. Se imposti Automatic-Reboot "true", imposta assolutamente anche un orario, altrimenti il server si riavvia quando fa comodo al timer.
Verifica: una prova a vuoto mostra quali pacchetti verrebbero presi in considerazione, senza installare nulla. Fai attenzione al singolare nel nome del comando:
unattended-upgrade --dry-run --debug
apt-config dump | grep -iE "unattended|periodic"
Nel log sotto /var/log/unattended-upgrades/, dopo la prima esecuzione, deve esserci qualcosa. Se resta vuoto, la configurazione non fa presa. In dettaglio: Configurare gli aggiornamenti di sicurezza automatici.
Passo 8: monitoraggio
Nei primi 30 minuti monitoraggio non significa costruire un Grafana. Significa che vieni avvisato quando il server si ferma o il disco si riempie.
apt install -y htop tmux curl
df -h /
free -m
Per iniziare bastano tre cose. Primo, un controllo di raggiungibilità esterno, che verifica da fuori e ti avvisa, perché un server andato in crash non manda più nessun allarme su se stesso. Secondo, un avviso sullo spazio disco, perché un filesystem pieno è la causa più frequente dei guasti che nessuno aveva visto arrivare. Terzo, uno sguardo al journal quando qualcosa è strano:
journalctl -p 3 -b --no-pager | tail -n 30
systemctl --failed
systemctl --failed dovrebbe restituire 0 loaded units listed. Ogni riga presente lì è un servizio che non parte e che conviene riparare adesso, non fra tre mesi. Altro qui: Configurare il monitoraggio del server.
Passo 9: il backup prima che ci sia qualcosa da perdere
Il momento migliore per il primo backup è quando i dati non ci sono ancora. Così provi la procedura senza pressione. Due cose vale la pena salvare subito, perché ricostruirle costa più tempo di tutto il resto: la configurazione sotto /etc e l'elenco dei pacchetti installati.
tar -czf /root/etc-backup-$(date +%F).tar.gz /etc
dpkg --get-selections > /root/pacchetti.txt
tar -tzf /root/etc-backup-$(date +%F).tar.gz | wc -l
Con questo non hai ancora un backup, ma solo una copia sullo stesso supporto. Un backup sta su un altro sistema, idealmente in un altro luogo. Uno strumento con cifratura e deduplica dei blocchi identici conviene dal primo giorno:
apt install -y borgbackup
borg --version
La verità scomoda: un backup da cui non è mai stato recuperato niente è soltanto un'ipotesi. Fissa un appuntamento per il primo ripristino e riporta indietro un singolo file. La strada per farlo la trovi in Strategia di backup per server root.
Se ti sei chiuso fuori
Succede, di solito al passo 3 o al passo 4. La via di ritorno è sempre la stessa: accedi tramite la console nell'area clienti, lì con nome utente e password invece che con la chiave. Poi, a seconda della causa:
- Firewall troppo severo:
ufw disable, correggi la regola,ufw enable. - Configurazione SSH rotta:
rm /etc/ssh/sshd_config.d/10-kernelhost.conf, poisshd -tesystemctl restart ssh. - Porta sbagliata dopo la modifica del socket:
systemctl revert ssh.socketazzera l'overlay, poi servonosystemctl daemon-reloadesystemctl restart ssh.socket. - Bloccato da fail2ban:
fail2ban-client set sshd unbanip 203.0.113.10. Perché non ti ricapiti, inserisci il tuo indirizzo fisso sottoignoreipnel filejail.local. - La chiave viene rifiutata: quasi sempre sono i permessi.
chmod 700sulla directory,chmod 600sul file, ed entrambi devono appartenere all'utente, non a root.
Il controllo finale
Che un comando non restituisca errori non significa che abbia avuto effetto. Questi sei controlli mostrano lo stato reale:
sshd -T | grep -E "^(permitrootlogin|passwordauthentication|port) "mostra i valori in vigore, non quelli desiderati.ufw status verbosesegnalaStatus: activecon una regola per la tua porta SSH.timedatectl statussegnalaSystem clock synchronized: yes.systemctl --failednon elenca nulla.unattended-upgrade --dry-run --debugarriva in fondo senza messaggi di errore.- Una nuova connessione SSH da una finestra appena aperta funziona, con la chiave e senza richiesta di password.
Solo quando il punto sei è a posto puoi chiudere la vecchia finestra di terminale.
Che cosa viene dopo
Una parola sulla scelta della distribuzione, perché decide i prossimi anni. Debian 12 da luglio 2026 è fuori dal supporto regolare e viene mantenuto fino a metà 2028 dal team LTS, con una selezione di pacchetti ridotta. Chi installa oggi da zero prende Debian 13 oppure Ubuntu 24.04 LTS. Ubuntu 22.04 LTS resta nel supporto standard fino al 2027, ma per un server destinato a girare per anni non è più la prima scelta. Debian 10 e Ubuntu 20.04 sono definitivamente chiusi rispettivamente da giugno 2024 e da maggio 2025 e non hanno posto su un server nuovo.
Contano nella pratica anche le differenze di versione nelle repository. Debian non fornisce per principio mysql-server, lì lo standard è MariaDB. Chi ha bisogno di una versione precisa di PHP, Node o Java fa meglio a controllare prima che cosa porta la distribuzione, invece di aggiungere repository di terze parti in un secondo momento. E se aggiungi repository di terze parti: apt-key è deprecato, le chiavi vanno in /etc/apt/keyrings/ e si referenziano nella definizione della fonte con signed-by.
Con questo hai un server aggiornato, che si mantiene aggiornato da solo, che fa entrare solo te e che segnala quando qualcosa non va. Tutto il resto, web server, database, certificati, si costruisce sopra questa base e non accanto.
Domande frequenti
In che ordine conviene configurare un nuovo server root?
Perché la mia modifica in sshd_config non ha effetto?
Perché la porta SSH su Ubuntu 24.04 non cambia?
Fail2ban non parte e segnala di non aver trovato nessun file di log per la jail sshd. Che fare?
Perché dopo il riavvio il mio hostname è di nuovo sparito?
Basta apt upgrade o serve apt full-upgrade?
2026 KernelHost GmbH. Tutti i diritti riservati. Questa guida è protetta dal diritto d'autore. La ripubblicazione su altri siti web, anche parziale o in forma modificata, non è consentita senza il nostro consenso scritto. Le citazioni con indicazione della fonte e un link sono le benvenute.

