What Is sshuttle? The Beginner's Guide to VPN Over SSH Without a VPN Server

CodexFuse Team · 2026-11-04T21:38:17.029Z · 13 min read min read

What Is sshuttle? The Beginner's Guide to VPN Over SSH Without a VPN Server

If you have been wondering what is sshuttle, here is the short answer: sshuttle is a free, open-source tool that turns an ordinary SSH connection into a transparent VPN — every TCP session on your machine can be routed through a remote server without installing any VPN software on that server at all. Its own project page describes it in one line as a "Transparent proxy server that works as a poor man's VPN. Forwards over ssh. Doesn't require admin. Works with Linux and MacOS. Supports DNS tunneling." (github.com/sshuttle/sshuttle, crawled 2026-11-04) Created by Avery Pennarun and released under the GNU Lesser General Public License v2.1, the project holds about 13,643 GitHub stars and shipped its current stable line, v2.0.0, on September 28, 2026. This sshuttle explained guide covers what it is, the problem it kills, how session-forwarding works, the one command to start, the flags you will actually use, and the real limits to know before you adopt it.

The natural place for sshuttle to reach is a small server you already own, so if you have not set one up yet, read our VPS hosting guide first — one always-on Linux box plus an SSH account is literally the entire infrastructure sshuttle needs.

What Is sshuttle, Exactly?

sshuttle is a transparent proxy that works as a VPN over SSH, with the README's own headline phrasing it as: "sshuttle: where transparent proxy meets VPN meets ssh." The project's docs state the defining line clearly: "sshuttle is not exactly a VPN, and not exactly port forwarding. It's kind of both, and kind of neither." What that means in practice: like a VPN, it can forward every port on an entire network instead of individual ports you name one by one — "It can forward every port on an entire network, not just ports you specify. Conveniently, it lets you use the 'real' IP addresses of each host rather than faking port numbers on localhost." But unlike a VPN server, there is nothing to install or configure on the remote side: the remote end just needs SSH access and a Python interpreter available, and sshuttle uploads its own Python source to the server and runs it automatically. Say it once: the whole pitch is no VPN software, no admin privileges, and no configuration on the remote server — if you have SSH credentials to a box, you have a VPN to that box's network.

What Problem Does sshuttle Solve?

It kills the pain of one-off, ad-hoc secure access. Before sshuttle, your options were all heavy: set up OpenVPN or WireGuard (server-side installs, certificates or keys, firewall ports), or stack ssh -L / -D port forwards for every single host and port you needed — which collapses the moment you need "everything on this internal network." The README lists the exact scenario it was built for: your client is Linux, FreeBSD, macOS, or experimental Windows; you can reach a remote network over SSH; you do not necessarily have admin access on that remote network; the remote network has no VPN or only an unpleasant one; and you refuse to create a separate port forward for every host and port. The docs close the pitch with a line worth quoting: "Fun, right? A poor man's instant VPN, and you don't even have to have admin access on the server." The emergency recipe the docs themselves recommend — when your real VPN breaks at the worst moment — is sshuttle --dns -NHr username@sshserver 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16, which proxies DNS and the three private IPv4 ranges straight through the tunnel.

How Does sshuttle Actually Work?

It forwards sessions, not packets — and that one design choice is the entire product. The man page's Discussion section states it verbatim: "Unlike most VPNs, sshuttle forwards sessions, not packets. That is, it uses kernel transparent proxying (iptables REDIRECT rules on Linux) to capture outgoing TCP sessions, then creates entirely separate TCP sessions out to the original destination at the other end of the tunnel." So when your browser opens a connection, the local kernel redirects it into sshuttle; sshuttle assembles the TCP stream locally and multiplexes it, statefully, over the SSH session; the copy of sshuttle running on the remote server disassembles it back into packets and opens a fresh TCP connection to the real destination. Unlike stateless packet-forwarding VPNs, "sshuttle is the opposite of stateless; it tracks every single connection." The observable result is that every app on your machine — browser, package manager, game launcher — just works, with real destination IP addresses, through an encrypted tunnel you started in seconds.

