I am also searching for a solution to this and the solution masseyb can be extended for persistence in a couple of ways:
- autossh
- systemd service file
- run ssh from a local docker container -- unsure on this one, I'm quite new to docker
Instead of starting portainer directly you can just add the environment in the portainer web interface (Environments -> create Environment). This is pretty much a requirement for these methods.
EDIT: portainer needs to be started with the port forwarding or with --network host so it can see the exposed port or with -v /var/run/docker-$${HOST}.sock:/var/run/docker-$${HOST}.sock so it can see the unix socket.
Autossh is a straightfoward method, just replace ssh with autossh and you are done.
For use with systemd: Here is a unit file I use for creating reverse tunnels, but it can easily be adjusted for local->remote tunneling by changing -R to -L (and optionally changing the description):
[Unit]
Description=A reverse tunnel using ssh for %I (format remote port:host:local port, connect to host forward remote port to local port)
Wants=network-online.target
After=network-online.target
StartLimitIntervalSec=0
[Service]
ExecStart=/usr/bin/bash -c 'URI=%i; REMOTE_PORT=$${URI%%%%:*}; LOCAL_PORT=$${URI##*:}; HOST=$${URI%:*}; HOST=$${HOST#*:}; /usr/bin/ssh -qNnT -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o ExitOnForwardFailure=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /etc/rtunnel/$${HOST}.id_rsa -R $$REMOTE_PORT:localhost:$$LOCAL_PORT sshdummy@$$HOST'
Restart=always
RestartSec=60
[Install]
WantedBy=multi-user.target
To set this up:
- save as something like /lib/systemd/system/rtunnel@.service on localhost
- adjust parameters as needed (change -R to -L for local->remote port forwarding)
- create a separate user on the server (mine is called sshdummy).
- create a password-less ssh key pair on localhost, save private key in
/etc/rtunnel/${host}.id_rsa and copy public id to sshdummy@host:~/.ssh/authorized_keys
- run
sudo systemctl enable --now rtunnel@10022:myhost:22 on your host (This creates a persistent tunnel from myhost:10022 to localhost:22)
- optional for 3.: set user's login shell to /bin/cat (for extra security)
- optional for 3.: add rule in
/etc/ssh/sshd_config for user so the ClientAliveInterval and ClientAliveCountMax values are set too:
Match User sshdummy
ClientAliveInterval 15
ClientAliveCountMax 3
explanation of ssh and systemd options:
StartLimitIntervalSec=0 stops systemd from killing the service if it fails to start after X seconds
Restart=always ensures the service is always restarted after RestartSec=60 seconds
-o ExitOnForwardFailure=yes ensures that ssh exits and thus the service restarts when the tunnel can't be set up
-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no disregard host key validation failures
-i /etc/rtunnel/$${HOST}.id_rsa use a separate ssh key for every host you want to connect to