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.

Psycho Pass S3 ep. 2

I haven’t written episodic post since forever. Not like this one will be any better than the last time anyway lol.

I guess it’s a good thing I watched the SS. It’s not that important so far apart of just introducing some of the new faces and explains how Kogami returned to Japan. Interesting, but not really necessary so far, I think.

More Akane screen time yay. I guess this season will end with the end of Sibyl System?

Weekly FGO Vol. 2

“But it’s not even a week since the last one”

I’ll do this whenever I feel like to =)

Anyway,

JP

Saber Wars 2 has started. 10 tickets were spent. Two SR event CEs were obtained. And then the rest of the pulls were crap. Oh well at least I got some event CEs although an SSR would be nice.

If the mission counter is to be believed, I’m about 3/4 way to the end. I haven’t checked any guides or spoilers yet so I don’t know if it’s way longer than I thought or if there will be another set of missions. Considering the duration it’s probably not going to happen though.

I cleared Eli challenge quest with help of one command spell. I probably should’ve waited until I got all the damage booster CEs especially considering it’s not repeatable. But I didn’t. It’s not that difficult, just rather annoying. Also I probably should level Spartacus a bit more. Except I don’t have enough grails. Yay.

There are still quite a lot of store items to be purchased and a bit more missions to be cleared. And challenge quest. It’ll be kind of annoying with all CE slots potentially taken up by event CE.

NA

I haven’t finished the Babylonia campaign quests yet. The item drop ones. Maybe once I finish the last bit of monuments from event store.

Next event will be Jailter. That’ll be fun. I sure can use a good area NP lancer.

It kinda sucks Okita pick up isn’t happening and the next pickup will be May next year. That sounds like a long time without Okita. On the brighter side, it’ll also give me ample time to save some quartzes and tickets.

Weekly FGO Vol. 1?

Dunnolol I’ve been kind of doing this somewhere else and I figured I should move it here.

FGO JP

Event starts later today! Maybe will do an 11 rolls. I hope to get some event CEs at least.

Now I think again, I’m not sure if I even want any of the new servants.

FGO NA

I’m done with Halloween missions. I haven’t finished Salomon so I can’t do challenge quests yet ;_; RIP fancy cube.

The Babylonia anime campaign is a nice surprise. It’s mostly the same as the one in JP.

yes-www

I’ve been using blanket rule of no-www this past years and that is coming to an end.

Leaking WordPress cookies to every single sites hosted on this domain is probably not the best idea. Not that there’s any problem but just in case. Also no cookie to worry about for uploads and other static sites. Or maybe not if WordPress sets the cookie properly (it seems to be mostly does).

I was thinking of moving everything but for some single-use domains like 0paste.com it’s probably fine with no-www.

The other benefit is I can point the bare domain to a cheap server just for redirection and properly set CNAME for www subdomain instead of relying Cloudflare’s top-level CNAME function (which apparently also called “ANAME”?).

I’ve switched the redirection for www to 302 (temporary redirect) from 301 (permanent redirect) a while ago so hopefully no browser still cache the 301.

HTML template

Apparently I made over 50 drafts for this blog years ago. This is one of them. And the content doesn’t seem to be too bad so might as well finish this post.

I occasionally write some HTML. There are some essential things needed for a valid page.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Title goes here</title>
<!-- additional meta goes here or wherever -->
</head>
<body>
Content goes here.
</body>
</html>

The doctype is just the basic HTML 5 doctype.

Followed by setting the language of the page. Usually English. Apparently it’s recommended by W3C. Although I sometimes forgot about it.

Then of course head, followed right away by charset. UTF-8 is the best set we currently have and so it’s set there. Without this tag, the page might be rendered in some other set.

I’m not sure if setting X-UA-Compatible is still relevant anymore but IE11 is still here so might as well set it. Or remove if IE compatibility isn’t needed.

Viewport setting is unfortunately essential so the page isn’t zoomed out when viewed using mobile device. Just don’t disable scaling as that’s rude (unless it’s game or something).

The rest are just usual HTML stuff.

Mastodon and FreeBSD

Together with updating all other craps and server migrations, I decided to finally update Mastodon install as well which I broke after upgrades and package removals.

Then in usual fashion, one of dependency didn’t install on FreeBSD because it’s missing pre-compiled binary and the build script has too strict settings causing the build to fail.

Did some hackery to figure out how to fix it (following this guide works) but then when I looked around the situation on the official uws module page it says it’s been unmaintained since forever. Googling around a bit it seems like the author is being a dick and ended up ragequitting the module. Mastodon dev was notified but no action is taken.

The good thing is I looked into replacing it with ws a long time ago and posted it to Mastodon issue tracker. As I’m not interested in doing the module-level hackery, I figured it’s easier to do it now. Also I forgot how I fixed it before which didn’t involve such hackery. Or maybe I did. I don’t know.

In the end I reapplied my patch and everything is good again.

Or not, because I switched PostgreSQL authentication to the shiniest Scram-SHA-256 which isn’t supported by node-postgres. The issue has been open forever and I’m not really interested in fixing it.

Thankfully someone tweeted me the existence of node-pg-native. I looked into it and even though it’s not a drop-in replacement for node-postgres, adding pg-native and setting NODE_PG_FORCE_NATIVE=1 environment variable will force the module to use native library which fixed the problem.

Except for node-libpq which for some reason doesn’t link correctly (my postgres is installed in non-standard path). Whoops. I think fixed it and hopefully it gets merged.

With all the fixes in place, everything seems fine.

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.