Diagnosing the Root Cause
The first step in resolving an intermittent SSH connection is to determine whether the issue lies with the server’s identity on the network or the network path itself. If the server loses its ability to be reached after some time, it often indicates that the IP address assigned to the machine has changed, or the router’s NAT (Network Address Translation) session has expired.
To verify if the IP address has changed, log into your server locally or via console access provided by your hosting provider. Run the command ip addr show to check the current IPv4 address. Compare this with the IP address you have been using in your SSH client. If they differ, your server is likely receiving a new lease from a DHCP server, which is common in cloud environments with ephemeral instances. If the IP remains static, the problem is likely related to connection state tracking in firewalls or intermediate network devices.
Another critical factor is the public IP usage. If you are connecting from a dynamic residential IP, your own outgoing port mappings might be resetting. However, the most frequent culprit for servers becoming "unreachable" specifically after a timeout is the expiration of the connection state in the server’s firewall or the cloud provider’s security group. These systems track active connections and drop them when they appear idle, but they may fail to re-establish the handshake properly if the client does not send periodic keep-alive signals.
Configuring SSH Keep-Alive Settings
To prevent the connection from being dropped by intermediate firewalls or routers, you must configure the SSH client to send periodic keep-alive messages. This ensures that the network devices recognize the connection as active and do not close the state table entry. You can achieve this by modifying the configuration file on your local client machine.
Edit your SSH client configuration file located at ~/.ssh/config. If the file does not exist, create it. Add the following lines to configure all connections or specify them for specific hosts:
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
The ServerAliveInterval directive tells the SSH client to send a message through the encrypted channel every 60 seconds if no data has been received from the server. The ServerAliveCountMax setting defines how many missed responses constitute a failure before disconnecting. With these settings, even if the server appears idle, the client will maintain the tunnel, preventing firewalls from timing out the connection. This is particularly effective against NAT timeouts which typically range from 5 to 15 minutes.
Adjusting Server-Side Firewall Rules
If client-side keep-alives do not resolve the issue, the problem may lie within the server’s own firewall, such as UFW (Uncomplicated Firewall) or iptables. Some firewall configurations drop established connections after a certain period of inactivity if the state tracking module is misconfigured or too aggressive.
Check your current firewall status by running sudo ufw status verbose. Ensure that the SSH port (usually 22) is allowed. More importantly, inspect the connection tracking limits. In Linux, the kernel parameter net.netfilter.nf_conntrack_tcp_timeout_established controls how long an established TCP connection is kept in memory. If this value is low, connections may be purged prematurely.
You can view the current timeout by running cat /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established. If it is set to a very low number, consider increasing it. However, note that changing kernel parameters requires root access and may affect system performance. A safer approach is to ensure that your cloud provider’s security groups (like AWS Security Groups or Azure Network Security Groups) do not have idle timeout settings that conflict with your application needs. These cloud-level firewalls often operate independently of the OS firewall and can block traffic before it reaches your local iptables rules.
Verifying Network Interface Stability
Sometimes, the network interface itself may go down or switch to a different carrier, causing the IP to become unreachable until the interface is restarted. This is less common in virtualized environments but can happen in bare-metal setups with unstable hardware or drivers.
Monitor the network interface logs by running dmesg | grep eth0 (replace eth0 with your actual interface name). Look for messages indicating link down/up events. If you see frequent disconnections, investigate physical cabling or virtual network driver updates. Additionally, ensure that your systemd-networkd or Netplan configuration is set to retry connection establishment automatically upon failure.
Related Troubleshooting Steps
If you have verified network stability and configured keep-alives but still face issues, consider other potential blockers. For instance, authentication failures can sometimes manifest as connection resets if the SSH daemon rejects the key repeatedly. Check the server logs at /var/log/auth.log for detailed rejection reasons. Also, ensure that your SSH service is running correctly by executing sudo systemctl status ssh.
For more complex scenarios involving credential management, refer to our guide on SSH Credentials Added Twice to rule out configuration conflicts. Similarly, if you cannot connect at all and need to regain access, see Unable to SSH into Ubuntu Server: Log in Locally First for recovery procedures.
Frequently Asked Questions
Why does my SSH connection drop exactly after 5 minutes?
This is typically caused by NAT timeout settings in your router or cloud provider’s load balancer. Most NAT devices drop idle TCP connections after 5 to 10 minutes to free up resources. Configuring ServerAliveInterval on your client sends periodic packets that reset this timer, keeping the connection alive indefinitely.
Can I enable keep-alives on the server side instead of the client?
No, the ServerAliveInterval directive is a client-side option. The server side uses ClientAliveInterval in /etc/ssh/sshd_config, which sends messages from the server to the client. While both can help, the client-side setting is more reliable for maintaining outbound connections through restrictive firewalls.
What should I do if I lose access and cannot reconnect?
If you are completely locked out, use your hosting provider’s console or VNC access to log in directly. Once logged in, restart the SSH service with sudo systemctl restart ssh and check /var/log/auth.log for errors. Ensure your firewall allows incoming traffic on port 22.
Does disabling password authentication affect SSH stability?
Disabling password authentication improves security but does not directly impact connection stability or timeouts. However, if you rely on key-based authentication, ensure your private key permissions are correct (chmod 600 ~/.ssh/id_rsa) to prevent authentication failures that might look like connection drops.
How do I check if my firewall is dropping idle connections?
You can monitor active connections using conntrack -L to see how many entries are tracked. If you suspect firewall drops, compare the connection duration with known NAT timeouts. Temporarily disabling the firewall with sudo ufw disable can help isolate if the firewall is the cause, but remember to re-enable it immediately after testing.