How to load container for offline use?

So Im trying to use VyOS as a container-host in an environment where the VyOS installation wont be able to reach internet as in not having access to a registry such as docker.io.

At first I tried to figure out a way to setup your own private registry.

I was thinking of having an easy way similar to when you need a quick http-server you can just run:

python3 -m http.server 8000

But it turned out to be more complicated than I wanted (unless someone have some tips?).

So instead I tried to save/load the container as a tar-file, like so:

Create a local “mirror” of the container (on a computer with internet access):

docker pull docker.io/technitium/dns-server:latest
docker save -o ~/docker/technitium_dns-server_`date +%Y-%m-%d`.tar docker.io/technitium/dns-server:latest
gzip -9 ~/docker/technitium_dns-server_2026-06-18.tar

Optionally the pulled image can be removed using “docker rmi [id]”.

Transfer gzip-file to VyOS using scp:

scp ~/docker/technitium_dns-server_2026-06-18.tar vyos@192.0.2.1:/config

Then on VyOS:

gunzip /config/technitium_dns-server_2026-06-18.tar.gz
podman load -i /config/technitium_dns-server_2026-06-18.tar

To verify that its loaded:

podman images

would output something like:

REPOSITORY                       TAG         IMAGE ID      CREATED      SIZE
docker.io/technitium/dns-server  latest      ba2762a21fbd  5 weeks ago  275 MB

To create directories needed for the container:

mkdir -p /config/dns-server/config
mkdir -p /config/dns-server/logs

Reference regarding defaults and available options for the particular container:

Config in VyOS:

set container name dns-server allow-host-networks
set container name dns-server capability 'net-bind-service'
set container name dns-server environment DNS_SERVER_WEB_SERVICE_LOCAL_ADDRESSES value '192.0.2.1'
set container name dns-server image 'docker.io/technitium/dns-server:latest'
set container name dns-server memory '4096'
set container name dns-server port dns-tcp destination '53'
set container name dns-server port dns-tcp protocol 'tcp'
set container name dns-server port dns-tcp source '53'
set container name dns-server port dns-udp destination '53'
set container name dns-server port dns-udp protocol 'udp'
set container name dns-server port dns-udp source '53'
set container name dns-server port mgmt-http destination '5380'
set container name dns-server port mgmt-http protocol 'tcp'
set container name dns-server port mgmt-http source '5380'
set container name dns-server restart 'on-failure'
set container name dns-server volume config destination '/etc/dns'
set container name dns-server volume config source '/config/dns-server/config'
set container name dns-server volume logs destination '/var/log/technitium/dns'
set container name dns-server volume logs source '/config/dns-server/logs'

But then I get stuck…

When doing commit of above Im getting:

[ container ]

WARNING: Image "docker.io/technitium/dns-server:latest" used in
container "dns-server" does not exist locally. Please use "add
container image docker.io/technitium/dns-server:latest" to add it to
the system! Container "dns-server" will not be started!

So somehow the vyos-configd doesnt fully understand that podman already have the image loaded.

So ehm, what to do next? :slight_smile:

Sometimes for testing I create images and load them onto VyOS using podman load as well, and the path I use to reference it is localhost/mycontainer:latest and it works fine.

Also instead of running podman images try show container image to see if the VyOS system sees your image.

vyos@vyos:/config$ podman images
REPOSITORY                       TAG         IMAGE ID      CREATED      SIZE
docker.io/technitium/dns-server  latest      ba2762a21fbd  5 weeks ago  275 MB

vyos@vyos:/config$ show container image 
REPOSITORY  TAG         IMAGE ID    CREATED     SIZE

Its like nope…

Turns out that you must use sudo when operating with podman in VyOS.

Got a hint of this in my thread with same content over at Reddit so I repost the findings here:

So I started over from a backup.

Now the image only exists when doing “sudo podman images” (imported through “sudo podman load -i [FILENAME]”):

vyos@vyos:~$ sudo podman images
REPOSITORY                       TAG         IMAGE ID      CREATED      SIZE
docker.io/technitium/dns-server  latest      ba2762a21fbd  5 weeks ago  275 MB

Now I add this to the config (no previous container config or custom private registry):

set container name dns-server allow-host-networks
set container name dns-server capability 'net-bind-service'
set container name dns-server environment DNS_SERVER_WEB_SERVICE_LOCAL_ADDRESSES value '192.0.2.1'
set container name dns-server image 'docker.io/technitium/dns-server:latest'
set container name dns-server memory '4096'
set container name dns-server restart 'on-failure'
set container name dns-server volume config destination '/etc/dns'
set container name dns-server volume config source '/config/dns-server/config'
set container name dns-server volume logs destination '/var/log/technitium/dns'
set container name dns-server volume logs source '/config/dns-server/logs'

And then run commit followed by save - no errors.

Doing a “sudo podman container ls” I can see it successfully started:

    vyos@vyos:~$ sudo podman container ls
    CONTAINER ID  IMAGE                                   COMMAND     CREATED         STATUS         PORTS       NAMES
    30eb4f60027f  docker.io/technitium/dns-server:latest  /etc/dns    27 seconds ago  Up 27 seconds              dns-server

And also verified by from a client visiting http://192.0.2.1:5380

Note that in above example Im using VRF’s so the container will use one interface (192.0.2.1 being in VRF_MGMT) for mgmt and another interface (being in VRF_PROD) for the actual service (being a DNS-server in this case).

For this to work in VyOS you need to add this to the config:

set vrf bind-to-all

Ah yes I should have seen that. Podman does namespace that data based on the user calling it, unlike docker. So sudo always has to be used. I’m just used to always doing sudo on VyOS when running a shell command so didn’t even think of it. :grinning_face: