Accessing Local Services Remotely: SSH Port Forwarding with DigitalOcean

Ever needed to access a web service running only on your local development machine from a remote server, like a DigitalOcean droplet? Perhaps you want to test a webhook integration hitting your local instance, or demo a local site without deploying it fully. SSH Remote Port Forwarding provides a secure and relatively simple way to achieve this.

This guide walks through setting up a DigitalOcean droplet and configuring your local SSH client to forward ports from the remote droplet back to your local machine.

Prerequisites

  • A DigitalOcean account.
  • An SSH client installed on your local machine (common on Linux, macOS; available on Windows via WSL, Git Bash, PuTTY, etc.).
  • An SSH key pair (recommended for secure authentication).

Step 1: Create a DigitalOcean Droplet

  1. Log in to your DigitalOcean account.
  2. Go to Create -> Droplets.
  3. Choose your desired region, Droplet type, and OS image (e.g., Ubuntu LTS).
  4. Authentication: This is crucial.
    • Select SSH keys.
    • Choose an existing SSH key you’ve uploaded to DigitalOcean, or click “New SSH Key” and paste your public key (~/.ssh/id_rsa.pub or similar). Using keys is more secure than password authentication.
  5. Choose any additional options (VPC, monitoring, etc.) as needed.
  6. Click “Create Droplet”.
  7. Once the droplet is created, DigitalOcean will display its public IP address. Copy this IP address – you’ll need it shortly.

Step 2: Configure Your Local SSH Client (~/.ssh/config)

To make connecting and setting up forwarding easier, let’s configure your local SSH client. Open (or create) the SSH configuration file on your local machine. This is typically located at ~/.ssh/config.

You can edit it using a text editor like vim, nano, or VS Code:

nano ~/.ssh/config
# or
vim ~/.ssh/config

Add an entry like the following, replacing <yourip address> with the actual IP address of your droplet:

Host dev       # A short alias for your droplet
    HostName <yourip address>   # The droplet's public IP
    User root             # Or your non-root user if you created one
    ServerAliveInterval 60    # Send keepalive packet every 60 seconds
    ServerAliveCountMax 120   # Try 120 times before disconnecting (2 hours total)

    # --- Remote Port Forwarding Rules ---
    # Format: RemoteForward <RemotePort> <LocalHost>:<LocalPort>
    # Forwards connections TO the droplet's RemotePort TO your local machine's LocalPort

    # Example 1: Access local port 3040 via droplet's port 4040
    RemoteForward 4040 localhost:3040

    # Example 2: Access local port 3000 via droplet's port 4000
    RemoteForward 4000 localhost:3000

    # Example 3: Access local port 3007 via droplet's port 4007
    RemoteForward 4007 localhost:3007

Explanation:

  • Host dev: Defines a shortcut name (dev). You’ll use ssh dev to connect.
  • HostName: The IP address or domain name of your droplet.
  • User: The username to log in as on the droplet (often root initially, but a non-root user is recommended for general use).
  • RemoteForward <RemotePort> <LocalHost>:<LocalPort>: This is the core forwarding rule. It tells the remote SSH server (on the droplet) to listen on <RemotePort>. Any connection received on that port on the droplet will be forwarded through the secure SSH tunnel back to your local machine, targeting <LocalHost>:<LocalPort>. localhost typically refers to your local machine itself.
  • ServerAliveInterval & ServerAliveCountMax: These options help prevent your SSH connection from disconnecting due to inactivity, which is crucial for long-running port forwarding.

Step 3: Keeping the Connection Alive

Idle SSH connections often get terminated by network devices (routers, firewalls). ServerAliveInterval and ServerAliveCountMax combat this:

  • ServerAliveInterval 60: Your local SSH client will send a “null packet” (keepalive message) to the server every 60 seconds to keep the connection active.
  • ServerAliveCountMax 120: If the server doesn’t respond to a keepalive message, the client will retry sending keepalives up to 120 times before giving up and disconnecting.

In our example (Interval 60, CountMax 120), the client will wait up to 60 * 120 = 7200 seconds (2 hours) for a response before disconnecting if the network appears down. This is generally much more robust than the default settings.

(Reference: Super User Question on preventing SSH disconnects)

Step 4: Configure the Server (Droplet) for Gateway Ports

By default, the RemoteForward directive only makes the <RemotePort> accessible from the droplet itself (i.e., connecting to localhost:<RemotePort> on the droplet). If you want other computers on the internet to be able to connect to your droplet’s <RemotePort> and have it forwarded to your local machine, you need to enable GatewayPorts on the droplet’s SSH server.

  1. SSH into your droplet using the alias you configured:
    ssh dev
    
  2. Edit the SSH server configuration file (sshd_config) using a text editor like nano or vim (you’ll need sudo):
    sudo nano /etc/ssh/sshd_config
    # or
    sudo vim /etc/ssh/sshd_config
    
  3. Find the GatewayPorts line. It might be commented out (#GatewayPorts no) or missing.
  4. Change it or add it to enable gateway ports:
    GatewayPorts yes
    
  5. Save the file and exit the editor (e.g., Ctrl+X, then Y, then Enter in nano).
  6. Restart the SSH service to apply the changes:
    sudo systemctl restart sshd
    

Security Warning: Setting GatewayPorts yes makes the forwarded port on your droplet accessible from anywhere that can reach your droplet’s IP address. This effectively exposes the service running on your local machine (localhost:<LocalPort>) to the internet via your droplet. Ensure that the local service is properly secured or that you understand the implications before enabling this. If you only need to access the forwarded port from the droplet itself, you can leave GatewayPorts as no (or commented out).

Step 5: Connect and Verify

Now, simply connect to your droplet using the alias:

ssh dev

As long as this SSH connection remains active, the port forwarding rules defined in your ~/.ssh/config will be in effect.

To test:

  • Ensure you have a service running on your local machine on one of the specified local ports (e.g., a web server on localhost:3000).
  • From the droplet’s command line, try accessing the corresponding remote port using curl or telnet:
    # On the droplet, testing the forward from RemotePort 4000 to LocalPort 3000
    curl localhost:4000
    
    You should see the response from the service running on your local machine’s port 3000.
  • If you enabled GatewayPorts yes, you could also try accessing <droplet-ip-address>:4000 from another machine (like your browser, or another server) to verify external access.

Conclusion

SSH remote port forwarding is a powerful technique for securely exposing local services via a remote server like a DigitalOcean droplet. By configuring your local ~/.ssh/config with RemoteForward rules and ensuring the connection stays alive with ServerAliveInterval, you can create stable tunnels. Remember to enable GatewayPorts yes on the server only if you need external access to the forwarded port, and be mindful of the security implications.