The essentials

Quick reference

One focused task per row. Jump to the related section for complete, working examples.

UseSyntaxExamples
Inspect engine and hostpodman info --format jsonView examples
Check subordinate ID rangesgetent subuid "$USER"; getent subgid "$USER"View examples
Pull an immutable imagepodman pull docker.io/library/nginx@sha256:DIGESTView examples
Run with a read-only rootpodman run --read-only --cap-drop=all \ --security-opt=no-new-privileges --tmpfs \ /tmp:rw,noexec,nosuid,nodev IMAGEView examples
Publish only on loopbackpodman run -p 127.0.0.1:8080:8080 IMAGEView examples
Bound memory and CPUspodman run --memory=512m --cpus=1.5 --pids-limit=256 \ IMAGEView examples
Create an application networkpodman network create app-netView examples
Create a named volumepodman volume create app-dataView examples
Relabel a private bind mountpodman run -v /srv/app/config:/app/config:ro,Z IMAGEView examples
Create a secret from standard inputprintf '%s' "$DB_PASSWORD" | podman secret create db_password -View examples
Mount a runtime secretpodman run --secret db_password,type=mount IMAGEView examples
Provide a build secretpodman build --secret id=npmrc,src="$HOME/.npmrc" -t \ localhost/app:build .View examples
Regenerate rootless unitssystemctl --user daemon-reloadView examples
Verify generated servicesystemd-analyze --user --generators=true verify \ app.serviceView examples
Inspect health statepodman inspect --format '{{.State.Health.Status}}' appView examples
Stream lifecycle eventspodman events --filter container=appView examples
Preview automatic updatespodman auto-update --dry-runView examples
Export a named volumepodman volume export app-data --output app-data.tarView examples
Archive an OCI imagepodman save --format oci-archive --output app-image.tar \ IMAGEView examples
Run Podman diagnosticspodman system check --quickView examples

Podman is a daemonless OCI container engine whose rootless mode gives each user separate storage, containers, and user-namespace mappings. Production operation still requires explicit image provenance, least privilege, persistent-data ownership, secret handling, health policy, and tested recovery. These recipes favor inspectable changes and fully qualified image names; review them against the installed Podman, kernel, cgroup, SELinux or AppArmor, and distribution versions before rollout.

Step by step

Detailed examples

01

Establish a rootless, version-aware baseline

Run Podman as the service account that will own the workload. Rootless and rootful stores are separate, so sudo podman does not reveal a user's containers. Normal rootless operation needs subordinate UID and GID ranges; after an administrator changes those ranges, existing mappings and storage may require a deliberate migration. Rootless OverlayFS needs a sufficiently recent kernel or fuse-overlayfs, and NFS-backed home directories require local graph storage. Quadlet requires cgroup v2. Package names, default network helpers, and feature availability vary by distribution and Podman release.

Capture a non-mutating readiness report
podman version
podman info --format 'rootless={{.Host.Security.Rootless}} cgroups={{.Host.CgroupsVersion}} graph={{.Store.GraphDriverName}}'
getent subuid "$USER"
getent subgid "$USER"
findmnt -T "$HOME" -o TARGET,FSTYPE,OPTIONS
podman system connection list
Back to quick reference ↑
02

Run containers with least privilege and bounded resources

Container isolation is not a permission to trust the workload. Start rootless, drop capabilities, block privilege escalation, make the root filesystem read-only, and add back only the writable paths and capabilities the process demonstrates it needs. Avoid --privileged, host PID or network namespaces, broad device access, and mounting the Podman socket: each materially expands host control. Pin production images by digest and establish an explicit update process. Low host ports, cgroup delegation, and resource flags differ across kernels and distributions, so verify effective settings with podman inspect and cgroup metrics.

Start a constrained loopback-only web process
image='docker.io/library/nginx@sha256:DIGEST'
podman run -d --name web --replace \
  --read-only --cap-drop=all --security-opt=no-new-privileges \
  --tmpfs /var/cache/nginx:rw,nosuid,nodev --tmpfs /var/run:rw,nosuid,nodev \
  --memory=512m --cpus=1.5 --pids-limit=256 \
  -p 127.0.0.1:8080:8080 "$image"
podman inspect web --format '{{json .HostConfig}}'
Back to quick reference ↑
03

