From 0592bb2244ee4a645f058c12a765ba81896128fb Mon Sep 17 00:00:00 2001 From: Damien Date: Thu, 25 Jun 2026 11:12:57 +0200 Subject: [PATCH] docs(postfix-pgsql): add README with usage and environment variables --- images/postfix-pgsql/README.md | 129 +++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 images/postfix-pgsql/README.md diff --git a/images/postfix-pgsql/README.md b/images/postfix-pgsql/README.md new file mode 100644 index 0000000..11b0057 --- /dev/null +++ b/images/postfix-pgsql/README.md @@ -0,0 +1,129 @@ +# Postfix PostgreSQL Relay Image + +A Postfix SMTP relay/MTA whose relay and transport decisions are driven by +PostgreSQL lookup maps instead of static config. It receives inbound mail and +forwards it to an internal SMTP target after checking the recipient's domain +against a database — it has no knowledge of, and makes no assumptions about, +what consumes the mail downstream. + +This mirrors the Postfix setup described in the SimpleLogin self-hosting +documentation (`postfix` + `postfix-pgsql`, a `relay_domains` PostgreSQL map, +and a `transport_maps` PostgreSQL map): https://github.com/simple-login/app + +No domain, hostname, or database credential is hardcoded in the image. +Everything is templated from environment variables by +`docker-entrypoint.sh` at container startup, then Postfix is started in the +foreground (`postfix start-fg`) so it runs correctly under Docker's process +supervision. + +## How it works + +On startup, the entrypoint renders three files from templates under +`/etc/postfix/templates/`: + +- `/etc/postfix/main.cf` — core Postfix configuration. +- `/etc/postfix/pgsql-relay-domains.cf` — PostgreSQL lookup that tells + Postfix which domains it should relay mail for. +- `/etc/postfix/pgsql-transport-maps.cf` — PostgreSQL lookup that tells + Postfix where to forward accepted mail (the internal SMTP relay target). + +## Environment variables + +### Required + +| Variable | Description | Example | +|----------|--------------|---------| +| `MAIL_DOMAIN` | Mail domain this relay handles (`mydomain`/`myorigin` in `main.cf`). | `example.com` | +| `MYHOSTNAME` | Hostname of this relay, used as Postfix's `myhostname` and as the MX target for `MAIL_DOMAIN`. | `mx1.example.com` | +| `POSTGRES_HOST` | Hostname of the PostgreSQL server holding the lookup tables. | `postgres` | +| `POSTGRES_PORT` | PostgreSQL port. | `5432` | +| `POSTGRES_USER` | PostgreSQL user used for the lookup queries. | `postfix` | +| `POSTGRES_PASSWORD` | PostgreSQL password for `POSTGRES_USER`. | `change-me` | +| `POSTGRES_DB` | PostgreSQL database name. | `relaydb` | +| `SMTP_RELAY_HOST` | Internal SMTP host that accepted mail is forwarded to after the relay-domains lookup matches. | `app-internal` | +| `SMTP_RELAY_PORT` | Port of the internal SMTP relay target. | `2525` | + +### Optional + +| Variable | Description | +|----------|--------------| +| `TLS_CERT_FILE` | Absolute path (inside the container) to a TLS certificate to use for `smtpd_tls_cert_file`. If unset, a self-signed certificate is generated on first start. | +| `TLS_KEY_FILE` | Absolute path (inside the container) to the private key matching `TLS_CERT_FILE`. Must be set together with `TLS_CERT_FILE`. | + +The PostgreSQL lookup tables are expected to expose at least a +`relay_domain(domain)` table; both lookups query it by recipient domain. + +## TLS certificates + +By default, if `TLS_CERT_FILE`/`TLS_KEY_FILE` are not provided, the +entrypoint generates a self-signed certificate at +`/etc/postfix/ssl/snakeoil.{pem,key}` on first start (matching the +self-signed fallback used in the upstream docs) and reuses it on subsequent +restarts if that path is kept on a persistent volume. + +To use your own certificate instead, mount it into the container and point +`TLS_CERT_FILE`/`TLS_KEY_FILE` at the mounted paths, e.g.: + +```bash +docker run \ + -v /path/to/fullchain.pem:/certs/fullchain.pem:ro \ + -v /path/to/privkey.pem:/certs/privkey.pem:ro \ + -e TLS_CERT_FILE=/certs/fullchain.pem \ + -e TLS_KEY_FILE=/certs/privkey.pem \ + ... +``` + +## Usage + +### `docker run` + +```bash +docker run -d \ + -p 25:25 \ + -e MAIL_DOMAIN=example.com \ + -e MYHOSTNAME=mx1.example.com \ + -e POSTGRES_HOST=postgres \ + -e POSTGRES_PORT=5432 \ + -e POSTGRES_USER=postfix \ + -e POSTGRES_PASSWORD=change-me \ + -e POSTGRES_DB=relaydb \ + -e SMTP_RELAY_HOST=app-internal \ + -e SMTP_RELAY_PORT=2525 \ + gitea.arnodo.fr/damien/postfix-pgsql:latest +``` + +### Docker Compose + +```yaml +services: + postfix: + image: gitea.arnodo.fr/damien/postfix-pgsql:latest + ports: + - "25:25" + environment: + MAIL_DOMAIN: example.com + MYHOSTNAME: mx1.example.com + POSTGRES_HOST: postgres + POSTGRES_PORT: "5432" + POSTGRES_USER: postfix + POSTGRES_PASSWORD: change-me + POSTGRES_DB: relaydb + SMTP_RELAY_HOST: app-internal + SMTP_RELAY_PORT: "2525" +``` + +## Version management + +The Debian base image tag is set in `POSTFIX_VERSION` (e.g. `12-slim`), +which also pins the `postfix`/`postfix-pgsql` package versions available via +`apt` for that Debian release. To change it: + +1. Edit `POSTFIX_VERSION` with the desired Debian tag. +2. Commit and push. +3. The CI builds the image with that base and tags it with both `latest` and + the value of `POSTFIX_VERSION`. + +## Reference + +- Upstream Postfix + PostgreSQL setup this image is based on: + https://github.com/simple-login/app