OK. At this point, I have a working router for my internal network. I’m using pf as my firewall, have a heavily (in my mind) secured ssh path into things and I’m having fun watching port scanners hit me and try to log into my ssh (which doesn’t accept passwords). I think it’s time to see if I can break everything by setting up a mail server! I mean, how hard can it be?
And that’s how all of this started. I figured it would be as simple as finding a good tutorial on the internet, standing up the right config changes on my machine and presto – I’ll have my own email server with the data being stored on my own hardware, not some cloud server that gets mined for ways to better market to me. Unfortunately, the state of US based ISPs made this much more difficult.
After some stumbling around, I discovered that inbound traffic on port 25 (smtp) was blocked at the perimeter by my ISP. I would need to get more creative. Later I discovered that they also block all outbound traffic on that port as well. More creativity needed to solve that problem.
Fortunately as a listener of many fine podcasts on the Jupiter Broadcasting Network (http://jupiterbroadcasting.com) including BSDNow (http://bsdnow.tv), I had heard of a company called Digital Ocean (http://digitalocean.com). This is a cloud hosting provider where all storage is SSD and you have gigabit networking right up to your VM. The best part is that you can stand up their low-end server for as little as $5.00 US per month.
The reason I need that server is that I need to be able to have a mail relay that doesn’t have the port restrictions on it to send and receive email on my behalf and forward traffic both ways. For example, someone sends me an email and the internet deilvers it on port 25 of my relay server. It then turns around and forwards it to a high-numbered port on my internal server (actually my router that I described in the last blog post). When I send mail from my server, it has to go out on a high numbered port and get relayed to my DigitalOcean server so that it can turn around and deliver it on port 25 for me.
Conceiving all of this in my mind as a design was one thing. Actually building it was another. I decided to use the OpenSMTP implementation that is part of the base operating system in OpenBSD and (of course) run the relay server on OpenBSD. And there was the first hiccup. While DigitalOcean recently added support for FreeBSD, they don’t officially support OpenBSD yet. Fortunately for me, the folks at the BSDNow podcast had already solved this for me. They pointed me at a nice blog post where someone set up a FreeBSD server on DigitalOcean and used the swapfile to load the miniroot filesystem from OpenBSD to run the install from (http://www.tubsta.com/2015/04/openbsd-on-digital-ocean/).
Cool! The one trick you have to know is that OpenBSD 5.7 does not work to install this way. You have to be on a newer release so I’m running 5.8-current on the server and its working just fine. Once I had that in place, I needed to open the appropriate ports on pf to allow traffic into the right ports but keep everything else locked down.
# $OpenBSD: pf.conf,v 1.54 2014/08/23 05:49:42 deraadt Exp $
#
# See pf.conf(5) and /etc/examples/pf.conf
set skip on lo
block return # block stateless traffic
pass # establish keep-state
# By default, do not permit remote connections to X11
block return in on ! lo0 proto tcp to port 6000:6010
block in log all
pass in on egress proto tcp to any port 22
pass in on egress proto tcp to any port smtp
pass in on egress proto tcp to any port 2525
pass in on egress proto tcp to any port submission
As you can see, it’s a pretty vanilla configuration but I’m opening port 25 (smtp), port 587 (submission) and port 2525 (my high numbered port that I will receive email from my internal server on to relay to the ultimate destination over port 25 on the public internet).
The next step was to actually stand up OpenSMTP on the relay server. I first needed to enable it to start at boot by adding:
smtpd_flags=""
to my /etc/rc.conf.local file. Then I followed the tutorial on this brilliant blog post (http://technoquarter.blogspot.com/p/series.html) to do most of the configuration of my relay server. I did have to modify the resulting /etc/mail/smtpd.conf for my relay use case as follows:
pki mail.mydomain.com certificate "/etc/ssl/mail.mydomain.com.crt"
pki mail.mydomain.com key "/etc/ssl/private/mail.mydomain.com.key"
listen on lo0
listen on egress tls pki mail.mydomain.com auth-optional
listen on egress port submission tls-require pki mail.mydomain.com auth
listen on egress port 2525 tls pki mail.mydomain.com auth-optional
table relays file:/etc/mail/relays
table aliases db:/etc/mail/aliases.db
table vusers file:/etc/mail/vusers
table vdomains file:/etc/mail/vdomains
accept from source <relays> for any relay as “@mydomain.com”
accept from any for domain <vdomains> relay via “tls://11.11.11.11:2525”
As you can see, the key changes were to add a relays table to identify the specific IP addresses I will relay mail to and from, the listen on port 2525 to ensure that I capture the outbound mail from my internal server, and the accept from lines at the bottom to identify who I am receiving email from and where I am relaying it to.
Now, I needed to configure my internal server. I modified /etc/rc.conf.local to allow the smtpd daemon to auto-start at boot, and used the same basic configuration of this server. It’s /etc/mail/smtpd.conf file, however, is the mirror image of the relay server’s:
pki mail.mydomain.com certificate “/etc/ssl/mail.mydomain.com.crt”
pki mail.mydomain.com key “/etc/ssl/private/mail.mydomain.com.key”
listen on lo0
listen on egress port 2525 tls pki mail.mydomain.com auth-optional
listen on egress port submission tls-require pki mail.mydomain.com auth
table aliases db:/etc/mail/aliases.db
table vusers file:/etc/mail/vusers
table vdomains file:/etc/mail/vdomains
table relays file:/etc/mail/relays
accept for local alias <aliases> deliver to mbox
accept from source <relays> for domain <vdomains> virtual <vusers> deliver to mbox
accept from local for any relay via “tls://mail.mydomain.com:2525” as “@mydomain.com”
As you can see, the key difference is that we are only listening on port 2525 (not port 25 and 2525 like we do on the relay server) and we are relaying via TLS to the DigitalOcean VM on port 2525 for outbound communication.
I opened up ports 587 and 2525 in my local /etc/pf.conf file, reloaded pf, started smtpd on both servers and… it didn’t work. Took me a bit of thinking but I had forgotten to port map those ports from my ISP’s cablemodem/router to my internal box. Once I did that, eveything worked… sort of.
It turns out that today, you are a spammer to the internet until proven otherwise. Fortunately, there is a great service called mxtoolbox.com that will scan your setup for you and let you know what needed to be done.
- I needed to make sure that my relay server’s reverse lookup on its IP address matched the name I was sending mail from. On DigitalOcean they take the name of your VM in the dashboard and use that. Easy enough to change.
- I needed to create an SPF record for the domain. This is a TXT record in DNS that tells senders which servers will accept email. I went with a simple one that just said “use any MX record you see in my DNS” to keep it easy. In the end, the record looks like “v=spf1 mx -all”.
- My internal server needed to have an MX record in my DNS for the domain. I could not get the relay server to successfully relay to the internal server without it. Not sure why, but this did solve the problem for me. I used a 10 priority for my relay server and a 100 priority for my internal server to ensure that mail would be directed at the relay by senders.
- I needed to add a DMARC record to tell senders where to send undeliverable reports. This ends up being another TXT record on the domain that looks like “v=DMARC1; p=none; rua=mailto:postmaster@mydomain.com”.
- I created an alias of “postmaster” to ensure that these emails make it to my account.
Once I had all of this working, I could successfully send email from Google to my new account on my mail server, it would arrive on port 25 of my relay, get passed along on port 2525 to my internal server, would be accepted and stored in my local account’s mbox. I could then read the message and reply to it, going out of port 2525 on my internal server to the relay server, then it would be passed along on port 25 to the destination.
I’m still showing up as spam in a lot of mail services so I clearly have more work to do, but I get a clean bill of health on mboxtools.com (including a detailed search for my relay server’s IP address in all of the blacklists, etc.) I’ll continue to research this and edit this post in the future when I figure it out. However, what I have now is working well enough (and was hard enough to figure out) that I wanted to share what I had learned.