SSHtun is a collection of bash scripts that allows a client to route selected traffic through an external server with the use of a transparent and encrypted tunnel between them.

It can be useful in scenarios in which the client is behind a firewall trying to reach blocked resources on the internet (school,office,protected LANs,etc...). It supports IPV6 (via radvd) and rules-based tunneling (via iptables), which means that only the traffic you specify will seamlessly go through the tunnel. It uses commands described in http://tldp.org/HOWTO/Linux+IPv6-HOWTO/configuring-ipv6to4-tunnels.html .


  • A server with a public IP to which the client has SSH access (root privileges for starting the daemon, normal user for using the tunnel)
  • "tun" kernel module available on both client and server
  • "ip" and "iptables" installed on both client and server
  • Optionally "radvd" on server, for IPV6 support

Installation and Configuration

NOTE: default values provided in config files are good except for the mandatory options listed when needed.


  • Add PermitTunnel yes to /etc/ssh/sshd_config
  • follow instructions in sshtun-server.conf.example
  • enable IPv4 forwarding:
    • echo 1 > /proc/sys/net/ipv4/ip_forward (on the fly)
    • add "net.ipv4.ip_forward=1" to /etc/sysctl.conf (permanent)
  • IPv6 setup (optional)
    • enable IPv6 forwarding:
      • echo 1 > /proc/sys/net/ipv6/conf/all/forwarding (on the fly)
      • add "net.ipv6.conf.default.forwarding=1" to /etc/sysctl.conf (permanent)
    • copy radvd.conf under /etc/
    • if you modify the IPV6_SUBNET remember to set the same value in radvd.conf
    • start radvd (optional if you are not interested in IPV6 feature) (default is "1337")
  • sshtun-server start (from root)


  • follow instructions in sshtun-client.conf.example
  • IPv6 setup (optional)
    • disable IPv6 forwarding (otherwise routing advertisement won't work):
      • echo 0 > /proc/sys/net/ipv6/conf/all/forwarding (on the fly)
      • add "net.ipv6.conf.default.forwarding=0" to /etc/sysctl.conf (permanent)
  • open tunnel.rules and make sure SSH traffic to the sever is not routed. Default is to route through the tunnel (almost) all traffic from/to internet
  • setup SSH "password-less" public key authentication (optional, read here how to do it:

  • sshtun-client start (from root)


Q: What is the difference between SSHtun and a proxy?
A: They work at different levels. In short, with SSHtun you don't have to change anything in the programs you use. It just works.

Q: How can I know that the tunnel is really working?
A: Go to some "what's my ip" site, such as icanhazip.com, and verify that the IP showed is the same of your server (unless you have escluded HTTP traffic from the tunnel routing).

Q: Can I route ALL my traffic with iptables rules?
A: No, some exceptions do apply. For example, all traffic from/to private addresses (your router, office LAN,etc..) must be passed-through. The connection to your sshtun server must also be excluded from tunneling.

Q: Is DNS-routing supported by sshtun?
A: Yes, just make sure you set public nameservers in your /etc/resolv.conf (Google ones are a good choice) and route DNS traffic through sshtun.

Q: SSH connection is successful, but soon after that an authentication error pops out from the console. How's that?
A: It seems like your permissions are wrong. Make sure that PermitTunnel yes appears in your /etc/ssh/sshd_config and that your remote user belongs to the right group assigned to the "tap<X>" interface. After that, restart SSH service on the server, close all your SSH sessions and reconnect to it.

Q: sshtun successfully starts on both client and server, I correctly see the packets going through the tap interface yet applications hang as if packets are dropped.
A: Make sure reverse path filtering is disabled:

  • cat /proc/sys/net/ipv4/conf/all/rp_filter
    • echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter (on the fly)
    • add "net.ipv4.conf.all.rp_filter=0" to /etc/sysctl.conf (permanent)

Note that sshtun already disable reverse path filtering on $TAP_IFACE for you, but it won't do it globally as it may be cause a security issue. More information here.