| Tested on | Red Hat Enterprise Linux 10.2 (Coughlan) |
|---|---|
| Package | podman-5.8.2-5.el10_2.x86_64 |
| Applies to | Linux workstations and servers where you run Podman commands against a local or remote Podman API socket over SSH or unix:// |
| Privilege | Normal user on the client with SSH key access to the remote account that owns the target socket; root on the client only when your workflow requires it |
| Scope | How remote Podman works, podman --remote and -c, podman system connection add, list, default, rename, and remove, rootful and rootless SSH sockets, CONTAINER_HOST, CONTAINER_CONNECTION, and CONTAINER_SSHKEY, client versus server file paths and configuration, rootful versus rootless remote stores, confirmed remote command limits, and SSH troubleshooting. Does not cover Docker API compatibility, raw REST programming, Podman Machine, or general SSH administration. |
| Related guides | Podman architecture Checkpoint and restore containers List containers Podman storage location |
You run podman on your laptop. The containers start on a build server across the network. Remote Podman keeps the CLI local and shifts storage, networking, and runtime to the host that owns the API socket.
This guide walks through named SSH connections, environment variables, and the client-versus-server split that trips people up on paths, versions, and bug fixes.
How remote Podman works
Local Podman client
│
│ SSH or socket URL
▼
Remote host
│
▼
Podman API socket
│
▼
Remote containers, images, and volumesThe binary you type into runs on your workstation. Container operations execute on the remote engine. That means:
- Images and layers live in the remote store
- Container filesystems and mounts resolve on the server
- Published ports bind on the remote host
- Many file-path arguments mean a path on the server, not your laptop
Some options still read files from the client before the API call — podman cp, --env-file, and build contexts are the common cases. The sections below call out which side owns each path.
podman --remote vs podman-remote
On Linux you do not need a separate binary. Switch the main podman command to remote mode:
podman --remote psThe short form works the same way:
podman -r psSome distributions also ship a standalone podman-remote package (common on macOS or Windows clients talking to a Linux VM). On RHEL 10 with Podman 5.8.2, which podman-remote returns nothing — the integrated podman binary handles remote mode.
Named connections are usually cleaner than typing --remote every time:
podman -c remote-root psPassing -c NAME selects remote mode and the connection profile in one flag.
Check remote and local versions
Local client only:
podman --versionSample output:
podman version 5.8.2A remote deployment exposes two Podman versions — client and server:
podman -c remote-root versionSample output:
Client: Podman Engine
Version: 5.8.2
API Version: 5.8.2
Go Version: go1.26.5 (Red Hat 1.26.5-1.el10_2)
OS/Arch: linux/amd64
Server: Podman Engine
Version: 5.8.2
API Version: 5.8.2
Go Version: go1.26.5 (Red Hat 1.26.5-1.el10_2)
OS/Arch: linux/amd64When something fails remotely, always read both blocks. Reporting only podman --version on the laptop hides the server build that actually created the container.
Client-side vs server-side behavior
Remote Podman splits work across two machines. The side that performs the failing operation is the side you usually patch.
Server-side — container creation, image pull and storage, networking, cgroup limits, runtime execution, and most API implementation bugs. Update or reconfigure Podman on the remote host.
Client-side — connection profile parsing, SSH transport, local flag handling before the API call, and client output formatting. Update the podman package on the workstation.
Example: a container starts but the wrong registry mirror is used — check the server's registries.conf and Podman version. A connection fails with ssh: handshake failed before any container command runs — fix SSH keys or client identity paths first.
Remote connection transport
Podman connection URLs support several schemes:
ssh://
unix://
tcp://For real remote Linux hosts, prefer ssh://. SSH encrypts the session and reuses your existing key-based authentication.
Use unix:// for a local API socket exposed through the same connection model — handy when you want one scripting interface for local and remote engines.
Treat plain tcp:// as insecure unless you add TLS and strict network controls. The Podman API grants broad container control as the socket user. Do not expose an unauthenticated TCP listener on a network boundary. For socket activation and TLS options, see Podman socket and Docker API.
Ensure the Podman API socket exists on the remote host
SSH-based connections reach a Unix socket on the destination. Enable socket activation on the server before you add a client profile.
Rootful socket on the remote host:
sudo systemctl start podman.socketThe default path is /run/podman/podman.sock. Confirm it exists:
ls -l /run/podman/podman.sockSample output:
srw-rw----. 1 root root 0 Aug 23 10:05 /run/podman/podman.sockRootless socket for a dedicated user (replace 1001 with the remote account UID):
systemctl --user start podman.socketRootless path:
/run/user/UID/podman/podman.sockOn the lab host the test user podmantest uses UID 1015, so the socket is /run/user/1015/podman/podman.sock. Never assume UID 1000 — run id -u USER on the server.
Add a remote rootful host
Create a named connection with an explicit socket path:
podman system connection add \
--identity ~/.ssh/id_ed25519 \
production \
ssh://root@podman.example.com/run/podman/podman.sockPodman 5.8.2 also accepts a host without the socket segment and normalizes the URI:
podman system connection add \
--identity ~/.ssh/id_ed25519 \
production \
ssh://root@podman.example.comThe stored URI becomes ssh://root@podman.example.com:22/run/podman/podman.sock when the default rootful path applies.
List what was saved:
podman system connection listSample output:
Name URI Identity Default ReadWrite
production ssh://root@podman.example.com:22/run/podman/podman.sock /root/.ssh/id_ed25519 false trueThe SSH user must be able to authenticate and reach the socket. Test plain SSH before blaming Podman:
ssh -i ~/.ssh/id_ed25519 root@podman.example.com 'podman --version'Sample output:
podman version 5.8.2Add a rootless remote host
Rootless connections point at the user-owned socket under /run/user/UID/. Using --socket-path keeps the UID visible in the command:
podman system connection add \
--identity ~/.ssh/id_ed25519 \
--socket-path /run/user/1015/podman/podman.sock \
dev-user \
podtest@podman.example.comEquivalent explicit URI form:
podman system connection add \
--identity ~/.ssh/id_ed25519 \
dev-user \
ssh://podtest@podman.example.com/run/user/1015/podman/podman.sockList both profiles:
podman system connection listSample output:
Name URI Identity Default ReadWrite
production ssh://root@podman.example.com:22/run/podman/podman.sock /root/.ssh/id_ed25519 false true
dev-user ssh://podtest@podman.example.com:22/run/user/1015/podman/podman.sock /root/.ssh/id_ed25519 false trueRootful and rootless sockets reach different storage namespaces on the same physical host.
List connections
Human-readable table:
podman system connection listScript-friendly JSON:
podman system connection list --format jsonSample output (trimmed):
[
{
"Name": "production",
"URI": "ssh://root@podman.example.com:22/run/podman/podman.sock",
"Identity": "/root/.ssh/id_ed25519",
"Default": true,
"ReadWrite": true
}
]Column meanings:
- Name — profile label for
-c/--connection - URI — endpoint including socket path
- Identity — private key path used for SSH URLs
- Default — whether this profile is used when remote mode has no explicit selection
- ReadWrite — connection is not read-only
Set the default connection
Pin one profile as the default remote target:
podman system connection default productionConfirm the Default column:
podman system connection listThen remote commands without -c use that profile:
podman --remote psDefault connection affects remote mode only. A plain podman ps is local only when no remote-selecting environment variable or -c/--remote option is active.
Select a connection per command
For multi-host administration, pass the profile on each command instead of flipping the default:
podman --connection production psShort form:
podman -c production ps-c implies remote mode — you do not need a separate --remote flag when the connection name is present.
CONTAINER_CONNECTION
Export the profile name for a shell session:
export CONTAINER_CONNECTION=productionRun remote commands in that session:
podman psPrecedence (highest wins):
--connection / -c → CONTAINER_CONNECTION → default connection profileUse CONTAINER_CONNECTION in scripts that already set up a named profile and should not hard-code --connection on every line.
CONTAINER_HOST
Point at a URL directly without a stored profile:
export CONTAINER_HOST='ssh://podtest@podman.example.com/run/user/1015/podman/podman.sock'
export CONTAINER_SSHKEY=~/.ssh/id_ed25519
podman psWithout CONTAINER_SSHKEY, SSH authentication may fail even when a named connection with --identity works. Sample failure:
Error: unable to connect to Podman socket: failed to connect: ssh: handshake failed: EOF: ssh://root@podman.example.com/run/podman/podman.sockSetting either CONTAINER_CONNECTION or CONTAINER_HOST automatically switches Podman into remote mode, so --remote is optional.
CONTAINER_HOST suits CI jobs, temporary endpoints, and environments that inject URLs from orchestration metadata.
CONTAINER_HOST vs named connection
| Named connection | CONTAINER_HOST |
|
|---|---|---|
| Storage | Local connection database | Environment variable |
| Multiple hosts | podman -c NAME per host |
Change env or use profiles |
| SSH identity | --identity saved in profile |
CONTAINER_SSHKEY or SSH agent |
| Default selection | podman system connection default |
Set env in shell or unit file |
| Typical use | Daily admin across several servers | Pipelines and ephemeral targets |
You can combine both: maintain named profiles for routine work and override with CONTAINER_HOST when a job needs a one-off endpoint.
SSH agent and identity files
Pass a non-default key when adding a connection:
podman system connection add \
--identity ~/.ssh/podman_ed25519 \
staging \
ssh://deploy@podman.example.comEncrypted keys may prompt for a passphrase unless ssh-agent already holds the key. Password-based SSH login can prompt interactively — key-based auth is the usual production pattern. This article does not cover SSH key generation; fix transport first when ssh USER@HOST fails.
Run normal Podman commands remotely
Once a connection works, subcommands behave like local Podman except for path and namespace rules.
List remote containers:
podman -c production psList remote images:
podman -c production imagesStart a container on the server:
podman -c production run -d --name remote-marker registry.access.redhat.com/ubi9/ubi-minimal:latest sleep 3600Sample output:
6c39729e0a9344ec7bfe95950bb3ccfdcccc120809d58886316e57f22acb2d97Confirm it is running remotely:
podman -c production ps --filter name=remote-markerSample output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6c39729e0a93 registry.access.redhat.com/ubi9/ubi-minimal:latest sleep 3600 1 second ago Up 1 second remote-markerRead container metadata:
podman -c production inspect remote-marker --format '{{.Name}}'Sample output:
remote-markerCheck OS inside the remote container:
podman -c production exec remote-marker cat /etc/os-release | head -2Sample output:
NAME="Red Hat Enterprise Linux"
VERSION="9.8 (Plow)"That output came from the server-side container — your local machine did not run the sleep process.
Local vs remote file paths
Remote mode is where path confusion hurts most. There is no single rule for every flag — test the operation you care about.
| Argument or operation | Path resolves on | Notes |
|---|---|---|
Bind-mount source (-v /host:/ctr) |
Server | Server /tmp is not your laptop /tmp |
podman cp host path |
Client (local file read/upload) | Copies between your machine and remote container |
--env-file |
Client | File is read locally; variables apply on server |
| Build context directory | Client | Context is sent to the server for the build |
--authfile / registry auth |
Client | Credentials travel with the API request |
SSH --identity |
Client | Private key on workstation |
| Image and volume store | Server | podman -c NAME images lists remote images |
Container filesystem paths in exec / cp container side |
Server | Paths inside the container namespace |
Prove podman cp reads the local file. Create a marker on the client:
echo "from-local-client" > /tmp/local-test.txtCopy into the remote container:
podman -c production cp /tmp/local-test.txt remote-marker:/tmp/from-client.txtRead it back from inside the container:
podman -c production exec remote-marker cat /tmp/from-client.txtSample output:
from-local-clientProve bind mounts use the server host path. Create a file in server /tmp:
touch /tmp/bind-remote-test.txtMount server /tmp into a one-off container:
podman -c production run --rm -v /tmp:/data registry.access.redhat.com/ubi9/ubi-minimal:latest ls /data/bind-remote-test.txtThe listing succeeds because /tmp is the remote host directory, not your laptop. SELinux relabel flags such as :Z on system directories may fail on the server — use a dedicated path when relabeling is required.
Remote configuration files
Two configuration layers matter.
Your client containers.conf (under ~/.config/containers/ or /etc/containers/) controls client defaults — connection behavior, some display options, and local paths the client reads before calling the API.
The server has its own container configuration. containers.conf controls engine and runtime defaults, storage.conf controls the container storage configuration, and registries.conf controls registry resolution and mirrors. Editing the corresponding client files does not change these server-side settings.
When runtime defaults look wrong on remote containers, inspect configuration on the server.
Rootless vs rootful remote connections
Two connections to the same hostname can reach completely different stores:
podman -c production images --format '{{.Repository}}:{{.Tag}}' | head -3Sample output (rootful):
registry.access.redhat.com/ubi9/ubi-minimal:latest
registry.access.redhat.com/ubi9/ubi:latest
quay.io/podman/hello:latestThe dev-user connection targets the rootless socket on the same host, so repeat the listing there:
podman -c dev-user images --format '{{.Repository}}:{{.Tag}}' | head -3Sample output (rootless):
docker.io/library/alpine:3.20Same machine, different sockets, different image lists. Pick the profile that matches the account namespace you intend to administer.
Remove a connection
Delete a stored profile locally:
podman system connection remove productionVerify:
podman system connection listRemoving a connection does not stop remote containers, disable podman.socket on the server, or delete SSH keys. It only drops the client-side profile.
Rename a connection
Podman 5.8.2 supports rename:
podman system connection rename production prodList to confirm:
podman system connection listUpdate scripts and environment variables that referenced the old name.
Use a local Unix socket as a named connection
The same connection machinery works for a local API socket:
podman system connection add local-api unix:///run/podman/podman.sockQuery through the profile:
podman -c local-api psUseful when you want scripts to always go through the connection layer even on the same host. This is not a remote host — it is the local rootful socket with a named alias.
Do not use plain TCP for normal remote administration
Podman accepts tcp:// URLs, but a plain TCP API socket is unencrypted and unauthenticated. Anyone who can reach the port can manage containers as the service user.
Prefer ssh:// for remote administration. If you must expose the API over the network, use TLS and access controls as covered in Podman socket and Docker API.
Remote limitations
Only list limitations confirmed on Podman 5.8.2 in this lab — run podman --remote COMMAND --help before assuming a subcommand works remotely.
| Command | Remote result on 5.8.2 |
|---|---|
podman unshare |
Error: cannot use command "podman unshare" with the remote podman client |
podman mount |
Same error pattern — requires local namespace access |
podman system migrate |
Blocked on remote client |
podman checkpoint |
Not available through remote CLI on this build |
Commands such as podman run, podman ps, podman logs, podman inspect, and podman pod create work remotely. When a command needs direct host namespace or local filesystem manipulation on the client, expect a remote-client error rather than a server failure.
Troubleshoot SSH remote connections
| Symptom | Likely cause | Direction |
|---|---|---|
ssh: handshake failed or unable to authenticate |
SSH keys, agent, or CONTAINER_SSHKEY missing |
Run ssh -i KEY USER@HOST first; add --identity or CONTAINER_SSHKEY |
connect failed (open failed) with socket path in error |
Wrong socket path in URI | Check systemctl status podman.socket and ls -l on the socket |
| Permission denied on socket | SSH user does not own rootless socket | Use correct UID path or rootful socket with authorized user |
| Empty or wrong image list | Connected to wrong profile (rootless vs rootful) | Compare podman system connection list URI paths |
| Client and server version skew | Mixed package versions | Run podman -c NAME version and align both sides |
cannot use command ... with the remote podman client |
Subcommand needs local host access | Run locally on the server or pick a different workflow |
Wrong socket example:
Error: unable to connect to Podman socket: Get "http://d/v5.8.2/libpod/_ping": ssh: rejected: connect failed (open failed): ssh://root@podman.example.com:22/run/podman/nope.sockThe SSH session succeeded; the socket path on the server did not.
Cleanup
Remove lab containers and connections:
podman -c production rm -f remote-marker 2>/dev/nullDrop test connection profiles:
podman system connection remove production dev-user local-api 2>/dev/nullClient-side files from path tests:
rm -f /tmp/local-test.txtReferences
- podman-system-connection(1) — add, list, default, rename, remove
- podman(1) —
--remote,--connection, and connection environment variables
Summary
Remote Podman keeps the CLI on your workstation and runs containers on the host that owns the API socket. Use podman --remote, podman -r, or podman -c NAME on Linux — a separate podman-remote binary is optional. Store SSH endpoints with podman system connection add, set a default, or pass -c per command. CONTAINER_CONNECTION and CONTAINER_HOST offer environment-driven selection; pair CONTAINER_HOST with CONTAINER_SSHKEY when the key is not SSH's default.
Always check client and server versions with podman -c NAME version and fix the side that owns the failing behavior. Bind mounts and most host paths are server-side; podman cp and --env-file read from the client. Rootful and rootless profiles on the same hostname reach different stores — match the socket path to the account you mean.
Prefer ssh:// over plain tcp://. Some subcommands such as unshare, mount, and system migrate cannot run through the remote client on Podman 5.8.2. For socket activation and Docker API compatibility, continue with the Podman socket guide.

