ssh-tunnel-debug

Diagnose and fix SSH tunnel issues. Use when a tunnel is not connecting, a port is not responding, an SSH tunnel shows as stopped, the user reports "Permission denied", "Connection refused", or any SSH tunnel-related error.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "ssh-tunnel-debug" with this command: npx skills add statechangelabs/ssh-tunnel-manager/statechangelabs-ssh-tunnel-manager-ssh-tunnel-debug

SSH Tunnel Debugger

You are diagnosing issues with SSH tunnels managed by the ssh-tunnels CLI. Follow this systematic approach to identify and fix the problem.

Step 1: Get the current state

ssh-tunnels status --json

Look for tunnels where enabled: true but alive: false or portOpen: false. These are the broken ones.

Step 2: Check the logs

For each broken tunnel:

ssh-tunnels logs <tunnel-id>

Step 3: Diagnose by error message

"Permission denied (publickey)"

Cause: Wrong SSH username or SSH key not authorized on the remote host. Fix:

ssh-tunnels remove <id>
ssh-tunnels add --name "Same Name" --host <host> --user root --localPort <port> --remoteHost <rhost> --remotePort <rport> --enabled

Try root first. If that doesn't work, ask the user what username they use to SSH into that server manually (ssh <user>@<host>).

"Connection refused"

Cause: SSH server is not running on the target host, or it's on a non-standard port. Checks:

# Test SSH connectivity directly
ssh -o ConnectTimeout=5 -o BatchMode=yes <user>@<host> echo "OK" 2>&1

If the SSH server is on a non-standard port, recreate the tunnel with --sshPort.

"Connection timed out" or "No route to host"

Cause: Host is unreachable — wrong hostname, firewall, or network issue. Checks:

# Test basic connectivity
ping -c 3 -W 5 <host> 2>&1
# Test SSH port specifically
nc -z -w 5 <host> <ssh-port> 2>&1 && echo "Port open" || echo "Port closed/filtered"

"Host key verification failed"

Cause: The server's host key changed or this is the first connection. Fix:

# Remove the old host key
ssh-keygen -R <host>
# The tunnel manager uses StrictHostKeyChecking=accept-new, so re-enabling should work
ssh-tunnels disable <id> && ssh-tunnels enable <id>

"bind: Address already in use"

Cause: Another process is already using the local port. Fix:

# Find what's using the port
lsof -i :<local-port> -P -n
# Either stop that process or change the tunnel's local port

To change the local port, remove and re-add the tunnel with a different --localPort.

"channel 0: open failed: connect failed: Connection refused"

Cause: The SSH tunnel is connected, but the remote service is not listening on the specified remoteHost:remotePort. Checks:

# SSH in and check if the service is running
ssh <user>@<host> "netstat -tlnp 2>/dev/null | grep <remote-port> || ss -tlnp | grep <remote-port>"

The remote service may be down, or --remoteHost / --remotePort may be wrong.

Empty log file or no log file

Cause: The SSH process crashed immediately or was never spawned. Checks:

# Check the PID file
cat ~/.ssh-tunnels/pids/<id>.pid 2>/dev/null
# Try a manual SSH connection to see what happens
ssh -v -N -L <localPort>:<remoteHost>:<remotePort> <user>@<host>

Step 4: Verify the fix

After making changes:

ssh-tunnels status --json

Confirm that alive: true and portOpen: true for the fixed tunnel.

Then test the actual connection through the tunnel:

# For PostgreSQL (port 5432)
pg_isready -h 127.0.0.1 -p <local-port> 2>&1 || echo "Not ready"

# For HTTP services
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:<local-port>/ 2>&1

# For any TCP service (generic check)
nc -z -w 3 127.0.0.1 <local-port> && echo "Port responding" || echo "Port not responding"

Step 5: Check for systemic issues

If multiple tunnels are failing:

# Check if SSH agent is running and has keys loaded
ssh-add -l 2>&1

# Check if there's a network-level issue
# (all tunnels to the same host failing = host or network problem)
ssh-tunnels status --json | grep -E '"host"|"alive"'

# Force a full re-sync
ssh-tunnels sync

Step 6: Nuclear option — full reset

If nothing else works, reset a specific tunnel:

ssh-tunnels disable <id>
# Clean up any stale state
rm -f ~/.ssh-tunnels/pids/<id>.pid
ssh-tunnels enable <id>
ssh-tunnels logs <id>

Menu bar app issues

If the menu bar app is not showing or not updating:

# Check if it's running
pgrep -f "electron.*app.mjs" && echo "Running" || echo "Not running"

# Restart it
pkill -f "electron.*app.mjs"
# The LaunchAgent should restart it automatically, or:
launchctl unload ~/Library/LaunchAgents/com.statechange.ssh-tunnel-manager.plist 2>/dev/null
launchctl load ~/Library/LaunchAgents/com.statechange.ssh-tunnel-manager.plist

# Check launch agent status
launchctl list | grep statechange

Quick reference

SymptomMost likely causeFirst thing to try
"Permission denied"Wrong SSH userRecreate with --user root
Tunnel stops immediatelyAuth failure or port conflictssh-tunnels logs <id>
Tunnel starts but port not openRemote service downSSH in and check the service
All tunnels failingNetwork issue or SSH agentssh-add -l, check connectivity
Tunnel works then diesServer-side timeoutCheck ServerAliveInterval
"Address already in use"Port conflictlsof -i :<port>

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

ssh-tunnel

No summary provided by upstream source.

Repository SourceNeeds Review
General

image-gen

Generate AI images from text prompts. Triggers on: "生成图片", "画一张", "AI图", "generate image", "配图", "create picture", "draw", "visualize", "generate an image".

Archived SourceRecently Updated
General

explainer

Create explainer videos with narration and AI-generated visuals. Triggers on: "解说视频", "explainer video", "explain this as a video", "tutorial video", "introduce X (video)", "解释一下XX(视频形式)".

Archived SourceRecently Updated
General

asr

Transcribe audio files to text using local speech recognition. Triggers on: "转录", "transcribe", "语音转文字", "ASR", "识别音频", "把这段音频转成文字".

Archived SourceRecently Updated