Linux Uptime

How to get DKIM (DomainKeys Identified Mail) working with Postfix on RHEL 5 / CentOS 5 using OpenDKIM 180


Update! RPMs and Yum now available.

I build and maintain the RPM packages of OpenDKIM for RHEL/CentOS and Fedora, which are available with Yum. For a much quicker and easier way to install OpenDKIM, read this.

Of course, if you still prefer to go old-skool and compile your own binaries from source, or if you’re building on a non-RedHat system, the following instructions will still work fine… they just require more effort. If you want to build your own RPMs, you can also download SRPMs for OpenDKIM.

Please note that I no longer maintain this outdated article. But I do maintain this article with more updated settings and instructions for configuring OpenDKIM. I recommend that you at least follow the updated configuration instructions on the newer post (particularly the opendkim.conf file details), even if you choose to build your own binaries by following the instructions in this post.

Build Your Own OpenDKIM Binaries

If you’d like to get DKIM working on an RHEL or CentOS box running Postfix, here’s how to do it (I’ve also verified these same steps work on a Fedora box). I had previously used dkimproxy, and had unsucessfully tried dkim-milter before making the switch to OpenDKIM. Both other methods may work for some, but OpenDKIM is the most current and the easiest way to get DKIM working so that’s what I recommend now.

For more information about DKIM and why you want to be running it on your mail server, check out http://www.dkim.org/. Now, on with the show!

Before you start

This tutorial assumes the following:

  • You are running a “modern” RedHat-compatible Linux distro (RHEL 5, CentOS 5, Fedora, etc). I was running CentOS 5.5 when I did this.
  • You are running Postfix 2.3.3 or better (do postconf -d mail_version to check).
  • Your Postfix configuration is currently working (this is very important – you don’t want to troubleshoot two programs at once).
  • Sendmail is turned off (do service sendmail status to verify).
  • The necessary commands in this tutorial are done as root. If you don’t know what that means, then you probably shouldn’t be doing this. You may be able to get away with just using sudo, but I wanted to make sure I didn’t run into any path issues, so I do it as root.

Of course, these steps will probably work with slighter earlier or slightly later versions of RHEL/CentOS and/or Postfix, but those are the versions I used to get DKIM working (update: I now run Postfix 2.8 on a few of my servers just fine with this setup).

Download and install OpenDKIM

Again, if you’re on a Fedora, RHEL, CentOS, or other RedHat compatible system, I strongly recommend you install the OpenDKIM RPM package from the EPEL repository by following these directions.

Otherwise, go to http://www.opendkim.org/ and hit the Download link to download the software. Save it to /usr/local/src on your server. For this HowTo, I used OpenDKIM version 2.4.2, which was released on August 6, 2011.

You’ll also need to install the OpenSSL and Sendmail development packages, because they contain some secret herbs and spices (otherwise known as “libraries”) you need to get OpenDKIM working. Do:

yum install sendmail-devel openssl-devel

Extract, configure, compile, and install OpenDKIM with:

tar zxvf opendkim-2.4.2.tar.gz
cd opendkim-2.4.2
./configure --sysconfdir=/etc --prefix=/usr/local --localstatedir=/var
make
make install

Note that the ./configure command includes a few very important flags, which will be passed into the startup script that’s created when the configure command runs. The first tells the system where OpenDKIM’s conf file will be located, the second sets the preferred prefix for some other important file locations, and the final one controls the directory where the PID file for OpenDKIM will be stored. If none of this makes any sense to you, that’s ok – just be sure to use those flags when you run configure, since they are the settings used throughout this tutorial.

Also, it’s important to note that the make install command must be performed as root (or using sudo), since it needs to install files files in the /usr/local/bin directory.

Create a new user and home directory

Add a new user for DKIM called opendkim with the following options:

useradd -r -g opendkim -G mail -s /sbin/nologin -d /var/run/opendkim -c "OpenDKIM" opendkim

This command will:

  • create a new system account (-r) and group (-g) called opendkim,
  • create a home directory (-d) for the new user in /var/run/opendkim,
  • also add the opendkim to the mail group (-G),
  • assign no shell access to this user (-s), and
  • set the account comment to “OpenDKIM (-c).

While the proper permissions for this account’s home directory should be set when the user is created, to avoid any permissions issues in further steps, it doesn’t hurt to manually set them with:

