Running containers without root is a lifesaver, but I hit a snag the other night. I had a small database container that wrote data to a named volume, and the next time I rebooted my machine the data was gone. Turns out the volume directory was being created under a transient mount that didn’t survive shutdown.
Why the Volume Vanishes
In rootless mode Podman keeps everything under ~/.local/share/containers/storage. When you do podman volume create, it records the mount point in a JSON file there. On reboot the user‑session systemd instance that owns the rootless runtime comes back up, but systemd doesn’t automatically remount the user‑created volumes unless you tell it to. The result? The container starts, and the volume looks like a fresh empty directory.
The Quick Fix: A Systemd User Unit
The cleanest way to make the volume stick is to let systemd mount it before the container starts. Podman can generate a unit for you, and you just add an ExecStartPre that mounts the volume. Here’s how I did it:
# 1. Create the volume (if you haven’t already)
podman volume create --name dbdata
# 2. Generate a systemd unit for the container
podman generate systemd --name mydb --files
# This creates mydb.service in the current directory
# 3. Edit the unit to mount the volume before the container runs
sed -i '/^ExecStart=/i ExecStartPre=/usr/bin/mount -t tmpfs -o rw,mode=1777 tmpfs $HOME/.local/share/containers/storage/volumes/dbdata/_data' mydb.service
# 4. Move the unit to the user systemd directory
mkdir -p ~/.config/systemd/user
mv mydb.service ~/.config/systemd/user/
# 5. Reload systemd, enable, and start
systemctl --user daemon-reload
systemctl --user enable --now mydb.service
That ExecStartPre line mounts a tmpfs into the volume’s data directory, guaranteeing the mount point exists every boot. If you want a persistent disk instead of RAM, swap the tmpfs line for a bind mount to a directory under /home/<user>/data:
ExecStartPre=/usr/bin/mount --bind /home/<user>/data/dbdata $HOME/.local/share/containers/storage/volumes/dbdata/_data
Security Considerations
Because the container runs as your UID/GID, the volume mount is owned by you, so no privilege escalation here. Still, if you bind‑mount a directory that holds sensitive data, double‑check the permissions (chmod 700). Adding --userns=keep-id to the podman run command—or to the unit file—keeps the UID mapping consistent across reboots.
Quick Checklist
| Step | Command | Note |
|---|---|---|
| Create volume | podman volume create dbdata |
Persist data across containers |
| Generate unit | podman generate systemd --name mydb --files |
Produces a systemd service |
| Mount pre‑start | ExecStartPre=... |
Guarantees volume mount |
| Enable unit | systemctl --user enable --now mydb.service |
Auto‑start on login |
With this setup the volume survives reboots, and the container boots up cleanly every time. If you’re using a different storage backend (e.g., Btrfs subvolumes), just tweak the mount options accordingly.
Happy homelabbing!
See also
- A single cron job ate all my RAM and crashed my server: how I added zram and tweaked ulimit
- systemd‑resolved’s DNS Cache Stale After a Router Update: My One‑Command Fix
- Finding the 10 Most Frequent Error Lines in a 5 GB Syslog with awk in a Few Seconds
- How I Use Find and Xargs to Delete Temp Files Older Than 7 Days Without Risking rm ‑rf
- Fixing ACME DNS‑01 on a Home Lab Using Pi‑hole and Cloudflare