Rootless Podman Volumes: Keeping Your Data Safe Across Upgrades
Rootless Podman lets you run containers without ever touching sudo.
That’s great, but it also means every volume lives in your home directory.
When you bump Podman or your distro, the storage layout can change and all your data can get wiped.
Below is a practical, coffee‑talk style walk‑through that shows how to sidestep this trap.
Why Rootless Volumes Are Different
When you run
podman run --volume /data:/data …
Podman creates a directory under
~/.local/share/containers/storage/volumes/<volume-name>/_data
It’s owned by you, so no root is needed.
The problem? That whole tree lives in your home.
A major upgrade can rewrite the storage format and delete the old tree or move it elsewhere.
The Upgrade Problem in Practice
Say you have a database container:
podman run -d --name mydb \
-v db-data:/var/lib/mysql \
mysql:8
A few months later you upgrade Podman from 4.3 to 5.0.
The new binary rewrites the storage layout and removes ~/.local/share/containers/storage/volumes/db-data.
Your database data is gone.
The real trick is to keep the data outside the default storage tree so upgrades leave it untouched.
Step 1 – Create a Dedicated Volume Directory
Pick a spot outside the default path. A common choice is a subfolder of your home:
mkdir -p ~/podman-volumes
chmod 700 ~/podman-volumes
700 keeps the directory private—a quick security win.
Step 2 – Use --mount Instead of -v
-v is convenient but always creates a volume in the default tree.
--mount lets you point to any host path:
podman run -d --name mydb \
--mount type=bind,source=$HOME/podman-volumes/db-data,target=/var/lib/mysql \
mysql:8
Now the MySQL data lives in ~/podman-volumes/db-data, safe from Podman’s internal rewrites.
Step 3 – Persist the Mount Across Upgrades
Because the mount is defined by a host path, it survives upgrades.
Just make sure the directory exists before you start the container.
A tiny wrapper script does the trick:
#!/usr/bin/env bash
VOL=$HOME/podman-volumes/db-data
mkdir -p "$VOL"
podman run -d --name mydb \
--mount type=bind,source="$VOL",target=/var/lib/mysql \
mysql:8
Make it executable and use it instead of the raw podman run.
Step 4 – Back Up the Volume
Even with a stable location, backups are a must.
The simplest way is tar:
tar czf ~/backups/db-data-$(date +%F).tar.gz -C $HOME/podman-volumes db-data
Restore with:
tar xzf ~/backups/db-data-2026-11-01.tar.gz -C $HOME/podman-volumes
If your database has hot‑backup tools, use those instead.
Trade‑offs and Caveats
| Approach | Pros | Cons |
|---|---|---|
Default rootless volume (-v) |
Quick, no extra config | Vulnerable to storage rewrites on upgrade |
Bind mount (--mount type=bind) |
Data stays where you want it | Requires manual path management |
External storage driver (e.g., overlay2 on a separate partition) |
Isolated from home directory | More complex, needs root |
podman volume create --opt type=tmpfs |
Fast, no disk usage | Data lost on reboot, not persistent |
For most homelab users, the bind‑mount method is the sweet spot: it keeps data safe, stays rootless, and is easy to script.
Security Note
Binding a host directory into a container gives the container full access to that directory.
If you’re pulling untrusted images, consider:
- Adding
:ro(read‑only) to the mount. - Running the container as a dedicated user.
podman run -d --name mydb \
--mount type=bind,source="$VOL",target=/var/lib/mysql,readonly \
--user 1000:1000 \
mysql:8
Common Pitfalls
| Symptom | Likely Cause | Fix |
|---|---|---|
| Container fails to start with “permission denied” | Host directory permissions too open | chmod 700 on the host dir |
| Data disappears after upgrade | Using -v instead of bind mount |
Switch to --mount |
| Container cannot write to volume | Volume mounted read‑only | Remove :ro or use writable bind |
| Podman complains “storage driver not supported” | Upgraded to a driver that requires root | Use overlay2 on a separate partition or keep using vfs |
Automating with systemd‑User Units
If you like systemd, a systemd‑user unit keeps the container configuration in one place and restarts it automatically.
# /etc/systemd/user/mydb.service
[Unit]
Description=MyDB Container
After=podman.service
[Service]
ExecStart=/usr/bin/podman run --rm --name mydb \
--mount type=bind,source=$HOME/podman-volumes/db-data,target=/var/lib/mysql \
mysql:8
ExecStop=/usr/bin/podman stop -t 10 mydb
Restart=on-failure
[Install]
WantedBy=default.target
Enable it with:
systemctl --user enable --now mydb.service
When to Use a Dedicated Storage Driver
If you’re running a production‑grade database that needs high performance, you might move the storage driver to a separate partition. That requires root and a bit more setup:
sudo mkdir -p /var/lib/podman
sudo chown $USER:$USER /var/lib/podman
sudo podman system reset
Edit /etc/containers/storage.conf to set graphroot to /var/lib/podman.
This isolates Podman’s storage from your home directory entirely, but it breaks the pure rootless model. Weigh the trade‑offs.
Quick Reference Commands
# Create a dedicated volume dir
mkdir -p ~/podman-volumes && chmod 700 ~/podman-volumes
# Run a container with a bind mount
podman run -d --name mydb \
--mount type=bind,source=$HOME/podman-volumes/db-data,target=/var/lib/mysql \
mysql:8
# Backup the volume
tar czf ~/backups/db-data-$(date +%F).tar.gz -C $HOME/podman-volumes db-data
# Restore the volume
tar xzf ~/backups/db-data-2026-11-01.tar.gz -C $HOME/podman-volumes
Rootless Podman is a great way to keep containers safe and lightweight, but it does bring a subtle upgrade risk for volumes.
By moving your data to a dedicated bind mount, scripting the setup, and backing up regularly, you can keep your data intact no matter how many times you upgrade Podman or your distro. For most homelab users, this approach strikes the right balance of simplicity, security, and reliability.
See also
- Fixing ProxyJump timeouts when a VPN drops your IP address.
- How to Keep a Linux Laptop Connected to a VPN When the Router Switches Between DHCP and Static IPs
- Testing Restic Incremental Backups on an Active MySQL Server Without Downtime
- Fixing the 2‑second DNS lookup lag on my Pi by tweaking resolvectl and systemd‑resolved cache
- Diagnosing a 30‑second Nginx start‑up lag on an 8‑core ARM home‑server