Manage Remote Podman Hosts with `podman-remote`

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

text
Local Podman client
        │ SSH or socket URL
Remote host
Podman API socket
Remote containers, images, and volumes

The 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:

bash
podman --remote ps

The short form works the same way:

bash
podman -r ps

Some 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:

bash
podman -c remote-root ps

Passing -c NAME selects remote mode and the connection profile in one flag.


Check remote and local versions

Local client only:

bash
podman --version

Sample output:

output
podman version 5.8.2

A remote deployment exposes two Podman versions — client and server:

bash
podman -c remote-root version

Sample output:

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/amd64

When 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:

text
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:

bash
sudo systemctl start podman.socket

The default path is /run/podman/podman.sock. Confirm it exists:

bash
ls -l /run/podman/podman.sock

Sample output:

output
srw-rw----. 1 root root 0 Aug 23 10:05 /run/podman/podman.sock

Rootless socket for a dedicated user (replace 1001 with the remote account UID):

bash
systemctl --user start podman.socket

Rootless path:

text
/run/user/UID/podman/podman.sock

On 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:

bash
podman system connection add \
  --identity ~/.ssh/id_ed25519 \
  production \
  ssh://root@podman.example.com/run/podman/podman.sock

Podman 5.8.2 also accepts a host without the socket segment and normalizes the URI:

bash
podman system connection add \
  --identity ~/.ssh/id_ed25519 \
  production \
  ssh://root@podman.example.com

The stored URI becomes ssh://root@podman.example.com:22/run/podman/podman.sock when the default rootful path applies.

List what was saved:

bash
podman system connection list

Sample output:

output
Name                URI                                                             Identity               Default     ReadWrite
production          ssh://root@podman.example.com:22/run/podman/podman.sock         /root/.ssh/id_ed25519  false       true

The SSH user must be able to authenticate and reach the socket. Test plain SSH before blaming Podman:

bash
ssh -i ~/.ssh/id_ed25519 root@podman.example.com 'podman --version'

Sample output:

output
podman version 5.8.2

Add 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:

bash
podman system connection add \
  --identity ~/.ssh/id_ed25519 \
  --socket-path /run/user/1015/podman/podman.sock \
  dev-user \
  podtest@podman.example.com

Equivalent explicit URI form:

bash
podman system connection add \
  --identity ~/.ssh/id_ed25519 \
  dev-user \
  ssh://podtest@podman.example.com/run/user/1015/podman/podman.sock

List both profiles:

bash
podman system connection list

Sample output:

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       true

Rootful and rootless sockets reach different storage namespaces on the same physical host.


List connections

Human-readable table:

bash
podman system connection list

Script-friendly JSON:

bash
podman system connection list --format json

Sample output (trimmed):

