On-demand SSH Socks proxy through systemd user units with socket-activation doesn't restart as wished

  • Can /usr/bin/ssh really not accept systemd-passed sockets?

I think that's not too surprising, considering:

  • OpenSSH is an OpenBSD project
  • systemd only supports the Linux kernel
  • systemd support would need to be explicitly added to OpenSSH, as an optional/build-time dependency, so it would probably be a hard sell.

  • Can only units of root use the BindTodevice option?

User systemd instances are generally pretty isolated, and e.g. can not communicate with the main pid-0 instance. Things like depending on system units from user unit files are not possible.

The documentation for BindToDevice mentions:

Note that setting this parameter might result in additional dependencies to be added to the unit (see above).

Due to the above-mentioned restriction, we can imply that the option doesn't work from user systemd instances.


  • Why is my proxy service not respawning correctly on first new connection after the old tunnel dies?

As I understand, the chain of events is as follows:

  • SocksProxyHelper.socket is started.
  • A SOCKS client connects to localhost:8118.
  • systemd starts SocksProxyHelper.service.
  • As a dependency of SocksProxyHelper.service, systemd also starts SocksProxy.service.
  • systemd-socket-proxyd accepts the systemd socket, and forwards its data to ssh.
  • ssh dies or is killed.
  • systemd notices, and places SocksProxy.service into a inactive state, but does nothing.
  • SocksProxyHelper.service keeps running and accepting connections, but fails to connect to ssh, as it is no longer running.

The fix is to add BindsTo=SocksProxy.service to SocksProxyHelper.service. Quoting its documentation (emphasis added):

Configures requirement dependencies, very similar in style to Requires=. However, this dependency type is stronger: in addition to the effect of Requires= it declares that if the unit bound to is stopped, this unit will be stopped too. This means a unit bound to another unit that suddenly enters inactive state will be stopped too. Units can suddenly, unexpectedly enter inactive state for different reasons: the main process of a service unit might terminate on its own choice, the backing device of a device unit might be unplugged or the mount point of a mount unit might be unmounted without involvement of the system and service manager.

When used in conjunction with After= on the same unit the behaviour of BindsTo= is even stronger. In this case, the unit bound to strictly has to be in active state for this unit to also be in active state. This not only means a unit bound to another unit that suddenly enters inactive state, but also one that is bound to another unit that gets skipped due to a failed condition check (such as ConditionPathExists=, ConditionPathIsSymbolicLink=, … — see below) will be stopped, should it be running. Hence, in many cases it is best to combine BindsTo= with After=.


  • Is this the right way to set-up an "on-demand ssh socks proxy"? If, not, how do you do it?

There's probably no "right way". This method has its advantages (everything being "on-demand") and disadvantages (dependency on systemd, the first connection not getting through because ssh hasn't begun listening yet). Perhaps implementing systemd socket activation support in autossh would be a better solution.