Rootless Podman: Running a Home‑NAS Service Without Privilege Escalation

Why Rootless Containers Matter for a Home‑NAS

When a home‑NAS sits on a single‑user machine, the first instinct is to give the NAS service full root access. That works, but it also opens a door for accidental or malicious privilege escalation. Rootless Podman lets you run containerized services—Nextcloud, Syncthing, or a simple Nginx reverse proxy—inside a user namespace that isolates the container from the host. The container can still read and write to your data directories, but it can’t touch the kernel or system services.

Rootless mode also removes the need for sudo or setuid binaries, shrinking the attack surface. It’s a solid fit for a self‑hosted NAS that’s exposed to the internet but should stay confined to the user’s home directory.


Prerequisites

ItemVersionNotes
Fedora 39 (or any recent distro)39+Rootless Podman is baked in.
podman4.8+sudo dnf install podman
systemd252+For user‑service units.
firewalld0.9+Optional, but recommended.
socat1.7+For port forwarding in some setups.

Tip: If you’re on Debian/Ubuntu, install podman from the official backports or use apt install podman. On Arch, pacman -S podman.


1. Preparing the Host

1.1 Create a Dedicated User

sudo useradd -m -s /usr/bin/bash nas
sudo passwd nas

Give the user a strong password and set up SSH keys if you plan to manage the NAS remotely.

1.2 Enable User‑Namespace Support

Most modern kernels already enable user namespaces. Verify:

cat /proc/sys/kernel/unprivileged_userns_clone

If the output is 0, enable it:

sudo sysctl -w kernel.unprivileged_userns_clone=1

Add to /etc/sysctl.d/99-userns.conf for persistence.

1.3 Install and Configure Firewalld

sudo dnf install firewalld
sudo systemctl enable --now firewalld

Open the ports you’ll expose (e.g., 80, 443, 8443 for HTTPS):

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

2. Setting Up the NAS Directory Structure

Create a data directory that the container will mount:

sudo mkdir -p /srv/nas
sudo chown nas:nas /srv/nas

Inside /srv/nas, create subdirectories for each service:

mkdir -p /srv/nas/nextcloud/data
mkdir -p /srv/nas/syncthing/config
mkdir -p /srv/nas/nginx/conf

Set appropriate permissions:

chmod 750 /srv/nas/nextcloud/data
chmod 750 /srv/nas/syncthing/config
chmod 750 /srv/nas/nginx/conf

3. Running a Simple Nginx Reverse Proxy

3.1 Pull the Image

podman pull docker.io/library/nginx:latest

3.2 Create a User Service File

Create /home/nas/.config/systemd/user/nginx.service:

[Unit]
Description=Rootless Nginx
After=network.target

[Service]
ExecStart=/usr/bin/podman run --rm \
  -p 80:80 \
  -p 443:443 \
  -v /srv/nas/nginx/conf:/etc/nginx/conf.d:ro \
  -v /srv/nas/nginx/html:/usr/share/nginx/html:ro \
  docker.io/library/nginx:latest
Restart=on-failure
RestartSec=10

[Install]
WantedBy=default.target

Security note: The --rm flag ensures the container is removed on exit, preventing stale containers from lingering.

3.3 Enable and Start the Service

loginctl enable-linger nas
sudo systemctl enable --user nginx.service
sudo systemctl start --user nginx.service

Check status:

systemctl --user status nginx.service

You should see the container running and listening on ports 80/443. Verify with curl http://localhost.


4. Deploying Nextcloud

4.1 Pull the Official Image

podman pull docker.io/library/nextcloud:latest

4.2 Create a User Service File

/home/nas/.config/systemd/user/nextcloud.service:

[Unit]
Description=Rootless Nextcloud
After=network.target

[Service]
ExecStart=/usr/bin/podman run --rm \
  -p 8080:80 \
  -v /srv/nas/nextcloud/data:/var/www/html \
  -v /srv/nas/nextcloud/config:/var/www/html/config \
  docker.io/library/nextcloud:latest
Restart=on-failure
RestartSec=10

[Install]
WantedBy=default.target

4.3 Start the Service

sudo systemctl enable --user nextcloud.service
sudo systemctl start --user nextcloud.service

Open http://<NAS_IP>:8080 and complete the web installer. Use the data directory you created earlier for uploads.


5. Adding Syncthing

5.1 Pull the Image

podman pull docker.io/linuxserver/syncthing:latest

5.2 Create a User Service File

/home/nas/.config/systemd/user/syncthing.service:

[Unit]
Description=Rootless Syncthing
After=network.target

[Service]
ExecStart=/usr/bin/podman run --rm \
  -p 8384:8384 \
  -v /srv/nas/syncthing/config:/config \
  -v /srv/nas/syncthing/data:/data \
  docker.io/linuxserver/syncthing:latest
Restart=on-failure
RestartSec=10

[Install]
WantedBy=default.target

5.3 Start the Service

sudo systemctl enable --user syncthing.service
sudo systemctl start --user syncthing.service

Access the web UI at http://<NAS_IP>:8384. The configuration lives in /srv/nas/syncthing/config, so you can back it up or version‑control it.


6. Managing Storage with BTRFS Subvolumes

If your NAS uses BTRFS, you can create subvolumes for each service to isolate snapshots and quotas.

sudo btrfs subvolume create /srv/nas/nextcloud
sudo btrfs subvolume create /srv/nas/syncthing
sudo btrfs subvolume create /srv/nas/nginx

Mount them with subvol= in /etc/fstab:

/dev/sda1 /srv/nas btrfs defaults,subvol=nas 0 0

This keeps the container data separate from the rest of the filesystem, making snapshots cleaner.


7. Security Hardening Tips

AreaRecommendation
User NamespacesKeep unprivileged_userns_clone enabled only for the NAS user.
File PermissionsUse 750 on data directories; only the NAS user and root can read/write.
FirewallsLimit inbound traffic to only required ports. Use firewall-cmd --zone=public --add-port=8080/tcp for Nextcloud.
TLSRun a separate container (e.g., Caddy) as a reverse proxy with Let’s Encrypt certificates.
UpdatesAutomate podman pull and systemctl restart via cron or systemd timers.
AuditEnable auditd and monitor /var/log/audit/audit.log for unexpected execve calls.

8. Troubleshooting Common Issues

8.1 “Failed to create user namespace” Error

podman run --userns=keep-id ...

If the kernel disallows user namespaces for the user, double‑check /proc/sys/kernel/unprivileged_userns_clone. Also ensure the user’s UID is not in the range reserved for system users (0–999).

8.2 Port Conflicts

If another service occupies port 80, either change the container’s exposed port or stop the conflicting service:

sudo systemctl stop httpd

8.3 Data Loss After Container Restart

Rootless containers use the user’s home directory for storage. If the container is removed (--rm), volumes persist. However, if you mount a host directory that is not owned by the NAS user, the container may not write to it. Verify ownership:

ls -ld /srv/nas/nextcloud/data

8.4 SELinux Denials

On Fedora, SELinux may block container writes. Use chcon -R -t svirt_sandbox_file_t /srv/nas/* or set --security-opt label=disable in the ExecStart line. Prefer the former for a more secure setup.


9. Automating Updates

Create a systemd timer to pull the latest images nightly and restart services.

/home/nas/.config/systemd/user/refresh-nas.timer:

[Unit]
Description=Refresh NAS containers

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target

/home/nas/.config/systemd/user/refresh-nas.service:

[Unit]
Description=Pull latest images and restart services

[Service]
Type=oneshot
ExecStart=/usr/bin/bash -c '
  podman pull docker.io/library/nginx:latest
  podman pull docker.io/library/nextcloud:latest
  podman pull docker.io/linuxserver/syncthing:latest
  systemctl --user restart nginx.service
  systemctl --user restart nextcloud.service
  systemctl --user restart syncthing.service
'

Enable the timer:

sudo systemctl enable --user refresh-nas.timer
sudo systemctl start --user refresh-nas.timer

10. Scaling Beyond a Single Host

If you later add a second NAS or move to a cloud VM, you can use podman-compose or podman generate systemd to export the current configuration into a reproducible format. The rootless approach remains unchanged; only the host user and storage paths need adjustment.


11. Final Thoughts

Rootless Podman gives you a lightweight, secure way to run containerized services on a home‑NAS. By keeping the containers in a user namespace, you avoid the pitfalls of running as root while still enjoying the flexibility of containers. The workflow above is straightforward, relies on standard systemd user units, and can be extended with TLS, backups, or more services without changing the core security posture.

Happy self‑hosting!


See also