This aims to do all the same things my SSH Reverse Tunnel on Mac OS X blog, except this is for Linux systems running systemd. Systemd as a process monitor makes an awesome way to implement the phone home ssh service.
I’m going to skip most of the details and justification for doing this and instead defer interested readers to my previous blog entry.
Setup the Server
All the steps are the same, except nowadays I’d recommend generating a ECDSA key. By default my Arch Linux systems makes a ECDSA key with a 256-bit length. This is very similar to the ECDSA algorithm used for things like Bitcoin, but this uses the NIST P-256 curve (Bitcoin uses secp256k1).
client $ ssh-keygen -f ~/.ssh/servername-home-fwd -t ecdsa
As my previous blog instructs, copy the key over to the server and install it in the
Astute readers will note the shorter length of the ECDSA public key. Depsite the shorter length, a 256-bit ECDSA key is believed to be stronger then the standard RSA 2048 key ssh-keygen would use by default (see keylength.com for more details).
Setup the Client
Now to setup the client running systemd (Arch Linux in my case), is approximately the same, except that systemd is used instead of launchd on Mac OS X.
To do this, a system service file is necessary, as opposed to a systemd user service running in the user’s session. The system file can be enabled by the system at boot. Typically system files run as root, so it’s necessary to specify the user tag to avoid running the ssh client as root.
Create the systemd unit file @
[Unit] Description=Phone Home Reverse SSH Service ConditionPathExists=|/usr/bin After=network.target [Service] User=localuser ExecStart=/usr/bin/ssh -NTC -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -o StrictHostKeyChecking=no -i %h/.ssh/servername-home-key -R 12345:localhost:22 [email protected] # Restart every >2 seconds to avoid StartLimitInterval failure RestartSec=3 Restart=always [Install] WantedBy=multi-user.target
local user is the user that the ssh client will run as, not root. The ssh client will login to
servername as user
remoteuser using key
servername-home-key and forwards the client’s local port
22 to the remote server’s port
After that file is modified, start the service:
client $ sudo systemctl restart phone-home.service
Check to see if it started:
client $ sudo systemctl status -l phone-home.service phone-home.service - Phone Home Reverse SSH Service Loaded: loaded (/etc/systemd/system/phone-home.service; enabled) Active: active (running) since Thu 2014-02-20 20:40:32 PST; 4min 45s ago Main PID: 2559 (ssh) CGroup: /system.slice/phone-home.service └─2559 /usr/bin/ssh -NTC -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -o StrictHostKeyChecking=no -i /home/user/.ssh/core-home-fwd -R 12345:localhost:22 [email protected] Feb 20 20:40:32 recon systemd: Started Phone Home Reverse SSH Service.
Finally, enable it to start at boot:
client $ sudo systemctl enable phone-home.service ln -s '/etc/systemd/system/phone-home.service' '/etc/systemd/system/multi-user.target.wants/phone-home.service'
Unfortunately there isn’t an easy way to hook in to the network state and only start this service when the network is up. Perhaps this will be easier to fix in the future as systemd evolves with Linux distributions. Ideally it would be nice to say “start this if there is a default route that likely leads to the Internet”.
Instead, the current implementation is a service that will attempt to connect to a remote server every 2 minutes and fail, not the end of the world but not perfect – yet.