Skip to content

Provisioning a Podman Host

Tej Pochiraju edited this page Jun 5, 2026 · 8 revisions

Provisioning a Podman Host

podman-api does not run containers itself — it drives a rootless podman.socket on each target host over SSH. This page turns a fresh Linux box into such a target. Commands below are for Debian 13 (trixie), validated end-to-end; adapt the package step for other distros.

0. Facts to capture first

SSH in and note these — they go straight into the hosts/<id>.yaml later:

ssh debian@<host>
whoami; id -u          # the user and its uid (socket path uses the uid)
cat /etc/os-release    # distro/version
uname -m               # arch

1. Install podman (rootless deps included)

sudo apt-get update
sudo apt-get install -y podman uidmap slirp4netns
podman --version       # Debian 13 ships podman 5.x, matching the v5 bindings
podman info --format '{{.Host.Security.Rootless}}'   # expect: true

2. Enable the rootless socket, persistently

The socket must survive logout, so enable lingering for the user, then start the user podman.socket:

sudo loginctl enable-linger "$USER"
export XDG_RUNTIME_DIR="/run/user/$(id -u)"
systemctl --user enable --now podman.socket

systemctl --user is-active podman.socket      # active
ls -l "$XDG_RUNTIME_DIR/podman/podman.sock"   # e.g. /run/user/1000/podman/podman.sock
podman ps                                     # smoke test

The socket path is /run/user/<uid>/podman/podman.sock — record it.

If podman ps warns about "no systemd user session", that's expected over a non-login SSH session; lingering keeps the socket alive regardless.

3. SSH identity for podman-api

podman-api connects as ssh://<user>@<host><socket> using a named identity file. Use a key the daemon host holds and the target authorises:

# on the podman-api host, confirm the key the server accepts:
ssh -v <user>@<host> true 2>&1 | grep -i "Server accepts key"

Best practice is a dedicated key per host (e.g. prod-1.id_ed25519) so you can rotate one target without touching others.

4. Write the host file

Drop a file into the directory podman-api scans with -hosts-dir:

# hosts/prod-1.yaml
id: prod-1
addr: debian@<host>                       # ssh://user@host (default port 22)
socket: /run/user/1000/podman/podman.sock
ssh_key: /etc/podman-api/keys/prod-1.id_ed25519
labels:
  env: prod
  region: ap-south-1

addr: unix connects to a local socket directly (dev only). Anything else opens an SSH tunnel using ssh_key. Real host files are git-ignored; commit only a sanitised example.

5. Verify through podman-api

With the daemon running (see Deploying):

curl -s -H "Authorization: Bearer $TOK" http://127.0.0.1:8080/hosts/prod-1/healthz
# {"status":"ok"}
curl -s -H "Authorization: Bearer $TOK" http://127.0.0.1:8080/hosts/prod-1
# ... "podman_version":"5.x.y" ...

A successful podman_version means the SSH tunnel, identity, and socket path are all correct. A full apply→list→delete then confirms play kube, secrets, and port mapping — see Operating.

6. Optional: run the integration suite against this host

The -tags=integration tests use a local socket. To exercise them on this box directly, install Go and run make test-integration there, or rely on the podman-in-podman CI job (Building).

7. Ingress: allow rootless privileged-port binding (only if using ingress)

The optional ingress feature (-ingress-enabled, see Operating) runs a managed Caddy pod that must publish :80 and :443 on the host. Under rootless podman those ports are blocked until you lower the unprivileged-port floor, persistently:

echo 'net.ipv4.ip_unprivileged_port_start=80' | \
  sudo tee /etc/sysctl.d/99-podman-ingress.conf
sudo sysctl --system

sysctl net.ipv4.ip_unprivileged_port_start   # => ... = 80

Without it the Caddy pod fails to start (cannot expose a privileged port). Hosts that never run ingress can skip this. Running Caddy rootful is not supported — podman-api drives every host over the single rootless user socket from § 2.

For HTTP-01 to issue certs, the host's :80/:443 must be reachable from the internet and each instance domain must already resolve to this host (operator-managed DNS).

Related

Clone this wiki locally