Auto-mounting network file systems with systemd
If you're new to systemd you're probably thinking that the title sounds like the sort of thing that should be easy, and you're right! If you're used to systemd, you'll already know that it's probably not easy, and you're also right!
On the surface, you should be able to just add your entries to /etc/fstab
as you've been doing up until now and if that's working for you: stick to it!
If, however, you either a) are having problems with mounts being attempted before your network is up (common with WiFi systems) or b) want to do everything the full systemd way, then read on!
The Mount File
Systemd includes a helpful mount
unit type, handled as a .mount
unit file (just like .service
etc). As of the time of writing, this file actually just gets 'executed' through the usual mount
command anyway, but let's have a look at what a mount file looks like.
Check out James Oguya's excellent post on this topic for the full details.
[Unit]
Description = Mount NFS Share
[Mount]
What=172.24.0.5:/srv/backups
Where=/mnt/backups
Type=nfs
Options=defaults
# Uncomment the below if your server is real slow
# TimeoutSec=10
[Install]
WantedBy=multi-user.target
and that's it! Sort of.
Put this file in /etc/systemd/system
like your other system units, but be warned: the file must be named exactly for its target mount point. In the example above, the file would be /etc/systemd/system/mnt-backups.mount
.
Don't ask me why, I don't know either.
Then run systemctl daemon-reload
and systemctl start mnt-backups.mount
to mount your filesystem. Now to mount at boot, you would think you can just systemctl enable ...
but unfortunately it's not that simple.
Putting a boot in it
Now if you just run systemctl enable ...
with your unit as it stands, it will almost certainly fail since systemd won't know to wait for the network before it actually runs the mount.
You can control this using the After=
option in the [Unit]
section:
[Unit]
Description = Mount Server Private Directory
After=## this bit here ##
[Mount]
...
Now your first thought will be to use the "special" remote-fs.target
here and this might work in simple setups. If your system is using Network Manager however, the accepted wisdom seems to be to use After=NetworkManager-wait-online.service
as your dependency. This will usually work for wired connections, so try this first.
There's a bit of a caveat here though:
NetworkManager doesn't actually wait
If you check the /usr/lib/systemd/system/NetworkManager-wait-online.service
file yourself, you'll notice the service is just using nm-online
to wait for the network. However, if you check the arguments being used, you'll see that using the -s
flag here only waits for NetworkManager itself to be ready, not the actual connection to be connected and ready. While you can simply remove the -s
flag here (see notes below), I find it better to create a new service.
Creating a service that actually waits
In my case, I created the following file at /etc/systemd/system/network-online.service
:
[Unit]
Description=Wait until NM actually online
Requires=NetworkManager-wait-online.service
After=NetworkManager-wait-online.service
[Service]
Type=oneshot
ExecStart=/usr/bin/nm-online -q --timeout=120
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
This will run after the existing NetworkManager-wait-online.service
but will only successfully start (and stay active) once Network Manager has actually connected to the network.
Run systemctl daemon-reload
and systemctl enable --now network-online.service
to confirm your service is working and enable the check to run at boot
Adding this to your mount
Now you have this service, you can slightly tweak your existing .mount
file with the following lines in the [Unit]
section:
Requires=network-online.service
After=network-online.service
Now your mount won't be run until NetworkManager reports your network as actually connected.
Putting it together
You can actually use this new network-online.service
as a After=
criteria on any other services you have that should wait until the network is actually connected, instead of just having the stack up.
Notes
What about if I'm not using NetworkManager?
Fair point actually. The overall principles at work remain the same: create a service with a command that will only return a success code when the network is available and have your mounts depend on that. You'll just have to find the right system service to use as an After=
substitute for NetworkManager-wait-online.service
and find a command you can use to replace nm-online
.
What about removing the -s
flag in the builtin unit?
So this is a valid approach with two important caveats:
- You might break existing stuff. In my non-rigorous testing, boot behaviour actually got worse when I made this change and there were a few services that seemed to have trouble starting/waiting for the modified service.
- DO NOT modify the builtin service file. If you're on a vaguely recent release, you should be able to create a
/etc/systemd/system/NetworkManager-wait-online.service.d/
directory and put.conf
files in there to override the built-in one. Check the docs or the better unofficial docs
Can't you do this in /etc/fstab
?
Yes and no, in my experience. Yes, /etc/fstab
is both the easiest and most Linux-y way of doing mounts, but it's also unintuitive, error-prone and doesn't integrate well with things like NetworkManager/netctl/whatever. Personally, I'd prefer to whip up an easy .mount
file then try and decipher whatever x-systemd.automount
means, and which column of this plaintext file it should be in.
Why not use automount
?
This is the big one: the answer to the vast majority of problems with NetworkManager/systemd/etc and mount delay is to use "automounts" which are essentially lazy filesystem mounts, that are auto-mounted the first time they're accessed. For the most part, these do solve a few of the problems from above. That being said, if you want your boot to actually wait for the filesystem rather than leave it until first access, you will need to use this method instead.