ssh tunnel via userspace systemd service

[image above is a screenshot of – in place of a systemd logo]

This is short how-to on setting up a systemd service that is run from a user account.

In the /etc/systemd/system directory:

a) create a service file that implements the service. In my case, I wanted to set up a service that would be started at boot and run under my userid. This service is to set up a ssh tunnel to a system that is on another, external network.

$ cat /etc/systemd/system/ssh-tunnel.service
Description=ssh tunnel




b) This is a service that is to be started after the is reached – obviously, no network, nothing happens. Then the section [Service] has details as to who’s UID it is to be invoked. Included are the User, Group, and WorkingDirectory details. The file that is to be run when this service is started is called and that is also indicated.

# ps -ef|grep ssh
root       898   812  0 Jul17 ?        00:00:00 /usr/libexec/sssd/sssd_ssh --uid 0 --gid 0 --logger=files
root      1333     1  0 Jul17 ?        00:00:00 /usr/sbin/sshd -D
harish   30062     1  0 16:30 ?        00:00:00 /bin/sh /home/harish/
harish   30063 30062  0 16:30 ?        00:00:00 /usr/bin/ssh -N -R 2048:localhost:22 harish@

c) As can be seen above, the is invoked under my UID and in this case, because I am have set it up as passwordless ssh connection (which you have set up earlier), the command will work seamlessly.

d) The file is as follows:

$ cat 
/usr/bin/ssh -N -R 2048:localhost:22 harish@

Essentially, the command says that is run (in my case a Red Hat Enterprise Linux 7.5 system running in an Intel NUC RYBDWi35) is connecting to port 2048 on the remote host under my UID and linking back up port 22 on this NUC. So, when I log into, I can run:

$ ssh -p 2048 localhost

and I am back into the NUC.

e) So, once the systemd service file, in this case, ssh-tunnel.service is created, you will have to enable it and start it.

# systemctl enable ssh-tunnel.service
Created symlink from /etc/systemd/system/ to /etc/systemd/system/ssh-tunnel.service.
# systemctl start ssh-tunnel.service
# systemctl status ssh-tunnel.service -l
● ssh-tunnel.service - ssh tunnel back
   Loaded: loaded (/etc/systemd/system/ssh-tunnel.service; enabled; vendor preset: disabled)
   Active: active (running) since Thu 2018-07-19 19:13:50 +08; 9s ago
 Main PID: 421 (
    Tasks: 2
   CGroup: /system.slice/ssh-tunnel.service
           ├─421 /bin/sh /home/harish/
           └─436 /usr/bin/ssh -N -R 2048:localhost:22 harish@

Jul 19 19:13:50 r7 systemd[1]: Started ssh tunnel.
Jul 19 19:13:50 r7 systemd[1]: Starting ssh tunnel...

That’s about it.

I really do like systemd for the elegance provided.

[Update based on comments on g+:

In this instance, since the shell script has exactly one line, it can be placed in the unit file where it refers to the script. The updated file is as follows:

# cat ssh-tunnel.service 
Description=ssh tunnel

ExecStart=/usr/bin/ssh -N -R 2048:localhost:22 harish@


[root@r7 system]#

The reason I had the script was because it was something I have been using for a long time – predates systemd and since I wanted to make sure that I could work this tunnel with systemd, I just kept the script.

Thanks to +Christoph Wickert!


  1. This may be a dumb question, Harish, but is there an advantage to having the systemd unit be a system unit (in /etc/systemd/system), as opposed to a user unit (in ~/.config/systemd/user)?

    • Good question, Paul. I am not entirely sure if there are advantages either way. I shall investigate and perhaps write up a how-to. Thanks for the comment!

Leave a Reply