Skip to content

Securing Your Install

BJD1997 edited this page Oct 9, 2026 · 2 revisions

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).

Only expose the API to your reverse proxy

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.

  1. Set API_BIND_ADDRESS to the address your reverse proxy connects to: this host's LAN address when the proxy runs on another machine, 127.0.0.1 when it runs on this same host. Then docker compose up -d.

  2. If other machines share that network, also allow only the proxy, in Docker's own DOCKER-USER firewall 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-persistent on Debian/Ubuntu).

Keep the install folder to what the app needs

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 .env

Why 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 updater service from the compose file (and UPDATER_URL from the api). The admin console then shows the manual update steps instead, and nothing in the stack has access to Docker at all.

Use your own database passwords

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.

Microsoft sign-in: choose who can sign in

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.)

Limit what stolen credentials could do

Reports are public input

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).


← Production & Scaling · Home

Clone this wiki locally