Automatic and resilient SSHFS mounting (systemd user services)

Goal: automatically mount remote directories in $HOME via SSHFS, so that:

  • the mount point is populated as soon as the remote machine is reachable;
  • it stays empty (without blocking the system) when it is not;
  • the mount recovers automatically after a network outage;
  • the connection automatically goes through a jump host (proxy) when outside the site network.

Tested on Ubuntu 24.04. No root privileges are required, except to install sshfs.


1. Prerequisites

sudo apt install sshfs netcat-openbsd

Authentication must be non-interactive (SSH key, no password prompt). A passphrase-protected key works if it is unlocked by the session’s SSH agent (the default under GNOME).

Check, for each machine:

ssh -o BatchMode=yes MACHINE true && echo OK

If the command fails (“Permission denied”), automatic mounting will not work.

2. SSH configuration (~/.ssh/config)

The host name, user and port are defined here, not in the service. The alias (MACHINE) is also used to name the mount point.

Host MACHINE
    HostName ADRESSE_OU_NOM
    Port XXXX
    User UTILISATEUR_DISTANT

Option: automatic jump host when off-site

If the machine can only be reached directly from the site network, add a Match block after the Host block. It checks within one second whether the SSH port responds; if not, it enables the jump host.

Standard SSH jump host:

Match originalhost MACHINE !exec "nc -z -w 1 ADRESSE_INTERNE 22"
    ProxyJump UTILISATEUR@PASSERELLE

Jump through a TLS tunnel (example with openssl s_client):

Match originalhost MACHINE !exec "nc -z -w 1 ADRESSE_INTERNE 22"
    ProxyCommand openssl s_client -quiet -connect IP_PASSERELLE:PORT -servername NOM_SNI
    ServerAliveInterval 30
    TCPKeepAlive no

Notes:

  • indentation has no meaning for ssh: Match always starts a new block;
  • the internal address appears twice (in HostName and in the nc test): remember to update both if it changes;
  • the jump host also applies to manual ssh, scp and rsync commands.

Check (shows the ProxyCommand only when off-site):

ssh -G MACHINE | grep -iE "proxycommand|proxyjump"

3. Mount points

One empty directory per machine, named for example _MACHINE:

mkdir -p ~/_MACHINE

4. systemd template service

Create ~/.config/systemd/user/sshfs@.service:

[Unit]
Description=SSHFS mount of %i

[Service]
ExecStart=/usr/bin/sshfs -f %i: %h/_%i -o BatchMode=yes,ConnectTimeout=5,ServerAliveInterval=15,ServerAliveCountMax=3
ExecStopPost=-/usr/bin/fusermount -uz %h/_%i
Restart=always
RestartSec=30

[Install]
WantedBy=default.target
  • %i: instance name (the SSH alias); %h: home directory.
  • -f: sshfs stays in the foreground, which lets systemd monitor it.
  • ServerAliveInterval=15 + ServerAliveCountMax=3: after ~45 s without a response, the connection is dropped instead of freezing the programs reading the directory.
  • ExecStopPost ... fusermount -uz: cleans up a stuck mount (“Transport endpoint is not connected”).
  • Restart=always + RestartSec=30: retries every 30 s.

5. Activation

systemctl --user daemon-reload
systemctl --user enable --now sshfs@MACHINE1 sshfs@MACHINE2

The mounts start when you log in. To have them start at boot, without an open session:

loginctl enable-linger $USER

6. Checking and monitoring

ls ~/_MACHINE
systemctl --user status sshfs@MACHINE
journalctl --user -u 'sshfs@*' -n 30 --no-pager

After any change to the service file:

systemctl --user daemon-reload
systemctl --user restart sshfs@MACHINE

7. Removing an instance

systemctl --user disable --now sshfs@MACHINE
systemctl --user reset-failed sshfs@MACHINE
rmdir ~/_MACHINE
Scroll to Top