Repository navigation
Securing Your Install
What to check on a Docker Compose or Portainer install, beyond the defaults. The app itself already runs as a non-root user on a read-only filesystem (v0.2.0 and later).
The compose files publish the API on port 8000 (the demo on 8001). By default that's on every interface of the host, and Docker's published ports bypass host firewalls such as UFW: a UFW rule won't block them.
-
Set
API_BIND_ADDRESSto the address your reverse proxy connects to: this host's LAN address when the proxy runs on another machine,127.0.0.1when it runs on this same host. Thendocker compose up -d. -
If other machines share that network, also allow only the proxy, in Docker's own
DOCKER-USERfirewall chain (UFW doesn't apply here):# Only the proxy (10.21.0.10 here) may reach the published port 8000. sudo iptables -I DOCKER-USER -p tcp -m conntrack --ctorigdstport 8000 --ctdir ORIGINAL ! -s 10.21.0.10 -j DROP
Make it survive a reboot with your distribution's tooling (for example
iptables-persistenton Debian/Ubuntu).
The install folder should hold only what the stack uses: the compose file,
.env, and the db/ and resolver/ folders that come with the release.
Keep everything else (notes, exports, database dumps, older copies of
.env) somewhere else, readable only by you, and keep .env itself private:
chmod 600 .envWhy it matters: the updater container reads the install folder to run updates, and it can control Docker through the Docker socket, which amounts to root on the host. If the updater were ever compromised, whoever controls it could read everything in that folder, and through Docker reach the rest of the host as well. So:
- Keep the folder clean, as above, so a compromised updater finds nothing beyond what the stack itself needs.
- If you don't use Update now, remove the
updaterservice from the compose file (andUPDATER_URLfrom the api). The admin console then shows the manual update steps instead, and nothing in the stack has access to Docker at all.
The compose files fall back to example passwords (dmarc, dmarc_app) when
POSTGRES_PASSWORD and DMARC_APP_DB_PASSWORD aren't set. The log shows a
SETUP PROBLEM line when they're still in use. On an existing install,
change the password in the database first (ALTER ROLE ... PASSWORD), then
in the env.
Anyone in a linked Microsoft tenant can sign in, and the first person to do so becomes the organization's admin. In each customer's tenant, open Entra → Enterprise applications → the sign-in app → Properties, set Assignment required to Yes, and assign only the people who should use the dashboard, the intended admin first. (Planned for v0.3.0: the platform admin names the expected admin when creating the organization.)
- Microsoft mail app: limit it to the reports mailbox, see Onboarding Your First Organization step 3.
- Cloudflare token: DNS edit on one zone only, with an IP filter and an expiry date, see the Configuration Reference.
Anyone can send a DMARC report to a domain's rua= address, including the
hosted one: it's in public DNS. Reports from senders that fail the report
sender check are left out (Settings → General), but a sender with its own
DMARC-protected domain can pass it. Treat sudden, unexplained senders with
care before approving or blocking them. Oversized messages (over 25 MB) are
skipped and the worker has a memory limit (WORKER_MEMORY_LIMIT, default
1 GB).
← Back to the README · Live demo · Report an issue · MIT licensed
- Quick Start: Docker Compose
- Deploying with Portainer
- Deploying on Azure
- Configuration Reference
- Onboarding an Organization
- IMAP Mailbox
- Google Workspace Mailbox
- Sign-in Providers
- Multi-Tenancy & RLS
- DMARC Subdomain Inheritance
- Report Attribution
- SPF Conditional Mode
- Detected Domains
- DNS Check Scheduling
- Domain Rating
🏗️ Architecture
🗺️ Roadmap