[GUIDE] Running Podman Containers on OpenWRT 24.10.2

I recently went through the process of getting Podman running properly on OpenWrt 24.10.2 and configuring it to behave well with OpenWrt’s native networking, firewall setup and daemon startup and configuration logic.
Since some of the information at https://openwrt.org/docs/guide-user/virtualization/docker_host was outdated, I’ve updated parts of it there, and I'm sharing this more complete guide here as well, for those who want a more practical walkthrough.


Installing Podman

First, install Podman using opkg:

opkg install podman

It will pull in a number of dependencies, including networking tools and container runtimes.


Basic Configuration

Storage Setup

Update Podman’s storage path to point to a disk with enough space, this folder, depending how careful you'll select containers, will tend to take quite some space:

/etc/containers/storage.conf

graphroot = "/home/podman/storage"

Then create the directory:

mkdir -p /home/podman/storage

Regular Cleanup

Add cleanup tasks to cron:

crontab -e

Add:

# Podman cleanup
10 0 * * 0 /usr/bin/podman system prune --volumes -f > /dev/null 2>&1
20 0 * * 0 /usr/bin/podman image prune -a -f > /dev/null 2>&1

Networking Setup

We want Podman to use a static bridge and be fully manageable by OpenWrt’s network config and firewall.
Here’s how to set it up:

/etc/containers/networks/podman.json

{
     "name": "podman",
     "driver": "bridge",
     "network_interface": "podman0",
     "subnets": [
          {
               "subnet": "192.168.11.0/24",
               "gateway": "192.168.11.1"
          }
     ],
     "ipv6_enabled": false,
     "internal": false,
     "dns_enabled": true,
     "ipam_options": {
          "driver": "host-local"
     }
}

/etc/containers/containers.conf

[network]
network_backend = "netavark"
firewall_driver = "none"
network_config_dir = "/etc/containers/networks/"
default_network = "podman"
default_subnet = "192.168.11.0/24"
default_rootless_network_cmd = "slirp4netns"

/etc/config/network

config device
        option type 'bridge'
        option name 'podman0'
        option bridge_empty '1'
        option ipv6 '0'

config interface 'podman0'
        option proto 'static'
        option device 'podman0'
        option ipaddr '192.168.11.1'
        option netmask '255.255.255.0'

/etc/config/firewall

Be careful that zone names for other zones must match your configuration

config zone
        option name 'Podman'
        option input 'DROP'
        option output 'ACCEPT'
        option forward 'REJECT'
        list network 'podman0'

config forwarding
        option src 'Podman'
        option dest 'Internet'

config forwarding
        option src 'lan'
        option dest 'Podman'

config rule
        option name 'DNS to Podman'
        option src 'Podman'
        option dest_port '53'
        option target 'ACCEPT'

Giving Access to Container Ports

Since we're using firewall_driver = "none", Podman won't open ports automatically.
If a container needs to be reachable, you'll need to manually create rules.
For this reason I am explicitely adding an IP to each container, more of this later.

Example:

config rule
        option src 'VPN'
        option name 'NRPE to Nagios'
        option dest_port '5666'
        option target 'ACCEPT'
        list proto 'tcp'
        list src_ip '192.168.0.5'
        option dest 'Podman'

config redirect
        option dest 'Podman'
        option target 'DNAT'
        option name 'Serve NRPE from container'
        option family 'ipv4'
        list proto 'tcp'
        option src 'VPN'
        option src_dport '5666'
        option dest_ip '192.168.11.2'
        option dest_port '5666'
        option src_ip '192.168.0.5'

Podman Init Script

Here’s how I run containers at boot using an init script.
The set of parameters it understands is basic, and it's not smart when it comes to enforce containers to have name and images, but it's good enough for me and easy to mod in case needed.
It is configurable via /etc/config/containers and is pretty flexible.

/etc/init.d/containers

START=90
STOP=20
USE_PROCD=1

NAME=containers
PROG=/usr/bin/podman

. /lib/functions.sh

start_service() {
    # At boot time, wait longer for dependencies
    local max_wait=60
    local count=0

    logger -t "$NAME" "Waiting for system readiness"

    # Wait for basic system services
    while [ $count -lt $max_wait ]; do
        # Check if essential services are ready
        if [ -S /var/run/ubus/ubus.sock ] && pgrep -f "ubusd" >/dev/null && \
           [ -d /sys/class/net ] && $PROG system info >/dev/null 2>&1; then
            break
        fi
        sleep 1
        count=$((count + 1))
    done

    if [ $count -ge $max_wait ]; then
        logger -t "$NAME" "Timeout waiting for system services and podman to be ready"
        return 1
    fi

    logger -t "$NAME" "Starting containers service"

    config_load containers
    config_foreach start_container container
}

