client_loop: send disconnect: Broken pipe: come evitare che SSH si disconnetta

La connessione di rete sotto la tua sessione SSH è morta, e ssh se n'è accorto quando ha provato a inviare qualcosa. La causa più comune è un router o un firewall che dimentica una connessione inattiva. Aggiungi ServerAliveInterval 60 a ~/.ssh/config così la sessione non è mai inattiva, e usa tmux per il lavoro che deve sopravvivere a un vero cambio di rete.

Aggiornata il . Il messaggio Broken pipe è stato riprodotto con OpenSSH 10.3 su macOS tramite un proxy locale che azzerava la connessione TCP.

Il messaggio

client_loop: send disconnect: Broken pipe

Nella nostra prova, un reset TCP sotto una sessione attiva ha stampato questo:

Read from remote host server: Connection reset by peer
client_loop: send disconnect: Broken pipe

I client più vecchi stampano lo stesso problema in un'altra forma:

packet_write_wait: Connection to 203.0.113.10 port 22: Broken pipe

Broken pipe significa che ssh ha scritto su una connessione che non esiste più. Non dice chi l'ha chiusa e non ha niente a che fare con le tue chiavi o la tua password.

Cause, in ordine di probabilità

1. Un router o un firewall ha chiuso una connessione inattiva

I router di casa, i firewall degli uffici e i gateway NAT del cloud tengono una tabella delle connessioni aperte e rimuovono quelle inattive, spesso dopo pochi minuti. La tua sessione sembra a posto finché non premi un tasto. L'indizio è che la sessione muore solo dopo che l'hai lasciata ferma, e a un momento abbastanza regolare. Una prova rapida è applicare la correzione qui sotto a una connessione e lasciarla inattiva più a lungo di quanto di solito sopravvive.

2. Il tuo computer è andato in stop o ha cambiato rete

Chiudere un portatile, o passare dal Wi-Fi all'hotspot del telefono, interrompe la connessione. Quando il tuo indirizzo cambia, nessun keepalive può salvarla. L'indizio è che succede subito dopo aver aperto il portatile o esserti spostato.

3. L'ha chiusa il server

Un riavvio, un crash o un timeout di inattività impostato dall'amministratore sembrano tutti simili dal tuo lato. Controlla l'uptime e il log del server, e cerca le impostazioni di inattività:

uptime
sudo journalctl -u ssh --since "1 hour ago"
sudo sshd -T | grep -iE '^(clientalive|channeltimeout|unusedconnectiontimeout)'

Una sessione chiusa di proposito dal server di solito stampa Connection to server closed by remote host. invece di Broken pipe.

La correzione sul client: ServerAliveInterval

Metti questo in ~/.ssh/config:

Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

Per provarlo una volta senza modificare alcun file:

ssh -o ServerAliveInterval=60 user@server

Dopo 60 secondi di silenzio dal server, ssh invia un piccolo messaggio attraverso la connessione cifrata e aspetta una risposta. Fa due cose:

  • Il traffico mantiene la connessione nella tabella del router.
  • Se le risposte si fermano, ssh rinuncia dopo ServerAliveCountMax tentativi, circa 3 minuti qui, invece di restare bloccato.

L'intervallo predefinito è 0, cioè disattivato, e il conteggio predefinito è 3. Se la tua connessione viene rimossa prima di un minuto, abbassa l'intervallo. Quando si raggiunge il limite, vedi questo:

Timeout, server 203.0.113.10 not responding.

Quel messaggio significa che il keepalive sta facendo il suo lavoro: la rete ha davvero smesso di rispondere.

Lo stesso sul server: ClientAliveInterval

Se gestisci il server e vuoi questo per tutti, aggiungi un file come /etc/ssh/sshd_config.d/keepalive.conf:

ClientAliveInterval 60
ClientAliveCountMax 3

Poi controlla e ricarica:

sudo sshd -t && sudo systemctl reload ssh

Su alcuni sistemi l'unità si chiama sshd. Oltre a mantenere vive le connessioni, questo ripulisce anche le sessioni di client scomparsi. Quando abbiamo congelato un client, il server ha registrato questo e ha chiuso la sessione:

Timeout, client not responding from user user 203.0.113.20 port 40896

TCPKeepAlive non è la stessa cosa

TCPKeepAlive è attivo per impostazione predefinita su entrambi i lati, e riattivarlo raramente aiuta. Ci sono due differenze:

  • Lo invia il sistema operativo con i suoi tempi. Su Linux l'attesa predefinita è di 2 ore, troppo lunga per mantenere viva una voce nella tabella di un router.
  • Sta fuori dal canale cifrato, quindi può essere falsificato. I messaggi server alive no.

Il manuale nota anche che il keepalive TCP fa morire le connessioni se una rotta cade per poco tempo. Se preferisci superare brevi interruzioni, puoi disattivarlo e affidarti al solo ServerAliveInterval.

Quando usare tmux invece

I keepalive impediscono che una connessione sana venga chiusa perché inattiva. Non possono salvare una sessione quando la rete sparisce davvero. Se la connessione termina, normalmente terminano anche la shell sul server e ciò che vi gira dentro.

Per i job lunghi, o se ti sposti tra reti, esegui il lavoro dentro tmux sul server:

tmux new -A -s work

Esegui lo stesso comando dopo esserti riconnesso e torni nella stessa sessione, con il job ancora in esecuzione. Vedi Mantenere vive le sessioni SSH con tmux. Usa entrambi: i keepalive per le cadute di tutti i giorni, tmux per ciò che non deve andare perso.

Se cambi rete spesso, un client Mosh va oltre: la sessione segue il nuovo indirizzo invece di chiudersi.

Domande

Cosa significa client_loop: send disconnect: Broken pipe?

La connessione di rete sotto la sessione SSH si è chiusa, e ssh se n'è accorto quando ha provato a inviare dati. Chiavi e password non c'entrano.

Che valore usare per ServerAliveInterval?

60 secondi vanno bene con la maggior parte di router e firewall. Se le sessioni inattive cadono prima di un minuto, usa 30. Con ServerAliveCountMax 3, una connessione morta si chiude dopo circa tre intervalli.

ServerAliveInterval tiene viva la sessione quando cambio rete?

No. Evita la chiusura per inattività su una connessione che funziona. Quando cambia il tuo indirizzo la connessione finisce, quindi esegui i lavori lunghi in tmux sul server oppure usa Mosh.

Fonti

Altro in Messaggi di errore

Tutte le guide