Podman
Build on the host, health-check a release socket, switch traffic when healthy. Deployment hooks is the contract.
Requires Guide host setup. On the remote: Podman, curl, OpenSSL, Caddy. The app answers GET /health on a Unix socket in the container.
orbit init writes this recipe when it recognizes a Stario or Python HTTP app (--recipe stario-podman or python-podman). Source: examples/podman-slot.
Each deploy: build image → start container on a release socket → health-check → point stable socket at it and reload Caddy → stop the previous container.
Project layout
ops/ .containerignore Containerfile deploy status removeops/.containerignore excludes Git metadata, caches, and ops/ from the Podman build context. Orbit still uploads ops/ to $SLOT_SRC.
ops/Containerfile
Multi-stage: uv sync, copy app, default stario serve. The deploy hook overrides the command to listen on /sockets/app.sock.
FROM python:3.14-slim-bookworm AS builder WORKDIR /workspaceRUN pip install --no-cache-dir uvCOPY . /workspaceRUN --mount=type=cache,target=/root/.cache/uv uv sync --no-dev FROM python:3.14-slim-bookwormWORKDIR /workspaceCOPY --from=builder /workspace /workspaceENV PATH="/workspace/.venv/bin:$PATH"CMD ["stario", "serve", "app.main:bootstrap"]For another Python server, change CMD and APP_CMD in ops/deploy. Listen on /sockets/app.sock in both. The container command sets STARIO_UNIX_SOCKET=/sockets/app.sock.
The complete hook also handles preview basic auth and idempotent re-deploy.
Three failure modes
Health-check the release
Poll GET /health on the release socket before you switch the stable route. On failure, remove the new container and exit non-zero. The old release keeps serving.
Caddy 502 after a healthy status
Caddy runs as group orbit. Without chgrp orbit on the socket, Caddy returns 502 while status still reports healthy.
Re-deploy or a missing Caddy binary
The complete ops/deploy and ops/remove hooks handle preview auth, an idempotent re-deploy, and a missing Caddy binary.
Public hostname
Point DNS at the host (A record) and use the slot name as the public hostname (app.example.com). Orbit does not configure DNS for you.
First deploy
First deploy in the guide. Then mostly:
orbit deployorbit remove ship app.example.com # keep data and envorbit remove ship app.example.com --purge