Systemd Mount Configuration#
Bluefin is built on bootc with an ostree/composefs backend, which makes the root filesystem read-only by default. Persistent state lives in /etc (mutable, 3-way merged on upgrades) and /var (persists across deployments). For secondary drives and extra mount points, two mechanisms are available: entries in /etc/fstab (which systemd auto-converts to native mount units at boot) or hand-authored .mount unit files.
Critical constraint: When composefs is enabled (the Bluefin default), you cannot use
/etc/fstabor a.mountunit to remount/. Use therootflags=kernel argument instead.
How systemd Processes Mounts#
systemd-fstab-generator(8) runs early at boot — before unit files are loaded — and translates each /etc/fstab entry into a transient .mount (or .swap) unit . Native .mount unit files in /etc/systemd/system/ or /usr/lib/systemd/system/ take precedence over fstab-generated ones .
Naming Convention#
Unit filenames mirror the mount point path with slashes replaced by dashes and the .mount suffix appended. Example: /var/data → var-data.mount. Escaping follows systemd.unit(5) rules .
fstab Field → Mount Unit Mapping#
| fstab field | Unit option | Purpose |
|---|---|---|
fs_spec | What= | Device, UUID, or label |
fs_file | Where= | Absolute mount point path |
fs_vfstype | Type= | Filesystem type (xfs, ext4, btrfs…) |
fs_mntops | Options= | Comma-separated mount options |
Useful x-systemd.* fstab Options#
| Option | Effect |
|---|---|
x-systemd.automount | Create a companion automount unit (on-demand mount) |
x-systemd.device-timeout= | How long to wait for the device to appear |
x-systemd.mount-timeout= | How long to wait for the mount command |
x-systemd.makefs | Format the device if it carries no filesystem signature |
x-systemd.growfs | Grow the filesystem to fill its partition |
x-systemd.requires= | Add Requires=/After= dependency on another unit |
nofail | Boot continues even if mount fails (Wants= only, no ordering) |
noauto | Do not add as dependency of local-fs.target (manual mount) |
_netdev | Treat as network mount; order after network-online.target |
Persistent Drive Configuration on Bluefin#
Because /etc persists and is 3-way-merged on upgrades , /etc/fstab and /etc/systemd/system/*.mount are valid locations for persistent non-root mount configuration. /var is shared across all deployments, making it the natural base for data directories (e.g. /var/data).
Recommended Approaches (Preference Order)#
| Approach | When to use | How |
|---|---|---|
/etc/systemd/system/<name>.mount | Most cases — tooling-friendly, declarative | Write unit file, systemctl enable, systemctl start |
/etc/fstab | Simple, human-managed mounts | Add entry; auto-converted at boot |
systemd.mount-extra= kernel arg | Install-time injection or immutable config | bootc install ... --karg "systemd.mount-extra=UUID=:/data:xfs:defaults" |
Injecting Mounts Before First Boot#
When provisioning via bootc install to-existing-root, find the new deployment directory and write the unit there before rebooting :
DEPLOY_PATH=$(ostree admin --sysroot=/target --print-current-dir)
cat > "${DEPLOY_PATH}/etc/systemd/system/var-data.mount" <<EOF
[Unit]
Description=Data drive
[Mount]
What=/dev/disk/by-uuid/<UUID>
Where=/var/data
Type=xfs
Options=defaults
[Install]
WantedBy=local-fs.target
EOF
systemctl --root="${DEPLOY_PATH}" enable var-data.mount
Alternatively, inject via kernel argument at install time — no file editing required :
bootc install to-existing-root \
--karg "systemd.mount-extra=UUID=<uuid>:/var/data:xfs:defaults"
The
systemd.mount-extrasyntax issource:path:type:options.
Native .mount Unit File Format#
Mount units must live at a path matching the escaped mount point . Place persistent user-managed units in /etc/systemd/system/; image-baked units go in /usr/lib/systemd/system/.
# /etc/systemd/system/var-data.mount
[Unit]
Description=External data drive
[Mount]
What=/dev/disk/by-uuid/xxxx-yyyy
Where=/var/data
Type=xfs
Options=defaults,noatime
TimeoutSec=30
[Install]
WantedBy=local-fs.target
Key [Mount] Options#
| Option | Required | Notes |
|---|---|---|
What= | Yes | Device node, UUID=, or label |
Where= | Yes | Absolute path; must match unit filename |
Type= | No | Filesystem type |
Options= | No | Comma-separated mount options |
TimeoutSec= | No | Default from DefaultTimeoutStartSec= in system.conf |
DirectoryMode= | No | Mode for auto-created mount point dir (default 0755) |
SloppyOptions= | No | Ignore unknown mount options (yes/no) |
LazyUnmount= | No | Detach filesystem even if busy |
Enable and start with:
systemctl enable --now var-data.mount
Constraints and Reference#
| Constraint | Detail |
|---|---|
No / in fstab/mount units | composefs handles root; use rootflags= karg instead |
/var content from image is copy-on-first-deploy | Like Docker VOLUME; changes to /var in subsequent image updates are NOT applied |
/etc/fstab for root is legacy | bootc direction is to migrate away from fstab root entries toward kernel arguments |
| SELinux labels on new toplevel dirs | Custom mount points may get default_t; may need SELinux file context entries |
| Unit file precedence | /etc/systemd/system/ overrides /usr/lib/systemd/system/; both override fstab-generated units |
Reference Links#
systemd.mount(5)man page — full unit option referencesystemd-fstab-generator(8)man page — fstab-to-unit conversion details- bootc Filesystem docs —
/etc,/var, composefs overview - bootc Install docs — injection before first boot,
systemd.mount-extra - systemd Building Images —
x-systemd.makefs,x-systemd.growfs, first-boot patterns