Routing fixes (2026-07-14): - Add missing ip rule 'from 10.11.13.0/24 lookup 100' to hotplug ifup case - Add UCI network rule persistence so netifd restores it on boot - Verify ip rule exists in zt-gateway-switch do_force/do_graceful - Fix BRIDGE_PORTS auto-detect: use /proc/net/dev instead of broken awk-over-ip pipeline (busybox awk mishandles exit in compound if) - Validate bridge port candidate exists as network interface - Fix setup-routing: use dev br-zt not dev ztX (ZT iface has no IP when enslaved to bridge, causing 'Nexthop has invalid gateway') - Replace ip rule replace (GNU-only) with del+add for busybox Infrastructure: - Fix deploy:install stdin starvation: ssh/scp consume pipe data in find|while loop; add </dev/null to prevent truncation - Move luci-dev skill from root/ to skills/ with .agents/skills/ symlink - Add policy routing and busybox gotcha sections to SKILL.md - Add diagnostics doc for the routing fix session
3.0 KiB
3.0 KiB
OpenWrt Docker Build Reference
Dockerfile Template
FROM openwrt/rootfs:latest
# Install LuCI and dependencies.
# Build this image with podman (NOT docker buildx) because Podman-backed Docker
# seccomp blocks uclient-fetch syscalls at a level BuildKit cannot override.
RUN mkdir -p /etc/apk/repositories.d /var/lock /var/run /www && \
printf \
'https://downloads.openwrt.org/snapshots/targets/x86/64/packages/packages.adb\n\
https://downloads.openwrt.org/snapshots/packages/x86_64/base/packages.adb\n\
https://downloads.openwrt.org/snapshots/packages/x86_64/luci/packages.adb\n\
https://downloads.openwrt.org/snapshots/packages/x86_64/packages/packages.adb\n\
https://downloads.openwrt.org/snapshots/packages/x86_64/routing/packages.adb\n' \
> /etc/apk/repositories.d/distfeeds.list && \
apk add --no-cache --allow-untrusted \
luci-base luci-mod-admin-full luci-proto-ppp \
uhttpd uhttpd-mod-ubus ucode-mod-lua \
ca-certificates curl
# Application files (self-contained image; compose may override with volumes)
COPY root/usr/sbin/zt-gateway-switch /usr/sbin/zt-gateway-switch
RUN chmod +x /usr/sbin/zt-gateway-switch && \
rm -f /var/run/zt-gateway-drain.* /tmp/zt-gw-stderr /tmp/zt-gw-out-*
COPY docker/openwrt-luci-entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
EXPOSE 80
ENTRYPOINT ["/entrypoint.sh"]
Build Commands
Use Podman (image storage is shared with Docker on Podman-backed systems):
podman build --security-opt seccomp=unconfined \
-t zt-gateway-luci:dev \
-f Dockerfile.openwrt .
Then start the stack with Docker Compose (it will find the already-built image):
docker compose up -d
Why Docker BuildKit Fails
Podman applies seccomp filtering at the OCI runtime level. BuildKit's RUN --security=insecure only affects BuildKit's internal seccomp sandbox, not the Podman runtime sandbox. Therefore docker buildx build --allow security.insecure still blocks musl-libc syscalls used by uclient-fetch.
podman build --security-opt seccomp=unconfined passes the flag directly to the runtime, bypassing both Podman and crun seccomp profiles, allowing apk add to function.
Common Issues
| Problem | Root Cause | Fix |
|---|---|---|
wget: Operation not permitted |
BuildKit/Podman seccomp blocks musl-libc syscalls used by uclient-fetch |
Use podman build --security-opt seccomp=unconfined |
wget: exited with error 8 |
APKINDEX.tar.gz 404; OpenWrt uses packages.adb |
Append /packages.adb to repo URLs |
UNTRUSTED signature |
Base rootfs lacks OpenWrt apk signing keys | apk add --allow-untrusted |
| Post-install script fails | /var/lock missing; procd scripts try to create lockfiles |
mkdir -p /var/lock /var/run before apk add |
uhttpd: not found |
Base image lacks web server | Explicitly install uhttpd uhttpd-mod-ubus |
conntrack-tools missing |
Kernel-userland packages don't exist as apk packages | Skip them; container shares host kernel |
sleep 0.5 fails |
busybox sleep only supports integer seconds |
Use sleep 1 |