Deploy with Docker Compose
This guide runs NullWard on a single Linux host with Docker Compose. The stack has three containers, plus an optional fourth for malware scanning: Container Image nullward harbor.sageisg.com/nullward/waf surrealdb surrealdb/surrealdb:v2 valkey valkey/valkey:8-alpine clamav (optional) clamav/clamav Before you start A Linux host with Docker Engine and the Docker Compose plugin. DNS records for the domains you want to protect, pointing at this host. Ports 80 and 443 reachable from the internet. Port 80 is needed for HTTP-to-HTTPS redirects and for Let's Encrypt HTTP-01 validation. A trusted network path to the host for administrators: an office network, VPN or bastion host. You'll use it to reach the management port. 1. Create the project directory 2. Create the .env file NullWard reads only a few environment variables, enough to start up and reach its database. Everything else is configured in the admin dashboard and stored in the database. Generate the secrets: Create /opt/nullward/.env: Protect it: chmod 600 .env. [!WARNING] NULLWARD_ENCRYPTION_KEY encrypts the secrets NullWard stores in the database: identity-provider client secrets, API keys for threat feeds and other providers, DNS credentials, tunnel keys and uploaded private keys. It must be base64 that decodes to exactly 32 bytes, which is what the openssl command above produces. Back it up. If you lose it, those secrets can't be decrypted. Every node of a cluster needs the same key and the same JWT secret. [!NOTE] The admin account named by NULLWARD_ADMIN_USERNAME is created on first start. Its password is reset to NULLWARD_ADMIN_PASSWORD every time NullWard starts, so change the password in .env and restart, not in the dashboard. All environment variables Variable Default Purpose NULLWARD_JWT_SECRET (required) Signs admin sessions NULLWARD_ENCRYPTION_KEY (required) Encrypts secrets at rest (base64, 32 bytes) NULLWARD_ADMIN_PASSWORD (required) Password of the bootstrap admin account NULLWARD_ADMIN_USERNAME admin Username of the bootstrap admin account NULLWARD_DB_HOST / NULLWARD_DB_PORT 127.0.0.1 / 7051 SurrealDB address NULLWARD_DB_NAMESPACE / NULLWARD_DB_DATABASE nullward / waf SurrealDB namespace and database NULLWARD_DB_USERNAME / NULLWARD_DB_PASSWORD root / root SurrealDB credentials NULLWARD_KEYDB_HOST / NULLWARD_KEYDB_PORT 127.0.0.1 / 7053 Valkey address (the variable names are historical) NULLWARD_KEYDB_PASSWORD / NULLWARD_KEYDB_DB (empty) / 0 Valkey password and database number NULLWARD_WEB_HOST / NULLWARD_WEB_PORT 0.0.0.0 / 7052 Management (admin dashboard and API) listener NULLWARD_PROXY_HTTP_ADDR 0.0.0.0:7050 Proxy HTTP listener NULLWARD_PROXY_ADDR 0.0.0.0:7443 Proxy HTTPS listener (and HTTP/3 over UDP) NULLWARD_HTTPS_REDIRECT_PORT (empty = 443) Public HTTPS port used in HTTP-to-HTTPS redirects NULLWARD_LOG_LEVEL info debug, info, warn or error 3. Create docker-compose.yml Replace 10.0.0.5 with an address on your trusted management network (see Protect the management port). The database and Valkey publish no ports. Only NullWard talks to them, over the Compose network. Optional: malware scanning To scan uploads with ClamAV, add this service: Add clamav_data: under volumes:. Then, in the dashboard, set Settings > Malware Scanner > ClamAV Host to clamav. ClamAV takes a few minutes to download its signatures on first start. 4. Start the stack 5. Sign in From a machine on your trusted network, open http://10.0.0.5:7052 (your management address) and sign in with NULLWARD_ADMIN_USERNAME and NULLWARD_ADMIN_PASSWORD. Then: Settings > Authentication > Admin External URL: set the address administrators use to reach the dashboard, for example https://waf-admin.example.com. It's used for admin single sign-on redirects and in tunnel install commands. Settings > License: paste your license key, if you have one. See License. Services > Services > Add Service: protect your first application. See Services. Protect the management port Port 7052 serves the admin dashboard and…
NullWard documentation