chown opendkim:opendkim /var/run/opendkim

then:

chmod 700 /var/run/opendkim

Create working directories

Make some new directories for OpenDKIM and give them the proper ownership and permissions with:

mkdir -p /etc/opendkim/keys
chown -R opendkim:opendkim /etc/opendkim
chmod -R go-wrx /etc/opendkim/keys

Copy the startup script to /etc/init.d/

Starting with version 2.3.0, OpenDKIM’s source package includes a contrib directory that contains a custom init script (written by yours truly) for use with all RedHat-compatible systems, including Fedora and CentOS. You can copy it to your /etc/init.d/ directory to make starting, stopping, restarting, and reloading OpenDKIM easy. Just do:

cp /usr/local/src/opendkim-2.4.2/contrib/init/redhat/opendkim /etc/init.d/

Now set the correct permissions for the init script with:

chmod 755 /etc/init.d/opendkim

Generate keys for signing

Now you’re getting to the good part. You need to generate a private and a public key for each of the domains for which you wish to sign mail. The private key is stored away from prying eyes on your server, while the public key gets published in your domain’s DNS records so that receiving mail servers can verify your DKIM-signed mail. If you’re hard-core, you can build the keys manually. Or, you can use the fancy script included with OpenDKIM to do it for you. I’ve manually generated enough keys in my life and have nothing to prove, so I use the script. 🙂

Before running this script, decide now what the name of your selector is going to be. A selector is a unique keyword that is associated with both keys (public and private), included in all the signatures, and published in your DNS records. For simplicity, I use the word default as my default selector. Not very creative, but it’s effective. Feel free to choose something different, but if you do, you’ll need to use it consistently throughout your setup. Also, while this should go without saying, you should use your mail domain instead of example.com throughout the following steps.

Create your keys with:

mkdir /etc/opendkim/keys/example.com
/usr/local/bin/opendkim-genkey -D /etc/opendkim/keys/example.com/ -d example.com -s default
chown -R opendkim:opendkim /etc/opendkim/keys/example.com
mv /etc/opendkim/keys/example.com/default.private /etc/opendkim/keys/example.com/default

You can do a man opendkim-genkey if you’re interested in what additional options are available when creating your keys. In this example, I used the -D (directory) option, the -d (domain) option, and the -s (selector) options. That’s all you need to get this going.

Edit configuration files

You’re getting really close now. You need to create or edit four files:

  1. /etc/opendkim.conf – OpenDKIM’s main configuration file
  2. /etc/opendkim/KeyTable – a list of keys available for signing
  3. /etc/opendkim/SigningTable – a list of domains and accounts allowed to sign
  4. /etc/opendkim/TrustedHosts – a list of servers to “trust” when signing or verifying

Use your favorite text editor to create an /etc/opendkim.conf file that looks like this:

##
## opendkim.conf -- configuration file for OpenDKIM filter
##
Canonicalization        relaxed/relaxed
ExternalIgnoreList      refile:/etc/opendkim/TrustedHosts
InternalHosts           refile:/etc/opendkim/TrustedHosts
KeyTable                refile:/etc/opendkim/KeyTable
LogWhy                  Yes
MinimumKeyBits          1024
Mode                    sv
PidFile                 /var/run/opendkim/opendkim.pid
SigningTable            refile:/etc/opendkim/SigningTable
Socket                  inet:[email protected]
Syslog                  Yes
SyslogSuccess           Yes
TemporaryDirectory      /var/tmp
UMask                   022
UserID                  opendkim:opendkim

You can do man opendkim.conf for more information on each of the options.

Next, you’ll need to create the three text files that you just mentioned in your config file. First, using your favorite text editor, create an /etc/opendkim/KeyTable file that looks like this:

default._domainkey.example.com example.com:default:/etc/opendkim/keys/example.com/default

The KeyTable file tells OpenDKIM where to find your keys. Each entry in the KeyTable file is a single line for each key location (for example, all of the text in the above example should be on a single line in your file). If you’re going to use multiple keys (to sign mail for virtual domains with different keys, for example), you’ll need to create a separate line in the KeyTable file for each domain.

Next, create an /etc/opendkim/SigningTable file that looks like this:

