Prerequisites
- A Linux VPS (Ubuntu 22.04+ recommended; anything with a modern kernel works).
- Root or sudo access — the installer writes to
/opt/maillayerand starts Docker containers. - Ports
80,443, and8024free on the host. (Skip the Caddy sidecar withMAILLAYER_NO_CADDY=1if you bring your own reverse proxy — see below.)
You don't need to install Docker first. If Docker isn't already on the box, the script runs Docker Inc's official installer (get.docker.com) for you. Skip this with MAILLAYER_NO_AUTO_DOCKER=1 if you manage Docker yourself.
Install
SSH into the box and run:
curl -fsSL https://install.maillayer.com/install.sh | sudo bashThe script does six things, in order:
- Auto-installs Docker + Compose v2 if they aren't already present. Waits for any in-progress
aptprocesses (cloud-init, unattended-upgrades) to finish first — fresh VPSes commonly have those running for the first 1–3 min after boot. - Checks the required ports are free. Fails fast with a clear remediation hint if 80, 443, or 8024 is already taken.
- Generates a random
AUTH_SECRETand saves it at/opt/maillayer/.env(mode 600). Re-runs preserve this value — rotating it would invalidate every encrypted credential in the database. - Writes
docker-compose.ymlwith two services:caddyon the public 80 + 443 (handles HTTPS) andmaillayeron host port 8024 (the dashboard). - Pulls the images and starts both containers with named volumes for the SQLite database and Caddy's cert state.
- Polls
/api/healthuntil it returns 200, then prints the dashboard URL.
Total time: ~30s on a box that already has Docker, ~90s if Docker is auto-installed.
curl -fsSL https://install.maillayer.com/install.sh -o install.sh
less install.sh
sudo bash install.shFirst sign-in
Open http://<your-server-ip>:8024 in a browser. The first account that signs up becomes the install owner. From there you'll create your first brand, configure an email provider, and (optionally) attach a custom domain — all from the dashboard.
Add a custom domain (built-in HTTPS)
The bundled Caddy sidecar is wired up at install time but stays inert until you give it a domain. To attach one:
- Point an
Arecord for your domain at this server's public IP. (If you use Cloudflare, set the proxy to DNS only — gray cloud — until the cert issues. You can re-enable orange-cloud proxy afterwards with SSL mode set to "Full (strict)".) - In the dashboard, go to Settings → Domain. Enter your domain and a contact email.
- Click Save & request certificate. Caddy issues a Let's Encrypt cert in the background (typically 30–60s). The status pill flips from Issuing cert… to Live once it's done.
Certificates are auto-renewed by Caddy — there's nothing to renew on your side. See Custom domain for the full flow including common DNS gotchas.
Override install defaults
Pass env vars before the curl command:
MAILLAYER_PORT=8080 \
MAILLAYER_DIR=/var/lib/maillayer \
curl -fsSL https://install.maillayer.com/install.sh | sudo -E bash| Env var | Default | What it does |
|---|---|---|
MAILLAYER_DIR | /opt/maillayer | Install root. |
MAILLAYER_PORT | 8024 | Local-IP dashboard port (always exposed for SSH-tunnel access). |
MAILLAYER_URL | (empty) | Public URL — set this if you proxy externally and aren't using the bundled Caddy. |
MAILLAYER_IMAGE | ghcr.io/mddanishyusuf/maillayer-pro:1 | Image tag. Pin to a specific version like :v1.2.4 to lock. |
MAILLAYER_NO_CADDY | 0 | Set to 1 to skip the bundled Caddy — bring your own reverse proxy. |
MAILLAYER_NO_AUTO_DOCKER | 0 | Set to 1 to disable the Docker auto-install. |
Bring your own reverse proxy
Already running nginx, Traefik, or Cloudflare Tunnel on the box? Skip the bundled Caddy sidecar:
MAILLAYER_NO_CADDY=1 \
curl -fsSL https://install.maillayer.com/install.sh | sudo -E bashThe installer writes a single-service compose file (only maillayer, no Caddy) and exposes port 8024 on the host. Point your existing proxy at localhost:8024 and set APP_URL in /opt/maillayer/.env to your public URL so tracking links resolve correctly. The Settings → Domain page will render a "Managed externally" notice instead of the cert-request form.
server {
listen 443 ssl;
server_name mail.example.com;
ssl_certificate /etc/letsencrypt/live/mail.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mail.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8024;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Day-to-day
- Logs (everything):
docker compose -f /opt/maillayer/docker-compose.yml logs -f - Logs (just one service):
docker compose -f /opt/maillayer/docker-compose.yml logs -f maillayer - Update to latest 1.x:
cd /opt/maillayer && docker compose pull && docker compose up -d - Re-run installer (also pulls latest):
curl -fsSL https://install.maillayer.com/install.sh | sudo bash— detects an existing install, preserves yourAUTH_SECRET, and force-recreates containers so config changes take effect. - Stop:
cd /opt/maillayer && docker compose down(data persists in volumes) - Backup: see Backups — TL;DR is to copy
/opt/maillayer/.env+ the SQLite volume.
Pinning to a specific version
The default :1 tag is rolling — it always points at the latest 1.x release. To pin a specific version (e.g. for a production install where you want explicit upgrades):
MAILLAYER_IMAGE=ghcr.io/mddanishyusuf/maillayer-pro:v1.2.4 \
curl -fsSL https://install.maillayer.com/install.sh | sudo -E bashAfter install, edit /opt/maillayer/docker-compose.yml and bump the image: line whenever you want to upgrade.
Uninstall
cd /opt/maillayer && docker compose down -v
sudo rm -rf /opt/maillayerdown -v removes the named volumes too, so this is destructive — your SQLite database and Caddy's cert state both go away. Back up first if you want to keep anything.