VPS Setup

Email revisited

SMTP is a venerable protocol but in its vanilla form it is ridiculously vulnerable to snooping and spoofing. This section is a modest attempt to mitigate these issues.


DKIM is a way to sign messages to prove to the recipient that the SMTP server they originate from is legitimately associated with the domain of the sender.

apt-get install opendkim opendkim-tools
opendkim-genkey -t -s mail -d bruant.info
mv mail.private /etc/mail/dkim.key

Beside the private key, a file named mail.txt will be generated. It’s meant to be added to a special TXT record in your zone file, for instance mine looks like:

mail._domainkey 10800 IN TXT "v=DKIM1; k=rsa; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDWAWDQQG9LCd5mC1fG0ZBqviZ4TSF25BqOkJS/I3rHQ4eXp1hgQnaJhanW+I9F2k+u0wBTVKtFbwsrAO71QTtxjHPoZ8p1o6/ooYOU6NB/KPK3iPqCwf2SyNUgfiOZGvwPn0bBswXLakh13BxgYl99xQWRTKsEbT/X7JOmAh1hYQIDAQAB"

For DKIM to work you will need reverse-DNS lookup to work. This is usually configured via the control panel of your VPS provider. Use dig to verify the correct mapping.

$ dig +nocmd +noquestion +nocomments +nostats -x 3104 IN     PTR     bruant.info

NOTE GMail will reject incoming emails when connecting over IPv6 if the (IPv6) reverse DNS is not correctly setup. Either set it or disable IPv6 completely in postfix (otherwise you’ll have random delivery failure, depending on whether postfix opts for IPv4 or IPv6 when connecting to GMail servers).

The OpenDKIM config file is /etc/opendkim.conf and should look like:

Syslog                  yes
Domain                  bruant.info
KeyFile                 /etc/mail/dkim.key
Selector                mail
AutoRestart             yes
Background              yes
Canonicalization        relaxed/relaxed
LogWhy                  yes
InternalHosts           /etc/mail/InternalHosts

The associated /etc/mail/InternalHosts is as follows:

Finally we need to configure how OpenDKIM will communicate with postfix. This is controlled by /etc/default/opendkim, which should look like:

SOCKET="inet:8891@localhost" # listen on loopback on port 8891

To complete the setup, add the following to /etc/postfix/main.cf:

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

As usual, restart all services whose configuration have changed:

service opendkim restart && service postfix restart


SPF is another way to prevent spoofing and will reduce the probability for emails sent from your server to be classified as spam.

Figure out which policy suits your need and edit our zone file accordingly. My own SPF-related records look like:

@ 10800 IN SPF "v=spf1 a ~all"
@ 10800 IN TXT "v=spf1 a ~all"

The duplication may not be necessary but better safe than sorry.

NOTE GMail documentation warn that strict constraints (“-” as opposed to ”~”) may be problematic.

It is also possible to enforce SPF checking on incoming emails. I didn’t do it yet so I cannot describe the process but some kind Ubuntu user made a basic guide.


I have a GPG key, unfortunately very few of the people I correspond with have so much as heard of public key encryption and even those who have are unwilling to go through the hassle of signing/encrypting emails.

But lo and behold, I stumbled upon a guy describing how he encrypts all incoming emails. It’s not as good as end-to-end encryption but at least it means emails are encrypted at rest on the server, a pretty significant step up in a VPS context.

The original guide was for Exim but a kind soul took care of adapting the process to work with Dovecot.

Using a recent version of Dovecot from a PPA (or built from source) drastically simplifies the process: the only steps left are configuring Dovecot to find the sieve script and adding the appropriate public key to the GPG keyring.

I made slight modifications to the sieve script to keep encrypted emails in the same inbox as other emails and avoid encrypting emails sent from my own domain. That last filter is a bit blunt and may need to be refined in the future but for now it’s good enough to avoid encrypting the diagnostics emails sent by local daemon (denyhosts, psad, …)

My ~/.dovecot.sieve looks like:

require ["vnd.dovecot.filter"];

if allof(address :matches "To" "hugues@bruant.info",
         not address :matches "From" "*@bruant.info"){
    filter "gpgit" "hugues@bruant.info";