Automated solution for hosting email, web, DNS, XMPP, and ZNC on OpenBSD.
Branch: master
Clone or download
Type Name Latest commit message Commit time
Failed to load latest commit information.
roles matrix needs valid tls now after all Feb 16, 2019
scripts update to OpenBSD 6.4 Oct 24, 2018
tasks bye bye relayd, hello nginx Feb 15, 2019
.gitignore add readme Jul 17, 2018
LICENSE Initial commit Jul 16, 2018 cleanup Feb 15, 2019
ansible.cfg initial commit Jul 17, 2018
inventory.ini initial commit Jul 17, 2018
site.yml bye bye relayd, hello nginx Feb 15, 2019
vars-sample.yml update to OpenBSD 6.4 Oct 24, 2018


Hi! This is my ansible playbook for self-hosting your own email, web hosting, XMPP chat, Matrix Homeserver, Tiny Tiny RSS, and and DNS records using OpenBSD. I use it to host everything on, but you can easily adapt it for your own domain by setting a few variables in vars.yml.


  1. Configure a secondary DNS provider and set them as your nameservers at your registrar. Set up reverse DNS for your server.
  2. ./scripts/
  3. cp vars-sample.yml vars.yml && vi vars.yml
  4. ansible-playbook site.yml
  5. ./scripts/ YOURDOMAIN and set DS records at your registrar for DNSSEC.


  • You have a public-facing server (probably a VPS) running OpenBSD, with an IPv4 and IPv6 address. I recommend Vultr.
  • You have your own domain name, and a registrar that supports DNSSEC. I recommend Namecheap.
  • You have a secondary DNS provider that supports DNSSEC. I recommend DNS Made Easy. (Why do I need this?)
  • You're crazy enough to run your own mail server :-)


  • A small and secure OpenBSD platform to host email, DNS, XMPP chat, and some web sites.

    • Scale: you and your family members, and maybe a few technically oriented friends.
    • Really not suited for the general public, no automated password reset, no web GUIs...
  • Use as much of the OpenBSD base system as possible:

  • Of course, some packages from the ports tree will be necessary:

  • And some third-party projects not currently in packages:

  • Encryption Everywhere:

    • Automated DNSSEC with nsd and cron tasks using ldns-signzone for daily zone re-signing and slave NOTIFYs
    • TLS for all public-facing services using LetsEncrypt certificates with automated renewal and daemon reload hooks
    • Automatic publishing of SSHFP records for authoritative SSH fingerprints
    • Automatic publishing of TLSA records for DANE email encryption
    • Automatic publishing of DKIM records for outgoing email verification
  • Keep it Simple

    • Unopinionated baseline for what most people want from a personal domain
    • Keep dependencies to a minimum and stick to UNIX conventions (simple passwd auth, mail stored in ~/Maildir, etc)
    • Automate the tedious stuff, so you can focus on hacking!


  1. Boot up your OpenBSD server.
  2. Create at least one user account. You will use this account to administer the system, so make sure to add yourself to the wheel group.
  3. Run scripts/ as root to add a package repo URL and set up doas for your user (required for Ansible).
  4. Configure your secondary DNS provider to accept NOTIFYs and perform zone transfers from your server's IP address.
  5. cp vars-sample.yml vars.yml and edit the configuration to your liking.
  6. Run the playbook! ansible-playbook site.yml
  7. Ensure you have reverse DNS in place for your server's IP address. This is a critical step to avoid your outgoing mail being flagged as spam. At Vultr, this is configured under "Settings > IPv4". You should set one for your primary IPv6 address as well.
  8. The last step is to configure DS records for DNSSEC at your domain registrar. Run scripts/ YOURDOMAIN to generate the records. At Namecheap, this is configured under "Advanced DNS > DNSSEC" in the web portal.
  9. Yell at me on Twitter when you inevitably find bugs in my code.

Operational Notes

  • Login info: the credentials for SMTP (STARTTLS, port 587) and IMAP (SSL, port 993) are simply your username (without the portion) and login password. XMPP uses the syntax for logins, but the password is the same. Mail is stored under ~/Maildir in each user's home directory for easy access using local clients like mutt.

  • Email Filtering: any sieve script located at ~/.dovecot.sieve will automatically apply filters to your incoming mail. You can compile the sieve script and check for syntax errors using sievec ~/.dovecot.sieve. For example, to filter all your cron emails into a folder called Logs:

require ["regex", "fileinto", "imap4flags", "mailbox", "envelope", "variables"];

if allof ( address :is "from" "",
           anyof ( header :contains "subject" "cron",
                   header :contains "subject" "output" )) {
  fileinto :create "Logs";
  • XMPP Chat: the XMPP server, Prosody, is really slick. As configured here, it supports HTTP file upload for image sharing, delivery to multiple devices via carbons, push notifications, group chats, message history, and basically everything you'd expect from a modern chat solution. XMPP isn't all that bad! The best clients are ChatSecure for iOS, Conversations for Android, and Gajim for *nix and Windows. No decent clients for OS X, sadly. All those clients support end-to-end crypto via OMEMO. Easily federate with others on separate XMPP servers for truly decentralized, open communication!

  • Additional accounts: to add more accounts, just use adduser. Unless they need a shell, it's probably best to set their shell to /sbin/nologin.

  • IPv6: spamd does not currently support IPv6, so don't go adding a AAAA record for mail in the zonefile!

  • Monitoring spamd: just run spamdb to see a list of senders currently greylisted/whitelisted.

  • Virtual Hosts: a default vhost will be created for, with a bare domain redirect. Shove HTML files into /var/www/htdocs/ to start sharing your worthless opinions with the internet! To add more vhosts, just put a configuration file in /etc/sites and include it in /etc/httpd.d/sites.conf.

  • Greylisting pitfalls: spamd works by greylisting. Unfortunately, big mailers like GMail often don't retry delivery from the same address, resulting in a greylist black hole described here. To alleviate this, I included a daily cron job that whitelists the IP addresses found in the SPF records for some of the big mailers like GMail and Yahoo. If you notice any other problematic domains, override the to the bigmailers list defined in roles/spamd/deaults/main.yml to have their IP ranges whitelisted. (And be sure to send me a pull request!)

  • Password Resets: I'm leaving password management up to you. Since this configuration uses plain UNIX accounts, you won't be able to add a password reset webpage without some kind of crappy setuid CGI script (yikes!). Look into LDAP authentication if you have a bunch of non-neckbeard users. Otherwise, man login.conf for information on enforcing password expiration and complexity.

  • Backups: another thing I'm leaving up to you, since your requirements will almost certainly be unique. Shouldn't be too difficult:

    • Maildirs: tar them up, maybe encrypt them, and scp them offsite periodically.
    • User accounts: back up /etc/{passwd,master.passwd,group}
    • Backup MX records: I don't bother with a backup MX. They are a massive target for spammers, and legit mail servers will keep retrying delivery for multiple days if your primary MX goes down.
    • Prosody: periodically tar up the HTTP upload dir and do a pg_dump to save user info and message archives.
    • Keys: tar up your DNSSEC keys (/var/nsd/keys) and DKIM keys (/etc/mail/dkim)
    • Assuming you copy all these items back to their original locations, the playbook won't generate new keys if they already exist.