Every developer has their own way of blowing off steam. Some people play video games, some hit the gym, and some, when hit with a wave of work frustration, decide it is the perfect time to question their entire self-hosted server architecture.
Lately, that therapeutic rabbit hole for me has been Podman.
If you have been around containerization, Docker is the household name. It is mainstream, battle-tested, and what most of us grew up using. But Podman has been steadily gaining ground with promises of better security, rootless containers, and a daemonless architecture.
Switching from Docker to Podman on a live server is not a trivial weekend tweak. It requires rethinking networking, permissions, and service management. But when you are looking for a productive distraction, it is an irresistible engineering challenge.
The Current State: My Docker-Powered Server
Right now, my single-server setup runs entirely on Docker and Docker Compose. It quietly carries the weight of multiple live web applications, client websites, and internal utilities:
- humfurie.org (My personal corner of the web and tech blog)
- pulpulitiko.com (A public policy and political data tracking platform)
- doc-agnes.com (Client production application)
- clofelcreates.com (Creative portfolio and client platform)
- AdGuard Home & background services (DNS filtering, background queue workers, automated webhooks)
Everything is orchestrated through Compose files and reverse-proxied behind Traefik. It works, but it has one glaring vulnerability: the Docker daemon is a single point of failure.
If the Docker daemon crashes or gets misconfigured, every single application goes down with it instantly. I have lived through that nightmare before. A minor misconfiguration brought the entire engine down, and I spent hours in panic mode debugging and bringing everything back online.
That experience alone makes the idea of a daemonless setup look very appealing.
The Big Cloud Dream vs. Budget Realities
While reading up on Podman, one of the biggest features that caught my eye is its native support for Kubernetes YAML specs.
Naturally, this got my imagination running.
Imagine a world where I received a proper salary increase to match my engineering workload, giving me the budget to casually spin up a multi-node cloud Kubernetes cluster. I could run two of my heavier services across distributed nodes, stick Cloudflare Load Balancing in front, connect the databases to Cloudflare Hyperdrive for edge connection pooling, and watch my 99 Google PageSpeed Insights score jump to a flawless 100 in an instant.
Unfortunately, cloud enterprise budgets do not grow on trees, and our current compensation definitely cannot sponsor multi-node Kubernetes clusters just yet.
So, for now, high-efficiency bare-metal self-hosting is the game. And that brings us back to Podman.
Technical Hurdle 1: Traefik and Rootless Port 80/443
Podman's main selling point is that it runs rootless by default without a central root daemon.
While this is great for security, it immediately introduces a classic Linux networking problem: unprivileged ports.
In standard Linux, non-root users cannot bind to ports below 1024. But Traefik needs to listen on Port 80 (HTTP) and Port 443 (HTTPS) to route incoming traffic to all my hosted sites.
If you run Traefik rootless out of the box, it will throw permission errors when attempting to bind to those ports.
To be completely honest, I am not deeply familiar with low-level kernel tweaks like sysctl, adjusting net.ipv4.ip_unprivileged_port_start, or granting specific Linux permissions like CAP_NET_BIND_SERVICE. Messing with those without fully understanding the underlying mechanics makes me hesitant. Permission errors on live production ports are the last thing you want to debug in the dark, and that is one of the main reasons I am proceeding cautiously.
Technical Hurdle 2: Discovering Quadlet and systemd
In the Docker ecosystem, docker compose is the standard. When looking for an equivalent in Podman, many people mention podman-compose, but it is a community-driven tool rather than an official part of the core project.
Then, I recently learned about Quadlet.
What makes Quadlet so fascinating is how it connects directly to Linux's native systemd. Instead of needing a heavy container daemon sitting in the middle, Quadlet reads your container declarations and generates actual systemd service units.
This means:
- Each container essentially runs like a native Linux application or service.
- If one container fails, it does not threaten a centralized daemon.
- The operating system itself manages startup dependencies, automated restarts on failure, and orderly reboots using standard
systemctlcommands.
It turns your containers into first-class citizens on the host OS.
Wrapping Up: All This DevOps for Nothing?
Migrating a dozen production services from Docker to rootless Podman with Quadlet and Traefik sounds like a steep mountain to climb. Between rootless port permissions and converting everything to Quadlet units, there are bound to be hurdles.
Sometimes I stop and ask myself: Is all of this deep-dive DevOps skill for nothing? When your day job underprices your technical capabilities, it is easy to feel like your effort is wasted.
Still, building resilient infrastructure on your own terms is rewarding. Even if work doesn't always recognize your technical range, the skills, architectural depth, and problem-solving you build belong entirely to you.
Over to You
If you have experience with Podman, Quadlet, or rootless Traefik:
- Have you migrated your live services from Docker to Podman and Quadlet?
- How did you handle Traefik's port 80/443 bindings without breaking rootless security?
- Any tips for someone testing Quadlet for the first time?
Let's discuss in the comments!