INSTALL GUIDE · UBUNTU / DEBIAN VPS
Blue Folder Mail on a VPS
A bare Ubuntu or Debian server. Two routes: Docker Compose (recommended, identical everywhere) or Node 20+ under systemd if you'd rather not run Docker.
Prerequisites
- Ubuntu 22.04+ / Debian 12+ with SSH access and sudo.
- A domain name with an A record pointing at the server's IP (for HTTPS).
- Ports 80/443 open to the internet; app port 8080 stays internal behind the proxy.
- A Resend account; an inbound provider (Mailgun / SendGrid / Postal / Resend) for receiving.
Route A — Docker Compose (recommended)
- Install Docker
curl -fsSL https://get.docker.com | sh
Ships the engine and the Compose plugin. - Install Blue Folder Mail
curl -fsSL https://raw.githubusercontent.com/gordonvividtone/bluefolder-mail/main/install.sh | bash
Or clone, cp .env.example .env, set INBOUND_SECRET + RESEND_API_KEY, then docker compose up -d.
- Create your mailbox
Open http://SERVER_IP:8080 (or finish HTTPS first), generate your key and save the backup password.
Data persists in the bfm-data volume. This is exactly the Docker guide — see it for S3 storage and update commands.
Route B — Node + systemd (no Docker)
Requires Node 20+ (Node 22.5+ uses the built-in node:sqlite; otherwise the better-sqlite3 native module is built automatically).
- Get the code
sudo mkdir -p /opt/bluefolder-mail sudo chown $USER /opt/bluefolder-mail git clone https://github.com/gordonvividtone/bluefolder-mail.git /opt/bluefolder-mail cd /opt/bluefolder-mail npm install cp .env.example .env # edit it
- Verify the full seal → store → decrypt path
npm run smoke
- Run it under systemd
Create /etc/systemd/system/bluefolder-mail.service:
[Service] WorkingDirectory=/opt/bluefolder-mail EnvironmentFile=/opt/bluefolder-mail/.env ExecStart=/usr/bin/node server/server.js Restart=always User=bluefolder [Install] WantedBy=multi-user.target
Then sudo systemctl enable --now bluefolder-mail. It listens on http://localhost:8080.
Storage & sending
- Storage — local disk by default (the SQLite index + sealed blobs). For object storage set STORAGE_BACKEND=s3 and the S3_* vars (AWS S3, Backblaze B2, MinIO, R2). Back up the data directory / bucket.
- Sending — verify your domains at resend.com and set RESEND_API_KEY in .env.
Receiving mail — the honest part
Recommended — webhook
Set a long random INBOUND_SECRET and point your provider's inbound/parse route at https://your-host/_inbound, passing the secret as the x-inbound-secret header or ?secret=…. Prefer full raw MIME so attachments survive. Works with Mailgun, SendGrid, Postal and Resend inbound.
Advanced — built-in SMTP
Set ENABLE_SMTP=1 and open port 25 only if you have a static IP with matching rDNS, correct MX, and SPF/DKIM/DMARC.
HTTPS & the front door
Put a reverse proxy in front for TLS and auth. Caddy is the least fuss — automatic Let's Encrypt:
# /etc/caddy/Caddyfile
mail.example.com {
reverse_proxy localhost:8080
}
Then add a login: set the built-in BASIC_AUTH_USER / BASIC_AUTH_PASS, or use the proxy's auth / an identity provider, or keep the port on a Tailscale network. With TLS terminating at the proxy, bind the app to localhost and never expose 8080 directly.