SSH Tunneling with TLS Obfuscation: Complete tunnelforge Guide

10 min read
Intermediate SSH Tunnel Censorship Obfuscation Privacy Guide

Prerequisites

  • A VPS with a public IP and SSH access
  • Basic familiarity with SSH

Quick Answer: SSH tunneling creates a SOCKS5 proxy through an encrypted SSH connection. The problem: SSH traffic is easily detected by DPI. Solution: tunnelforge wraps SSH in TLS so it looks like HTTPS, adds multi-user management, a Telegram bot, and a kill switch. Install: curl -fsSL https://raw.githubusercontent.com/SamNet-dev/tunnelforge/main/install.sh | sudo bash.

Need a VPS? Vultr (free credit), DigitalOcean ($200 free credit), or RackNerd (cheap annual deals).


What Is SSH Tunneling?

SSH (Secure Shell) isn't just for remote server access — it can also create encrypted tunnels that carry any traffic. When you create an SSH tunnel, your computer opens a local SOCKS5 proxy that routes traffic through the SSH connection to your server.

Your Device
    |
    | SOCKS5 proxy at localhost:1080
    | → Encrypted SSH tunnel
    |
    v
Your Server (VPS)
    |
    | Traffic exits to the internet from your server's IP
    |
    v
Destination (websites, apps)

The one-liner that makes this work:

ssh -D 1080 -N -f user@your-server
  • -D 1080 — create a SOCKS5 proxy on local port 1080
  • -N — don't open a shell (just tunnel)
  • -f — run in background

Then configure your browser or system to use localhost:1080 as a SOCKS5 proxy. All traffic flows through your server.


The Problem: SSH Is Detectable

SSH tunneling is simple and effective — but it has a critical weakness in censored countries:

DPI (Deep Packet Inspection) can easily identify SSH traffic.

The SSH protocol has a distinctive handshake that starts with SSH-2.0-OpenSSH_... in plaintext. Even after the handshake, SSH packet patterns (sizes, timing, encryption layer structure) are fingerprint-able. DPI systems in Iran, China, and Russia detect and block or throttle SSH connections, especially on non-standard ports.

Without obfuscation:
Your Device → [SSH handshake visible] → DPI sees "This is SSH" → BLOCKED

With TLS obfuscation:
Your Device → [TLS handshake, looks like HTTPS] → DPI sees "Normal HTTPS" → ALLOWED
    └→ Inside the TLS wrapper: SSH tunnel (invisible to DPI)

This is where TLS obfuscation comes in — wrapping the SSH connection inside a TLS layer so it looks identical to normal HTTPS traffic.


How TLS Obfuscation Works

TLS obfuscation (using stunnel) wraps the entire SSH connection in a TLS (HTTPS) layer:

  1. Your device opens a TLS connection to your server on port 443 (just like visiting a website)
  2. The DPI system sees a standard TLS handshake with a valid certificate — indistinguishable from HTTPS
  3. Inside the TLS tunnel, an SSH connection carries your traffic
  4. The server unwraps TLS, passes the SSH traffic to the SSH daemon, and forwards your traffic to the internet
Layer 1 (visible to DPI): TLS/HTTPS connection to port 443
    Layer 2 (encrypted, invisible): SSH connection
        Layer 3 (encrypted): Your actual internet traffic (SOCKS5 proxy)

To the censor, your connection looks like you're browsing a website. They'd have to break TLS encryption to know it's actually an SSH tunnel.


Part 1: Basic SSH Tunnel (Without Obfuscation)

If your country doesn't heavily censor SSH, a basic tunnel might be enough:

Create the Tunnel

# On your local machine
ssh -D 1080 -N -f user@your-server-ip

Configure Your Browser

Firefox (recommended — has built-in SOCKS5 support):

  1. Settings → Network Settings → Manual Proxy Configuration
  2. SOCKS Host: 127.0.0.1, Port: 1080
  3. Select SOCKS v5
  4. Check "Proxy DNS when using SOCKS v5" (important — prevents DNS leaks)

System-wide (Linux — for curl and apps that support ALL_PROXY):

export ALL_PROXY=socks5://127.0.0.1:1080
# Note: HTTP_PROXY and HTTPS_PROXY expect HTTP proxy URLs, not SOCKS5
# Use ALL_PROXY for SOCKS5, or use proxychains for apps that don't support it

Or use proxychains (for any app):

sudo apt install proxychains4 -y
# Edit /etc/proxychains4.conf — set: socks5 127.0.0.1 1080
proxychains4 curl ifconfig.me    # Should show your server IP

Local Port Forwarding

Access a specific service through the tunnel:

# Forward local port 8080 to a remote web service on port 80
ssh -L 8080:localhost:80 -N -f user@your-server
# Now visit http://localhost:8080 to access the remote server's port 80

# Forward to a database behind the server
ssh -L 5432:db-internal:5432 -N -f user@jump-server
# Now connect to localhost:5432 to reach the internal database

Make It Persistent

The tunnel dies if your connection drops. Use autossh to auto-reconnect:

sudo apt install autossh -y

# Persistent SOCKS5 tunnel
autossh -M 0 -f -N -D 1080 user@your-server \
  -o "ServerAliveInterval=30" \
  -o "ServerAliveCountMax=3" \
  -o "ExitOnForwardFailure=yes"

Full SSH reference: SSH Cheat Sheet


Part 2: tunnelforge (SSH + TLS Obfuscation + Management)

tunnelforge automates everything: SSH tunnel + TLS obfuscation + multi-user management + Telegram bot + kill switch.

What tunnelforge Gives You

  • TLS obfuscation — SSH traffic wrapped in TLS, looks like HTTPS to DPI
  • Interactive TUI — visual interface for all management
  • Live dashboard — real-time connection stats, bandwidth, connected users
  • Multi-user — create SSH users with individual limits
  • Telegram bot — manage everything from your phone
  • Kill switch — auto-blocks direct internet if tunnel drops (prevents leaks)
  • Auto-reconnect — tunnel recovers automatically from disconnections

Install

curl -fsSL https://raw.githubusercontent.com/SamNet-dev/tunnelforge/main/install.sh | sudo bash

The interactive wizard:

  1. Configures the SSH server for tunneling
  2. Sets up TLS obfuscation (stunnel) on port 443
  3. Creates the first tunnel user
  4. Optionally configures the Telegram bot

TUI Dashboard

tunnelforge

The TUI shows:

  • Server status and uptime
  • Active connections per user
  • Bandwidth usage (real-time)
  • TLS obfuscation status
  • Connected IPs

Manage Users

# Add a user
tunnelforge user add alice

# Add with limits
tunnelforge user add bob --max-connections 3 --expires 2026-12-31

# List users
tunnelforge user list

# Remove user
tunnelforge user remove alice

# Disable/enable
tunnelforge user disable bob
tunnelforge user enable bob

Each user gets SSH credentials that work through the TLS-obfuscated port (443).

Client Connection

Users connect using any SSH client:

# Direct SSH tunnel (if SSH isn't blocked)
ssh -D 1080 -N -p 443 alice@your-server

# Through TLS obfuscation (if SSH is blocked)
# Users need an stunnel client or tunnelforge client
# tunnelforge provides connection instructions for each user
tunnelforge user link alice

Telegram Bot

tunnelforge telegram setup

Bot commands:

  • /tf_status — server status
  • /tf_users — list active users
  • /tf_add username — create user
  • /tf_remove username — delete user
  • /tf_traffic — bandwidth stats
  • /tf_restart — restart tunnel

Auto-alerts: tunnel down, tunnel recovered, user quota exceeded.

Kill Switch

The kill switch prevents your real IP from leaking if the tunnel drops:

tunnelforge killswitch enable

It adds firewall rules that block all outbound traffic except through the tunnel. If the tunnel disconnects, your internet stops instead of leaking your real IP.


Part 3: Manual TLS Obfuscation (Without tunnelforge)

If you want to set up TLS obfuscation manually:

Server Side (stunnel)

# Install stunnel
sudo apt install stunnel4 -y

# Get a TLS certificate
sudo certbot certonly --standalone -d your-domain.com

# Configure stunnel
sudo nano /etc/stunnel/stunnel.conf
[ssh-over-tls]
accept = 443
connect = 127.0.0.1:22
cert = /etc/letsencrypt/live/your-domain.com/fullchain.pem
key = /etc/letsencrypt/live/your-domain.com/privkey.pem
# Start stunnel
sudo systemctl enable --now stunnel4

Now port 443 accepts TLS connections and forwards the decrypted traffic to SSH on port 22.

Client Side (stunnel)

# Install stunnel on your local machine
sudo apt install stunnel4 -y

# Create client config
cat > ~/stunnel-client.conf << EOF
[ssh-tunnel]
client = yes
accept = 127.0.0.1:2222
connect = your-server:443
EOF

# Start stunnel client
stunnel ~/stunnel-client.conf

# Now SSH through the TLS wrapper
ssh -D 1080 -N -p 2222 [email protected]

The connection path:

SSH client → stunnel client (local) → TLS to port 443 → stunnel server → SSH daemon (port 22)

