Files
selfpost/README.md
T
2026-08-08 10:36:24 +03:00

4.9 KiB
Raw Blame History

SelfPost

SelfPost

Self-hosted outbound SMTP relay with a web control panel, shipped as a single Docker image. Postfix, OpenDKIM, and a small Go panel run together under supervisord; you configure domains, DKIM keys, and SASL applications once, then point your apps at the SMTP endpoint.

SelfPost sends mail straight to the internet from your own IP, with per-domain DKIM signing. It is outbound only — no inbound mail, mailboxes, or webmail.

For: operators who run their own VPS or home server and want a simple relay they control, without a third-party SMTP provider.

Key properties: one container, multi-domain DKIM, SASL per application, send log and DNS checks in the panel, encrypted backups.

Features

  • Outbound SMTP (465/smtps; optional 587 submission) with per-domain DKIM signing
  • Web panel — domains, applications, deliveries, mail queue, system log, backup
  • Multi-domain relay — each SASL application is bound to one sending domain
  • DNS status checks (PTR, SPF, DKIM, DMARC) with in-panel re-check
  • Two-level rate limiting — IP backstop (Postfix) and per-domain/per-app limits
  • Full-server backup and single-domain export/import (optional password encryption)
  • Single Docker image; data in a ./data bind mount

Documentation

Document Contents
Operator guide Reverse proxy, environment variables, DNS, IP warmup, panel operations, rate limiting, backup/restore, ports, image tag
Product boundaries Purpose, deployment assumptions, out-of-scope items, multi-domain model
Architecture As-built technical design
Security Accepted security trade-offs and requirements
Development Building, testing, and contributing
CHANGELOG Release history

Repository: https://github.com/mixeme/selfpost — source, issues, releases, and the ghcr.io/mixeme/selfpost image.

Requirements

Providing these is the operator's job — SelfPost cannot fix a blocked port or a missing PTR record for you. Details: Operator guide.

Platform

  • Docker + Compose v2 on the host
  • A reverse proxy in front of the panel (SelfPost never terminates HTTPS itself)
  • Rough sizing: 1 vCPU, 512 MB1 GB RAM, 810 GB disk (send log and rotated mail.log are the main growth drivers)

Network and IP

  • Static IP address
  • Outbound TCP port 25 unblocked (many consumer/cloud hosts block it by default)
  • PTR/rDNS for that IP pointing at your mail hostname (SELFPOST_HOSTNAME)
  • Reasonable starting IP reputation — a fresh IP still needs warmup

Per sending domain

For every domain you add in the panel:

  • SPF TXT record authorizing this server
  • DKIM TXT record (value shown on the domain page)
  • DMARC _dmarc TXT record

See DNS setup in the operator guide.

Quick start

mkdir -p selfpost && cd selfpost
curl -O https://raw.githubusercontent.com/mixeme/selfpost/main/deploy/docker-compose.yml
curl -O https://raw.githubusercontent.com/mixeme/selfpost/main/deploy/.env.example
mv .env.example .env   # then edit SELFPOST_HOSTNAME etc.
docker compose up -d

SELFPOST_HOSTNAME is required — bare FQDN only (e.g. mail.example.com). It is the Postfix HELO name, the SASL realm, and must match the PTR record and certificate CN/SAN.

This starts SelfPost only. You still need a reverse proxy with TLS certificates bind-mounted at ./certs — see Reference deploy and the reverse-proxy section in the operator guide.

On first start, docker compose logs -f prints a one-time setup link to create the admin account. The same link is also in ./data/setup-token on the host — see Operations → First-time setup link.

Reference deploy

Artefact Path
Compose file (fixed image tag) deploy/docker-compose.yml
Environment template deploy/.env.example
Apache vhost (recommended) deploy/apache/selfpost-vhost.conf
nginx deploy/nginx/
Caddy deploy/caddy/
Traefik deploy/traefik/

The compose file maps ports 465 (always) and 587 (when SUBMISSION_ENABLE=true). TLS certificate paths inside the container are fixed to match the ./certs bind mount. Bump the pinned image tag deliberately when upgrading — never use :latest (why).

License

AGPL-3.0. The AGPL closes the "SaaS loophole": if you run a modified version as a network-accessible service, you must make the modified source available to its users — not only when you distribute copies of the code.