Self-hosting
Run the AnhourMail stack on your own machine from the public repository.
The whole stack is open source and runs with Docker Compose. This guide starts a local development copy: nothing it sends ever leaves your machine.
What you need
- Docker with Docker Compose
- Node.js 22 and npm
- Git
Run it
git clone https://github.com/anhourtec/anhourmail.git
cd anhourmail
cp .env.example .env
npm ci
npm run stack:up
npm run db:seed -- --demo
npm run devnpm run stack:upstarts Postgres, Redis, the Stalwart mail server and Mailpit. It checks that the ports in.envare free first.npm run db:seed -- --democreates demo accounts and writes their sign-in details tocredentials.mdin the repository root. That file is for your machine only and is never committed.npm run devstarts the site, the docs and the console. The addresses are printed in the terminal and listed in the README.
How mail stays local
In development, every message to an outside address is delivered to Mailpit, a local inbox you can open in the browser. The mail server's container also has no route to the internet, so nothing can be delivered outside your machine even by mistake.
About the mail server
AnhourMail uses Stalwart, licensed under AGPL-3.0. The version is
pinned in docker-compose.yml, and we run it unmodified, configured only through its API.
Running it for real
Production needs more than this guide covers: a server whose provider allows outbound mail, reverse DNS, TLS certificates, DNS records and a warm-up period for a new IP address. A production guide will follow.
Two things apply from the first day:
- Set
PLATFORM_DOMAINin.envto your own domain. The console builds every server name it shows your users (incoming mail, sending, mail apps, the DNS records for their domains) under it, and checks their DNS against the same names. - Give each part of AnhourMail its own mail-server key, limited to its job: the console and webmail get a key that
can't create or change mail accounts, and the background worker gets one that can't open a mailbox. Each part
refuses to start with a key that isn't its own. One job (creating accounts) can still set an account's password, so
a production deployment also runs an internal proxy in front of the mail server that blocks that, and a check that
reports it if it ever happens.
deploy/README.mdin the repository has the settings and the details. - Create your first administrator with the worker's one-off job (below). It emails a one-time link to choose a
password and refuses once an administrator exists. Don't run the demo seed on a real server: it refuses when
NODE_ENVisproduction.
npm run job:bootstrap-admin --workspace @anhourmail/worker -- --email you@example.org --first-name Ada