26

I've read the tutorial posted by MountainX (Setup DKIM (DomainKeys) for Ubuntu, Postfix and Mailman), but I can't figure out how to apply these steps if I want to host and send e-mails for several domains. Does anybody have a clue?

3 Answers 3

38

Good! I figured this out from the post mentioned in the question. I made a kind of mix between the answer itself and the links provided in it. Specially the fourth link is the one I used.

So the thing goes like this. Suppose you've got a server or VPS and make one of your domains to be the main domain and be used as the server name (in my example: mydomain.com).

So, first of all, we'll change to root to make things easier, but you can skip this step and use sudo before every command.

sudo su

Now, we install OpenDKIM:

apt-get install opendkim opendkim-tools

Let's fix the configuration file. We're opening /etc/opendkim.conf for editing. I use nano, but it's the same with other editor.

nano /etc/opendkim.conf

Once opened, make it look like this. If you feel comfortable, you can change some options, but the Domain, KeyFile and Selector must remain commented.

# This is a basic configuration that can easily be adapted to suit a standard
# installation. For more advanced options, see opendkim.conf(5) and/or
# /usr/share/doc/opendkim/examples/opendkim.conf.sample.
#
#Domain                  example.com
#KeyFile                 /etc/opendkim/201205.private
#Selector                201205
#
# Commonly-used options
Canonicalization        relaxed/simple
Mode                    sv
SubDomains              yes
# Log to syslog
Syslog                  yes
LogWhy                  yes
# Required to use local socket with MTAs that access the socket as a non-
# privileged user (e.g. Postfix)
UMask                   022
UserID                  opendkim:opendkim
#
KeyTable                /etc/opendkim/KeyTable
SigningTable            /etc/opendkim/SigningTable
ExternalIgnoreList      /etc/opendkim/TrustedHosts
InternalHosts           /etc/opendkim/TrustedHosts
#
Socket                  inet:8891@localhost
#EOF

Next, we create some of the folder and files that will hold information about what should OpenDKIM use and process. For now, the TrustedHosts file. We create and edit it:

mkdir /etc/opendkim
nano /etc/opendkim/TrustedHosts

We must put into this file a list of trusted addresses: localhost and 127.0.0.1, and your server name and IP:

127.0.0.1
localhost
192.99.34.121
mydomain.com

Now we edit OpenDKIM config file.

nano /etc/default/opendkim

And add these lines at the end of the file. They'll tell OpenDKIM in which port it should expect signing requests:

SOCKET="inet:8891@localhost"

We open the Postfix config file.

nano /etc/postfix/main.cf

And add these lines to the end of the file. They'll tell Postfix that it should send e-mails to be signed and where.

milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891

If you're not adding domains right now, you can restart everything, so the configuration takes effect.

/etc/init.d/opendkim restart
/etc/init.d/postfix reload
/etc/init.d/postfix restart

Done! The server is ready to work with DKIM. Now, you need to add your domains to this system. The following process is the same for all the domains you want to add. I'll use otherdomain.com for the example, replace it with your own.

Remember I was root from before, but if you're not, run sudo su or precede your commands with the keyword sudo.

sudo su

First, we create a directory for our domain and go inside of it:

mkdir -p /etc/opendkim/keys/otherdomain.com
cd /etc/opendkim/keys/otherdomain.com

Now we generate a key for the domain:

opendkim-genkey -r -d otherdomain.com

We give the OpenDKIM user ownership of the newly created file:

chown opendkim:opendkim default.private

And we open the KeyTable file to add our new key for our new domain:

nano /etc/opendkim/KeyTable

We add it to the end of the file (after all other domains we may have here):

default._domainkey.otherdomain.com otherdomain.com:default:/etc/opendkim/keys/otherdomain.com/default.private

We open the SigningTable file.

nano /etc/opendkim/SigningTable

