Reliable Network Shares

Introduction

I run a homelab that consists of (at least) a Plex media server and a NAS to store the media for that server. In the past, I’ve had power outages that have put the server out of service due to a failing network mount. Either the Plex’s host comes up too fast and the NAS hasn’t finished booting or the NAS is not yet connected to the network by the time the Plex host tries to mount the network share.

In the past I had tried to write scripts that would start on boot and delay by a certain amount of time. After hours of troubleshooting, I would find something that seemingly worked, the shares mounting correctly during my testing. Only when the next power outage would occur, Plex still wouldn’t be functional after my electricity came back on.

So I set out to find a more resilient, robust, and reliable solution. Below I will share an explanation and a rough guide on using the solution that many before me probably knew about, but I had yet to discover.

Automount

Now, I know you systemd nerds already know what I’m talking about, but for the uninitiated, systemd has an Automount unit configuration that, in tandem with a Mount unit configuration, allow for automatically mounting a filesystem (networked or otherwise) in an on-demand fashion.

This means that the mounting of the specified filesystem only occurs when the mount point is accessed. This is useful to us as our Plex server should only be trying to access the mount point I care about after the server has finished booting. It also builds in some resiliency should the NAS not be ready yet, even at that point, as the mount service itself will automatically retry mounting the filesystem in that situation.

Mount & Automount

Below I will include the raw text you should put in the mount and automount files, as well as an explanation of the parameters:

# mnt-filesystem.mount
[Unit]
Description=Mount File System
After=network-online.target
Wants=network-online.target

[Mount]
What=//SERVER_IP_OR_HOSTNAME/sharename
Where=/mnt/filesystem
Type=cifs
Options=username=your_username,password=your_password,iocharset=utf8,rw
TimeoutSec=30

[Install]
WantedBy=multi-user.target

In my use-case, I’m mounting a share, so in that mount file, it makes sense to request that the unit only run after the network is online. Otherwise, it would surely fail without any network connection.

Under the [Mount] section of the mount file, I specify the server IP/hostname and share name as the path with the What parameter. I also specify that this filesystem should be mounted at /mnt/filesystem. I’m using an SMB share so I specify the filesystem type of cifs (nickname for our particular implementation of the SMB protocol meaning Common Internet File System). There are also a specific set of options I’m using which aren’t listed here; it would not be appropriate to cover the topic of mounting options here.

Lastly, I specify a timeout with TimeoutSec of 30 seconds. It’s not strictly necessary as there are defaults in place, but I would prefer specifying this so I know myself how long it is normal to be waiting.

There’s one part of making this files that I should mention. The name of the mount unit file should correspond to the path of the mount point (or the Where parameter value), except replace all but the starting slash with dashes (ex: /mnt/filesystem becomes mnt-filesystem.mount).

The WantedBy parameter tells systemd which boot target should trigger this unit to run should the given boot target to be read (again, not appropriate to delve into detail about this topic here).

#mnt-filesystem.automount
[Unit]
Description=Automount File System

[Automount]
Where=/mnt/filesystem
TimeoutIdleSec=30

[Install]
WantedBy=multi-user.target

Above is the automount file. This will be tied to the similarly named mount file, and without the mount file, this automount file will do nothing when enabled. This file tells systemd, “Hey, you see that mount point? Well if another unit wants to mount that, delay it until something tries to access the mount point.” It takes most of the same parameters as the mount file, but doesn’t need almost any.

The most important is the Where. That should be set to the same value as the Where parameter in the mount file. This automount file also has the same requirement to be named similarly to the Where path, replacing slashes with dashes, omitting the first slash in the path entirely.

Both of these files should be placed in /etc/systemd/system/.

Enabling the unit

Now that we’ve crafted our unit files, we should enable them! Actually, you only need to enable the mount unit. systemd takes care of the rest! Obviously in the next few snippets, you’ll be replacing values with your own, but to enable the unit run:

sudo systemctl enable mnt-filesystem.mount

After entering your sudo password, you should get a message about the unit being symlinked. To test it out before closing things off, you should also start the unit:

sudo systemctl start mnt-filesystem.mount

Then touch a file in the mount point:

sudo touch /mnt/filesystem/foo.txt

Then check if the filesystem was mounted:

mount | grep filesystem

If all is well, you should get a line back from the terminal featuring your successful mount. If you get nothing in return, see sudo systemctl status mnt-filesystem.mount for more information on what could have gone wrong.

If you make any further modifications to the mount or automount files, be sure to run sudo systemctl daemon-reload to keep systemd in the loop with your changes, re-reading them and updating its understanding of them.

Further Reading

systemd.mount man page systemd.automount man page