Empress is a lightweight email-focused fork of Sovereign focused on:
- Making it simple to run your own secure email server.
- Making it simple to escape from your existing email provider to your own server.
- 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.
HARD-HAT AREA!
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.
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.
- 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).
- 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.)
- A wildcard TLS certificate. We recommend self-signed certs or the free ones from StartSSL.
- 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.
Make sure you have git
, python2
, pip
, and virtualenv
before starting.
git clone git://github.com/taoeffect/empress.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.
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
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).
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 me@example.com --machine example.com
For goodness sake, change the root password:
passwd
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:
deploy ALL=(ALL) NOPASSWD: ALL
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
{SHA512-CRYPT}$6$drlIN9fx7Aj7/iLu$XvjeuQh5tlzNpNfs4NwxN7.HGRLglTKism0hxs2C1OvD02d3x8OBN9KQTueTr53nTJwVShtCYiW80SGXAjSyM0
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
.
First, make sure you’ve got Ansible 1.6+ installed.
To run the whole dang thing:
./setup_site.sh
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.
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:
example.com
mail.example.com
autoconfig.example.com
(for email client automatic configuration)
Create a MX
record for example.com
which assigns mail.example.com
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 check-auth@verifier.port25.com 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.