Mount Units, The SystemD Way to Fstab

Mount Units, The SystemD Way to Fstab

We’ve all been there: the server starts up, the excitement is high, and then bam the service finishes its boot sequence before the storage even has a chance to get ready. It’s embarrassing, it’s frustrating, and nobody wants to talk about it. But 'finishing' too early is a timing issue we can actually fix.

AI flash memory of fictional AI F.R.I.D.A.Y from the movie Avengers:Age of Ultron.

Fig. 1. Marvell Avengers: Age of Ultron F.R.I.D.A.Y AI flash storage
Source: Adapted from [1]

The Old Way

In the past I have typically relied on fstab for refreshing mount points after system restart events to handle mount reconnection. SystemD has been with us for quite a while now and yet I keep learning ways to leverage its power.

It’s time to modernize.

How It Looked With fstab

For NFS, the “classic” setup is dead simple. You add your line, run a mount -a, and hope for the best.

Fstab Edit Example

Terminal window
sudo nano /etc/fstab
/etc/fstab
192.168.1.4:/data/ /mnt/data/ nfs rw,async,noatime,nolock,vers=4.2,hard,bg,nofail,_netdev 0 0

NFS Mount Configuration Breakdown

Here’s what’s happening.

  • The Source and Destination: We identify the remote server 192.168.1.4:/data/ and map it to a local folder /mnt/data/.
  • Performance Tuning rw,async,noatime: This enables read-write access, optimizes speed via asynchronous writes, and skips updating “last accessed” timestamps to save on metadata overhead.
  • Connection Management nolock,vers=4.2: This disables file locking (often a lifesaver in home labs) and forces NFS version 4 for better firewall traversal.
  • Reliability and Boot Safety (hard,bg,nofail): If the server is offline, the system retries the connection (hard) in the background (bg). Crucially, nofail ensures your machine finishes booting even if the share is missing.
  • The _netdev Flag: This tells the system: “Don’t even try this until the network is actually up.”

So What’s Wrong With That?

Actually, nothing technically. fstab isn’t deprecated. But it lacks patience.

If you have a service that depends on that mount, it won’t wait. While nofail and bg prevent a hung boot, they don’t force a dependent service to sit and wait for the mount to actually appear. The service starts, sees an empty folder, fails, and gives up.

Ideally, developers would build robust retry logic into every app, but if you think developers go beyond “It works fine on my machine,” well… I have a bridge to sell you.

We usually “fix” this with ugly bandaids: arbitrary sleep timers, post-it notes, or manually restarting services in the correct order. In the worst case scenario, you’re calling a vendor who follows a brain dead script just to restart two services in the right order. It’s embarrassing and time consuming. I don’t want to call anyone!

We need an elegant solution that eliminates the ambiguity.

Evolution 1: The Standard SystemD Way

The first step toward modernization is moving the mount logic out of fstab and into SystemD native units. This allows us to create a formal dependency.

Step A: The Mount Unit

Instead of fstab, we create a mount unit with systemD.

Terminal window
sudo nano /etc/systemd/system/mnt-data.mount
Terminal window
[Unit]
Description=NFS Mount for Data
After=network-online.target
Wants=network-online.target
[Mount]
What=192.168.1.4:/data/
Where=/mnt/data/
Type=nfs
Options=rw,async,noatime,nolock,vers=4.2,hard,bg,nofail,_netdev,retrans=10,timeo=100,retry=5
[Install]
WantedBy=multi-user.target

Step B: The Service Override

Now we can tell our service to wait for that mount using an override.

Terminal window
sudo systemctl edit myservice.service
Terminal window
[Unit]
Requires=mnt-data.mount
After=mnt-data.mount
PartOf=mnt-data.mount

The catch, This is better, but it’s still a bit “static.” It assumes you know every service that will ever need that mount. Plus, in the world of Proxmox and LXCs, .automount units (the next logical step) often fail because they require a real kernel to handle the FUSE/autofs handshake.

Enable Services

Terminal window
sudo systemctl daemon-reload
Terminal window
sudo systemctl enable mnt-data.mount
Terminal window
sudo systemctl start mnt-data.mount

Evolution 2: The Bulletproof Retry Wrapper

This is my favorite option. It’s the most versatile because it doesn’t require the autofs kernel module (making it perfect for LXCs), but it provides the “self-healing” logic that fstab and standard mount units lack.

