# Deploying Send-Only Postfix with DKIM in Docker on Ubuntu
This guide deploys the boky/postfix Docker container with OpenDKIM and TLS on Ubuntu 22.04 (1 GB RAM, 1 vCPU). The server only sends mail via authenticated sessions or from localhost on port 587. Features automatic DKIM key generation and mounts Let's Encrypt certificates. Prerequisites: a domain managed in Cloudflare and a VPS with outbound port 25 allowed by your hoster.
Server Preparation
Update packages:
apt update && apt upgrade -y
Remove old Docker packages:
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done
Install official Docker:
apt update
apt install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update && apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Install Certbot:
apt install certbot
Add an A record in Cloudflare: mail → VPS IP, with proxying disabled. Issue the certificate:
certbot certonly --standalone -d mail.yourdomain.com
Create a renewal hook to restart the container:
nano /etc/letsencrypt/renewal-hooks/post/restart-postfix.sh
Contents:
#!/bin/bash
docker restart postfix
Make it executable: chmod +x /etc/letsencrypt/renewal-hooks/post/restart-postfix.sh.
Creating User and docker-compose
Create an unprivileged user:
useradd -m emailuser -G docker -s /bin/bash
passwd emailuser
su emailuser
Create docker-compose.yml:
services:
postfix:
image: boky/postfix
container_name: postfix
restart: unless-stopped
ports:
- "587:587"
volumes:
- ./dkim:/etc/opendkim/keys
- /etc/letsencrypt/live/mail.yourdomain.com/fullchain.pem:/etc/opendkim/keys/mail.crt:ro
- /etc/letsencrypt/live/mail.yourdomain.com/privkey.pem:/etc/opendkim/keys/mail.key:ro
environment:
HOSTNAME: mail.yourdomain.com
DOMAIN: yourdomain.com
DKIM_SELECTOR: mail
DKIM_DOMAINS: yourdomain.com
DKIM_KEY_LENGTH: 2048
ENABLE_DKIM: 1
ENABLE_TLS: 1
TLS_KEY: /etc/opendkim/keys/mail.key
TLS_CERT: /etc/opendkim/keys/mail.crt
SMTP_USER: [email protected]|password
RELAY_NETWORKS: 127.0.0.1/32
FORCE_HELO: 1
LOG_TO_STDOUT: 1
ALLOWED_SENDER_DOMAINS: mail.yourdomain.com
DKIM_AUTOGENERATE: "true"
Run: docker compose up -d. After key generation, remove DKIM_AUTOGENERATE.
DNS Configuration
In the ./dkim directory, find the .txt file with the public key. Extract the line like:
v=DKIM1; h=sha256; k=rsa; s=email; p=MNOGO_SIMVOLOV
(join key parts without brackets/quotes). Add TXT record in Cloudflare:
- Name:
mail._domainkey - Content: key string
SPF record for the domain:
- Name:
yourdomain.com - Content:
v=spf1 a mx ip4:YOUR_VPS_IP -all
rDNS and Port 25
Contact your hoster:
- Open outbound port 25.
- Set rDNS for
mail.yourdomain.com→ VPS IP.
Testing
Test on mail-tester.com or appmaildev.com. Enter the container:
docker exec -it postfix bash
echo -e "Subject: DKIM Test\n\nThis is a test message" | sendmail -f [email protected] [email protected]
Expected result: 10/10 on testers, emails land in Gmail inbox.
- DKIM: automatic generation of 2048-bit keys.
- SPF: restricts sending by IP.
- TLS: Let's Encrypt with auto-renewal.
- Auth: SMTP_USER for relay.
Key Points
- The boky/postfix container includes Postfix + OpenDKIM out of the box.
- Mount volumes for keys and certs with
:rofor security. - RELAY_NETWORKS=127.0.0.1/32 blocks unauthenticated external sends.
- Disable AUTOGENERATE after DKIM generation.
- rDNS is critical for deliverability with major providers.
— Editorial Team
No comments yet.