Tu homelab probablemente corre Docker. Y Docker funciona bien — hasta que un container comprometido escala a root via el daemon de Docker, o un CVE como el reciente CVE-2026-31431 en Docker Engine te hace reconsiderar tu postura de seguridad. Docker corre como root, y si alguien rompe el container, el daemon es el único muro entre ese container y tu host.

Podman resuelve esto de raíz: sin daemon, sin root, con la misma CLI de Docker y compatibilidad con docker-compose.yml. En 2026, con la atención puesta en seguridad de containers, Podman ya no es una alternativa experimental — es producción-ready para homelabs.

Esta guía cubre instalación, podman-compose, Quadlets systemd, rootless networking, y cómo migrar tu homelab desde Docker sin romper nada.

Podman vs Docker — Architecture and Security

La diferencia fundamental no es lo que puedes correr, sino cómo lo corres.

Aspecto Docker Podman
Arquitectura Cliente → dockerd (daemon root) → containerd → runc Cliente → conmon → runc (sin daemon)
Modelo Client-server Fork/exec directo
Root Daemon corre como root, containers heredan Rootless nativo, cada usuario corre sus containers
Pods No nativo Sí (comparten network, IPC, UTS)
Systemd Manual con restart scripts Quadlets nativos

Docker usa un modelo client-server: cada docker run pasa por el daemon dockerd que corre como root. Si explotan el daemon —ya sea via un container malicioso o una API expuesta— tienen root en tu host.

Podman usa fork/exec: el proceso podman run crea el container directamente usando conmon y runc. No hay daemon. En modo rootless, todo corre dentro de un user namespace, así que aunque escapen del container, solo tienen los permisos del usuario no-root.

Para un homelab donde compartes acceso o expones servicios web, esta diferencia es enorme.

Installing Podman on Debian/Ubuntu

En Debian 12, Ubuntu 24.04, o derivados, la instalación es directa:

1
2
3
4
5
6
7
# Instalar Podman y podman-compose
sudo apt update
sudo apt install podman podman-compose -y

# Verificar instalación
podman --version
podman info | grep rootless

Podman viene preconfigurado para usar Docker Hub como registry por defecto. Si necesitas registries privados, edita /etc/containers/registries.conf:

1
2
3
4
5
unqualified-search-registries = ["docker.io"]

[[registry]]
prefix = "docker.io"
location = "docker.io"

Para rootless, verifica que tu usuario tenga entradas en /etc/subuid y /etc/subgid:

1
2
3
4
5
cat /etc/subuid
# gntech:100000:65536

cat /etc/subgid
# gntech:100000:65536

Estas entradas se crean automáticamente al instalar Podman. Si no existen, créalas con sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $(whoami).

Running Rootless Containers — First Steps

La CLI de Podman es idéntica a Docker en el 99% de los casos. Literalmente puedes hacer alias docker=podman y seguir trabajando.

1
2
3
4
5
6
7
8
9
# Pull y run como lo harías con Docker
podman pull docker.io/library/nginx:alpine
podman run -d --name web -p 8080:80 nginx:alpine

# Comandos familiares
podman ps
podman logs -f web
podman exec -it web sh
podman stop web && podman rm web

La diferencia más notable en rootless: los puertos privilegiados (<1024) no funcionan sin configuración extra. Para exponer en puerto 80 o 443, necesitas:

1
2
3
4
5
6
# Opción 1: Aumentar el límite de puertos privilegiados
sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80
echo "net.ipv4.ip_unprivileged_port_start=80" | sudo tee /etc/sysctl.d/99-unprivileged-ports.conf

# Opción 2: Usar un reverse proxy como Caddy/Traefik en modo rootful que redirija
# Opción 3: Usar systemd socket activation (más adelante)

Docker Compose to podman-compose — Migrating Your Stacks

Aquí es donde muchos homelabbers se preocupan. La buena noticia: podman-compose acepta el mismo docker-compose.yml que ya tienes.

1
2
3
4
5
6
7
8
9
# Instalar podman-compose (ya viene con el paquete en Debian 12)
# Si necesitas la última versión:
pip3 install podman-compose

# Usarlo exactamente como docker compose
cd /opt/stacks/nginx-proxy-manager
podman-compose up -d
podman-compose ps
podman-compose logs -f

Tu docker-compose.yml existente funciona sin cambios para la mayoría de casos:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
version: "3.8"
services:
  app:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_PASSWORD: changeme
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

Diferencias que encontré al migrar stacks reales:

  • Network mode host no funciona en rootless Podman (usar --network slirp4netns:port_handler=slirp4netns)
  • depends_on puede no respetar el orden de inicio — usar healthchecks explícitos
  • ulimits necesita ajustes en rootless (algunos valores requieren --privileged)

Podman Quadlets — systemd-Native Container Management

Los Quadlets son, para mí, la razón más convincente para migrar a Podman. En lugar de scripts de restart o restart: always en compose, defines containers como archivos .container que systemd maneja nativamente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# ~/.config/containers/systemd/nginx.container
[Unit]
Description=Nginx reverse proxy
After=network-online.target
Wants=network-online.target

[Container]
Image=docker.io/library/nginx:alpine
PublishPort=8080:80
Volume=/opt/nginx/html:/usr/share/nginx/html:Z
Environment=NGINX_HOST=homelab.local
AutoUpdate=registry