Terminal window
sudo nano /etc/systemd/system/mnt-data-retry.service
Terminal window
[Unit]
Description=NFS Mount Retry Wrapper
After=network-online.target
Wants=network-online.target
DefaultDependencies=no
[Service]
Type=simple
ExecStart=/bin/bash -c '\
until mountpoint -q /mnt/data; do \
echo "Attempting to mount NFS..."; \
mount -t nfs -o rw,async,noatime,nolock,vers=4.2,hard,retrans=10,timeo=100 192.168.1.4:/data /mnt/data && echo "NFS Mounted Successfully"; \
sleep 5; \
done; \
while sleep 60; do \
ls /mnt/data >/dev/null || { echo "NFS mount went stale! Exiting..."; exit 1; }; \
done'
ExecStop=/usr/bin/umount -l /mnt/data
Restart=always
RestartSec=10
StartLimitIntervalSec=0
[Install]
WantedBy=multi-user.target

Explanation

This runs a bit of a watchdog script right inside the service.

  • until mountpoint: It loops infinitely until the mount succeeds. No more boot races.
  • The Heartbeat ls /mnt/data: Every 60 seconds, it pokes the mount. If the share goes offline and the mount becomes “stale,” the script exits.
  • Restart=always: When the script exits due to a stale mount, SystemD waits 10 seconds and starts the retry loop all over again.

Connect the Service to the Wrapper

Now, we use an override on our application to bind it to our mount wrapper

Terminal window
sudo systemctl edit myservice.service
Terminal window
[Unit]
# If the retry-service stops or fails, this service stops too.
BindsTo=mnt-data-retry.service
After=mnt-data-retry.service
[Service]
# Give the filesystem a second to settle
ExecStartPre=/usr/bin/sleep 2

Enable Services

Terminal window
sudo systemctl daemon-reload
Terminal window
sudo systemctl enable mnt-data-retry.service
Terminal window
sudo systemctl start mnt-data-retry.service

Set and Forget

  • Eliminates Boot Races: Your app won’t start until the mount is confirmed.
  • Prevents Root Overflow: Your app won’t write data to the local OS drive if the share drops, because the app will be shut down instantly.
  • Automatic Reconnection: If your NFS Server reboots, the wrapper detects the failure, kills the app, and waits patiently to reconnect and restart everything once the mount is back.
  • No 90-Second Hangs: The umount -l (lazy unmount) ensures the system shuts down cleanly without waiting for a dead network connection.

If you aren’t restricted by the LXC container namespace and have access to a full kernel (Bare Metal or VMs), .automount is the new standard. It provides ondemand mounting of the share.

Step A: Create the Mount Service

The .mount unit we created in Evolution 1 above remains the foundation. Note that for automounting, you generally remove the WantedBy=multi-user.target from this file, as the automount unit will be the one responsible for pulling it in.

Terminal window
sudo /etc/systemd/system/mnt-data.mount
Terminal window
[Unit]
Description=NFS Mount for Data
[Mount]
What=192.168.1.4:/data/
Where=/mnt/data/
Type=nfs
Options=rw,async,noatime,nolock,vers=4.2,hard,retrans=3,timeo=100

Step B: Create the Automount Service

Terminal window
sudo /etc/systemd/system/mnt-data.automount
Terminal window
[Unit]
Description=Automount for NFS Data Share
ConditionPathExists=/mnt/data
[Automount]
Where=/mnt/data
# Optional: Unmounts the share if it's unused for 5 minutes
IdleTimeoutSec=300
[Install]
WantedBy=multi-user.target

Step C: Application Override

Even with the automounter, we still want our application to be aware of the mount. So we’ll create an override for that service to tell the application that it is shackled to the mount.

Terminal window
sudo systemctl edit myservice.service
Terminal window
[Unit]
# BindsTo: If the mount unit fails or stops, the service stops too
BindsTo=mnt-data.mount
After=mnt-data.mount
[Service]
# The 'poke': This forces the automounter to engage before the app starts
ExecStartPre=/usr/bin/ls /mnt/data

Enable Services

Terminal window
sudo systemctl daemon-reload
Terminal window
sudo systemctl enable mnt-data.mount
Terminal window
sudo systemctl enable mnt-data.automount

Now That’s Resilient

I hope that removes some of the confusion surrounding systemd and its more exotic functions using file names like automount. Generally we don’t want to spend a lot of time in this space. We just want to connect to our file shares and get back to the applications but it’s all interesting.

As a wise man used to tell me.

Happy Friday.

References

[1] W. D. S. M. Pictures, "Marvell Avengers: Age of Ultron F.R.I.D.A.Y AI flash storage," *Screenshot* 2015. Accessed: Dec. 18, 2025.