Files
docker-images/images/postfix-pgsql/README.md

130 lines
4.7 KiB
Markdown

# 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