SSH Tunneling
SSH allows tcp port forwarding between ssh client and ssh server as part of the encrypted ssh connection.
Server → Client (local)
A socket on the server (source) gets forwarded to the client (target).
ssh user@host -L target_ip:target_port:source_ip:source_port
Use case 1: Admin software
Server socket with port 9000 will be available on client machine at port 5000.
ssh user@host -L 127.0.0.1:5000:127.0.0.1:9000
Useful if admin software is only accessible on the server (localhost binding) and not exposed to the network.
Use Case 2: Quick demo
Server socket with port 9000 will be accessible at client network on port 8080 of the client machine.
ssh user@host -L 8080:127.0.0.1:9000
ssh user@host -L 0.0.0.0:8080:127.0.0.1:9000
Useful for a quick demo of a service running in a different network (e.g. cloud) to multiple participants in the same network (e.g. company).
Use case 3: Jump Host
Server can reach host with ip addr 192.168.1.15. Service on 192.168.1.15:8080 will be available on client machine at port 8081.
ssh user@host -L 127.0.0.1:8081:192.168.1.15:8080
Hop to hop forwarding of hosts accessible in the server network(s).
Client → Server (remote)
A socket on the client (source) gets forwarded to the server (target).
ssh user@host -R target_port:source_ip:source_port
Use case 1: Microservice development
Service on port 8000 of the client machine will be available on server at port 8081. Unless GatewayPorts is set
to yes in sshd config (default no) the serverside bind will always be localhost (127.0.0.1).
ssh user@host -R 8081:127.0.0.1:8000
Useful to integrate a microservice on developer machine into a foreign environment (e.g. test cluster). Also works with
other source addresses than 127.0.0.1.
Use case 2: TLS terminating web proxy as a service
Client starts a http server on local machine on port 8000. That service will be available as https://server.tld
ssh user@host -R 8001:127.0.0.1:8000
Processing order:
- Webbrowser (User Agent) requests https://server.tld
- Reaches a reverse proxy on port 443
- does tls termination
- and proxying, nginx:
proxy_pass 127.0.0.1:8001;
- SSH Tunnel
- local machine port 8000 http server
SSH Config
port forwarding can also be specified on the client in ~/.ssh/config:
Host server-01
HostName 192.168.1.2
Port 22
User clusteradm
LocalForward localhost:9001 localhost:9000
RemoteForward 8001 localhost:8000
KeepAlive yes
IdentitiesOnly yes
IdentityFile ~/.ssh/server_01_clusteradm
Config format is (Local|Remote)Forward target source
connect via $ ssh server-01
Persistent connections
Just use the autossh command in place of ssh. AutoSSH uses heartbeats to check if the connection is still open and
open another one otherwise automatically and fully transparent.
Dedicated tunneling server
It’s possible to run a standalone ssh server which just allows port forwarding and no remote command execution. Setup:
mkdir -p /jail
adduser --gecos "" --no-create-home --shell /bin/false --disabled-password --uid 1000 sshtunnel
Excerpt from /etc/ssh/sshd_config:
# AllowUsers list all users which should be able to login
AllowUsers sshtunnel
Match User sshtunnel
PermitTTY no
Banner none
X11Forwarding no
AllowAgentForwarding no
# AllowTcpForwarding: yes (= local+remote), local, remote, no
AllowTcpForwarding local
GatewayPorts no
PermitTunnel no
ChrootDirectory /jail
ForceCommand /bin/false
PermitOpen 127.0.0.1:8730
Start sshd in foreground: $ sshd -D -e
Connect client: $ ssh -N -L 127.0.0.1:8730:127.0.0.1:8730 sshtunnel@localhost
Flag -N prevents the spawning of a shell (which would result in a connection abortion otherwise).
Rsync tunneling (also sftp)
rsync can copy (sync) files between hosts. Therefore, it can use ssh as a transfer protocol. But that implies running
the rsync command on the server:
rsync -av -e ssh user@host:/backup/ /datadir/
That won’t work with a tunneling only ssh server. Luckily rsync can also be operated with a standalone server, so the rsync protocol can be tunneled via ssh.
Server Setup
adduser --gecos "" --no-create-home --shell /bin/false --disabled-password --uid 1001 rsyncbackup
sudo mkdir -p /jail/backup
sudo chown -R root:root /jail # user cannot have write permission to chroot dir
sudo chown -R rsyncbackup:rsyncbackup /jail/backup
sudo chmod -R 755 /jail/backup
Excerpt from /etc/ssh/sshd_config:
# allow sftp connections
Subsystem sftp internal-sftp
# AllowUsers list all users which should be able to login
AllowUsers rsyncbackup
Match User rsyncbackup
PermitTTY no
Banner none
X11Forwarding no
AllowAgentForwarding no
# AllowTcpForwarding: yes (= local+remote), local, remote, no
AllowTcpForwarding local
GatewayPorts no
PermitTunnel no
ChrootDirectory /jail
ForceCommand internal-sftp
PermitOpen 127.0.0.1:8730
In addition to rsync this config also allows file browsing via sftp in the /jail dir.
Rsync server config in /etc/rsyncd.conf:
use chroot = true
hosts allow = 127.0.0.1/32
port = 8730
timeout = 300
max connections = 2
reverse lookup = no
log file = /dev/stdout
log format = %h %o %f %l %b
pid file = /var/run/rsyncd.pid
[backup_sink]
comment = Backup
path = /jail
read only = no
list = yes
uid = rsyncbackup
gid = rsyncbackup
Start rsync server: $ rsync --daemon --config /etc/rsyncd.conf
Client Setup
Record in .ssh/config:
Host backup-conn
HostName 192.168.1.32
Port 2201
User rsyncbackup
KeepAlive yes
LocalForward 127.0.0.1:8730 127.0.0.1:8730
Run a rsync job:
ssh -N backup-conn & # no tty possible, either use pubkey-auth or use sshpass to submit the password
pid=$!
sleep 3
time rsync bigfile rsync://localhost:8730/backup_sink/backup
kill $pid
Check that /jail/backup/bigfile has been created on the server.