mirror of
https://github.com/bokysan/docker-postfix.git
synced 2025-09-06 06:25:40 +08:00
Initial support for DKIM and testing
This commit brings two important features: - **DKIM support** It's now possible to configure this postfix image to sign messages using DKIM by simply generating the keys and providing them in the approprate folder. This should bring us one step closer to directly sending out emails without relying on a 3rd-party proxy. - **test support** A nice and handy script, conviniently called `test.sh` has been provided, builds the image, spins it up and tries to send out an email. You'll need `docker-compose` to run it, though.
This commit is contained in:
parent
d7b6bdc32c
commit
928e5d64c7
10 changed files with 210 additions and 15 deletions
14
Dockerfile
14
Dockerfile
|
@ -1,5 +1,5 @@
|
|||
FROM alpine:latest
|
||||
MAINTAINER Bojan Cekrlic - https://github.com/bokysan/docker-postfix/
|
||||
LABEL maintaner="Bojan Cekrlic - https://github.com/bokysan/docker-postfix/"
|
||||
|
||||
# See README.md for details
|
||||
|
||||
|
@ -27,23 +27,25 @@ ENV INBOUND_DEBUGGING=
|
|||
|
||||
# Install supervisor, postfix
|
||||
RUN true && \
|
||||
apk add --no-cache --update postfix ca-certificates tzdata supervisor rsyslog && \
|
||||
apk add --no-cache --update postfix ca-certificates tzdata supervisor rsyslog opendkim && \
|
||||
apk add --no-cache --upgrade musl musl-utils && \
|
||||
(rm "/tmp/"* 2>/dev/null || true) && (rm -rf /var/cache/apk/* 2>/dev/null || true)
|
||||
|
||||
# Set up configuration
|
||||
COPY supervisord.conf /etc/supervisord.conf
|
||||
COPY rsyslog.conf /etc/rsyslog.conf
|
||||
COPY opendkim.conf /etc/opendkim/opendkim.conf
|
||||
COPY run.sh /run.sh
|
||||
RUN chmod +x /run.sh
|
||||
COPY opendkim.sh /opendkim.sh
|
||||
RUN chmod +x /run.sh /opendkim.sh
|
||||
|
||||
# Set up spool volume
|
||||
VOLUME [ "/var/spool/postfix", "/etc/postfix" ]
|
||||
# Set up volumes
|
||||
VOLUME [ "/var/spool/postfix", "/etc/postfix", "/etc/opendkim/keys" ]
|
||||
|
||||
# Run supervisord
|
||||
USER root
|
||||
WORKDIR /tmp
|
||||
|
||||
EXPOSE 587
|
||||
ENTRYPOINT ["/run.sh"]
|
||||
CMD ["/bin/sh", "-c", "/run.sh"]
|
||||
|
||||
|
|
37
README.md
37
README.md
|
@ -21,13 +21,18 @@ To run the container, do the following:
|
|||
docker run --rm --name postfix -e "ALLOWED_SENDER_DOMAINS=example.com" -p 1587:587 boky/postfix
|
||||
```
|
||||
|
||||
You can now send emails by using `localhost:1587` as your SMTP server address. **Please note that
|
||||
the image uses the submission (587) port by default**. Port 25 is not exposed on purpose, as it's
|
||||
regularly blocked by ISP or already occupied by other services.
|
||||
You can now send emails by using `localhost:1587` as your SMTP server address. Of course, if
|
||||
you haven't configured your `example.com` domain to allow sending from this IP (see
|
||||
[openspf](http://www.openspf.org/)), your emails will most likely be regarded as spam.
|
||||
|
||||
All standard caveats of configuring the SMTP server apply -- e.g. you'll need to make sure your DNS
|
||||
entries are updated properly if you don't want your emails marked as spam.
|
||||
|
||||
**Please note that the image uses the submission (587) port by default**. Port 25 is not
|
||||
exposed on purpose, as it's regularly blocked by ISP or already occupied by other services.
|
||||
|
||||
|
||||
|
||||
## Configuration options
|
||||
|
||||
The following configuration options are available:
|
||||
|
@ -40,6 +45,7 @@ $RELAYHOST_PASSWORD = An (optional) login password for the relay server
|
|||
$MYNETWORKS = allow domains from per Network ( default 127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 )
|
||||
$ALLOWED_SENDER_DOMAINS = domains sender domains
|
||||
$MASQUERADED_DOMAINS = domains where you want to masquerade internal hosts
|
||||
|
||||
```
|
||||
### `HOSTNAME`
|
||||
|
||||
|
@ -132,6 +138,27 @@ Example:
|
|||
docker run --rm --name postfix -e "ALLOWED_SENDER_DOMAINS=example.com example.org" -e "MASQUERADED_DOMAINS=example.com" -p 1587:587 boky/postfix
|
||||
```
|
||||
|
||||
## `DKIM`
|
||||
|
||||
**This image is equiped with support for DKIM.** If you want to use DKIM you will need to generate DKIM keys yourself.
|
||||
You'll need to create a folder for every domain you want to send through Postfix and generate they key(s) with the following command, e.g.
|
||||
|
||||
```
|
||||
mkdir -p /host/keys; cd /host/keys
|
||||
mkdir example.com; cd example.com
|
||||
opendkim-genkey -s mail -d example.com
|
||||
cd ..
|
||||
mkdir example.org; cd example.org
|
||||
opendkim-genkey -s mail -d example.corg
|
||||
```
|
||||
|
||||
`opendkim-genkey` is usually in your favourite distribution provided by installing `opendkim-tools` or `opendkim-utils`.
|
||||
|
||||
Add the created `mail.txt` files to your DNS record. Afterwards, just mount `/etc/opendkim/keys` into your image and DKIM
|
||||
will be used automatically, e.g.:
|
||||
```
|
||||
docker run --rm --name postfix -e "ALLOWED_SENDER_DOMAINS=example.com example.org" -v /host/keys:/etc/opendkim/keys -p 1587:587 boky/postfix
|
||||
```
|
||||
|
||||
## Extending the image
|
||||
|
||||
|
@ -142,7 +169,7 @@ startup script.
|
|||
E.g.: create a custom `Dockerfile` like this:
|
||||
```
|
||||
FROM boky/postfix
|
||||
MAINTAINER Some Randombloke "randombloke@example.com"
|
||||
LABEL maintainer="Jack Sparrow <jack.sparrow@theblackpearl.example.com>"
|
||||
ADD Dockerfiles/additional-config.sh /docker-init.db/
|
||||
```
|
||||
|
||||
|
@ -161,4 +188,4 @@ postconf -e "address_verify_negative_cache=yes"
|
|||
## Security
|
||||
|
||||
Postfix will run the master proces as `root`, because that's how it's designed. Subprocesses will run under the `postfix` account
|
||||
which will use `UID:GID` of `100:101`.
|
||||
which will use `UID:GID` of `100:101`. `opendkim` will run under account `102:103`.
|
||||
|
|
19
docker-compose.yml
Normal file
19
docker-compose.yml
Normal file
|
@ -0,0 +1,19 @@
|
|||
version: '3.6'
|
||||
services:
|
||||
postfix_test_587:
|
||||
hostname: "postfix"
|
||||
image: "boky/postfix"
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: [ "CMD", "sh", "-c", "netstat -an | fgrep 587 | fgrep -q LISTEN" ]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
start_period: 10s
|
||||
retries: 2
|
||||
ports:
|
||||
- "1587:587"
|
||||
volumes:
|
||||
- "./test-keys:/etc/opendkim/keys"
|
||||
environment:
|
||||
ALLOWED_SENDER_DOMAINS: "example.org"
|
||||
INBOUND_DEBUGGING: 1
|
20
opendkim.conf
Normal file
20
opendkim.conf
Normal file
|
@ -0,0 +1,20 @@
|
|||
AutoRestart Yes
|
||||
AutoRestartRate 10/1h
|
||||
UMask 002
|
||||
Syslog yes
|
||||
SyslogSuccess Yes
|
||||
LogWhy Yes
|
||||
|
||||
Canonicalization relaxed/simple
|
||||
|
||||
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
|
||||
InternalHosts refile:/etc/opendkim/TrustedHosts
|
||||
KeyTable refile:/etc/opendkim/KeyTable
|
||||
SigningTable refile:/etc/opendkim/SigningTable
|
||||
|
||||
Mode sv
|
||||
PidFile /var/run/opendkim/opendkim.pid
|
||||
SignatureAlgorithm rsa-sha256
|
||||
|
||||
UserID opendkim:opendkim
|
||||
Socket inet:8891@localhost
|
10
opendkim.sh
Normal file
10
opendkim.sh
Normal file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/sh
|
||||
if [ ! -d /etc/opendkim/keys ]; then
|
||||
sleep 9999999999999999999
|
||||
elif [ -z "$(find /etc/opendkim/keys -type d ! -name .)" ]; then
|
||||
sleep 9999999999999999999
|
||||
else
|
||||
/usr/sbin/opendkim -D -f -x /etc/opendkim/opendkim.conf
|
||||
fi
|
||||
|
||||
|
63
run.sh
63
run.sh
|
@ -154,11 +154,22 @@ postconf -e "mynetworks=$MYNETWORKS"
|
|||
if [ ! -z "$INBOUND_DEBUGGING" ]; then
|
||||
echo -e "‣ $notice Enabling additional debbuging for: ${emphasis}$MYNETWORKS${reset}"
|
||||
postconf -e "debug_peer_list=$MYNETWORKS"
|
||||
|
||||
sed -i -E 's/^[ \t]*#?[ \t]*LogWhy[ \t]*.+$/LogWhy yes/' /etc/opendkim/opendkim.conf
|
||||
if ! egrep -q '^LogWhy' /etc/opendkim/opendkim.conf; then
|
||||
echo >> /etc/opendkim/opendkim.conf
|
||||
echo "LogWhy yes" >> /etc/opendkim/opendkim.conf
|
||||
fi
|
||||
else
|
||||
sed -i -E 's/^[ \t]*#?[ \t]*LogWhy[ \t]*.+$/LogWhy no/' /etc/opendkim/opendkim.conf
|
||||
if ! egrep -q '^LogWhy' /etc/opendkim/opendkim.conf; then
|
||||
echo >> /etc/opendkim/opendkim.conf
|
||||
echo "LogWhy no" >> /etc/opendkim/opendkim.conf
|
||||
fi
|
||||
fi
|
||||
|
||||
# Split with space
|
||||
if [ ! -z "$ALLOWED_SENDER_DOMAINS" ]; then
|
||||
echo -en "‣ $notice Setting up allowed SENDER domains:"
|
||||
echo -en "‣ $info Setting up allowed SENDER domains:"
|
||||
allowed_senders=/etc/postfix/allowed_senders
|
||||
rm -f $allowed_senders $allowed_senders.db > /dev/null
|
||||
touch $allowed_senders
|
||||
|
@ -179,7 +190,7 @@ if [ ! -z "$ALLOWED_SENDER_DOMAINS" ]; then
|
|||
# Since we are behind closed doors, let's just permit all relays.
|
||||
postconf -e "smtpd_relay_restrictions=permit"
|
||||
else
|
||||
echo -e "ERROR: You need to specify sender domains otherwise Postfix will not run!"
|
||||
echo -e "ERROR: You need to specify ALLOWED_SENDER_DOMAINS otherwise Postfix will not run!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
@ -189,6 +200,50 @@ if [ ! -z "$MASQUERADED_DOMAINS" ]; then
|
|||
postconf -e "local_header_rewrite_clients = static:all"
|
||||
fi
|
||||
|
||||
DKIM_ENABLED=
|
||||
if [ -d /etc/opendkim/keys ] && [ ! -z "$(find /etc/opendkim/keys -type d ! -name .)" ]; then
|
||||
DKIM_ENABLED=", ${emphasis}opendkim${reset}"
|
||||
echo -e "‣ $notice Configuring OpenDKIM."
|
||||
mkdir -p /var/run/opendkim
|
||||
chown -R opendkim:opendkim /var/run/opendkim
|
||||
dkim_socket=$(cat /etc/opendkim/opendkim.conf | egrep ^Socket | awk '{ print $2 }')
|
||||
if [ $(echo "$dkim_socket" | cut -d: -f1) == "inet" ]; then
|
||||
dkim_socket=$(echo "$dkim_socket" | cut -d: -f2)
|
||||
dkim_socket="inet:$(echo "$dkim_socket" | cut -d@ -f2):$(echo "$dkim_socket" | cut -d@ -f1)"
|
||||
fi
|
||||
echo -e " ...using socket $dkim_socket"
|
||||
|
||||
postconf -e "milter_protocol=2"
|
||||
postconf -e "milter_default_action=accept"
|
||||
postconf -e "smtpd_milters=$dkim_socket"
|
||||
postconf -e "non_smtpd_milters=$dkim_socket"
|
||||
|
||||
echo > /etc/opendkim/TrustedHosts
|
||||
echo > /etc/opendkim/KeyTable
|
||||
echo > /etc/opendkim/SigningTable
|
||||
|
||||
echo "127.0.0.1" >> /etc/opendkim/TrustedHosts
|
||||
echo "localhost" >> /etc/opendkim/TrustedHosts
|
||||
echo "" >> /etc/opendkim/TrustedHosts
|
||||
if [ ! -z "$ALLOWED_SENDER_DOMAINS" ]; then
|
||||
for i in $ALLOWED_SENDER_DOMAINS; do
|
||||
private_key=/etc/opendkim/keys/$i/mail.private
|
||||
if [ -f $private_key ]; then
|
||||
echo -e " ...for domain ${emphasis}$i${reset}"
|
||||
echo "*.$i" >> /etc/opendkim/TrustedHosts
|
||||
echo "mail._domainkey.$i $i:mail:$private_key" >> /etc/opendkim/KeyTable
|
||||
echo "*@$i mail._domainkey.$i" > /etc/opendkim/SigningTable
|
||||
else
|
||||
echo " ...$warn skipping for domain ${emphasis}$i${reset}. File $private_key not found!"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
else
|
||||
echo -e "‣ $info No DKIM keys found, will not use DKIM."
|
||||
postconf -# smtpd_milters
|
||||
postconf -# non_smtpd_milters
|
||||
fi
|
||||
|
||||
# Use 587 (submission)
|
||||
sed -i -r -e 's/^#submission/submission/' /etc/postfix/master.cf
|
||||
|
||||
|
@ -202,6 +257,6 @@ if [ -d /docker-init.db/ ]; then
|
|||
done
|
||||
fi
|
||||
|
||||
echo -e "‣ $notice Staring ${emphasis}rsyslog${reset} and ${emphasis}postfix${reset}"
|
||||
echo -e "‣ $notice Starting: ${emphasis}rsyslog${reset}, ${emphasis}postfix${reset}$DKIM_ENABLED"
|
||||
exec supervisord -c /etc/supervisord.conf
|
||||
|
||||
|
|
|
@ -22,3 +22,16 @@ autorestart = false
|
|||
directory = /etc/postfix
|
||||
command = /usr/sbin/postfix -c /etc/postfix start
|
||||
startsecs = 0
|
||||
|
||||
|
||||
[program:opendkim]
|
||||
command = /opendkim.sh
|
||||
user = opendkim
|
||||
autostart = true
|
||||
autorestart = true
|
||||
startsecs = 2
|
||||
stopwaitsecs = 2
|
||||
stdout_logfile = /dev/stdout
|
||||
stderr_logfile = /dev/stderr
|
||||
stdout_logfile_maxbytes = 0
|
||||
stderr_logfile_maxbytes = 0
|
||||
|
|
15
test-keys/example.org/mail.private
Normal file
15
test-keys/example.org/mail.private
Normal file
|
@ -0,0 +1,15 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXgIBAAKBgQC/f+ltPdT/pAp0EjKSiR0m8KT3dNSoC2XSyK0viIHNwwx0IS/G
|
||||
7Xkl1wR2vzIN+3EvXXeQtajJQ+55+xEUQlXa1RIStZmamCGEKNbXsgNhUBW5tlMJ
|
||||
HMxiUbHQHDrv0rDl/9nqpEGeCGRMlWTM4HbQgXm9LWc4bKaDe7ByzmWWhwIDAQAB
|
||||
AoGAfz9jwK9Bhc1fFNmyuSRbNrDZLYV4eWF5e6LVUayHdE6TS+dxc+IAimBiGvXZ
|
||||
MOlPwIV/Ga1cRsDZCj0GkEuz99kCC4S59jb4N1d44y7NIzzdBn3dAWe1gYRB4gZF
|
||||
NiBlt63zOUBw26j2PCN98GKzHl2u/rmpkI6CyUqws0zZ2MECQQD6LEqQcEYhQjm9
|
||||
4Ygu/CUm5QZ1lkMT9F9kiS4u5f/h67tQsAHjCPZSGH3wm2fmII0MfmcY4XxeV8DU
|
||||
2fDg4hhZAkEAw/XEuCP5k3+S8Aw4rmkE1/JkIkQOOB0o5EAWHDlIOii/0FNGiB3B
|
||||
EsRDsAmu5yz9Wy25lrgi3CHNXZRHlGlJ3wJBANzKmkQ/0qUnva5Hjdlpz6A0IS9G
|
||||
Ho1N76LbL1dUxjCty/O6Yu/syPhLhVsEzP3dXJ7aMENVPl5FNHqmnmDbKoECQQCI
|
||||
eodD6GpOPC/OV/SyJBpnfD4ZT2TH2Cc+sRO1HIAdYXwWT6lz66UouOCbnmLeRws9
|
||||
kZ8MRbqhrjklz7v6tUnpAkEAjCkM1+NWpXtdafH20kDXyZ/EEIYPoNKFJlCDuAhh
|
||||
drB2AbWplr7U5q1Gx/r+TNHLj461L+Ys0WtvjQ+mi9p+OQ==
|
||||
-----END RSA PRIVATE KEY-----
|
2
test-keys/example.org/main.txt
Normal file
2
test-keys/example.org/main.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
mail._domainkey IN TXT ( "v=DKIM1; k=rsa; "
|
||||
"p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/f+ltPdT/pAp0EjKSiR0m8KT3dNSoC2XSyK0viIHNwwx0IS/G7Xkl1wR2vzIN+3EvXXeQtajJQ+55+xEUQlXa1RIStZmamCGEKNbXsgNhUBW5tlMJHMxiUbHQHDrv0rDl/9nqpEGeCGRMlWTM4HbQgXm9LWc4bKaDe7ByzmWWhwIDAQAB" ) ; ----- DKIM key mail for example.org
|
32
test.sh
Executable file
32
test.sh
Executable file
|
@ -0,0 +1,32 @@
|
|||
#!/bin/sh
|
||||
docker build . -t boky/postfix
|
||||
docker-compose up -d
|
||||
|
||||
# Wait for postfix to startup
|
||||
echo "Waiting for startup..."
|
||||
while ! docker ps | fgrep postfix_test_587 | grep -q healthy; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
cat <<"EOF" | nc -C localhost 1587
|
||||
HELO test
|
||||
MAIL FROM:test@example.org
|
||||
RCPT TO:check-auth@verifier.port25.com
|
||||
DATA
|
||||
Subject: Postfix message test
|
||||
From: test@example.org
|
||||
To: check-auth@verifier.port25.com
|
||||
Content-Type: text/plain
|
||||
|
||||
This is a simple text
|
||||
.
|
||||
QUIT
|
||||
EOF
|
||||
|
||||
# Wait for email to be delivered
|
||||
echo "Waiting to shutdown..."
|
||||
sleep 5
|
||||
|
||||
# Shut down tests
|
||||
docker-compose down
|
||||
|
Loading…
Add table
Reference in a new issue