Re-decentralize email. Make it secure. Make it simple. Make it yours.
Python Shell
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



Empress is a lightweight email-focused fork of Sovereign focused on:

  1. Making it simple to run your own secure email server.
  2. Making it simple to escape from your existing email provider to your own server.
  3. Bringing down the cost of running your own secure email server.

Some features and security fixes may be backported to sovereign. This is not marked as a fork by GitHub because we do not intend to submit regular pull requests upstream, or to sync all changes back from sovereign. For our use-case, GitHub's normal forking model doesn't work well.


This project is a work-in-progress and is just lifting off the ground.

On the TODO is:

  • Updating this README (e.g. replacing/fixing sovereign links to Empress)
  • Closing Issues.
  • As much as is feasible making these playbooks "plug-n-play" and "swappable". I.e. make it simple for someone to choose Exim instead of Postfix, MySQL instead of Postgresql, etc.

Services Provided

What do you get if you point this thing at a VPS? All kinds of good stuff!

  • IMAP over TLS via Dovecot, complete with full text search provided by Solr.
  • POP3 over TLS, also via Dovecot
  • SMTP over TLS via Postfix, including a nice set of DNSBLs to discard spam before it ever hits your filters.
  • Webmail via Mailpile.
  • Virtual domains for your email, backed by SQLite.
  • Spam fighting via DSPAM
  • Mail server verification via OpenDKIM, so folks know you’re legit.
  • Firewall management via Uncomplicated Firewall (ufw).
  • Intrusion prevention via fail2ban and rootkit detection via rkhunter.
  • SSH configuration preventing root login and insecure password authentication
  • Nightly backups to Tarsnap.
  • A bunch of nice-to-have tools like mosh and htop that make life with a server a little easier.

No setup is perfect, but the general idea is to provide a bunch of useful services while being reasonably secure and low-maintenance. Set it up, SSH in every couple weeks, but mostly forget about it.

Don’t want one or more of the above services? Comment out the relevant role in site.yml. Or get more granular and comment out the associated include: directive in one of the playbooks.


What You’ll Need

  1. A VPS (or bare-metal server if you wanna ball hard). My VPS is hosted at RamNode. You’ll probably want at least 512 MB of RAM between nginx, Mailpile, Solr, and MariaDB (drop-in replacement for MySQL).
  2. 64-bit Debian 7 or an equivalent Linux distribution. (You can use whatever distro you want, but deviating from Debian will require more tweaks to the playbooks. See Ansible’s different packaging modules.)
  3. A wildcard TLS certificate. We recommend self-signed certs or the free ones from StartSSL.
  4. A Tarsnap account with some credit in it. You could comment this out if you want to use a different backup service. Consider paying your hosting provider for backups or using an additional backup service for redundancy.


0. Clone the Repository

Make sure you have git, python2, pip, and virtualenv before starting.

git clone git://
cd empress
virtualenv .env
.env/bin/pip install -r requirements.txt

Prior to 1.3, pip doesn't verify SSL certificates, which impacts Debian Wheezy, but will not impact Jessie. You may install an alternate version of ansible (eg. from wheezy-backports) at your own risk.

1. Get a wildcard TLS certificate

Generate a private key and a certificate signing request (CSR):

openssl req -nodes -newkey rsa:2048 -keyout roles/common/files/wildcard_private.key -out mycert.csr

Send your CSR to StartSSL. They will give you your signed public certificate. Place the certificate in roles/common/files/wildcard_public_cert.crt.

Download your certificate authority’s combined cert to roles/common/files/wildcard_ca.pem. You can also download the intermediate and root certificates separately and concatenate them together in that order.

Lastly, test your certificate:

openssl verify -verbose -CAfile roles/common/files/wildcard_ca.pem roles/common/files/wildcard_public_cert.crt

Self-signed TLS certificate

If you don't purchase or set up an existing certificate, empress will generate one for you on the server.

Self-signed certs are free, easy, but are not yet authenticated by TLS (but will be).

2. Get a Tarsnap machine key

If you haven’t already, download and install Tarsnap, or use brew install tarsnap if you use Homebrew.

Create a new machine key for your server:

tarsnap-keygen --keyfile roles/tarsnap/files/decrypted_tarsnap.key --user --machine

3. Prep the server

For goodness sake, change the root password:


Create a user account for Ansible to do its thing through:

useradd deploy
passwd deploy
mkdir /home/deploy

Authorize your ssh key if you want passwordless ssh login (optional):

mkdir /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
nano /home/deploy/.ssh/authorized_keys
chmod 400 /home/deploy/.ssh/authorized_keys
chown deploy:deploy /home/deploy -R

This account should be set up for passwordless sudo. Use visudo and add this line:


4. Configure your installation

Modify the settings in vars/user.yml and vars/mail.yml to your liking (these two files will likely be combined). If you want to see how they’re used in context, just search for the corresponding string.

Setting password_hash for your mail users is a bit tricky. You can generate one using doveadm-pw.

# doveadm pw -s SHA512-CRYPT
Enter new password: foo
Retype new password: foo

Remove {SHA512-CRYPT} and insert the rest as the password_hash value.

Alternatively, if you don’t already have doveadm installed, Python 3.3 or higher on Linux will generate the appropriate string for you (assuming your password is password):

python3 -c 'import crypt; print(crypt.crypt("password", salt=crypt.METHOD_SHA512))'

On OS X and other platforms the passlib package may be used to generate the required string:

python -c 'import passlib.hash; print(passlib.hash.sha512_crypt.encrypt("password", rounds=5000))'

Finally, replace the TODOs in the file hosts. If your SSH daemon listens on a non-standard port, add a colon and the port number after the IP address.
In that case you also need to add your custom port to the task Set firewall rules for web traffic and SSH in the file roles/common/tasks/ufw.yml.

5. Run the Ansible Playbooks

First, make sure you’ve got Ansible 1.6+ installed.

To run the whole dang thing:


To run just one or more piece, use tags. I try to tag all my includes for easy isolated development. For example, to focus in on your firewall setup:

ansible-playbook -i ./hosts --tags=ufw site.yml

You might find that it fails at one point or another. This is probably because something needs to be done manually, usually because there’s no good way of automating it. Fortunately, all the tasks are clearly named so you should be able to find out where it stopped. I’ve tried to add comments where manual intervention is necessary.

6. Set up DNS

If you’ve just bought a new domain name, point it at Linode’s DNS Manager or similar. Most VPS services (and even some domain registrars) offer a managed DNS service that you can use for this at no charge. If you’re using an existing domain that’s already managed elsewhere, you can probably just modify a few records.

Create an A records which point to your server IP for:

  • (for email client automatic configuration)

Create a MX record for which assigns as the domain’s mail server.

To ensure your emails pass DKIM checks you need to add a txt record. The name field will be default._domainkey.EXAMPLE.COM. The value field contains the public key used by OpenDKIM. The exact value needed can be found in the file /etc/opendkim/keys/EXAMPLE.COM/default.txt it’ll look something like this:

v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKKAQfMwKVx+oJripQI+Ag4uTwYnsXKjgBGtl7Tk6UMTUwhMqnitqbR/ZQEZjcNolTkNDtyKZY2Z6LqvM4KsrITpiMbkV1eX6GKczT8Lws5KXn+6BHCKULGdireTAUr3Id7mtjLrbi/E3248Pq0Zs39hkDxsDcve12WccjafJVwIDAQAB

Set up SPF and reverse DNS as per this post. Make sure to validate that it’s all working, for example by sending an email to and reviewing the report that will be emailed back to you.


Create an issue.


Fork me. Branch off of master. Do stuff. Send PR.


You can install sovereign to a VM with vagrant:

virtualenv .env
.env/bin/pip install -r requirements.txt
PATH=".env/bin:$PATH" vagrant up

and to re-run ansible on the same machine:

PATH=".env/bin:$PATH" vagrant provision

to run some automated tests, you can use:

./.env/bin/python -m unittests tests


Original content is GPLv3, same as Ansible. All files and templates based on third-party software should be considered under their respective licenses.