Podman es un motor de contenedores compatible con las imágenes OCI y con la mayoría de comandos de Docker, pero con dos diferencias de diseño importantes: no tiene un demonio central y puede ejecutar contenedores con un usuario normal, sin privilegios de root. En este tutorial instalarás Podman en Ubuntu 24.04, ejecutarás contenedores rootless, los agruparás en un pod y los convertirás en servicios de systemd con Quadlet para que arranquen solos con el servidor.
Requisitos previos
Para seguir esta guía necesitas:
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath.
- Un usuario no root con privilegios
sudo. Inicia sesión con él directamente por SSH (no consunisudo -i), porque los contenedores rootless necesitan una sesión de usuario completa de systemd. - Si UFW está activo, permiso para abrir el puerto
8080/tcp.
No hace falta desinstalar Docker: ambos pueden convivir, porque Podman guarda imágenes y contenedores en sus propios directorios.
Podman frente a Docker
| Aspecto | Docker | Podman |
|---|---|---|
| Arquitectura | Demonio dockerd ejecutándose como root | Sin demonio: cada contenedor es un proceso hijo de conmon |
| Contenedores sin root | Modo rootless opcional, con configuración aparte | Funciona sin root de serie |
| CLI | docker | podman, con los mismos subcomandos y opciones más comunes |
| Pods | No | Sí, varios contenedores comparten red, como en Kubernetes |
| Arranque automático | Política --restart del demonio | Unidades de systemd generadas con Quadlet |
| Compose | Plugin docker compose | podman-compose o la API compatible con Docker |
La principal consecuencia práctica: con Docker, cualquier usuario del grupo docker es en la práctica root en el servidor. Con Podman rootless, un contenedor comprometido solo tiene los permisos de tu usuario.
Paso 1: Instalar Podman
Podman está en los repositorios oficiales de Ubuntu 24.04. Instálalo:
sudo apt update
sudo apt install podman
Comprueba la versión instalada:
podman version
Client: Podman Engine
Version: 4.9.3
API Version: 4.9.3
Go Version: go1.22.2
Built: Thu Jan 1 00:00:00 1970
OS/Arch: linux/amd64
Ubuntu 24.04 incluye Podman 4.9, que ya trae Quadlet, pods y el modo rootless completo.
Paso 2: Comprobar la configuración rootless
Podman rootless asigna a cada usuario un rango de UID y GID subordinados, que se mapean dentro del contenedor. En Ubuntu, adduser crea esos rangos automáticamente. Compruébalo:
grep "^$USER:" /etc/subuid /etc/subgid
/etc/subuid:your_user:100000:65536
/etc/subgid:your_user:100000:65536
Si no aparece ninguna línea (por ejemplo, porque el usuario se creó con useradd), asígnale un rango libre:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 your_user
Confirma que Podman funciona en modo rootless:
podman info --format '{{.Host.Security.Rootless}}'
true
Paso 3: Ejecutar el primer contenedor
La configuración de Ubuntu no define registros de búsqueda por defecto, así que usa siempre nombres de imagen completos, con el registro incluido. Es además más seguro, porque evitas descargar por error una imagen de otro registro con el mismo nombre.
Arranca Nginx publicando el puerto 8080:
podman run -d --name web -p 8080:80 docker.io/library/nginx:alpine
Los usuarios sin privilegios no pueden abrir puertos por debajo de 1024, por eso se usa el 8080 en el host. Comprueba que el contenedor está en marcha y responde:
podman ps
curl -I http://localhost:8080
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1b2c3d4e5f6 docker.io/library/nginx:alpine nginx -g daemon o... 5 seconds ago Up 5 seconds 0.0.0.0:8080->80/tcp web
HTTP/1.1 200 OK
Server: nginx/1.27.2
Fíjate en cómo se ve el proceso desde el host. Nginx se ejecuta como root dentro del contenedor, pero en el servidor es un proceso de tu usuario o de un UID subordinado:
podman top web user huser
USER HUSER
root 1000
nginx 100100
Los comandos habituales funcionan igual que en Docker: podman logs web, podman exec -it web sh, podman stop web, podman images. Elimina el contenedor antes de seguir:
podman rm -f web
Si quieres seguir escribiendo docker, el paquete podman-docker instala un comando docker que llama a Podman. No lo instales si Docker ya está en el servidor, porque ambos usan el mismo nombre de comando.
Paso 4: Agrupar contenedores en un pod
Un pod es un grupo de contenedores que comparten el espacio de red: se comunican entre sí por localhost y los puertos se publican una sola vez, en el pod. Es el mismo concepto que un pod de Kubernetes.
Crea un pod que publique el puerto 8080:
podman pod create --name webapp -p 8080:80
Añade Nginx y un Redis al pod. Los contenedores no llevan -p, porque la red es la del pod:
podman run -d --pod webapp --name webapp-nginx docker.io/library/nginx:alpine
podman run -d --pod webapp --name webapp-redis docker.io/library/redis:7-alpine
Comprueba que Nginx puede llegar a Redis por localhost:
podman exec webapp-nginx sh -c 'printf "PING\r\n" | nc -w 1 127.0.0.1 6379'
+PONG
Lista los pods y sus contenedores:
podman pod ps
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
7e8f9a0b1c2d webapp Running 30 seconds ago 3d4e5f6a7b8c 3
Son tres contenedores porque cada pod tiene un contenedor infra que mantiene los espacios de nombres compartidos.
Podman puede exportar el pod como un manifiesto de Kubernetes, útil para migrar después a un clúster o recrearlo en otro servidor:
podman kube generate webapp > webapp.yaml
Para recrearlo a partir del archivo usarías podman kube play webapp.yaml. Elimina el pod antes del siguiente paso:
podman pod rm -f webapp
Paso 5: Arrancar contenedores con systemd usando Quadlet
Como no hay demonio, Podman no puede reiniciar contenedores al arrancar el servidor por sí solo. La solución es systemd: con Quadlet describes el contenedor en un archivo .container y systemd genera y gestiona el servicio.
Primero habilita lingering para tu usuario. Sin esto, los servicios de usuario de systemd se detienen al cerrar la sesión SSH y no arrancan hasta que vuelves a entrar:
sudo loginctl enable-linger "$USER"
Crea el directorio donde Quadlet busca las definiciones de usuario:
mkdir -p ~/.config/containers/systemd
Crea la definición del contenedor:
nano ~/.config/containers/systemd/web.container
[Unit]
Description=Nginx con Podman
[Container]
Image=docker.io/library/nginx:alpine
ContainerName=web
PublishPort=8080:80
[Service]
Restart=on-failure
[Install]
WantedBy=default.target
Recarga systemd para que Quadlet genere la unidad web.service y arráncala:
systemctl --user daemon-reload
systemctl --user start web.service
No uses systemctl --user enable con unidades de Quadlet: el arranque automático lo define la sección [Install] del archivo .container. Comprueba el servicio:
systemctl --user status web.service
● web.service - Nginx con Podman
Loaded: loaded (/home/your_user/.config/containers/systemd/web.container; generated)
Active: active (running) since Thu 2026-09-25 10:40:12 UTC; 6s ago
Los logs del contenedor van al journal:
journalctl --user -u web.service -n 20
Para probar el arranque automático, reinicia el servidor con sudo reboot, vuelve a conectarte y ejecuta curl -I http://localhost:8080. Si cambias el archivo .container, repite systemctl --user daemon-reload y systemctl --user restart web.service.
Para exponer el servicio desde fuera, abre el puerto en UFW:
sudo ufw allow 8080/tcp
Paso 6: Usar archivos de Docker Compose
Si ya tienes proyectos con compose.yaml, podman-compose los ejecuta con Podman. Está en los repositorios de Ubuntu:
sudo apt install podman-compose
Desde el directorio de un proyecto, los comandos son los mismos que con Docker Compose:
podman-compose up -d
podman-compose ps
podman-compose down
Recuerda escribir las imágenes con su nombre completo (docker.io/library/postgres:16) y no publicar puertos por debajo de 1024. podman-compose cubre los casos habituales, pero no todas las opciones de Compose; para servicios en producción, Quadlet es la opción más sólida.
Solución de problemas
Error: short-name "nginx" did not resolve to an alias. No hay registros de búsqueda configurados. Usa el nombre completo de la imagen, por ejemplo docker.io/library/nginx:alpine.
rootlessport cannot expose privileged port 80. Los usuarios sin privilegios no pueden abrir puertos por debajo de 1024. Publica en un puerto alto y pon delante un proxy inverso, o baja el límite con sudo sysctl net.ipv4.ip_unprivileged_port_start=80 (y hazlo permanente en /etc/sysctl.d/) si aceptas esa implicación de seguridad.
Failed to connect to bus al usar systemctl --user. La sesión no se abrió con login real, típico al cambiar de usuario con su. Conéctate por SSH directamente con ese usuario.
El contenedor se detiene al cerrar SSH. Falta sudo loginctl enable-linger your_user.
potentially insufficient UIDs or GIDs available in user namespace. El usuario no tiene rangos en /etc/subuid y /etc/subgid. Añádelos como en el paso 2 y ejecuta podman system migrate.
Conclusión
Has instalado Podman en Ubuntu 24.04, has ejecutado contenedores sin root y sin demonio, has agrupado servicios en un pod exportable a Kubernetes y has convertido un contenedor en un servicio de systemd con Quadlet. Como siguientes pasos, puedes definir redes y volúmenes con archivos .network y .volume de Quadlet, activar actualizaciones automáticas de imágenes con AutoUpdate=registry y podman-auto-update.timer, o poner Caddy o Nginx delante para servir tus contenedores con HTTPS.
