CertGrid CertGrid
Hands-on Lab·Podman

Moving Podman Images Without a Registry

`podman image scp localhost/multi:1 lab02::` copies an image host to host and prints `Loaded image`. Give it a raw `user@host::` instead of a named connection and it copies every blob and then fails.

Registries and Remote Hosts Guide 39 of 47 Intermediate

Written against the versions above. Podman follows the distribution here rather than a vendor repository, so the version you get is the one Ubuntu shipped. The commands are stable across 5.x.

The 2 hosts these commands ran on: podman01, podman02.
Server NameIP AddressOSRolesCPURAMHDD
PODMAN01192.168.0.21Ubuntu 26.04 LTSPrimary Container Host2 Core4 GB50 GB
PODMAN02192.168.0.22Ubuntu 26.04 LTSRootless and Remote Client Host2 Core4 GB50 GB

Before you start

  1. The obvious form, which does not work

    The documentation-shaped guess is a raw ssh destination:

    podman image scp localhost/multi:1 sysadmin@192.168.0.22::

    And it half works, which is the annoying part. Every blob copies, then:

    level=warning msg="Unknown connection name given. Please use system connection
    add to specify the default remote socket location"
    ...
    Copying blob sha256:6f09edfb3f6d...
    Writing manifest to image destination
    Error: failed to connect: ssh: handshake failed: EOF

    The warning at the top is the real message and it arrives before the work rather than after. image scp addresses a named system connection, not a host - it needs the socket path and identity that a connection carries, and a bare user@host gives it neither.

    Note the destination's image list is still empty afterwards. The blobs went somewhere and the load never happened.

    bash Example session
    podman images --format 'table {{.Repository}} {{.Tag}} {{.Size}}' localhost/multiREPOSITORY       TAG         SIZElocalhost/multi  1           8.66 MBlocalhost/multi  builder     182 MBpodman images --format 'table {{.Repository}} {{.Tag}} {{.Size}}' localhost/multiREPOSITORY       TAG         SIZElocalhost/multi  1           8.66 MBlocalhost/multi  builder     182 MBpodman image scp localhost/multi:1 sysadmin@192.168.0.22::time="2026-08-22T12:40:05Z" level=warning msg="Unknown connection name given. Please use system connection add to specify the default remote socket location"Copying blob sha256:6f09edfb3f6d7173733adc8eec8ea00626550dc6fc2dcf07d40e13f5c1e907c4Copying blob sha256:7da0375eb2ecd60c8f630fc42f4cc36c6d2b3923f404212810c167019169b092Copying config sha256:9f00b68fe5e6bb84503d42c233b5a42d492c28bca1305725319db6fa702e5f04Writing manifest to image destinationError: failed to connect: ssh: handshake failed: EOF[exit 125]

    Expected resultA source image, an empty destination, and blobs copied followed by a handshake failure.

    Success conditionYou have seen the form that looks right and is not.

  2. Name the destination first

    Two things the destination needs: its own podman.socket enabled, and a named connection pointing at it from the source.

    podman system connection add --identity ~/.ssh/id_ed25519 lab02 \
      ssh://sysadmin@192.168.0.22/run/user/1000/podman/podman.sock

    Note the direction. guide 72 set up podman02 → podman01; this is podman01 → podman02, and the two are independent. ssh trust is not symmetric, and this is exactly what the first attempt was missing.

    bash Example session
    systemctl --user is-active podman.socketactivepodman system connection add --identity ~/.ssh/id_ed25519 lab02 ssh://sysadmin@192.168.0.22/run/user/1000/podman/podman.sockpodman system connection lsName        URI                                                              Identity                        Default     ReadWritelab02       ssh://sysadmin@192.168.0.22:22/run/user/1000/podman/podman.sock  /home/sysadmin/.ssh/id_ed25519  true        true

    Expected resultAn active socket on the destination, and a lab02 connection on the source.

    Success conditionThe source can name the destination.

  3. Copy it, and run it there

    $ podman image scp localhost/multi:1 lab02::
    Copying blob sha256:6f09edfb3f6d...
    Writing manifest to image destination
    Loaded image: localhost/multi:1

    Loaded image is the line the first attempt never reached. The destination now lists localhost/multi:1 at 8.66 MB, and running it there prints compiled in a stage that was thrown away - the multi-stage image from guide 33, now on a host that has never built anything.

    The name travels unchanged, including the localhost/ prefix from guide 30 - which reads oddly on the destination, since it came from somewhere else. Append a new name to retag on arrival: podman image scp localhost/multi:1 lab02::app:1.

    When this is the right tool: an air-gapped host, a one-off, a machine where standing up a registry is more work than the transfer. It goes over ssh, needs no daemon and no TLS certificate, and there is nothing left running afterwards.

    When it is not: more than a couple of hosts, or anything repeated. It is a point-to-point copy with no deduplication between destinations and no record of what has which version - which is what a registry is for, and what guide 74 sets up. podman save and podman load remain the answer when the two machines cannot reach each other at all.

    bash Example session
    podman image scp localhost/multi:1 lab02::Copying blob sha256:6f09edfb3f6d7173733adc8eec8ea00626550dc6fc2dcf07d40e13f5c1e907c4Copying blob sha256:7da0375eb2ecd60c8f630fc42f4cc36c6d2b3923f404212810c167019169b092Copying config sha256:9f00b68fe5e6bb84503d42c233b5a42d492c28bca1305725319db6fa702e5f04Writing manifest to image destinationLoaded image: localhost/multi:1podman images --format 'table {{.Repository}} {{.Tag}} {{.Size}}' localhost/multiREPOSITORY       TAG         SIZElocalhost/multi  1           8.66 MBlocalhost/multi  builder     182 MBpodman run --rm localhost/multi:1compiled in a stage that was thrown away

    Expected resultLoaded image, the image listed on the destination, and its output when run there.

    Success conditionAn image built on one host is running on another, with no registry involved.

Troubleshooting

Official sources