start_container() {
    local cfg="$1" enabled name

    config_get enabled "$cfg" enabled 0
    config_get name "$cfg" name "$cfg"
    config_get image "$cfg" image "$cfg"

    config_get dns "$cfg" dns ""
    config_get hostname "$cfg" hostname ""
    config_get image "$cfg" image ""
    config_get ip "$cfg" ip ""
    config_get memory "$cfg" memory ""
    config_get pid "$cfg" pid ""
    config_get pull "$cfg" pull "missing"
    config_get restart "$cfg" restart ""

    envs=""
    append_env() {
        envs="$envs -e $1"
    }
    config_list_foreach "$cfg" env append_env

    vols=""
    append_vol() {
        vols="$vols -v $1"
    }
    config_list_foreach "$cfg" volume append_vol

    [ "$enabled" -eq 0 ] && return 0

    logger -t "$NAME" "Starting container $name"
    logger -t "$NAME" "Pulling latest version for $name - $image"

    $PROG pull $image  >/dev/null 2>&1 || logger -t "$NAME" "Pulling failed for $image"

    # Build the Podman command
    podman_cmd="$PROG run -d"
    [ -n "$dns" ] && podman_cmd="$podman_cmd --dns $dns"
    [ -n "$hostname" ] && podman_cmd="$podman_cmd --hostname $hostname"
    [ -n "$ip" ] && podman_cmd="$podman_cmd --ip $ip"
    [ -n "$memory" ] && podman_cmd="$podman_cmd --memory $memory"
    [ -n "$pid" ] && podman_cmd="$podman_cmd --pid $pid"
    [ -n "$restart" ] && podman_cmd="$podman_cmd --restart $restart"
    podman_cmd="$podman_cmd $envs $vols --name $name $image"

    logger -t "$NAME" "Running '$podman_cmd'"

    procd_open_instance "$name"
    procd_set_param command sh -c "
        $podman_cmd || exit 1
        exec $PROG wait '$name'
    "
    procd_set_param respawn
    procd_close_instance
}

stop_service() {
    config_load containers
    config_foreach stop_container container
}

stop_container() {
    local cfg="$1" name
    config_get name "$cfg" name "$cfg"
    $PROG stop "$name" 2>/dev/null
    $PROG rm "$name" 2>/dev/null
}

# Standard init handlers
start() { start_service; }
stop() { stop_service; }
restart() { stop; start; }
reload() { stop; start; }

Make it executable:

chmod +x /etc/init.d/containers

And enable it for next boot

/etc/init.d/containers enable

Example Container Config

/etc/config/containers

config container 'test'
    option enabled '1'
    option name 'test'
    option dns '9.9.9.9'
    option image 'quay.io/podman/hello'
    option memory '64m'
    option hostname 'hello'
    option ip '192.168.11.2'
    option pid 'host'
    option restart 'unless-stopped'
    list env 'TZ=Europe/Amsterdam'
    list volume '/etc/openwrt_release:/etc/openwrt_release:ro'
    list volume '/home/test_container/etc/:/etc/test'
    list cmd 'ping'
    list cmd '-c'
    list cmd '4'
    list cmd '192.168.11.1'

Preserving Configs During Sysupgrade

Add this to /etc/sysupgrade.conf:

/etc/containers
/etc/config/containers
/etc/init.d/containers
/home/

Hope this helps someone!

2 Likes

Great work, would you consider adding this to the official wiki?

Wiki is a good first step I am wondering though whether we should clean up some of the scripts and integrate them into the package.

It's a good idea but reviewing the changes might be a lenghty process.

I spent some time during holidays to make podman work and write this document, I am happy to bring this further but I will need some help if this is an involved task.
Let me know what’s your suggestion and if someone can help :slight_smile:

My suggestion is again to do it on the wiki. Forum is indeedindexed by searched engine and most likely LLMs but not the best place to share colaborative documentation.

The current guide on the wiki (https://openwrt.org/docs/guide-user/virtualization/docker_host?s[]=podman) is a bit different from the approach I have taken.
I would have to either spend time understanding overlaps, edit and merge, or delete what’s there and replace, but I am not comfortable enough doing so.
What now?

add a new topic https://openwrt.org/docs/guide-user/virtualization/podman

Done. Cheers :slight_smile:

1 Like

Great work - on behalf of this community- thank you!