[Service]
Restart=always
RestartSec=10

[Install]
WantedBy=default.target

Para activarlo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Crear el directorio y archivo
mkdir -p ~/.config/containers/systemd

# Recargar systemd user units
systemctl --user daemon-reload

# Iniciar y habilitar
systemctl --user start nginx
systemctl --user enable nginx

# Ver logs
journalctl --user -u nginx -f

Los Quadlets soportan también Pods (nginx.pod) y volumes (nginx.volume), permitiendo definir stacks completos como archivos systemd:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# ~/.config/containers/systemd/webstack.pod
[Unit]
Description=Web application stack

[Pod]
Network=webnet

# ~/.config/containers/systemd/webapp.container
[Unit]
Description=Web application
Pod=webstack.pod

[Container]
Image=docker.io/nginx:alpine
Volume=/opt/app:/usr/share/nginx/html:Z

Systemd maneja auto-start en boot, restart on failure, y logging integrado con journald. Sin scripts externos, sin agentes, sin nada más que systemd.

Rootless Networking — How It Works

Podman rootless usa slirp4netns por defecto: un pequeño proceso userspace que hace NAT entre el namespace de red del container y la red del host. No requiere privilegios, pero tiene overhead de CPU y no soporta tráfico ICMP.

Desde Podman 5.x, pasta es una alternativa más rápida:

1
podman run -d --network pasta --name web -p 8080:80 nginx:alpine

Para redes más avanzadas (macvlan, ipvlan):

1
2
3
4
5
6
# Crear una red macvlan (rootless requiere configuración adicional)
podman network create -d macvlan \
  --subnet 10.0.20.0/24 \
  --gateway 10.0.20.1 \
  -o parent=eth0 \
  macvlan-net

En rootless, las redes macvlan no funcionan sin privilegios extra. La alternativa práctica es exponer puertos via --publish y usar un reverse proxy en un container rootful (o en el host) para enrutar tráfico.

Practical Migration Guide — Docker to Podman

Si ya tienes un homelab con Docker, la migración puede ser gradual. Nadie te obliga a migrar todo de un día para otro.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Paso 1: Alias temporal para probar
alias docker=podman

# Paso 2: Probar en un container no crítico
podman run --rm hello-world

# Paso 3: Migrar un stack docker-compose
cd /opt/stacks/mi-app-no-critica
docker-compose down
podman-compose up -d

# Paso 4: Verificar logs y conectividad
podman-compose logs
podman-compose ps

# Si todo funciona, actualizar scripts/cron para usar podman-compose

Para compatibilidad con herramientas que esperan el socket de Docker (como Portainer, Watchtower), Podman expone un socket compatible:

1
2
3
4
5
6
# Exponer socket de Docker compatible
podman system service --time=0 unix:///run/user/1000/docker.sock

# O activar el servicio systemd
systemctl --user enable podman.socket
systemctl --user start podman.socket

Luego configura tus herramientas para apuntar a unix:///run/user/1000/docker.sock via DOCKER_HOST.

Para builds de Dockerfiles, funciona igual:

1
2
3
4
5
# Build con un Dockerfile existente
podman build -t myapp:latest .

# Multi-stage builds
podman build -t myapp:latest -f Dockerfile.multistage .

BuildKit no está disponible en Podman, pero podman build usa Buildah internamente y maneja cache layer como Docker.

Limitations and Tradeoffs

Ninguna herramienta es perfecta. Estas son las limitaciones reales que encontré:

Limitación Impacto Workaround
No Docker Swarm Orquestación multi-host Usar K3s, Nomad, o Docker Compose
No BuildKit Builds multi-etapa más lentos Aceptable para homelab
Macvlan rootless complicado IPs dedicadas a containers Usar port publishing + reverse proxy
host network no disponible Containers que necesitan red del host Usar --network slirp4netns con ports
Podman desktop menos maduro No hay Docker Desktop equivalente CLI + Quadlets es suficiente
Ciertas imágenes con --privileged Algunos tools requieren capabilities root Evaluar si realmente necesitas privilegios

Para un homelab —donde no corres Swarm, no necesitas clusters Kubernetes, y valoras seguridad sobre features— estas limitaciones son aceptables.

Conclusion

Podman ha madurado lo suficiente como para reemplazar a Docker en un homelab. La arquitectura sin daemon y rootless reduce significativamente la superficie de ataque, los Quadlets integran containers con systemd de forma elegante, y la compatibilidad con docker-compose.yml hace que la migración sea incremental y de bajo riesgo.

Mi recomendación: empieza con un container no crítico. Ponle un alias alias docker=podman en tu shell. Corre un stack con podman-compose. Cuando te sientas cómodo, migra el resto. No hay prisa — pero el rootless es el futuro de los containers, y Podman ya está aquí.

1
2
3
4
5
6
7
8
9
# Resumen: migrar un container hoy
alias docker=podman
docker run -d --name test -p 8080:80 nginx:alpine
docker ps
curl http://localhost:8080
docker stop test && docker rm test

# Si funciona, migra tu primer stack productivo
podman-compose -f /opt/stacks/nginx-proxy-manager/docker-compose.yml up -d