Make network exposure and data ownership explicit

A published port binds on every host address unless an address is supplied, so bind loopback unless direct network exposure is intentional. Rootless networking commonly uses pasta on current Podman releases, while older or differently configured installations may use slirp4netns; latency, source-address behavior, and host reachability differ. Prefer named volumes for portable engine-managed data. For bind mounts, validate ownership through the user namespace and apply :Z only to content private to one container; relabeling system paths can break host services. Never remove or prune storage until inventory, backups, and restore tests are complete.

Provision an isolated application data path
podman network create app-net
podman volume create app-data
podman network inspect app-net
podman volume inspect app-data
podman run --rm --network app-net \
  --mount type=volume,source=app-data,target=/data \
  docker.io/library/alpine@sha256:DIGEST sh -c 'id; stat -c "%u:%g %a %n" /data'
Back to quick reference ↑
04

Keep credentials out of images, arguments, and logs

Environment variables, Containerfile ARG values, command-line arguments, and image layers are routinely exposed through inspection, process listings, caches, or logs. Use Podman secrets as mounted files for runtime credentials and build-secret mounts for package-manager tokens. A secret is scoped to the Podman store and is not automatically backed up with a container. Rotate it through the authoritative secret manager, recreate or restart consumers as required by the application, and avoid printing its content. Prefer registries with TLS verification and authenticate through a protected auth file rather than embedding credentials in image names or scripts.

Create and consume a file-mounted secret
read -r -s -p 'Database password: ' DB_PASSWORD
printf '\n'
printf '%s' "$DB_PASSWORD" | podman secret create db_password -
unset DB_PASSWORD
podman secret inspect db_password
podman run --rm --secret db_password,type=mount \
  docker.io/library/alpine@sha256:DIGEST \
  sh -c 'test -s /run/secrets/db_password && echo secret-mounted'
Supply a package token only during a build step
test -r "$HOME/.npmrc"
podman build \
  --secret id=npmrc,src="$HOME/.npmrc" \
  --label org.opencontainers.image.revision=GIT_COMMIT \
  -t localhost/app:build .
podman image inspect localhost/app:build --format '{{json .Config.Labels}}'
Back to quick reference ↑
05

Manage long-running containers declaratively with Quadlet

Quadlet turns .container, .volume, .network, and related definitions into ordinary systemd services. Rootless definitions belong under ~/.config/containers/systemd and are controlled with systemctl --user; setting User= in a rootful Quadlet does not turn it into a rootless workload. The generated service is not the source of truth and must not be edited or enabled directly. Put the desired target in the Quadlet's [Install] section; the generator applies it during reload. Verify and start the service after reloading. User services that must survive logout require an administrator to enable lingering. Pre-pull images or raise TimeoutStartSec where registry latency can exceed the service startup timeout.

Define and verify a rootless Quadlet service
install -d -m 0700 "$HOME/.config/containers/systemd"
install -m 0600 ./app.container "$HOME/.config/containers/systemd/app.container"
systemctl --user daemon-reload
systemd-analyze --user --generators=true verify app.service
systemctl --user start app.service
systemctl --user status app.service --no-pager
journalctl --user -u app.service -n 100 --no-pager
Example rootless app.container source
[Unit]
Description=Rootless application container
After=network-online.target
Wants=network-online.target

[Container]
Image=registry.example.com/team/app@sha256:DIGEST
ContainerName=app
PublishPort=127.0.0.1:8080:8080
ReadOnly=true
NoNewPrivileges=true
DropCapability=all
Volume=app-data.volume:/var/lib/app
Secret=db_password,type=mount
HealthCmd=/usr/local/bin/healthcheck
HealthInterval=30s
HealthTimeout=5s

[Service]
Restart=on-failure
TimeoutStartSec=300

[Install]
WantedBy=default.target
Back to quick reference ↑
06

Observe health and stage updates for rollback

A health check should test a meaningful local dependency, finish quickly, and avoid credentials in output. Health status does not by itself restart a standalone container; combine application readiness with the Quadlet and systemd failure policy appropriate to the service. Treat logs and events as potentially sensitive. For automatic updates, use a fully qualified image reference and run --dry-run first. Digest pinning deliberately disables tag-driven movement, so update the reviewed digest through deployment configuration. Registry outages, authentication expiry, and pull latency must not erase the last known-good local image; test failure and rollback behavior before scheduling unattended updates.

Collect a bounded operational snapshot
podman ps --filter name=app --format '{{.Names}} {{.Status}} {{.Image}}'
podman inspect app --format 'image={{.ImageName}} health={{.State.Health.Status}} restart={{.HostConfig.RestartPolicy.Name}}'
podman stats --no-stream app
podman logs --since 15m --tail 200 app
podman auto-update --dry-run
systemctl --user show app.service -p ActiveState -p SubState -p NRestarts
Back to quick reference ↑
07

Back up data consistently and prove recovery

Container deletion, image archives, and container filesystem exports are not backups of named volumes. For databases and other stateful services, use the application's native backup or quiesce protocol; stopping the writer creates an outage but is the simplest portable consistency boundary. Export every required named volume, save the exact image or record its digest, retain Quadlet configuration separately, protect archives like production data, and test restoration into an isolated name and network. Do not rely on an export created while writes were active unless the application explicitly guarantees crash-consistent recovery.

Create a cold, checksummed recovery set
state_dir=${XDG_STATE_HOME:-$HOME/.local/state}
backup_dir=$state_dir/backups/podman/app-2026-08-12
install -d -m 0700 "$backup_dir"
systemctl --user stop app.service
trap 'systemctl --user start app.service' EXIT
podman volume export app-data --output "$backup_dir/app-data.tar"
podman save --format oci-archive --output "$backup_dir/app-image.tar" registry.example.com/team/app@sha256:DIGEST
install -m 0600 "$HOME/.config/containers/systemd/app.container" "$backup_dir/app.container"
sha256sum "$backup_dir/app-data.tar" "$backup_dir/app-image.tar" "$backup_dir/app.container" > "$backup_dir/SHA256SUMS"
systemctl --user start app.service
trap - EXIT
sha256sum -c "$backup_dir/SHA256SUMS"
Restore into a disposable validation volume
state_dir=${XDG_STATE_HOME:-$HOME/.local/state}
backup_dir=$state_dir/backups/podman/app-2026-08-12
sha256sum -c "$backup_dir/SHA256SUMS"
podman load --input "$backup_dir/app-image.tar"
podman volume create app-data-restore-test
podman volume import app-data-restore-test "$backup_dir/app-data.tar"
podman run --rm --network none \
  --mount type=volume,source=app-data-restore-test,target=/data,ro \
  docker.io/library/alpine@sha256:DIGEST find /data -xdev -maxdepth 2 -type f -print
Back to quick reference ↑
08

Troubleshoot without erasing evidence or weakening isolation

Start with version, inspect, events, journald, storage, network, cgroup, and mandatory-access-control evidence. A permission denial is not a reason to add --privileged, disable SELinux or AppArmor, or expose the API socket. Rootless containers may fail because subordinate IDs, filesystem type, cgroup delegation, low-port policy, or user-service lifetime differ from the tested host. podman system check can detect storage problems, but repair, reset, prune, volume removal, and network removal can destroy recoverable state. Back up and understand the scope before any repair command.

Gather diagnostics without changing the workload
podman version
podman info --debug
podman inspect app
podman port app
podman network inspect app-net
podman volume inspect app-data
podman system df
podman system check --quick
journalctl --user -u app.service --since -30min --no-pager
ausearch -m AVC,USER_AVC -ts recent 2>/dev/null || true
Back to quick reference ↑

Sources and further reading

References

Authoritative documentation used to verify and expand this cheat sheet.

  1. Podman projectpodman(1) — Pod Managerdocs.podman.io
  2. Podman projectpodman-run(1) — Run a process in a new containerdocs.podman.io
  3. Podman projectpodman-systemd.unit(5) — Quadlet systemd unitsdocs.podman.io
  4. Podman projectpodman-secret(1) — Manage Podman secretsdocs.podman.io
  5. Podman projectpodman-auto-update(1) — Auto-update containersdocs.podman.io
  6. Podman projectpodman-volume-export(1) — Export volume datadocs.podman.io
  7. Podman projectpodman-save(1) — Save images to an archivedocs.podman.io

Help us improve

Found a typo or missing example?

Tell us what would make this cheat sheet clearer, more complete, or more useful.

Share feedback