This is an update to the original How to Setup DomainKeys Identified Mail (DKIM) with Postfix and FreeBSD. A lot has changed in the time since that was written. First off, it's no longer called DomainsKeys. Now a days the standard goes by DKIM and the software used is OpenDKIM. Setting up DKIM is usually part of the solution to your outgoing email ending up in the "Junk" folder.
Your outbound SMTP server will sign every outgoing email with a cryptographic private key using the message content. Your email domain has a corresponding TXT record in DNS the that contains a matching public key. The receiving end will take the key and validate the signature, thus authenticating the message and confirming that it was indeed sent by your email server.
The result of this setup will also validate DKIM signatures for incoming mail in Postfix.
Requirements
- Tested with FreeBSD 13.0 and later
- Postfix 2.5 or later installed and running
- BIND 9.0 or later installed and running
- Your Domain, Email, and DNS are working properly
Install and Configure OpenDKIM
OpenDKIM is the latest and recommended implementation maintained by a 100% open source community. Install the mail/opendkim port using the package.
pkg install -y mail/opendkim
The port installs a configuration file under "/usr/local/etc/mail/opendkim.conf". Many of the defaults are adequate for a single domain. The only required edit is the Socket parameter. In addition to that, we'll make changes to support both single and multiple domains.
edit /usr/local/etc/mail/dkim-filter.conf
Comment out the line "KeyFile". Then un-comment "KeyTable" a few lines below that. Lastly un-comment "SigningTable" further down the file around line 632. Specify full paths to the corresponding files that will contain the key information.
#KeyFile /var/db/dkim/example.private
...
KeyTable /var/db/dkim/keytable
...
SigningTable /var/db/dkim/signingtable
The "KeyTable" is a map of domains to arbitrary key names and the "SigningTable" maps those key names to a selector and private key.
Scroll all the way down to (nearly) the bottom of the file at about line 660 and configure the "Socket" parameter. To keep things simple we will use an INET socket on the loopback device with port 8891, or any other available port number you prefer. If you want to have the milter listen on all interfaces simply omit the '@localhost' component. The line should be similar to the following.
Socket inet:8891@localhost
Save and close the file.
Generate Domain Keys
The opendkim-genkey utility is used to generate private and public key pairs for your domain(s). These keys will be stored in the "/vat/db/dkim/keys/domain.tld" folder as "default" for the private key and "default.txt" for the public key that gets used in the DNS server. The files are named according to the selector used, which in this case is 'default'.
Replace "domain.tld" with your email domain name. If you host multiple domains, repeat these commands for each domain you wish to enable the feature on. The selector can be specified using the optional '-s' flag which defaults to 'default'.
mkdir -p /var/db/dkim/keys/domain.tld
dkim-genkey -D /var/db/dkim/keys/domain.tld -d domain.tld
Add the key(s) into the KeyTable file.
edit /var/db/dkim/keytable
Each line of the file follows the format, "[KEYNAME] [DOMAIN]:[SELECTOR]:[KEY]". The key's given name is arbitrary. The selector will be 'default' unless you overrode it while generating your key pairs. The last part is the absolute path to the file containing the private key that was generated earlier.
For example, add the following line to "/var/db/dkim/keytable". If you have multiple domains add one line for each domain.
thisisakey_name1 domain.tld:default:/var/db/dkim/keys/domain.tld/default.private
Save and close this file when done.
Add a mapping to the SigningTable file
edit /var/db/dkim/signingtable
The format of this file can vary based on your specific needs. In this example we'll use the basic [DOMAIN] [KEYNAME] style formatting. The domain is the FQDN of the email domain you are protecting/authenticating. Although the official OpenDKIM documentation mentions using a wildcard, I found that (at least on FreeBSD) the wildcard is not required.
For example, add the following line to "/var/db/dkim/signingtable". If you have multiple domains add one line for each domain.
domain.tld thisisakey_name1
Save and close this file when done.
Configure Postfix
Link the included OpenDKIM milter to Postfix, it's done with a single line.
Open your "/usr/local/etc/postfix/main.cf" file.
edit /usr/local/etc/postfix/main.cf
Add the line as shown below. Or append to it if you already have existing milters in use.
smtpd_milters = inet:localhost:8891
Save and close the file.
Enable and Start the Software
Enable the OpenDKIM milter service.
sysrc milteropendkim_enable="YES"
Start up the OpenDKIM milter service, reload the postfix configuration, and monitor the logs for any errors.
service milter-opendkim start
postfix reload
tail -f /var/log/maillog
If all goes well, hit CTRL+C to exit out of the log file viewer.
The OpenDKIM milter service will need to be reloaded anytime a new entries are added to your KeyTable and SigningTable
service milter-opendkim reload
Add DNS Records
This last step assumes you are using BIND on FreeBSD. If you use alternate DNS management software (provided by your ISP or hosting), then consult it's documentation on how to add a TXT record to your domain.
The TXT record that you will add is pre-generated for you in "/var/db/dkim/keys/domain.tld/default.txt". Copy the entire contents of that file, and paste at the end of your zone records file. You could have something similar to the following.
domain.tld. IN SOA ns.domain.tld. root.domain.tld. (
1125170171
10800
3600
604800
38400 )
domain.tld. IN NS ns.domain.tld.
mail.domain.tld. IN A 123.156.189.123
ns.domain.tld. IN A 123.156.189.124
default._domainkey IN TXT "v=DKIM1; g=*; k=rsa; p=00EBAQUAA4GNADCBiQKXXXXXXXXXXXXXXX...." ; ----- DKIM default for domain.tld
Save the records file and reload your zone information using the "rndc reload" command.
rndc reload domain.tld
Send an Email
Send a test email then look at the message source code. You'll see a header named "DKIM-Signature:", this verifies that everything is working properly on the mail server's end.
Extra Credit
It's a very inconvenient situation if the milter stops working. If you are using sysutils/monit, here's a sample configuration that may be used to monitor and restart the service if it fails.
check process milter-opendkim
matching "/usr/local/sbin/opendkim"
start program = "/usr/sbin/service milter-opendkim start"
stop program = "/usr/sbin/service milter-opendkim stop"
The complete configuration of a fully functional Monit is outside the scope of this guide.
- Log in to post comments