*@example.com default._domainkey.example.com

The SigningTable file tells OpenDKIM how to use your keys, as in which senders should use which selectors for their signatures. In the above example, I’m saying that everyone (*) sending mail from the server “example.com” should use the selector named “default.” It’s important to note that the * wildcard symbol will only work if the SigningTable option uses the refile: prefix before the filename (see the opendkim.conf documentation for more details).

Now create an /etc/opendkim/TrustedHosts file that looks like this:

127.0.0.1
hostname1.example1.com
hostname2.example1.com
example1.com
hostname1.example2.com
hostname2.example2.com
example2.com

The TrustedHosts file tells OpenDKIM who to let use your keys. Because it’s referenced by the ExternalIgnoreList directive in your conf file, OpenDKIM will ignore this list of hosts when verifying incoming mail. And, because it’s also referenced by the InternalHosts directive, this same list of hosts will be considered “internal,” and OpenDKIM will sign their outgoing mail.

IMPORTANT: Make sure you list the IP address for localhost (127.0.0.1) in the TrustedHosts file or OpenDKIM won’t sign mail sent from this server. If you have multiple servers on the same network that relay mail through this server and you want to sign their mail as well, they must be listed in the TrustedHosts file. Put each entry on its own line. An entry can be a hostname, domain name (e.g. “example.com”), IP address, an IPv6 address (including an IPv4 mapped address), or a CIDR-style IP specification (e.g. “192.168.1.0/24”).

It should also go without saying (but I’ll say it anyway) that if you’re planning to sign outgoing mail for remote hosts, your Postfix should have been previously configured to allow relaying for those hosts, as “explained” here… although, when referring to Postfix’s programmer-centric documentation, I generally use the term “explain” very loosely. 😉

Edit your Postfix configuration

Now you’re ready to add the following lines to your Postfix main.cf file, which will make Postfix aware of OpenDKIM and allow it to sign and verify mail:

smtpd_milters           = inet:127.0.0.1:8891
non_smtpd_milters       = $smtpd_milters
milter_default_action   = accept

If you’re running a version of Postfix prior to 2.6, you may also need to add:

milter_protocol   = 2

See http://www.postfix.org/MILTER_README.html#version for more info.

Start OpenDKIM and restart Postfix

It’s time to fire things up! Assuming you’re using bash, do:

hash -r

to rehash your shell so you can find the init script.

Now start OpenDKIM with:

service opendkim start

You should get a message that says:

Starting OpenDKIM Milter:     [  OK  ]

However, if you get an error message such as:

Starting OpenDKIM Milter: opendkim: /etc/opendkim.conf: configuration error at line 6: unrecognized parameter

don’t freak out. You probably just mistyped something in one of the config files. Go to the line number of the file listed, and check your work against the example(s) in this HowTo. Then try starting up OpenDKIM again.

Once it starts, refresh Postfix with:

postfix reload

If everything looks good, I recommend running chkconfig on OpenDKIM to make sure it starts when you boot your server:

chkconfig --level 2345 opendkim on

If things didn’t go right, try some of these startup troubleshooting tips before moving on.

Startup troubleshooting tips

Tip 1: The best advice I can give when troubleshooting any mail issues (including OpenDKIM) is to start a second shell session in another window and do:

tail -f /var/log/maillog

while you’re starting, stopping, and/or restarting OpenDKIM and Postfix. This allows you to see more details about any errors in your configuration.

Tip 2: To get the most verbose information from OpenDKIM, make sure the LogWhy option in your /etc/opendkim.conf file is uncommented and set to Yes. If your outgoing mail isn’t getting signed and you want to know why, this should tell you.

Tip 3: If you can’t get things working on your own, I recommend subscribing to the OpenDKIM-Users discussion list at http://lists.opendkim.org/. It’s a low-traffic list with very helpful and friendly members (including me!) who are happy to nudge you in the right direction.

The Most Important Step: Adding DNS Records

Now that your mail server is signing outgoing mail and verifying incoming mail, you’ll need to put some information in your DNS records to tell other mail servers how your keys are set up, and provide the public key for them to check that your mail is properly signed. Do:

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

The output should look something like this:

