compose.yml
Minimum viable setup — port 3000, one named volume, two env vars:
services:
maillayer:
image: ghcr.io/mddanishyusuf/maillayer-pro:1
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- maillayer-data:/app/data
environment:
AUTH_SECRET: ${AUTH_SECRET}
APP_URL: ${APP_URL}
volumes:
maillayer-data:Create .env next to your compose file with both values:
# Required: public URL where this install is reachable.
# Used for tracking-link generation, unsubscribe URLs, and the
# domain reported to the license server during activation.
APP_URL=https://maillayer.example.com
# Required (or generated on first boot — see callout below).
# Decrypts every stored provider credential — back this up.
AUTH_SECRET=$(openssl rand -base64 48)Then start it:
docker compose up -dAPP_URL, the install falls back tohttp://localhost:3000 internally — license activation will fail withinvalid_domain and tracking links inside emails will point at localhost. Set it to whatever your reverse proxy serves the install at (e.g.https://maillayer.example.com)./app/data/.auth_secret in the volume. Subsequent restarts pick it up automatically. Just don't lose the volume.Coolify
New Application → Docker Image → enter ghcr.io/mddanishyusuf/maillayer-pro:1. In the volumes tab map/app/data to a Coolify-managed volume. Set AUTH_SECRET in the environment variables tab.
CapRover / Dokploy
Both accept a docker-compose.yml directly. Paste the snippet above into their compose UI, set the env vars, deploy.
Tag pinning
:1— pinned to major version 1 (recommended). Pulls patches and minors; never breaking changes.:1.0.0— exact version. Maximum stability, manual updates.:latest— always the most recent release. Risky if breaking changes ship.
Reverse proxy / TLS
The container speaks plain HTTP on port 3000. Front it with Caddy, Traefik, nginx, or Coolify's built-in proxy. Update APP_URL to match the public HTTPS URL once your proxy is live (e.g. https://mail.example.com) and docker compose up -d --force-recreate so the change takes effect — both license activation and tracking links read from this env var.
Maillayer auto-detects when its bundled Caddy sidecar isn't present (xcloud, Coolify, and any compose without it) and hides the in-app Settings → Domain page. To make that explicit and skip the runtime detection, set MAILLAYER_NO_CADDY=1 in your environment:
environment:
AUTH_SECRET: ${AUTH_SECRET}
APP_URL: ${APP_URL}
MAILLAYER_NO_CADDY: "1"