Podman senza root su Linux: container che partono al boot
Questa guida porta un container dall’installazione del pacchetto fino all’avvio automatico con il sistema, senza mai usare sudo se non per installare Podman. Si parte dai repository di Ubuntu, Debian o Fedora. Poi si lancia un server web con un utente normale, si pubblica una porta e si collega una cartella della home. Alla fine il container diventa un servizio systemd per utente, descritto con Quadlet, che parte all’accensione anche se nessuno ha fatto login. Strada facendo si incontrano le tre trappole tipiche del rootless: subuid e subgid, porte sotto la 1024 ed etichette SELinux sui volumi.
La documentazione di Podman lo descrive come uno strumento senza demone che si appoggia a un runtime OCI come crun o runc. I suoi container possono girare come root oppure come utente non privilegiato. La CLI è tanto vicina a quella di Docker che, sempre secondo la documentazione, la maggior parte degli utenti può usare alias docker=podman senza problemi. Il repository ufficiale aggiunge altre due cose: l’assenza del demone serve alla sicurezza e a consumare meno risorse a riposo, e un container rootless non ha mai più privilegi dell’utente che l’ha lanciato. Il codice è rilasciato con licenza Apache-2.0. Podman funziona anche su Windows e macOS, tramite una macchina virtuale gestita con podman machine o con Podman Desktop, ma questa guida resta su Linux.
Cosa serve
- Una distribuzione che abbia il pacchetto
podmannei repository ufficiali. Le istruzioni di installazione lo indicano su Ubuntu dalla 20.10, su Debian dalla 11 (Bullseye) e su Fedora. Qui si considerano Ubuntu 24.04 o successive, Debian 12 e 13 e la Fedora corrente. Per la parte su Quadlet vale l’avviso all’inizio della relativa sezione. - Un account utente normale con accesso a
sudo, che serve solo per installare il pacchetto. - Un intervallo di UID e GID subordinati assegnato all’utente in
/etc/subuide/etc/subgid, come spiega la pagina di troubleshooting. - Per Quadlet, un sistema con cgroup v2: è un requisito esplicito del riferimento di Quadlet.
Per Ubuntu 20.04, il cui supporto standard è terminato nel maggio 2025 e la cui manutenzione estesa è disponibile tramite Ubuntu Pro fino al 2030, qui non ci sono istruzioni. Raspberry Pi OS a 64 bit, indicato come beta sul sito di Podman, segue la procedura di Debian. Linux Mint segue quella di Ubuntu, oppure quella di Debian se si usa LMDE.
Installare Podman dai repository della distribuzione
Il pacchetto della distribuzione si aggiorna insieme al resto del sistema. Va però tenuto presente il ritmo del progetto: pubblica release maggiori o minori quattro volte l’anno, nella seconda settimana di febbraio, maggio, agosto e novembre. Il supporto upstream riguarda normalmente l’ultima release, con eccezioni LTS: il ramo Podman 5.8 riceve correzioni critiche e di sicurezza fino al 7 giugno 2027. Un ramo stabile può quindi contenere una versione parecchio più vecchia di quella attuale.
Su Ubuntu e Debian si aggiorna prima l’indice dei pacchetti, poi si installa:
sudo apt-get update
sudo apt-get -y install podman
Su Fedora basta un comando:
sudo dnf -y install podman
Su Fedora, nelle installazioni nuove la rete rootless predefinita non è più slirp4netns ma passt. Chi ha container configurati per slirp4netns deve quindi verificare che quel pacchetto resti installato. Per controllare l’installazione:
podman info
Il comando deve stampare un riepilogo con host, storage e registri, senza messaggi di errore.
Controllare subuid e subgid dell’utente
Senza root, Podman si appoggia agli user namespace. Il root del container corrisponde all’utente che lo lancia, mentre le altre identità presenti nel container vengono prese da un intervallo di UID subordinati assegnato a quell’utente. Se l’intervallo manca, i container che usano più utenti al loro interno falliscono, quindi conviene controllarlo subito:
cat /etc/subuid
Ogni riga ha il formato NOMEUTENTE:UID:INTERVALLO. Questo è l’esempio della documentazione, in cui l’utente johndoe riceve gli UID da 100000 a 165535:
johndoe:100000:65536
test:165536:65536
Nel file deve esserci una riga con il proprio nome utente, e una riga equivalente deve trovarsi in /etc/subgid, che ha lo stesso formato. Gli intervalli di utenti diversi non devono sovrapporsi, perché altrimenti un utente potrebbe attaccarne un altro. Devono anche coprire gli UID usati nel container: se dentro il container c’è un utente con UID 10000, servono almeno 10000 subuid. Se la riga manca, l’amministratore può assegnarla con usermod e le opzioni --add-subuids e --add-subgids.
Dopo ogni modifica a quei due file bisogna fermare tutti i container in esecuzione e terminare il processo di pausa di Podman, ed è quello che fa il comando qui sotto. Attenzione: ferma tutti i container dell’utente che stanno girando. Prima di lanciarlo bisogna quindi controllare che nessuno di questi stia servendo qualcosa di importante.
podman system migrate
Avviare il primo container come utente normale e pubblicare una porta
Il tutorial ufficiale usa un server nginx chiamato basic_httpd, che serve solo la pagina iniziale. Il comando si lancia senza sudo. L’opzione -d manda il container in background e -p 8080:80/tcp inoltra la porta 8080 dell’host alla porta 80 del container:
podman run --name basic_httpd -d -p 8080:80/tcp docker.io/nginx
Il nome dell’immagine include il registro, docker.io. C’è un motivo: il registries.conf di esempio nella documentazione avverte che con i nomi brevi si rischia di scaricare un’immagine con lo stesso nome pubblicata da qualcun altro su un registro diverso. Dato che il container gira staccato dal terminale, Podman stampa il suo ID. Per vedere i container attivi:
podman ps
In modalità rootless il container spesso non riceve un indirizzo IP, perciò la prova si fa sulla porta pubblicata:
curl http://localhost:8080
Se restituisce l’HTML della pagina iniziale di nginx, il container funziona e la porta è raggiungibile.
Porte sotto la 1024: perché usare porte alte
L’esempio usa la porta 8080 e non la 80. Senza root la differenza conta, perché un container rootless ha soltanto i privilegi dell’utente che lo lancia. La prima porta che un utente senza privilegi può aprire si legge così:
cat /proc/sys/net/ipv4/ip_unprivileged_port_start
Se il valore è 1024, la 80 e la 443 non sono disponibili. Il valore corrisponde al parametro di sistema net.ipv4.ip_unprivileged_port_start, che vale per tutta la macchina e non per un singolo utente. Modificarlo esce quindi dal perimetro rootless di questa guida. Per un servizio personale la soluzione più lineare resta una porta alta come la 8080.
Collegare un volume (e su Fedora aggiungere :Z)
Una cartella dell’host si monta nel container con -v percorso_host:percorso_container. Nell’esempio la cartella ~/mycontent deve esistere già. Sui sistemi con SELinux, come Fedora e RHEL, il contenuto montato deve avere l’etichetta giusta. Podman, per impostazione predefinita, non cambia le etichette impostate dal sistema, e senza l’etichetta giusta il processo nel container riceve un Permission denied. Il suffisso :Z chiede a Podman di applicare un’etichetta privata, che solo quel container può usare:
podman run -v ~/mycontent:/content:Z fedora touch /content/file
Se termina senza errori, in ~/mycontent compare il file file. Se due container devono condividere la stessa cartella, si usa invece il suffisso minuscolo :z, che applica un’etichetta condivisa. Le directory di sistema non vanno mai rietichettate, perché altri servizi confinati da SELinux potrebbero smettere di funzionare. Per quei casi la documentazione indica di disattivare la separazione SELinux del singolo container con --security-opt label=disable.
Lo stesso errore può dipendere anche dagli user namespace. Succede quando l’immagine gira con un proprio utente non root: gli esempi citati sono Jupyter Notebook e Postgres. In quel caso bisogna correggere la mappatura degli user namespace: spesso basta --userns=keep-id, ma se l’applicazione richiede uno specifico UID/GID interno occorre configurare la mappatura corrispondente.
Fermare e rimuovere un container
Nei comandi che seguono, al posto di <container_id> va scritto l’ID stampato da podman run, oppure quello che compare nella colonna CONTAINER ID di podman ps. Per fermare il server:
podman stop <container_id>
Un container fermo non compare in podman ps: serve l’opzione -a:
podman ps -a
La rimozione non si può annullare: il container viene cancellato e per riaverlo bisogna crearlo di nuovo. Prima di procedere conviene confrontare l’ID con l’elenco appena ottenuto, così da non eliminare il container sbagliato.
podman rm <container_id>
Se il container non compare più in podman ps -a, la rimozione è riuscita.
Avvio automatico con Quadlet e systemd –user
Avviso: questa sezione richiede Podman 4.4 o successivo, con Quadlet installato. Il pacchetto standard di Debian 12 è fermo alla versione 4.3.1 e non consente di seguire questa procedura: occorre prima passare a una distribuzione o a un pacchetto che includa Quadlet. Il comando
podman quadlet listesiste inoltre solo da Podman 5.6. Il segnale da riconoscere è questo: subito doposystemctl --user daemon-reload, l’avvio del servizio fallisce perché l’unità non viene trovata (un messaggio del tipo «Unit sleep.service not found»). In quel caso conviene controllare la versione conpodman versione confrontarla con l’ultima release su GitHub, prima di cercare errori nel file.
Quadlet è il generatore systemd di Podman. Si scrive un file .container e Quadlet, a ogni avvio e a ogni systemctl daemon-reload, lo trasforma in un normale file .service. Per un utente normale il percorso di riferimento è ~/.config/containers/systemd/, da creare se non esiste. Quadlet richiede cgroup v2: la pagina di riferimento indica di verificarlo con podman info --format {{.Host.CgroupsVersion}}.
Il file di esempio della pagina di podman-auto-update si chiama sleep.container. Dopo averlo creato, se ne controlla il contenuto:
cat ~/.config/containers/systemd/sleep.container
[Container]
Image=registry.fedoraproject.org/fedora:latest
Exec=sleep infinity
AutoUpdate=registry
La sola chiave obbligatoria è Image, e per il suo valore è raccomandato il nome completo dell’immagine. AutoUpdate=registry serve solo se si usa podman auto-update. Per far partire il servizio al boot l’esempio da solo non basta. Le unità generate da Quadlet sono transitorie, quindi su di esse systemctl enable non funziona: è il generatore stesso ad applicare la sezione [Install] del file. In fondo a sleep.container vanno quindi aggiunte queste due righe:
[Install]
WantedBy=default.target
Per ricreare il server nginx di prima, nella sezione [Container] si sostituisce l’immagine con Image=docker.io/nginx, si aggiunge PublishPort=8080:80 e si rimuove Exec=sleep infinity, così da usare il comando predefinito dell’immagine nginx. Le opzioni User, Group e DynamicUser di systemd non sono supportate: un Quadlet rootless deve trovarsi in uno dei percorsi di ricerca dell’utente con cui deve girare. Ora si chiede a systemd di rileggere le unità dell’utente, così che Quadlet generi il servizio:
systemctl --user daemon-reload
Il servizio prende il nome dal file, quindi si chiama sleep.service:
systemctl --user start sleep.service
Se systemd risponde che l’unità non esiste, ci sono tre cause possibili: un errore di sintassi nel file, un’opzione che la versione installata non conosce, oppure una versione di Podman troppo vecchia, come spiega l’avviso all’inizio della sezione. Con Podman 5.6 o successivo si può leggere lo stato dei Quadlet dell’utente con:
podman quadlet list
Per ogni Quadlet il comando mostra il nome del file, l’unità systemd, il percorso su disco e lo stato, che per un servizio avviato è active/running. Sulle versioni precedenti che supportano Quadlet, si controlla invece il servizio con systemctl --user status sleep.service. Controllo finale:
podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f8e4759798d4 registry.fedoraproject.org/fedora:latest sleep infinity 2 seconds ago Up 2 seconds systemd-sleep
Il nome del container è systemd-sleep perché Quadlet aggiunge il prefisso systemd-, così da evitare conflitti con i container creati a mano. Per scegliere un altro nome si usa la chiave ContainerName. Al primo avvio lo scaricamento dell’immagine può durare più dei 90 secondi che systemd concede di default all’avvio di un servizio. In quel caso si scarica l’immagine in anticipo, oppure si aggiunge al file una sezione [Service] con TimeoutStartSec=900, che porta il limite a 15 minuti.
Partire al boot anche senza login: loginctl enable-linger
Alla chiusura della sessione systemd ferma anche i container legati a quella sessione, compresi quelli in background. Il lingering evita che i processi dell’utente vengano terminati e permette a un servizio per utente come sleep.service di restare attivo, e di partire con il sistema, anche se nessuno fa login. Si attiva dal proprio utente:
loginctl enable-linger
Per tornare al comportamento predefinito:
loginctl disable-linger
Disinstallare e ripulire
Conviene procedere in quest’ordine:
- Fermare il servizio con il sottocomando
stopdisystemctl --userapplicato asleep.service, prima di cancellare il file. - Eliminare
sleep.containerda~/.config/containers/systemd/e rilanciaresystemctl --user daemon-reload. - Fermare e rimuovere i container creati a mano, come
basic_httpd, conpodman stopepodman rm, come descritto nella sezione «Fermare e rimuovere un container». - Se non servono più servizi rootless all’avvio, disattivare il lingering con
loginctl disable-linger. - Rimuovere il pacchetto
podmancon il gestore della distribuzione:apt-getsu Ubuntu e Debian,dnfsu Fedora.
Se qualcosa va storto
- Problemi di vario tipo: molti problemi segnalati risultano già corretti nelle versioni più recenti. Prima di aprire una segnalazione conviene confrontare l’output di
podman versioncon l’ultima release pubblicata su GitHub. - «newuidmap»: executable file not found: il funzionamento rootless richiede
newuidmapenewgidmap. Su Ubuntu e Debian, se mancano, si installa il pacchettouidmapconsudo apt-get install uidmap; su Fedora sono forniti dashadow-utils. - «setup user: invalid argument»: l’utente richiesto dal container non rientra nell’intervallo di
/etc/subuide/etc/subgid, che va allargato. - «there might not be enough IDs available in the namespace»: si risolve con
podman system migrate. - Permission denied su un volume: la causa è SELinux, e allora servono i suffissi
:Zo:z, oppure gli user namespace, e allora spesso basta--userns=keep-id, a meno che l’applicazione non richieda uno specifico UID/GID interno. - I container si chiudono al logout: manca il lingering, che si attiva con
loginctl enable-linger. - Errori su XDG_RUNTIME_DIR o «mkdir /run/user/1000: permission denied»: con cgroup v2 Podman rootless ha bisogno di una sessione di login valida, e fallisce per esempio se lanciato con
su - utente -c. La sessione va aperta con un login vero, anche via ssh, oppure conmachinectl shell. - Permission denied con la home montata noexec: lo storage dei container va spostato su un mount che consenta l’esecuzione, tramite
~/.config/containers/storage.conf.
Documentazione di riferimento
Pagine consultate il 20 ottobre 2026:
- Podman — Installation instructions
- Basic Setup and Use of Podman (tutorial ufficiale)
- Podman — Troubleshooting
- podman-auto-update(1)
- podman-systemd.unit(5), riferimento Quadlet
- podman-quadlet-list(1)
- Documentazione di Podman
- Repository ufficiale di Podman