output
[
    {
        "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:

bash
podman system connection default production

Confirm the Default column:

bash
podman system connection list

Then remote commands without -c use that profile:

bash
podman --remote ps

Default 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:

bash
podman --connection production ps

Short form:

bash
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:

bash
export CONTAINER_CONNECTION=production

Run remote commands in that session:

bash
podman ps

Precedence (highest wins):

text
--connection / -c  →  CONTAINER_CONNECTION  →  default connection profile

Use 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:

bash
export CONTAINER_HOST='ssh://podtest@podman.example.com/run/user/1015/podman/podman.sock'
export CONTAINER_SSHKEY=~/.ssh/id_ed25519
podman ps

Without CONTAINER_SSHKEY, SSH authentication may fail even when a named connection with --identity works. Sample failure:

output
Error: unable to connect to Podman socket: failed to connect: ssh: handshake failed: EOF: ssh://root@podman.example.com/run/podman/podman.sock

Setting 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:

bash
podman system connection add \
  --identity ~/.ssh/podman_ed25519 \
  staging \
  ssh://deploy@podman.example.com

Encrypted 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:

bash
podman -c production ps

List remote images:

bash
podman -c production images

Start a container on the server:

bash
podman -c production run -d --name remote-marker registry.access.redhat.com/ubi9/ubi-minimal:latest sleep 3600

Sample output:

output
6c39729e0a9344ec7bfe95950bb3ccfdcccc120809d58886316e57f22acb2d97

Confirm it is running remotely:

bash
podman -c production ps --filter name=remote-marker

Sample output:

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-marker

Read container metadata:

bash
podman -c production inspect remote-marker --format '{{.Name}}'

Sample output:

output
remote-marker

Check OS inside the remote container:

bash
podman -c production exec remote-marker cat /etc/os-release | head -2

Sample output:

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:

bash
echo "from-local-client" > /tmp/local-test.txt

Copy into the remote container:

bash
podman -c production cp /tmp/local-test.txt remote-marker:/tmp/from-client.txt

Read it back from inside the container:

bash
podman -c production exec remote-marker cat /tmp/from-client.txt

Sample output:

output
from-local-client

Prove bind mounts use the server host path. Create a file in server /tmp:

bash
touch /tmp/bind-remote-test.txt

Mount server /tmp into a one-off container:

bash
podman -c production run --rm -v /tmp:/data registry.access.redhat.com/ubi9/ubi-minimal:latest ls /data/bind-remote-test.txt

The 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:

bash
podman -c production images --format '{{.Repository}}:{{.Tag}}' | head -3

Sample output (rootful):

output
registry.access.redhat.com/ubi9/ubi-minimal:latest
registry.access.redhat.com/ubi9/ubi:latest
quay.io/podman/hello:latest

The dev-user connection targets the rootless socket on the same host, so repeat the listing there:

bash
podman -c dev-user images --format '{{.Repository}}:{{.Tag}}' | head -3

Sample output (rootless):

output
docker.io/library/alpine:3.20

Same 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:

bash
podman system connection remove production

Verify:

bash
podman system connection list

Removing 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:

bash
podman system connection rename production prod

List to confirm:

bash
podman system connection list

Update 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:

bash
podman system connection add local-api unix:///run/podman/podman.sock

Query through the profile:

bash
podman -c local-api ps

Useful 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:

output
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.sock

The SSH session succeeded; the socket path on the server did not.


Cleanup

Remove lab containers and connections:

bash
podman -c production rm -f remote-marker 2>/dev/null

Drop test connection profiles:

bash
podman system connection remove production dev-user local-api 2>/dev/null

Client-side files from path tests:

bash
rm -f /tmp/local-test.txt

References


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.


Frequently Asked Questions

1. Do I need a separate podman-remote binary on Linux?

No on RHEL 10 with Podman 5.8.2. The main podman binary supports remote mode through podman --remote, podman -r, or podman -c CONNECTION. A standalone podman-remote package exists on some platforms but is not required on every Linux install.

2. What is the difference between CONTAINER_HOST and a named connection?

A named connection is a stored profile with URI, identity path, and default flag managed by podman system connection. CONTAINER_HOST sets a direct endpoint URL in the environment for CI or one-off scripts. Command-line --connection overrides CONTAINER_CONNECTION, which overrides the default connection profile.

3. Does podman --remote use my local or remote storage?

Images, containers, volumes, and network namespaces live on the remote Podman server. The CLI runs locally and forwards API calls over SSH or a socket URL. Bind-mount host paths refer to the server filesystem unless a command explicitly uploads from the client, such as podman cp or --env-file.

4. Should I update the client or server when remote Podman fails?

Check both sides with podman -c CONNECTION version. Server-side behavior such as container creation, storage, networking, and image pulls usually needs a fix on the remote host. Client-side issues such as SSH transport, connection parsing, and output formatting may need a client update.

5. Is plain tcp:// safe for Podman remote administration?

No for normal use. Plain TCP to the Podman API is unencrypted and unauthenticated while granting broad control as the socket user. Prefer ssh:// for remote Linux hosts. If you need TCP, use TLS and access controls as described in the Podman socket guide.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)