DPI sees only TLS traffic to port 443 — identical to visiting a website.


Part 4: SSH Tunnel vs Other Methods

Method Speed DPI Resistance Complexity Best For
SSH tunnel (basic) Good Low (SSH is detectable) Very easy Light censorship
SSH + TLS (tunnelforge) Good High (looks like HTTPS) Easy (automated) Moderate censorship
VLESS+Reality Good Excellent Moderate Heavy censorship
Hysteria2 Fastest Excellent Easy Heavy censorship + speed
SOCKS5 (Dante) Good Low Easy No censorship, just privacy
WireGuard Fastest VPN Low (easily detected) Easy Privacy, not censorship

When to Use SSH Tunneling

  • You already have SSH access to a server (no additional software needed on server)
  • You need a quick tunnel without installing proxy software
  • You want multi-hop through jump hosts (SSH natively supports this)
  • Your setup uses SSH keys already and you want to reuse that infrastructure

When to Use Something Else


Part 5: Advanced SSH Tunneling

Multi-Hop (Chaining Servers)

Route through multiple servers for extra privacy:

# Jump through server1 to reach server2
ssh -J user@server1 -D 1080 -N user@server2

# Or chain in SSH config:
# Host hop1
#     HostName server1.com
#     User user
# Host final
#     HostName server2.com
#     User user
#     ProxyJump hop1

Reverse Tunnel (Access Home from Anywhere)

If your home is behind NAT/CGNAT, create a reverse tunnel from home to your VPS:

# On your home machine (connects OUT to your VPS)
autossh -M 0 -f -N -R 2222:localhost:22 user@your-vps

# Now from anywhere, SSH to your VPS port 2222 reaches your home machine
ssh -p 2222 homeuser@your-vps-ip

This is how you access a home server without port forwarding. See Home Server Guide.

Dynamic Port Forwarding + ProxyChains

Use SSH tunnel with any command-line tool:

# Create tunnel
ssh -D 1080 -N -f user@server

# Use with any program via proxychains
proxychains4 curl ifconfig.me
proxychains4 wget https://example.com/file.zip
proxychains4 nmap -sT target.com

Part 6: Security Hardening

Harden the SSH Server

# Only allow tunnel users (no shell access)
# In /etc/ssh/sshd_config:
Match User tunnel-user
    AllowTcpForwarding yes
    X11Forwarding no
    PermitTunnel no
    GatewayPorts no
    AllowAgentForwarding no
    ForceCommand /bin/true

This allows the user to create tunnels but prevents them from getting a shell or doing anything else on the server.

Use Key-Only Authentication

# Disable password login
PasswordAuthentication no

Guide: SSH Keys Setup

Use Fortify

Fortify auto-detects SSH and hardens it:

bash <(curl -sL https://github.com/SamNet-dev/fortify/raw/main/install.sh)
fortify --harden ssh

Guide: Fortify Server Hardening

Fail2ban (Brute Force Protection)

sudo apt install fail2ban -y
sudo systemctl enable --now fail2ban

Guide: Fail2ban Setup


Troubleshooting

# Check SSH service
sudo systemctl status sshd

# Check stunnel (TLS obfuscation)
sudo systemctl status stunnel4

# Check if port 443 is listening
ss -tlnp | grep 443

# Test SSH connection directly
ssh -v user@server -p 22

# Test through TLS
openssl s_client -connect your-server:443

# Check tunnel is working
curl --socks5 127.0.0.1:1080 ifconfig.me
Problem Fix
SSH connection refused Check sshd running: systemctl status sshd. Check firewall
SSH connection times out Port blocked by ISP. Use TLS obfuscation on port 443
TLS connection fails Check stunnel config and certificate paths. Renew cert: certbot renew
Tunnel works but internet is slow Check server bandwidth. Try compression: ssh -C -D 1080 ...
SOCKS5 proxy not working in browser Check proxy is set to SOCKS5 (not HTTP). Enable "Proxy DNS"
DNS leaking through tunnel Enable "Proxy DNS when using SOCKS v5" in Firefox, or use proxychains
Tunnel drops frequently Use autossh with keepalive: ServerAliveInterval=30
"Permission denied" Check SSH key permissions (600) or password. Check AllowUsers in sshd_config

Related Guides

SamNet Open Source Tools

Tool Purpose
tunnelforge SSH tunnel manager with TLS obfuscation, TUI, Telegram bot
fortify Server security hardening
paqctl Censorship bypass (Paqet + GFW-Knocker)
MTProxyMax Telegram proxy manager
cfray Cloudflare clean IP scanner
wg-orchestrator WireGuard VPN management

Related Tools