The startup sequence makes the no-server-side-setup claim concrete. When sshuttle starts it: (1) opens an SSH session to the server named by -r; (2) uploads its own Python source code to the remote end and executes it there — nothing is ever installed; (3) installs firewall rules locally to intercept outgoing traffic; (4) forwards intercepted sessions through the tunnel; (5) removes the firewall rules and cleans up when you press Ctrl+C. You will be prompted for two passwords in order: your local sudo password (firewall rules need root), then your SSH password or key passphrase. And in a nice touch, "The SSH connection endpoint is automatically excluded from forwarding" — sshuttle can never accidentally swallow its own tunnel.

Why Not Just Forward TCP Packets Over SSH? (The TCP-over-TCP Problem)

Because that is the classic TCP meltdown, and sshuttle was built specifically to dodge it. As Avery Pennarun writes in the docs' how-it-works page: "But you can't safely just forward TCP packets over a TCP session (like ssh), because TCP's performance depends fundamentally on packet loss; it must experience packet loss in order to know when to slow down! At the same time, the outer TCP session (ssh, in this case) is a reliable transport, which means that what you forward through the tunnel never experiences packet loss... But neither does your inner TCP session, and extremely screwy performance ensues." The man page puts the congestion-control version bluntly: "if you pass tcp packets through a tcp-based tunnel (such as ssh), the inner tcp packets will never be dropped, and so the inner tcp stream's congestion control will be completely broken, and performance will be terrible." That is why packet-level VPNs like OpenVPN and IPsec "cannot use tcp-based encrypted streams like ssh or ssl, and have to implement their own encryption from scratch, which is very complex and error prone" — and it is why the README explicitly warns off OpenSSH's built-in PermitTunnel tunnels: "it's disabled by default on openssh servers; plus it does TCP-over-TCP, which has terrible performance." The classic external citation for the phenomenon is Olaf Titz's 2001 paper "Why TCP Over TCP Is A Bad Idea," referenced by Wikipedia's tunneling and OpenSSH articles; the same logic is why WireGuard chose UDP-only transport. sshuttle's answer, verbatim from the docs: "sshuttle assembles the TCP stream locally, multiplexes it statefully over an ssh session, and disassembles it back into packets at the other end. So it never ends up doing TCP-over-TCP. It's just data-over-TCP, which is safe."

How Do You Run sshuttle? The 5-Minute First Run

The first run is one command. Here is the full arc, from zero to tunneled:

  1. Install it locally. The docs' install page is route-first: apt-get install sshuttle on Ubuntu 16.04 or later (and Debian stretch or later), dnf install sshuttle on Fedora, pacman -S sshuttle on Arch, brew install sshuttle on macOS, or sudo pip install sshuttle anywhere with Python. Nothing needs installing on the server.
  2. Open the tunnel. sshuttle -r username@sshserver 0/0 — and the docs give you permission to take the shortcut, because "There is a shortcut for 0.0.0.0/0 for those that value their wrists." The official full form is sshuttle -r username@sshserver 0.0.0.0/0.
  3. Answer the two password prompts. First your local sudo password (sshuttle needs to write firewall rules), then the SSH credential for the remote account. A normal, non-admin account on the server is fine — root is needed locally, never remotely.
  4. Verify traffic is flowing through the tunnel. Visit an IP-check page or ping an internal host on the server's private network — requests that were unreachable before should now answer, with the server's egress IP on the far side.
  5. Add --dns for real privacy. Plain IP traffic is tunneled, but DNS lookups still go out locally unless you say otherwise: sshuttle --dns -r username@sshserver 0/0 captures local DNS requests and forwards them to the remote server's resolver — "If you would also like your DNS queries to be proxied through the DNS server of the server you are connect to." Stop everything with Ctrl+C.

The Flags You Will Actually Use

You can live on four flags. Each one answers a real-world need, straight from the man page:

FlagWhat it doesWhen you need it
--dnsCaptures plain DNS on port 53 and forwards it to the remote server's resolverEvery time you route 0/0 — otherwise DNS leaks around the tunnel
-N / --auto-netsAsks the server which subnets its routing table suggests, and routes those automatically"I want the remote network, whatever it is" — the emergency recipe's secret sauce (no IPv6 auto-detection)
-H / --auto-hostsScans for remote hostnames and writes them into your local /etc/hosts for the sessionAccessing internal machines by name (e.g. db-prod) instead of IP; cache lives at ~/.sshuttle.hosts on the server
-x / --excludeExcludes a subnet from forwarding: 0/0 -x 1.2.3.0/24 tunnels everything except that subnetKeep your LAN or a service reachable directly; -X reads the exclusion list from a file
-v / -vvRaises verbosityDebugging connection or firewall-rule problems
--methodChooses the firewall backend: auto | nat | nft | tproxy | pf | ipfwRarely — auto guesses from your PATH; use tproxy for IPv6 + UDP-DNS cases
--pythonNames the remote Python interpreter (default: python3, falling back to python)Minimal servers where the interpreter has an unusual name

Two more mechanics worth knowing once: subnet syntax is a.b.c.d[/width][port[-port]] — 0/0 means all IPv4, ::/0 means all IPv6 — and it is "valid to run sshuttle more than once simultaneously on a single client machine, connecting to a different server every time, so you can be on more than one VPN at once." The -r target is passed straight to SSH, so any alias from your ~/.ssh/config works — our SSH config file guide shows how to define those aliases once and reuse them everywhere. And on a home router you can turn the whole subnet into tunnel users with --listen 0.0.0.0:0 plus kernel IP forwarding enabled.

sshuttle vs Tailscale vs OpenVPN vs WireGuard: Which Do You Actually Need?

The honest answer depends on whether you want an always-on network or an ad-hoc tunnel. Our published Tailscale setup guide covers the mesh side: Tailscale runs WireGuard underneath, with near-zero config and always-on device networking — but it requires installing its client everywhere and relies on Tailscale's coordination servers for initial setup. sshuttle is the opposite philosophy: nothing to install on the server, no keys to exchange, no coordination service — one command and you are tunneled, then you press Ctrl+C and it is gone.

sshuttleTailscaleOpenVPNWireGuard
Server-side setupNone — SSH + Python onlyClient install per deviceServer install, certs, portsKey pairs, config files
Server privileges neededNormal user accountAdmin install on devicesRoot / adminRoot / admin
TransportTCP only (no UDP)UDP (WireGuard)TCP or UDPUDP only
Setup effortVery low — one commandMedium — accounts + installsHigh — certs and routingMedium — key management
Best forAd-hoc tunnels, emergencies, reaching private subnets with only SSH credsAlways-on device meshEnterprise/legacy compatibilityFast modern always-on VPNs

The comparison table's skeleton comes from TheLinuxCode's sourced rundown (OpenVPN "Fast" with strong AES, WireGuard "Very Fast" over UDP with Curve25519, sshuttle "Medium" setup "Very Low — Just connect", TCP-only, SSH encryption). One third-party caveat with attribution: SysTutorials measures about 5–20ms of extra latency from Python-based routing versus native VPN software, depending on network and server — noticeable in a fast-twitch game, invisible in an SSH session. So the rule of thumb: sshuttle wins when the situation is temporary and you already have SSH; Tailscale or WireGuard win when the tunnel should always be on and carry UDP traffic like voice and video. Different lanes, never rivals.

The Real Limits: Read These Before You Adopt It

sshuttle is TCP-only — that is the single most important limit, and it deserves one clear statement: UDP traffic (voice calls, most game traffic, QUIC) is not tunneled; only DNS gets special handling through --dns, which captures plain DNS on port 53. Second, the remote server sees all your traffic in the clear at its end — the tunnel is encrypted from your machine to the server, but the server then makes the connections on your behalf, so only ever point sshuttle at a server you fully trust. Third, this is an ad-hoc tunnel, not a drop-in always-on privacy VPN: there is no kill-switch culture, no exit-node rotation, no marketing-grade anonymity — it is a tool for reaching networks you control, not for hiding from them. And the root requirement stays local: you need root (sudo) on your own machine to write firewall rules, while the server side stays privilege-free. Know those four lines and sshuttle does exactly what its README promises — a poor man's VPN with none of a VPN's setup ceremony.

