OpenDKIM on Debian 9.4 (stretch)

Bind9 Debian Linux opendkim Postfix

I spent a lot of time trying to get OpenDKIM to work on Debian Stretch.

Having searched the Internet thoroughly, once again I found many different configurations, none of which actually worked for me.

These are my various config files, with the domain name(s) swapped for “example.com” and the ‘selectors’ swapped for “example-selector-name”

If you follow these intructions to the letter, you should be able to get a working OpenDKIM configuration – with one important note:

For some reason, which I have been unable to fix – running OpenDKIM from systemctl does not work on my system (an upgrade from 7.11 so that could be the issue).

The service starts, and reports as running ok, however OpenDKIM simply does not work… YMMV

I ended up having to put the startup command into /etc/rc.local like this:

echo "Starting OpenDKIM"
/usr/sbin/opendkim -P /var/run/opendkim/opendkim.pid -l -x /etc/opendkim.conf -u opendkim

But note!!! rc.local is no longer enable by default no Debian 9 so you need to see this post to enable it.

/etc/opendkim.conf

OversignHeaders         From
Canonicalization        relaxed/simple
# Canonicalization        relaxed/relaxed
ExternalIgnoreList      refile:/etc/opendkim/TrustedHosts
InternalHosts           refile:/etc/opendkim/TrustedHosts
KeyTable                /etc/opendkim/KeyTable
# My KeyTable does not use wildcards, so the "refile:" is not required.
# KeyTable                refile:/etc/opendkim/KeyTable
LogWhy                  Yes
MinimumKeyBits          1024
Mode                    sv
PidFile                 /var/run/opendkim/opendkim.pid
SigningTable            refile:/etc/opendkim/SigningTable
Socket                  inet:12301@127.0.0.1
Syslog                  yes
SyslogSuccess           Yes
TemporaryDirectory      /var/tmp
UMask                   022
UserID                  opendkim:opendkim

/etc/default/opendkim

# Command-line options specified here will override the contents of
# /etc/opendkim.conf. See opendkim(8) for a complete list of options.
#DAEMON_OPTS=""
# Change to /var/spool/postfix/var/run/opendkim to use a Unix socket with
# postfix in a chroot:
#RUNDIR=/var/spool/postfix/var/run/opendkim
RUNDIR=/var/run/opendkim
#
# Uncomment to specify an alternate socket
# Note that setting this will override any Socket value in opendkim.conf
# default:
# SOCKET=local:$RUNDIR/opendkim.sock
SOCKET="inet:12301@127.0.0.1"
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=

/etc/opendkim/KeyTable

example.com example.com:example-selector-name:/etc/opendkim/keys/example.com/example.com.private
example2.com example2.com:example2selector-name:/etc/opendkim/keys/excmaple2.com/example2.com.private

/etc/opendkim/SigningTable

*@example.com example.com
*@example2.com example2.com

/etc/opendkim/TrustedHosts

127.0.0.1
localhost
- other server ip addresses as required -
*.example.com
*.example2.com

Generate your private and public keys.

opendkim-genkey --bits=2048 --domain=example.com --selector=example-selector-name
opendkim-genkey --bits=2048 --domain=example2.com --selector=example2-selector-name

opendkim-genkey generates two files:

/etc/opendkim/keys/example.com/example-selector-name.private
/etc/opendkim/keys/example.com/example-selector-name.txt


example-selector-name.private is your private key - you must keep this secure!
example-selector-name.txt is your public key (in Bind DNS TXT record format)

Publish your keys in DNS
example-selector-name.txt is used for your DNS record. If running your own DNS server, do not bother trying to copy and paste this into your Bind zone files, simply copy “example-selector-name.txt” (for each domain you want to enable DKIM for) to your Bind folder (usually /var/named/chroot/var/named/ if running chroot) and then use an INCLUDE statement to include the file – like this:

$INCLUDE example-selector-name.txt

Don’t forget to increment your serial number and reload bind following this step.

Now test your key(s)

opendkim-testkey -d example.com -s example-selector-name -k /etc/opendkim/keys/example.com/example-selector-name.private -vvv
opendkim-testkey -d example2.com -s example2-selector-name -k /etc/opendkim/keys/example2.com/example2-selector-name.private -vvv

In the above command -d is YOUR domain -s is YOUR CHOSEN SELECTOR and -k is the FULL path to your private key.

Test results:

opendkim-testkey: using default configfile /etc/opendkim.conf
opendkim-testkey: key loaded from /etc/opendkim/keys/gtkc.net/example-selector-name.private
opendkim-testkey: checking key 'example-selector-name._domainkey.example.com'
opendkim-testkey: key not secure # see NOTE below
opendkim-testkey: key OK

NOTE: “key not secure” is ok, it just means that you are not running DNSSEC

Once you have everything working as per above, you are ready to change your Postfix configuration so that you can sign outgoing mail:

Add the following lines to /etc/postfix/main.cf:

milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:127.0.0.1:12301,inet:127.0.0.1:54321
non_smtpd_milters = $smtpd_milters

NOTE: In the above I’m using OpenDMARC as well – hence I have two entries.

My OpenDKIM listens on port 12301, and OpenDMARC listens on port 54321

Testing your OpenDKIM DNS TXT record with dig

dig example-selector-name._domainkey.example.com TXT

You should get something like this: (IP addresses removed)

; <<>> DiG 9.10.3-P4-Debian <<>> example-selector-name._domainkey.example.com TXT
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6772
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 8

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;example-selector-name._domainkey.example.com. IN   TXT

;; ANSWER SECTION:
example-selector-name._domainkey.example.com. 300 IN TXT    "v=DKIM1; h=sha256; k=rsa; " "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq1jpxc3kgbSnYBuecJmfjLy2hKzPPZ8cm0t1Tb3BAZDOir5ygLnvHYfq59TTxvH+0OCQHMIOoiMtAEM0/qNF5t9/2PCtaTTgZ0NkAYkhqhQKTOlJssBMNweHiLO8Z7dgBakBIPgzGogvwbNSCDPk+XosJheRs2H3Ak5d7cVEPWyE5l1wZWKYsiGmjINHD4qS0x9yoTdmxpo/dl" "Tu1+K2P+x5NdhzayAmG4L/GFpYSIRbRHLkK6wX864dziXm1WPGK2auNMx8W1jiwSJWQX8lqTaQz6J9MyFOhYa7vfWNttG6qxh3dkKfaOY7APbnL1fk+YOwESAORJVlGj5be008rwIDAQAB"

;; AUTHORITY SECTION:
example.com.            300     IN      NS      ns0.example.com.
example.com.            300     IN      NS      ns1.example.com.
example.com.            300     IN      NS      ns2.example.com.
example.com.            300     IN      NS      ns3.example.com.

;; ADDITIONAL SECTION:
ns0.example.com.        300     IN      A       x.x.x.x
ns1.example.com.        300     IN      A       x.x.x.x
ns1.example.com.        300     IN      AAAA    xxxx:xxxx:x:x
ns2.example.com.        300     IN      A       x.x.x.x
ns2.example.com.        300     IN      AAAA    xxxx:xxx:x::x
ns3.example.com.        300     IN      A       x.x.x.x
ns3.example.com.        300     IN      AAAA    xxxx:xxxx:x::x

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon Jul 30 16:12:19 BST 2018
;; MSG SIZE  rcvd: 716