default._domainkey IN TXT "v=DKIM1; g=*; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHY7Zl+n3SUldTYRUEU1BErHkKN0Ya52gazp1R7FA7vN5RddPxW/sO9JVRLiWg6iAE4hxBp42YKfxOwEnxPADbBuiELKZ2ddxo2aDFAb9U/lp47k45u5i2T1AlEBeurUbdKh7Nypq4lLMXC2FHhezK33BuYR+3L7jxVj7FATylhwIDAQAB" ; ----- DKIM default for example.com

If you manage your own DNS or have full access to your domain’s zone file, you’ll need to paste the entire contents of the default.txt file at the bottom of your domain’s zone file. If you’re using a web interface to manage your zone file, be careful that the long lines of the public key don’t wrap and create line-feed characters (or fix them if they do). Otherwise, your public key won’t work.

If you’re using GoDaddy’s Total DNS, the TXT Name would  default._domainkey and the TXT Value would be everything inside the quotes (starting with v=). You can ignore the semi-colon and comments at the end.

If you’re using some other third-party DNS provider, follow their instructions for adding a new TXT Record.

You should also add another TXT Record to your zone file that reads:

_adsp._domainkey.example.com    IN    TXT    "dkim=unknown"

This record publishes your Author Domain Signing Practices. “Unknown” is the least strict setting, and the best place to start. You can learn more and tinker with other options later, but most people just use “Unknown” for now, since ADSP is relatively new (as of the writing of this post).

And, as long as you’re messing with your domain’s zone file, now might be a good time to ensure that you already have a valid SPF Record in place. Having both DKIM and SPF in place will increase your chances of having your outgoing mail successfully delivered.

Testing Things Out

As I mentioned in my troubleshooting tips, the best way to see that everything is working on the server side is to keep an eye on your /var/log/maillog file. Do a:

tail -f /var/log/maillog

When OpenDKIM starts (or restarts), you should see lines like:

opendkim[4397]: OpenDKIM Filter: mi_stop=1
opendkim[4397]: OpenDKIM Filter v2.4.2 terminating with status 0, errno = 0
opendkim[27444]: OpenDKIM Filter v2.4.2 starting (args: -x /etc/opendkim.conf)

When you send a mail that gets successfully signed, you should see:

opendkim[22254]: 53D0314803B: DKIM-Signature header added

The best way to check that your signed mail is being authenticated and that your DNS records are properly set up is to use one of the free testing services. My favorites are:

Each of these will tell you if things are working properly, and give you some pointers on troubleshooting if needed.

If you have a Gmail account, you can also send a signed message there for a quick and easy test. address Here’s what a signed message in Gmail will look like:

DKIM Test Message

Look, Ma! My emails have DKIM Signatures!

The signed by: line tells you that the message has been verified as signed by the sender (you may need to press the show details link near the top of the message to see it). I like to click the Show Original link (under the Reply drop-down on the right) to see the signed headers in all their glory. 🙂

Further reading

I have to admit that there wasn’t a whole lot of publicly available information on getting OpenDKIM working with Postfix. Hopefully, this HowTo will make it easier for you than it was for me.

  • DKIM.org – the official site for DomainKeys Identified Mail
  • OpenDKIM Project Site – the program I used to get DKIM working
  • Sendmail DKIM – a detailed article from Eland Systems about DKIM. They use the dkim-milter package, upon which OpenDKIM is based. I much prefer the newer OpenDKIM, but this article explains DKIM very well and has some good tips.
  • Mail-DKIM and DKIM-proxy – my first experiments with DKIM were with these tools. I never got it working quite right, but there’s lots of good info there.
  • OpenSPF.org – not technically related to DKIM, but it’s another spam-fighting technique that you should be using if you’re sending email

Good luck! Pease post in the comments with your successes, questions, or suggestions.

Upgrading OpenDKIM

If you’ve followed this guide to compile and install OpenDKIM, and would like to upgrade to a newer version, simply download the updated version (using the download link above), then repeat these steps:

tar zxvf opendkim-2.4.2.tar.gz
cd opendkim-2.4.2
./configure --sysconfdir=/etc --prefix=/usr/local --localstatedir=/var
make
make install

This will upgrade your OpenDKIM and keep your existing configuration intact. Remember to restart OpenDKIM after your upgrade with:

service opendkim restart

Do:

tail -f /var/log/maillog

to verify that the newer version started up with no problems.