6 min to read
Understanding SSH Tunneling
A comprehensive guide to SSH tunneling and port forwarding

Overview
SSH (Secure Shell) is not just a tool for remote server access; it’s also a powerful solution for secure network tunneling. This guide will explore SSH tunneling, its various types, and practical applications in real-world scenarios.
What is SSH Tunneling?
SSH tunneling is a method of transporting arbitrary networking data over an encrypted SSH connection. It can be used to add encryption to legacy applications, implement VPNs, and access remotely exposed services through firewalls.
Types of SSH Tunneling
1️⃣ Local Port Forwarding
# Basic syntax
ssh -L [local_port]:[remote_server]:[remote_port] user@ssh_host
# Example: Access remote web server
ssh -L 8080:localhost:80 user@example.com
2️⃣ Remote Port Forwarding
# Basic syntax
ssh -R [remote_port]:[local_server]:[local_port] user@ssh_host
# Example: Expose local SSH server
ssh -R 9000:localhost:22 user@example.com
3️⃣ Dynamic Port Forwarding
# Basic syntax
ssh -D [local_port] user@ssh_host
# Example: Create SOCKS proxy
ssh -D 1080 user@example.com
Practical Implementation
1️⃣ Setting Up Persistent Tunnels
# Create tunnel script
cat <<EOF > /usr/local/bin/redis-tunnels.sh
#!/bin/bash
ssh -N -i /home/ec2-user/.ssh/id_rsa \
-L 0.0.0.0:6395:redis-endpoint:6379 \
ec2-user@10.33.1.252 &
wait
EOF
chmod +x /usr/local/bin/redis-tunnels.sh
2️⃣ Creating Systemd Service
# /etc/systemd/system/redis-tunnels.service
[Unit]
Description=Redis SSH Tunnels
After=network.target
[Service]
User=ec2-user
ExecStart=/usr/local/bin/redis-tunnels.sh
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
3️⃣ Managing the Service
# Enable and start the service
sudo systemctl daemon-reload
sudo systemctl enable redis-tunnels.service
sudo systemctl start redis-tunnels.service
Useful SSH Options
1️⃣ Common Flags
-N # No command execution
-f # Background execution
-C # Enable compression
-v # Verbose mode
2️⃣ Security Best Practices
- Use SSH keys instead of passwords
- Restrict IP access through firewalls
- Regularly monitor SSH logs
- Keep SSH software updated
Benefits and Considerations
1️⃣ Advantages
- Enhanced network security
- Encrypted connections
- Easy access to restricted services
- No need for VPN setup
2️⃣ Limitations
- Requires active SSH connection
- Potential performance overhead
- Need for proper port management
Real-World Examples
1️⃣ Database Access Through Bastion Host
# Access RDS through bastion host
ssh -L 3306:my-rds.region.rds.amazonaws.com:3306 user@bastion-host
# Multiple database connections
ssh -L 3306:prod-db:3306 -L 3307:stage-db:3306 user@bastion-host
2️⃣ Accessing Internal Web Services
# Access internal Jenkins
ssh -L 8080:jenkins-internal:8080 user@jump-server
# Access multiple web services
ssh -L 8080:web1:80 -L 8081:web2:80 user@gateway
Advanced Configurations
1️⃣ Automatic Tunnel Recovery
# /etc/systemd/system/tunnel-monitor.service
[Unit]
Description=Monitor and Recover SSH Tunnels
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/monitor-tunnels.sh
Restart=always
RestartSec=30
[Install]
WantedBy=multi-user.target
# /usr/local/bin/monitor-tunnels.sh
#!/bin/bash
while true; do
if ! netstat -an | grep "LISTEN" | grep -q ":6379"; then
echo "Redis tunnel down, restarting..."
systemctl restart redis-tunnels.service
fi
sleep 60
done
2️⃣ SSH Config File Setup
# ~/.ssh/config
Host bastion
HostName bastion.example.com
User ec2-user
IdentityFile ~/.ssh/id_rsa
LocalForward 6379 redis.internal:6379
LocalForward 3306 mysql.internal:3306
ServerAliveInterval 30
ServerAliveCountMax 3
Security Hardening
1️⃣ SSH Tunnel Restrictions
# /etc/ssh/sshd_config
AllowTcpForwarding yes
GatewayPorts no
PermitRootLogin no
AllowUsers tunnel-user
2️⃣ Firewall Configuration
# Allow SSH on bastion host
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Restrict tunnel access
sudo iptables -A INPUT -p tcp --dport 6379 -s 10.0.0.0/8 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 6379 -j DROP
Monitoring and Troubleshooting
1️⃣ Tunnel Status Check
# Check active tunnels
netstat -tulpn | grep ssh
# Monitor SSH connections
watch -n 1 "netstat -an | grep :22"
# Check tunnel logs
journalctl -u redis-tunnels -f
2️⃣ Performance Optimization
# SSH config for better performance
Host *
Compression yes
CompressionLevel 6
TCPKeepAlive yes
ServerAliveInterval 30
ServerAliveCountMax 3
ControlMaster auto
ControlPath ~/.ssh/control-%h-%p-%r
ControlPersist 1h
Load Balancing and High Availability
1️⃣ Multiple Tunnel Setup
# Primary tunnel
ssh -L 6379:redis-primary:6379 user@bastion-1 &
# Backup tunnel
ssh -L 6380:redis-secondary:6379 user@bastion-2 &
# HAProxy configuration
frontend redis_frontend
bind *:6379
default_backend redis_backends
backend redis_backends
server primary 127.0.0.1:6379 check
server backup 127.0.0.1:6380 check backup
2️⃣ Automatic Failover Script
#!/bin/bash
PRIMARY_PORT=6379
BACKUP_PORT=6380
while true; do
if ! nc -z localhost $PRIMARY_PORT; then
echo "Primary tunnel down, switching to backup..."
systemctl start backup-tunnel.service
fi
sleep 30
done
Common Issues and Solutions
1️⃣ Connection Issues
- Channel request failed: administratively prohibited
# Solution: Update sshd_config
AllowTcpForwarding yes
- Connection timed out
# Add to ~/.ssh/config
ServerAliveInterval 30
ServerAliveCountMax 3
2️⃣ Performance Issues
- Slow connection
# Enable compression
ssh -C -L 6379:redis:6379 user@bastion
- High CPU usage
# Adjust compression level
ssh -o "CompressionLevel 4" -L 6379:redis:6379 user@bastion
3️⃣ Security Issues
- Unauthorized access
# Restrict access
sudo iptables -A INPUT -p tcp --dport 6379 -j DROP
- Connection closed by remote host
# Check connection
netstat -tulpn | grep ssh
Comments