DKIM signing with OpenSMTPD and dkimproxy

After a long wait of OpenSMTPD 6.6 and its accompanying rspamd filter, I finally sent my mails DKIM-signed. Along the way I also discovered rspamd does a bit too much for my need and learned that it’s way simpler to use dkimproxy instead.

Outline of the steps required as follow:

  • Install OpenSMTPD
  • Install dkimproxy
  • Create signing keys
  • Decide “selector” name
  • Add relevant DKIM entry to all relevant domains
  • Setup dkimproxy to sign stuff
  • Setup OpenSMTPD to relay to dkimproxy before finally sending the message
  • Test
  • Done

Signing keys are created by:

openssl genrsa -out /etc/mail/dkim/selector1.key 1024

Followed by creating the public key for DNS entry:

openssl rsa -in /etc/mail/dkim/selecto1.key -pubout -out /etc/mail/dkim/selector1.pub

Don’t forget to fix private key permission to 400 owned by whatever user running dkimproxy.

The dkimproxy setting is pretty simple:

listen 127.0.0.1:10027
relay 127.0.0.1:10028
domain domain1.com,domain2.net
signature dkim(c=relaxed)
signature domainkeys(c=nofws)
keyfile /etc/mail/dkim/selector1.key
selector selector1

It’s pretty straightforward.

And equally straightforward the settings for OpenSMTPD:

table aliases file:/etc/mail/aliases

listen on lo0
listen on lo0 port 10028 tag DKIM

action "local" mbox alias <aliases>
action "relay_dkim" relay host smtp://127.0.0.1:10027
action "outbound" relay

match tag DKIM for any action "outbound"
match for local action "local"
match for any action "relay_dkim"

First line sets the aliases.

Followed by a listener on localhost because this is just an example for sending-only server.

The listener on port 10028 is to accept the signed mail by DKIM to be finally sent.

local action sending mails to mbox for local user.

relay_dkim action will send mails to dkimproxy which will sign the email…

And relayed to 10028, accepted by smtpd, tagged DKIM and thus will be finally sent to where it should be. I learned the hard way it needs to come first because mails will be acted on first match.

Local for local. Don’t bother doing anything.

And finally the rest will be relayed to dkimproxy. As mentioned above, this must come after the outbound action for DKIM tagged mails.

If you want to run proper mail server with rspamd and stuff, read this instead. That article was also the reason I started looking into all this DKIM stuff.

Letsencrypt, cavemen edition

Just had to do some letsencrypt setup in some servers so I figured I should write down what I did so I can just check this page again instead of digging how I did it previously.

Requirements:

  • nginx
  • certbot

This assumes the server only serves https and redirects all http traffic. Adjust as needed otherwise.

Full nginx SSL/TLS config not included.

First add this config to nginx to handle verification:

# part of default port 80 config block
location /.well-known/acme-challenge/ {
    root /var/www/certbot;
}

And then create the directory (I’m not actually sure if needed):

# mkdir -p /var/www/certbot

Make the first cert because I’m too lazy to ensure the config directory is setup correctly:

# certbot certonly --webroot -w /var/www/certbot -d DOMAIN_NAME_GOES_HERE --keep --agree-tos --email SOME_KIND_OF@EMAIL_ADDRESS --no-eff-email

At this step, the certificate and all should have been properly generated.

Then use it in nginx configuration, the relevant server block:

ssl_certificate /etc/letsencrypt/live/DOMAIN_NAME_GOES_HERE/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/DOMAIN_NAME_GOES_HERE/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/DOMAIN_NAME_GOES_HERE/chain.pem;

If the full path seems too long, symlink it to nginx config base directory or something.

Update certbot CLI configuration located at /etc/letsencrypt/cli.ini:

rsa-key-size = 4096
text = True
authenticator = webroot
webroot-path = /var/www/certbot

To add more certificates:

# certbot certonly -d ANOTHER_DOMAIN

Don’t forget to update nginx configuration as before.

Since the certificate needs renewal periodically, create this simple script:

#!/bin/sh
# I personally put this in /root/bin/refresh-ssl-certbot

/usr/bin/certbot renew
/path/to/sbin/nginx -s reload

Make executable, etc. Try it to make sure it runs properly.

Then add it crontab. I usually do it weekly.

And done.

There might be smarter way using certbot’s nginx plugin or something but I haven’t bothered reading its documentation and initially this was just a stopgap switching from acme-client which is way simpler but stopped working for me few months ago.

IP address checker

Random idea I came up when reading nginx mailing list. A very simple way to set up external IP address checker using nginx on a remote server.

location = /ip {
    default_type text/plain;
    types { }

    return 200 $remote_addr\n;
}

Accessing /ip will then return the current external IP address. A more fancy output like JSON is possible as well.

Ruby 2.3 on FreeBSD 11

Compiling Ruby on FreeBSD is not quite simple.

  • make sure to tell it to also find libraries in /usr/local
  • and tell configure script to find OpenSSL in /usr because the later version isn’t quite compatible with latest ruby yet

So here’s the configure line

CFLAGS=-I/usr/local/include \
CPPFLAGS=-I/usr/local/include \
LDFLAGS=-L/usr/local/lib \
./configure --prefix="/opt/ruby23" --disable-install-doc --with-openssl-dir=/usr \
&& make \
&& make install

Miura Fold

This is mostly for my own reminder.

  1. Google “miura fold”
  2. Read some articles, watch some videos
  3. Remember this:
    1. Long/initial fold must be odd-numbered.
    2. Short/following fold must have approximately same degree.
    3. Open up, fold following the short, zigzagged lines.
    4. ???
    5. Profit?

Not sure if useful.

Network performance checklist: TSO/LSO

Took me good few hours to find out why specific combination of task performs incredibly slowly on my server.

For reference, in my case it’s port-forwarded ssh/https connection over openvpn.

[ Client ] --(Internet)--> [ Gateway ] --(OpenVPN)--> [ Server (SSH) ]

Doing anything which takes up bandwidth (displaying log files, etc) will shoot the cpu load (at interrupt) up by a lot. By a lot I mean over 50% of one core.

This guy have the reasoning why it’s happening but I don’t know how much of it is correct. VMware support page also suggesting disabling it if network performance is slow.

In FreeBSD it’s:

echo 'net.inet.tcp.tso=0' >> /etc/sysctl.conf

In Windows it’s this .reg file:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters]
"DisableTaskOffload"=dword:00000001

It seems to involve a shell script in Linux so I won’t bother writing it off here since it differs by system.

As usual, YMMV.

…and there goes my time 🙁

PSA: Never trust external X-Forwarded-For

For god knows how long, proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; is one of the line usually included in nginx config snippet for proxying to a unicorn (Rails) backend.

…which is something you should never do unless you have another load balancer in front of the nginx being configured.

That line basically tells nginx to append $remote_addr to whatever X-Forwarded-For value currently set. It is only useful when your nginx is behind other load balancer which set up its own (hopefully correctly) X-Forwarded-For. It should be set explicitly to $remote_addr for any external-facing proxy. Otherwise fun things will happen.

FreeBSD pkg (manual) upgrade thingy

For working with locked packages (the ones which must be upgraded through compilation because of using custom options)

#!/bin/sh
# filename: pkg-lock-outdated

pkg query -e '%k = 1' %o | while read pkgorig; do
  pkg version -ovL => -O "$pkgorig"
done

The script above is to list locked packages which need upgrading. And to upgrade everything at once (and sit in front of PC waiting for whole process)

#!/bin/sh

listfile="/tmp/pkgforupgrade.$(date '+%Y%m%d%H%M%S')"
pkg-lock-outdated | cut -f 1 -d '<' > "$listfile"

while read <&3 outdated; do
  pkg unlock "$outdated"
  portmaster "$outdated"
  pkg lock "$outdated"
done 3< "$listfile"

rm -f "$listfile"

There’s another alternative of unlocking all packages at once, run batched portmaster, and lock them all again.