Docker
Status: draft
The repository has a multi-stage Dockerfile and a docker-compose.yml. The build stage (rust:1-bookworm) downloads Trunk, builds the web UI and the release binary; the runtime image (debian:bookworm-slim) holds only wpg, curl (for the health check) and the sample templates in /usr/share/wpg/templates.
Build
docker build -t wpg .
docker build -t wpg --build-arg FEATURES=pcap . # with the libpcap backend
The build needs Internet access: crates.io, the Trunk release on GitHub, and the Tailwind CSS and wasm-bindgen tools that Trunk downloads. Behind a TLS-intercepting proxy, pass the proxy’s CA certificate (PEM) as a build secret and the proxy address as the standard build arguments. The certificate is trusted in the build stage only and does not end up in the runtime image:
docker build -t wpg --secret id=ca_certs,src=/path/to/proxy-ca.pem \
--build-arg HTTPS_PROXY=http://proxy.example:3128 .
If Docker Hub rate-limits anonymous pulls, the base images can be taken from another registry with --build-arg RUST_IMAGE=mirror.gcr.io/library/rust:1-bookworm --build-arg RUNTIME_IMAGE=mirror.gcr.io/library/debian:bookworm-slim.
Run
Sending on the host’s interfaces needs the host network namespace and two capabilities. Everything else is dropped:
docker run -d --name wpg --network host \
--cap-drop ALL --cap-add NET_RAW --cap-add NET_ADMIN \
-e WPG_PASSWORD='change me' \
-e WPG_TX__ALLOWED_IFACES='["eth1"]' \
-v wpg-data:/var/lib/wpg \
wpg
Or with Compose (reads WPG_PASSWORD, WPG_BIND, WPG_ALLOWED_IFACES and WPG_FEATURES from the environment or a .env file):
WPG_PASSWORD='change me' WPG_ALLOWED_IFACES='["eth1"]' docker compose up -d --build
docker compose ps # shows "healthy" once /api/health answers
docker compose logs -f wpg
| Setting | Image default | Notes |
|---|---|---|
WPG_SERVER__BIND | 0.0.0.0:8080 | With --network host this is the host’s port. Use 127.0.0.1:8080 to keep it local. |
WPG_PASSWORD | none | Required for a non-loopback bind: the server refuses to start otherwise. A plain password or an argon2id hash. WPG_AUTH__PASSWORD_FILE=/run/secrets/... works with Docker secrets. |
WPG_DATA_DIR | /var/lib/wpg (volume) | Database, user templates, TLS certificate. |
WPG_TEMPLATES__LIBRARY_PATHS | ["/usr/share/wpg/templates"] | Mount your own library and add its path. |
WPG_TX__ALLOWED_IFACES | all | Interfaces jobs may send on. |
Other settings: any WPG_<SECTION>__<KEY> variable, or mount a wpg.toml and set WPG_CONFIG. See the configuration reference.
The process runs as root inside the container, but with only CAP_NET_RAW and CAP_NET_ADMIN. A non-root user would need file capabilities on the binary, which fail to execute when the container’s capability set lacks one of them, so the image keeps it simple.
Limits
- Use Linux hosts. Docker Desktop on macOS and Windows runs containers inside a VM:
--network hostthere is the VM’s network, so frames never reach your physical NIC. wpg doctorinside the container reports the container’s view (capabilities, interfaces). The image is built without thedpdkfeature (it would need the DPDK libraries in both stages); hugepages andvfio-pcifor DPDK are prepared on the host in any case.- Without
--network host(the default bridge network with-p 8080:8080) the GUI works, but jobs can only send on the container’s owneth0.
Verification status
Checked in October 2026 (Docker 29.8, Linux 6.18 host, image without extra features):
docker buildcompleted (Trunk web UI andcargo build --release --locked); the runtime image is about 170 MB on disk (44 MB compressed).docker run --network host --cap-drop ALL --cap-add NET_RAW --cap-add NET_ADMIN -e WPG_PASSWORD=...: the health check turnedhealthy,/api/healthand the web UI answered, andwpg doctorinside the container reported raw sockets withCAP_NET_RAW/CAP_NET_ADMIN.wpg sendwith theafpacketbackend onloinside the container sent 100 frames, andwpg capturein the same container received them.--build-arg FEATURES=pcap: the image shipslibpcap0.8,wpg doctorfinds it, andwpg send --backend pcapsent 50 frames onlo.docker compose up -d --no-build: the service turnedhealthy, login withWPG_PASSWORDsucceeded (204) and a wrong password was refused (401). WithoutWPG_PASSWORD, compose refuses to start with the message from the compose file.
The development sandbox only allows HTTPS through its proxy, so apt-get there had to be pointed at https://deb.debian.org with a throw-away copy of the Dockerfile; the Dockerfile in the repository was otherwise used unchanged. Docker Desktop (macOS / Windows) was not checked.