Installing Podman Locally and on a VPS
A practical install guide for Podman on macOS and Debian/Ubuntu servers, including first-run checks.
Category: On-Premises & Private Cloud
I wanted the same container runtime on my MacBook and on the VPS — same commands, same compose file, same mental model. I picked Podman over Docker mostly because it runs rootless by default and doesn’t need a daemon on Linux, which matters on a small VPS where every background process costs something.
This post is the install baseline the rest of the series rests on.
The setup
- Local: macOS with Homebrew, Podman running inside its managed VM.
- Server: Debian/Ubuntu VPS, Podman installed from the distro packages.
- Compose:
podman-composeon both sides — no Docker binaries involved.
Local installation (macOS)
brew update
brew install podman podman-compose
Podman on macOS runs inside a lightweight Linux VM — initialise and start it:
podman machine init
podman machine start
A quick sanity pass to make sure the client can reach the VM:
podman --version
podman info
podman system connection list
Gotcha: Homebrew installs both podman compose (the subcommand) and podman-compose (a separate Python project). The subcommand will happily call out to docker-compose if it’s on the PATH, which defeats the point. Pin the provider explicitly:
export PODMAN_COMPOSE_PROVIDER=/opt/homebrew/bin/podman-compose
echo 'export PODMAN_COMPOSE_PROVIDER=/opt/homebrew/bin/podman-compose' >> ~/.zshrc
source ~/.zshrc
Server installation (Debian/Ubuntu VPS)
sudo apt-get update
sudo apt-get -y install podman podman-compose git
Same verification pass as on macOS:
podman --version
podman info
podman system connection list
Problem: On multi-container compose setups I wanted service-name DNS (one service reaching another by its compose service name) to work out of the box. The default installation doesn’t always include the network plugins that provide this.
Implementation: Install the netavark + aardvark stack — Podman’s modern network + DNS layer:
sudo apt-get -y install netavark aardvark-dns
Solution: Compose services resolve each other by name inside the Podman network, without me having to hand-wire IPs.
First-run check (both environments)
Pulling a real image and running a throwaway container is the cheapest way to confirm the runtime and the registry path both work:
podman pull docker.io/library/node:20-bookworm-slim
podman run --rm docker.io/library/node:20-bookworm-slim node --version
A Node version back on stdout means the whole chain — runtime, image resolver, registry auth, container exec — is healthy.
Common first-install issues
connection refusedon the Podman socket (macOS). The VM is either not running or in a bad state.podman machine stop && podman machine startresolves it almost every time.invalid username/passwordpulling public images. Stale auth state in~/.config/containers/auth.json. A plainpodman pulloften clears it without any extra login.podman composepicks the wrong provider. SetPODMAN_COMPOSE_PROVIDERexplicitly — don’t rely on the auto-detection.
Day-to-day commands
The three commands I run ninety percent of the time:
podman compose -f compose.yml up --build -d
podman compose -f compose.yml logs -f
podman compose -f compose.yml down
Same three commands on laptop and server — that’s the whole point.
What to take away
- Keeping the local and server installations symmetric pays off on every deploy — no mental translation needed.
- Rootless Podman is the default, and it’s the right default for a small single-service VPS.
- Pin
PODMAN_COMPOSE_PROVIDERexplicitly; the auto-detected fallback todocker-composeis a silent behaviour change waiting to happen. - Install
netavarkandaardvark-dnson the server if you use compose service-name DNS. - A successful
podman run --rm node:20 node --versionis a complete smoke test.