ServerlessBase Blog
  • How SSH Works: Secure Remote Server Access Explained

    SSH provides encrypted remote access to servers. Learn how it works, key authentication, and secure configuration.

    How SSH Works: Secure Remote Server Access Explained

    You've probably SSH'd into a server a dozen times. You type ssh user@hostname, enter a password, and suddenly you're at a command prompt on a machine halfway across the world. But what's actually happening under the hood? SSH isn't just a convenient way to log in—it's a sophisticated protocol that encrypts every byte of data traveling between your machine and the server.

    SSH (Secure Shell) replaced insecure protocols like Telnet and rlogin decades ago. Before SSH, when you typed a password over a network, anyone with packet-sniffing tools could capture it in plain text. SSH solves this by encrypting the entire session, making it impossible for attackers to intercept credentials or command traffic.

    The SSH Architecture

    SSH operates as a client-server protocol. Your local machine runs the SSH client, and the remote server runs the SSH daemon (sshd). The client initiates a connection, and the server accepts it after authentication.

    The protocol uses a layered architecture similar to TCP/IP. At the transport layer, SSH establishes a secure channel using symmetric encryption. The client and server negotiate encryption algorithms during the initial handshake. Common choices include AES-256 for encryption and ChaCha20-Poly1305 for authenticated encryption.

    Once the secure channel is established, SSH runs multiple logical channels over it. Each channel carries a specific type of traffic—typically a shell session, but also file transfers (SFTP), port forwarding, or X11 forwarding. This multiplexing allows SSH to carry multiple independent sessions over a single TCP connection.

    The Handshake Process

    The SSH handshake begins when you run ssh user@hostname. Here's what happens step by step:

    1. Connection Initiation: Your client connects to the server's SSH port (default 22) and sends a connection request.

    2. Protocol Version Negotiation: Both sides announce their supported SSH protocol versions (currently SSH-2 is the standard). They agree on the highest compatible version.

    3. Key Exchange: This is the most critical security step. The client and server exchange public keys and perform a Diffie-Hellman key exchange to generate a shared secret key. This secret never travels over the network—it's computed independently by both sides using their public keys and a random value.

    4. Authentication: After establishing the secure channel, the server authenticates the client. This typically involves password authentication or public key authentication.

    5. Session Setup: Once authenticated, the client requests a shell session or other service. The server creates the appropriate environment and streams the session data back and forth over the encrypted channel.

    The Diffie-Hellman key exchange ensures that even if an attacker captures all the traffic during the handshake, they cannot compute the shared secret without the private keys. This mathematical property is what makes SSH secure against passive eavesdropping.

    Public Key Authentication

    Password authentication is convenient but fundamentally insecure. If an attacker captures your password, they can use it to log in. Public key authentication solves this by using cryptographic keys instead of passwords.

    Here's how public key authentication works:

    1. Key Generation: You generate a key pair on your local machine using ssh-keygen. This creates a private key (kept secret) and a public key (shared with servers).

    2. Public Key Upload: You copy your public key to the server's ~/.ssh/authorized_keys file. This file contains all public keys that are allowed to authenticate as that user.

    3. Authentication: When you connect, your client sends your public key to the server. The server checks if this key exists in the authorized_keys file. If it does, the server generates a random challenge, encrypts it with your public key, and sends it back. Your client decrypts the challenge using your private key and returns the result. If the server can decrypt it, authentication succeeds.

    This approach is secure because even if an attacker captures your private key, they cannot authenticate without the corresponding public key that's stored on the server. And because the private key never leaves your machine, it's never transmitted over the network.

    # Generate a new SSH key pair
    ssh-keygen -t ed25519 -C "your_email@example.com"
     
    # Copy the public key to a server
    ssh-copy-id user@hostname
     
    # Or manually copy the public key
    cat ~/.ssh/id_ed25519.pub | ssh user@hostname "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

    SSH Config File

    Managing SSH connections can be tedious when you have multiple servers with different usernames, ports, or key files. The SSH configuration file solves this by allowing you to define host aliases and connection parameters.

    The configuration file is located at ~/.ssh/config on Linux and macOS, or %USERPROFILE%\.ssh\config on Windows. Here's a typical configuration:

    Host production-server
        HostName 192.168.1.100
        User admin
        Port 2222
        IdentityFile ~/.ssh/id_rsa_production
        ServerAliveInterval 60
        ServerAliveCountMax 3
     
    Host staging-server
        HostName staging.example.com
        User deploy
        IdentityFile ~/.ssh/id_ed25519_staging
        ForwardX11 yes

    With this configuration, you can connect to the production server with a simple command:

    ssh production-server

    The SSH client automatically applies all the settings defined for that host alias. This makes it much easier to manage complex connection scenarios without memorizing long connection strings.

    Port Forwarding and Tunneling

    One of SSH's most powerful features is port forwarding, which allows you to create secure tunnels through firewalls. There are three types of port forwarding:

    Local Port Forwarding: Redirects a local port to a remote server's port. This is useful for accessing services on a remote server as if they were running locally.

    ssh -L 8080:localhost:80 user@remote-server

    This command creates a tunnel that forwards local port 8080 to port 80 on the remote server. You can now access http://localhost:8080 in your browser, and the request is routed through the SSH connection to the remote server.

    Remote Port Forwarding: Redirects a remote port to a local port. This is useful for accessing services on your local machine from a remote server.

    ssh -R 8080:localhost:3000 user@remote-server

    This creates a tunnel that forwards remote port 8080 to local port 3000. Anyone connecting to port 8080 on the remote server will have their traffic routed to port 3000 on your local machine.

    Dynamic Port Forwarding (SOCKS Proxy): Creates a SOCKS proxy that can forward traffic through the SSH connection. This is useful for routing all your traffic through the SSH tunnel.

    ssh -D 1080 user@remote-server

    You can then configure your browser or other applications to use localhost:1080 as a SOCKS proxy. All traffic will be encrypted and routed through the SSH connection to the remote server.

    Security Best Practices

    SSH security depends on proper configuration. Here are essential best practices:

    Disable Password Authentication: Public key authentication is far more secure than passwords. Disable password authentication entirely by editing /etc/ssh/sshd_config:

    PasswordAuthentication no
    PubkeyAuthentication yes

    Use Strong Key Types: Modern SSH supports stronger key algorithms like Ed25519. Generate keys with ssh-keygen -t ed25519 instead of the older RSA keys.

    Restrict Root Login: Prevent direct root login by setting:

    PermitRootLogin no

    Use Key-Based Authentication Only: Remove password authentication entirely if possible.

    Change the Default Port: Attackers scan for SSH on port 22 by default. Change the port in /etc/ssh/sshd_config:

    Port 2222

    Enable Two-Factor Authentication: Use tools like Google Authenticator to add MFA to SSH login.

    Limit User Access: Restrict which users can SSH into the server using AllowUsers or AllowGroups in /etc/ssh/sshd_config.

    Use Firewall Rules: Restrict SSH access to specific IP addresses using iptables or UFW:

    sudo ufw allow from 192.168.1.0/24 to any port 22

    Monitor SSH Logs: Regularly review /var/log/auth.log (Linux) or /var/log/secure (macOS) for failed login attempts.

    Troubleshooting Common Issues

    SSH problems can be frustrating, but most have simple solutions.

    "Connection Refused": The server isn't running SSH or the port is blocked. Check if the SSH daemon is running:

    sudo systemctl status sshd

    "Permission denied (publickey)": The server doesn't have your public key. Verify the key is in ~/.ssh/authorized_keys on the server and has the correct permissions (600 for the file, 700 for the directory).

    "Host key verification failed": The server's host key has changed. This can happen if you've reinstalled SSH or if someone has tampered with the server. Run ssh-keygen -R hostname to remove the old key and try again.

    "Connection timed out": The server is unreachable. Check your network connection, firewall rules, and verify the hostname/IP is correct.

    "Agent failed": SSH agent issues can prevent key authentication. Start the agent if it's not running:

    eval "$(ssh-agent -s)"
    ssh-add ~/.ssh/id_ed25519

    SSH in Production Environments

    In production environments, SSH security is critical. Many organizations implement additional measures:

    Fail2Ban: Automatically blocks IP addresses that make too many failed SSH login attempts.

    sudo apt install fail2ban
    sudo systemctl enable fail2ban
    sudo systemctl start fail2ban

    Key Management: Use tools like HashiCorp Vault or AWS Secrets Manager to manage SSH keys securely.

    Network Segmentation: Restrict SSH access to specific network segments or use VPNs for remote access.

    Monitoring: Set up alerts for failed SSH login attempts and unusual connection patterns.

    Regular Updates: Keep SSH clients and servers updated to patch security vulnerabilities.

    Disable Unused Features: Turn off unnecessary SSH features like X11 forwarding or port forwarding unless you need them.

    Conclusion

    SSH is a fundamental tool for server administration and remote development. Understanding how it works—from the key exchange to the secure channel—helps you use it more effectively and configure it more securely.

    The key takeaways are: SSH encrypts all traffic using symmetric encryption negotiated during the handshake, public key authentication is far more secure than passwords, and SSH's port forwarding capabilities enable powerful tunneling scenarios.

    For teams managing multiple servers, SSH configuration files and key management tools can significantly reduce operational overhead. Platforms like ServerlessBase simplify deployment and server management, but SSH remains essential for direct server access and troubleshooting.

    The next step is to implement these practices on your own servers. Start by generating SSH keys, configuring your SSH config file, and disabling password authentication. Then explore port forwarding to create secure tunnels for accessing services behind firewalls. With these skills, you'll have a solid foundation for secure remote server administration.

    Leave comment