I recently needed to connect to a PostgreSQL database hosted on Namecheap shared hosting. Shared hosting doesn't expose databases to the outside world — there's no direct connection at all. The only way in was through an SSH tunnel. The script creates a SSH tunnel in the background allowing me to connect to PostgreSQL via PgAdmin.
#!/bin/bash
SERVER="[email protected]"
REMOTE_PORT=5432
LOCAL_PORT=5432
SSH_PORT=21098
echo "Checking for existing tunnel..."
is_tunnel_running() {
timeout 2 nc -z localhost $LOCAL_PORT 2>/dev/null
}
if is_tunnel_running; then
echo "Tunnel already running on port $LOCAL_PORT"
exit 0
fi
echo "Starting tunnel: localhost:$LOCAL_PORT -> $SERVER:$REMOTE_PORT"
ssh -N -L $LOCAL_PORT:127.0.0.1:$REMOTE_PORT $SERVER -p $SSH_PORT -o BatchMode=yes -o ConnectTimeout=10 &
SSH_PID=$!
echo "SSH PID: $SSH_PID"
echo "Waiting for tunnel to establish..."
sleep 3
if ! kill -0 $SSH_PID 2>/dev/null; then
echo "SSH process died. Check your SSH keys or connection."
exit 1
fi
echo "Verifying tunnel..."
if ! nc -z localhost $LOCAL_PORT 2>/dev/null; then
echo "Tunnel failed to establish"
kill $SSH_PID 2>/dev/null
exit 1
fi
echo "Success! Tunnel is running in background on port $LOCAL_PORT"
echo "PID: $SSH_PID"
echo "To stop the tunnel, run: kill $SSH_PID"
The flags used are important, for example -N prevents executing remote commands (we only need port forwarding), -L maps my local port 5432 to the remote server's localhost:5432, and -p handles the non-standard SSH port my host uses. BatchMode=yes is the key to making this hands-free — it tells SSH to never prompt for a password and rely entirely on key-based authentication. If your keys aren't set up, the script will tell you the SSH process died and exit. After starting the tunnel, it waits a few seconds, checks the process is alive, and verifies the tunnel actually works by probing the local port with nc. If everything passes, the tunnel stays up in the background until you kill it.