And append at the end of the file (again, we'll have one line for each domain):

otherdomain.com default._domainkey.otherdomain.com

This SigningTable lists all mails which get signed. Just by adding a domain name, all mails from that domain will be signed.

I'm not sure of the necessity to do the next step, but I just did it, just in case... We open the TrustedHosts file.

nano /etc/opendkim/TrustedHosts

And add at the end of the file:

otherdomain.com

One last thing: we show the contents of the file /etc/opendkim/keys/otherdomain.com/default.txt.

cat /etc/opendkim/keys/otherdomain.com/default.txt

And add the information between the quotes to a TXT record in the DNS Zone of the domain, and we must also use default._domainkey as the name of the record. NOTE: "between the quotes" is the text that starts with "v=DKIM1;k=rsa; p=WIGfM...".

If we're done adding domains (by now), we restart everything to apply the changes.

/etc/init.d/opendkim restart
/etc/init.d/postfix reload
/etc/init.d/postfix restart

Done!

8
  • 2
    Great guide, but I had to remove the *@ from the SigningTable entries to avoid an error "no signing table match for '[email protected]'" in the mail.log, per lists.opendkim.org/archive/opendkim/users/2011/08/1332.html
    – dw1
    Aug 20, 2015 at 14:39
  • 1
    Thanks for this guide, I had the same problem as dw1 but after removing the *@ from the SigningTable everything worked as expected. One more thing is that in the /etc/opendkim/TrustedHosts file the IP of the host has only to be in there once, regardless of how many domains run via this host. If you want to use some other selector as default make sure to change it in all files!
    – Flatron
    Feb 6, 2016 at 2:53
  • Followed all the guide but the DKIM signature doesn't seem to be added... how can I debug this?
    – the_nuts
    Apr 17, 2016 at 11:10
  • 1
    Thanks for this! I am on Ubuntu 16.x and opendkim 2.10.3... I DID need the *@ part ahead of the domain name in SigningTable; nothing was signed until I corrected this. cc: @the_nuts Mar 16, 2017 at 15:33
  • 1
    First restart of services may not succeed, if the files /etc/opendkim/KeyTable and /or /etc/opendkim/SigningTable are not present. Simply create them using # touch /etc/opendkim/KeyTable # touch /etc/opendkim/SigningTable May 6, 2019 at 12:26
4

This script automates the part after "Done! The server is ready to work with DKIM"

To help automate this process a little I created this bash script. Just add one 'domain.com' per line inside the domains=() array.

First create the files and directories if they do not already exist

/etc/opendkim/keys/
/etc/opendkim/KeyTable
/etc/opendkim/SigningTable
/etc/opendkim/TrustedHosts
/etc/opendkim/spfs.txt

spfs.txt file will contain all the spf records you need to add to your DNS records for each domain.

NOTE: do not run more than once, it does not check to see if a domain already exists. Script also needs to be run as root.

#!/bin/bash
domains=(
        'domain.com'
)
for domain in "${domains[@]}"
do
keydir="/etc/opendkim/keys/$domain"
if [ -d "$keydir" ]
then
cd $keydir
else
mkdir $keydir
cd $keydir
fi
opendkim-genkey -r -d $domain
chown opendkim:opendkim default.private
echo "default._domainkey.$domain $domain:default:$keydir/default.private" >> /etc/opendkim/KeyTable
echo "$domain default._domainkey.$domain" >> /etc/opendkim/SigningTable
echo "$domain" >> /etc/opendkim/TrustedHosts
echo "$(cat $keydir/default.txt)" >> spfs.txt
done
4

This script automates the part after "Done! The server is ready to work with DKIM"

To help automate this process a little I created this bash script. Just add one domain like 'example.com' per line inside the domains=() array.

This script creates the files for you and checks if a line is already in the file

Spfs.txt is removed and recreated everytime its run and checks the 2nd line of default.txt against spfs.txt before appending

You must place your servers ipv4 and ipv6 (if you have them) in the variables provided. It checks if they arent empty

you can run this file multiple times thanks to the checks added.

#!/bin/bash
# List of domains
domains=( 
        'example.com'
)
# file paths and directories
dkim="/etc/opendkim"
keys="$dkim/keys"
keyfile="$dkim/KeyTable"
signfile="$dkim/SigningTable"
trustfile="$dkim/TrustedHosts"
spffile="$dkim/spfs.txt"
# Set Ipv6 and Ipv4 addresses for the server here
ipv4=""
ipv6=""
# loopback addresses for the server
loop=( localhost 127.0.0.1 )
function loopback {
        for back in "${loop[@]}"
        do
                if ! grep -q "$back" "$trustfile"; then
                        echo "$back" >> "$trustfile"
                fi
        done
}
# Check for files and create / write to them if they dont exist
if [ ! -d "$keys" ]; then
        mkdir "$keys"
fi
if [ ! -f "$keyfile" ]; then
        touch "$keyfile"
fi
if [ ! -f "$signfile" ]; then
        touch "$signfile"
fi
if [ ! -f "$trustfile" ]; then
        touch "$trustfile"
        loopback
else
        loopback
fi
if [ ! -f "$spffile" ]; then
        touch "$spffile"
else
        rm -rf "$spffile"
        touch "$spffile"
fi
if [ ! -z "$ipv6" ]; then
        if ! grep -q "$ipv6" "$trustfile"; then
                echo "$ipv6" >> "$trustfile"
        fi
fi
if [ ! -z "$ipv4" ]; then
        if ! grep -q "$ipv4" "$trustfile"; then
                echo "$ipv4" >> "$trustfile"
        fi
fi
# Generate keys and write the spfs records we need for each domain to one file
for domain in "${domains[@]}"
do
        keydir="$keys/$domain"
        default="$keydir/default.txt"
        if [ ! -d "$keydir" ]; then
                mkdir $keydir
        fi
        cd $keydir
        opendkim-genkey -r -d $domain
        chown opendkim:opendkim default.private
        key="default._domainkey.$domain $domain:default:$keydir/default.private"
        sign="$domain default._domainkey.$domain"
        trust="$domain"
        spf="$(cat $default)"
        # Check only the last line against the spf file as the first line is always the same
        spflast="$(tail -1 $default)"
        if ! grep -q "$key" "$keyfile"; then
                echo "$key" >> "$keyfile"
        fi
        if ! grep -q "$sign" "$signfile"; then
                echo "$sign" >> "$signfile"
        fi
        if ! grep -q "$trust" "$trustfile"; then
                echo "$trust" >> "$trustfile"
        fi
        if ! grep -q "$spflast" "$spffile"; then
                echo "$spf" >> "$spffile"
        fi
done

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .