Setting Up maddy On A VPS

by Brian Picciano - (5 min read)

In the previous post I left off with being blocked by my ISP from sending outbound emails on port 25, effectively forcing me to set up maddy on a virtual private server (VPS) somewhere else.

After some research I chose Vultr as my VPS of choice. They apparently don’t block you from sending outbound emails on port 25, and are in general pretty cheap. I rented their smallest VPS server for $5/month, plus an additional $3/month to reserve an IPv4 address (though I’m not sure I really need that, I have dDNS set up at home and could easily get that working here as well).


The first major hurdle was getting TLS certs for (not the real domain) onto my Vultr box. For the time being I’ve opted to effectively copy-paste my local LetsEncrypt setup to Vultr, using certbot to periodically update my records using DNS TXT challenges.

The downside to this is that I now require my Cloudflare API key to be present on the Vultr box, which effectively means that if the box ever gets owned someone will have full access to all my DNS. For now I’ve locked down the box as best as I can, and will look into changing the setup in the future. There’s two ways I could go about it:

  • SCP the certs from my local box to the remote everytime they’re renewed. This would require setting up a new user on the remote box with very narrow privileges. This isn’t the worst thing though.

  • Use a different challenge method than DNS TXT records.

But again, I’m trying to set up maddy, not LetsEncrypt, and so I needed to move on.


In the previous post I talked about how I’m using nix to generate a systemd service file which encompasses all dependencies automatically, without needing to install anything to the global system or my nix profile.

Since that’s already been set up, it’s fairly trivial to use nix-copy-closure to copy a service file, and all of its dependencies (including configuration) from my local box to the remote Vultr box. Simply:

nix-copy-closure -s <ssh host> <nix store path>

I whipped up some scripts around this so that I can run a single make target and have it build the service (and all deps), do a nix-copy-closure to the remote host, copy the service file into /etc/systemd/service, and restart the service.


For the most part the maddy deployment on the remote box is the same as on the local one. Down the road I will likely change them both significantly, so that the remote one only deals with SMTP (no need for IMAP) and the local one will automatically forward all submitted messages to it.

Once that’s done, and the remote Vultr box is set up on my nebula network, there won’t be a need for the remote maddy to do any SMTP authentication, since the submission endpoint can be made entirely private.

For now, however, I’ve set up maddy on the remote box’s public interface with SMTP authentication enabled, to make testing easier.


And now, to test it! I changed the SMTP credentials in my ~/.mailrc file as appropriate, and let a test email rip:

echo 'Hello! This is a cool email' | mailx -s 'Subject' -r 'Me <[email protected]>' '[email protected]'

This would, ideally, send an email from my SMTP server (on my domain) to a test gmail domain. Unfortunately, it did not do that, but instead maddy spit this out in its log:

maddy[1547]: queue: delivery attempt failed {“msg_id”:”330a1ed9”,”rcpt”:”[email protected]”,”reason”:”[2001:19f0:5001:355a:5400:3ff:fe73:3d02] Our system has detected that\nthis message does not meet IPv6 sending guidelines regarding PTR\nrecords and authentication. Please review\n for more information\n. gn42si18496961ejc.717 - gsmtp”,”remote_server”:””,”smtp_code”:550,”smtp_enchcode”:”5.7.1”,”smtp_msg”:” said: [2001:19f0:5001:355a:5400:3ff:fe73:3d02] Our system has detected that\nthis message does not meet IPv6 sending guidelines regarding PTR\nrecords and authentication. Please review\n for more information\n. gn42si18496961ejc.717 - gsmtp”}

Luckily Vultr makes setting up PTR records for reverse DNS fairly easy. They even allowed me to do it on my box’s IPv6 address which I’m not paying to reserve (though I’m not sure what the long-term risks of that are… can it change?).

Once done, I attempted to send my email again, and what do you know…



So now I can send emails. There are a few next steps from here:

  • Get the VPS on my nebula network and lock it down properly.

  • Fix the TLS cert situation.

  • Set up the remote maddy to forward submissions to my local maddy.

  • Use my sick new email!