DEV Community

Dmitry Romanoff
Dmitry Romanoff

Posted on

Keeping Your SSH Tunnel Alive: A Handy Bash Script for Monitoring

If you're working with remote resources like AWS DocumentDB or any cloud-hosted service behind a bastion host, chances are you're using SSH tunnels to securely access them. While setting up an SSH tunnel is straightforward, keeping it alive and monitoring its status over time can be a bit trickier.

Today, I’m sharing a lightweight Bash script I wrote to set up and monitor an SSH tunnel. It’s simple, portable, and gives you real-time feedback on the tunnel’s status.


💡 Use Case

Imagine this: You have an AWS DocumentDB cluster that's only accessible through a bastion host. You want to:

  • Forward a local port (e.g. 27088) to the remote DocumentDB port (27017).
  • Automatically monitor if the SSH tunnel drops.
  • Get a simple minute-by-minute status update.
  • Clean up the SSH process cleanly if the script or terminal is terminated.

🧩 The Script

Here’s the script in full:

#!/bin/bash

KEY="my-bastion-host-key-pair.pem"
USER="ec2-user"
HOST="ec2-YYY-YYY-YYY-YYY.compute-1.amazonaws.com"
REMOTE_HOST="docdb-dima-1.cluster-xxxxxxxxxxxx.us-east-1.docdb.amazonaws.com"
LOCAL_PORT=27088
REMOTE_PORT=27017

START_TIME=$(date +%s)

# Start SSH tunnel in the background
ssh -i "$KEY" \
    -o ServerAliveInterval=60 \
    -o ServerAliveCountMax=3 \
    -L ${LOCAL_PORT}:${REMOTE_HOST}:${REMOTE_PORT} \
    ${USER}@${HOST} -N &

SSH_PID=$!

# Trap to clean up if script is terminated
trap "kill $SSH_PID 2>/dev/null" EXIT

# Monitor loop
while kill -0 $SSH_PID 2>/dev/null; do
    NOW=$(date +%s)
    ELAPSED_MIN=$(( (NOW - START_TIME) / 60 ))
    printf "\r⏱️  SSH tunnel alive for %d minute(s)..." "$ELAPSED_MIN"
    sleep 60
done

printf "\n❌ SSH tunnel disconnected after %d minute(s).\n" "$ELAPSED_MIN"
Enter fullscreen mode Exit fullscreen mode

🔍 How It Works

Let’s break it down:

  • SSH Tunnel Setup: Uses ssh -L to forward localhost:27088 to the remote DocumentDB endpoint via the bastion host.
  • Keepalive Options:

    • ServerAliveInterval=60: Sends a keepalive packet every 60 seconds.
    • ServerAliveCountMax=3: If three keepalives are missed, the connection is considered dead.
  • Background Process: The SSH tunnel runs in the background.

  • Monitoring Loop: Every minute, it checks if the SSH process is still alive using kill -0 $SSH_PID.

  • Cleanup Trap: If the script is interrupted (Ctrl+C or killed), it cleans up the SSH process to avoid zombie tunnels.


✅ When to Use This

  • Developing with services behind a bastion host.
  • Need a quick local connection to remote databases.
  • Want visibility into tunnel uptime without heavy tooling.
  • Avoiding tools like autossh or systemd for simpler setups.

🧹 Final Thoughts

This script might look simple, but it has saved me countless hours of wondering “is my tunnel still alive?” during long development or migration sessions.

Top comments (1)

Collapse
 
rdarrylr profile image
Darryl Ruggles

I run into disconnected tunnels all the time. This looks to be super helpful - thanks!