Docker Compose Deployment
This guide covers deploying CheeseWAF on containerized infrastructure. The repository provides a hardened Dockerfile and Compose example; the example builds the image locally. Do not treat cheesewaf:dev as a vendor-signed or registry-published image unless you have separately verified the image provenance. The runtime is configured to run as an unprivileged user (UID 10001) with a read-only root filesystem.
Compose Configuration
Reference deploy/docker/docker-compose.yml:
When building locally, ensure the build context points to the root of the CheeseWAF repository so both the frontend (web/) and backend Go modules build successfully.
The sample 8080:8080 mapping publishes the data-plane listener on all Docker host interfaces. Put it behind an intentional firewall/reverse-proxy policy, or bind it to a controlled interface; only the admin mapping is loopback-bound by default.
Launching & Initialization
Start the container daemon and view logs:
On initial startup, the container generates self-signed TLS certificates for the admin API. This Compose file binds the admin port to the Docker host’s loopback interface (127.0.0.1:9443), so open https://127.0.0.1:9443/setup on the Docker host. From another machine, set CHEESEWAF_SSH_TARGET to your SSH target and create a tunnel with ssh -N -L 9443:127.0.0.1:9443 "$CHEESEWAF_SSH_TARGET", then use the same local URL; if you intentionally change the port binding, apply an appropriate access-control policy. You can also run the CLI wizard inside the container:
While first-install setup is pending, the container log never prints the setup token or complete URL. It shows only the base /setup URL, the protected /var/lib/cheesewaf/setup.url path, and an opaque receipt. Read the complete URL from that mode 0600 file within its 10-minute validity period. After setup completes, the token is revoked; expired setup.url files are cleaned up.
Stopping containers with docker compose -f deploy/docker/docker-compose.yml down safely preserves SQLite data, certificates, and log streams inside the named volumes cheesewaf-data and cheesewaf-logs. If storage.postgresql is configured, it receives external access-log records; the Docker volume still contains the management database for the default storage.profile: temporary. The reserved production profile currently fails closed at startup.