Sources

  • sshuttle/sshuttle GitHub repository (README, license, release history) — github.com/sshuttle/sshuttle (crawled 2026-11-04)
  • sshuttle official docs — Installation — sshuttle.readthedocs.io/en/stable/installation.html (crawled 2026-11-04)
  • sshuttle official docs — Usage — sshuttle.readthedocs.io/en/stable/usage.html (crawled 2026-11-04)
  • sshuttle official docs — How It Works — sshuttle.readthedocs.io/en/stable/how-it-works.html (crawled 2026-11-04)
  • sshuttle official man page — sshuttle.readthedocs.io/en/stable/manpage.html (crawled 2026-11-04)
  • sshuttle official docs — Useless Trivia (Avery Pennarun, Tunnel Vision) — sshuttle.readthedocs.io/en/stable/trivia.html (crawled 2026-11-04)
  • GitHub releases API — sshuttle/sshuttle v2.0.0 (2026-09-28) — api.github.com/repos/sshuttle/sshuttle/releases (fetched 2026-11-04)
  • Olaf Titz, "Why TCP Over TCP Is A Bad Idea" (2001-04-23), via Wikipedia — Tunneling protocol — en.wikipedia.org/wiki/Tunneling_protocol (crawled 2026-11-04)
  • SysTutorials — "VPN Over SSH: Using Sshuttle And Alternatives" — systutorials.com/how-to-set-up-a-vpn-over-ssh/ (crawled 2026-11-04)
  • TheLinuxCode — "Creating a Secure and Private VPN Using sshuttle on Linux" — thelinuxcode.com/creating-vpn-over-ssh-sshuttle-linux/ (crawled 2026-11-04)
  • Kali Linux Tools — sshuttle — kali.org/tools/sshuttle/ (crawled 2026-11-04)

Frequently Asked Questions

Does sshuttle need to be installed on the remote server?

No. The remote server only needs SSH access and a Python interpreter available — when sshuttle starts, it uploads its own Python source code to the remote end and executes it there. That is the entire server-side story, and it is why the docs call it "a poor man's instant VPN" you can run with a normal, non-admin account.

Does sshuttle work on Windows?

Only experimentally. The README lists Windows support as experimental, installed via pip install sshuttle, while Linux, FreeBSD, and macOS are the fully supported platforms. For Windows users needing the same ad-hoc tunneling, the docs' install page still leads with native Linux and macOS routes.

Is sshuttle faster than OpenVPN or WireGuard?

Generally no — it is the convenience option, not the performance option. sshuttle routes TCP sessions statefully through a user-space Python process and an SSH stream, while OpenVPN and WireGuard forward packets in kernel space over UDP. The tradeoff is setup ceremony: one command and no server configuration versus certificate management and port configuration.

Can sshuttle tunnel UDP traffic like DNS or voice calls?

Not really — sshuttle forwards TCP sessions only. The one exception is DNS: --dns captures plain DNS queries on port 53 and forwards them to the remote server's resolver, which stops DNS from leaking around the tunnel. Everything else UDP — VoIP, gaming, QUIC — travels outside the tunnel.

Is sshuttle a good replacement for a privacy VPN subscription?

No, and it does not try to be. sshuttle encrypts your traffic to the remote server, but that server then sees and originates all of it — so you must fully trust whoever owns the box. It is built for ad-hoc access to networks you already have SSH credentials for, not for anonymous browsing, geo-unblocking, or always-on privacy.

Featured on Twelve Tools Hunt for Tools Featured on LaunchBuff Launch Llama Tools Launch your MCP Top Web Development Companies in the US - OnToplist.com Designer Listings Listed on SeeWhatNewAI