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:
Matchalways starts a new block; - the internal address appears twice (in
HostNameand in thenctest): remember to update both if it changes; - the jump host also applies to manual
ssh,scpandrsynccommands.
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