Automated solution for hosting email, web, DNS, XMPP, Git, and ZNC on OpenBSD.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Cullum Smith de7708c08f fix changelog formatting 2 years ago
roles cleanup 2 years ago
scripts add matrix password reset script 2 years ago
tasks add davical support. needs some cleanup 2 years ago
.gitignore add readme 3 years ago fix changelog formatting 2 years ago
LICENSE Initial commit 3 years ago update readme 2 years ago
ansible.cfg initial commit 3 years ago
inventory.ini initial commit 3 years ago
site.yml add davical support. needs some cleanup 2 years ago
vars-sample.yml add davical support. needs some cleanup 2 years ago


Hi! This is my ansible playbook for self-hosting your own email, web hosting, XMPP chat, Matrix Homeserver, Tiny Tiny RSS, Git repos, 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.

NEW: Read the changelog before running this playbook after updates! There are often breaking changes!!


  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.
  6. Create your user account with dankctl useradd.


  • 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, Matrix, TTRSS, Git, 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
    • Automate the tedious stuff, so you can focus on hacking!


  1. Boot up your OpenBSD server.
  2. Create a user account for provisioning the system. Make sure to add the account to the wheel group. Don’t use your preferred username for this account - save that for your LDAP username.
  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. Create your “real” user account in LDAP via dankctl useradd your_username -c "Your Name" -G ssh,sudo -r admin -k "your ssh key"
  10. Yell at me via email, xmpp, or matrix 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!

  • Account Maintenance: to add, remove, and modify accounts and groups, use the dankctl command. It’s help output should be quite self-explanatory.

  • 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: Passwords can be reset using dankctl resetpass. Currently, only an administrator can do this, since giving users write access to their LDAP user entry could allow them to write a non-hashed password into their userPassword field. It’s on my todo list to make some kind of web interface for this.

  • SSH: SSH keys are stored in LDAP and can be added/removed using dankctl usermod. If a user has a shell on the box, he can run this command with his own credentials. Users must be in the ssh group to connect.

  • 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)
    • LDAP: you can either tar up /var/db/ldap or save the output of ldap search as the root DN.
    • Assuming you copy all these items back to their original locations, the playbook won’t generate new keys if they already exist.