|
@@ -0,0 +1,264 @@
|
|
|
+# Simple Self-Hosted Mail
|
|
|
+
|
|
|
+A quick way to host your own mail.
|
|
|
+
|
|
|
+## Overview
|
|
|
+
|
|
|
+This is a `docker-compose`-based environment for setting up a personal
|
|
|
+mailserver as quickly and simply as possible. Included are a collection of
|
|
|
+components, bundled together via a compose file, which provide a simple but
|
|
|
+fully-functional mail stack.
|
|
|
+
|
|
|
+It supports:
|
|
|
+
|
|
|
+- Multiple users
|
|
|
+- Multiple domains
|
|
|
+- Webmail
|
|
|
+- Antispam
|
|
|
+- DKIM/SPF/DMARC to ensure good outgoing delivery rates
|
|
|
+- SSL
|
|
|
+- Server-side mail filtering
|
|
|
+
|
|
|
+The framework is built from the following components:
|
|
|
+
|
|
|
+- [Haraka](https://haraka.github.io/) message transfer agent (SMTP)
|
|
|
+- [Dovecot](https://www.dovecot.org) mail delivery agent (IMAP) and filtering
|
|
|
+ (Sieve)
|
|
|
+- [Rainloop](https://www.rainloop.net/) moden web-mail interface
|
|
|
+- [Rspamd](https://www.rspamd.com/) spam filtering system
|
|
|
+- [MariaDB](https://mariadb.org) database for simple user management
|
|
|
+- [ClamAV](https://www.clamav.net/) anti-virus
|
|
|
+- [Nginx](https://nginx.org) reverse proxy for Rainloop
|
|
|
+- [Redis](https://redis.io) backend for Rspamd
|
|
|
+
|
|
|
+The default configuration is fairly minimal but will be enough to get started
|
|
|
+straight out of the box, but can be tweaked by modifying the config files in the
|
|
|
+repository.
|
|
|
+
|
|
|
+## Getting Started
|
|
|
+
|
|
|
+### Prerequisites
|
|
|
+
|
|
|
+You will need:
|
|
|
+
|
|
|
+- A domain, and a way to edit the DNS. [Cloudflare](https://cloudflare.com)
|
|
|
+ works well.
|
|
|
+- A Linux server, with Docker installed.
|
|
|
+- IMAP[S], SMTP[S] and HTTP[S] ports free
|
|
|
+- SSL certificates from [Let's Encrypt](https://letsencrypt.org) via
|
|
|
+ [Certbot](https://certbot.eff.org)
|
|
|
+
|
|
|
+#### SSL
|
|
|
+
|
|
|
+The configuration expects you to have SSL certificates, and will look for them
|
|
|
+in [Certbot](https://certbot.eff.org)'s default directory. (`/etc/letsencrypt/`)
|
|
|
+
|
|
|
+An example of using `certbot` to obtain a certificate using your Cloudflare
|
|
|
+account:
|
|
|
+
|
|
|
+```bash
|
|
|
+docker run -ti --rm -v /etc/letsencrypt:/etc/letsencrypt \
|
|
|
+ certbot/dns-cloudflare \
|
|
|
+ certonly --dns-cloudflare \
|
|
|
+ --dns-cloudflare-credentials /etc/letsencrypt/renewal/cloudflare.ini \
|
|
|
+ -d mail.MYDOMAIN.XYZ
|
|
|
+```
|
|
|
+
|
|
|
+This assumes that you have written your cloudflare credentials to
|
|
|
+`/etc/letsencrypt/renewal/cloudflare.ini` - more information is available on
|
|
|
+this and other ways of getting free SSL certificates in the documtation for
|
|
|
+[Certbot](https://certbot.eff.org)
|
|
|
+
|
|
|
+### Installation
|
|
|
+
|
|
|
+#### Clone the repository
|
|
|
+
|
|
|
+```bash
|
|
|
+git clone https://git.sd.ai/simon/simple-selfhosted-mail
|
|
|
+```
|
|
|
+
|
|
|
+All following comands are relative to the root directory of the repository.
|
|
|
+
|
|
|
+#### DKIM keys
|
|
|
+
|
|
|
+You'll want to generate a DKIM key for your domain, as follows:
|
|
|
+
|
|
|
+```bash
|
|
|
+cd dkim
|
|
|
+./dkim_gen_key.sh MYDOMAIN.XYZ
|
|
|
+
|
|
|
+cat MYDOMAIN.XYZ/dns
|
|
|
+```
|
|
|
+
|
|
|
+The file `MYDOMAIN.XYZ/dns` contains the DNS records you need to add to your
|
|
|
+domain for SPF, DKIM and DMARC.
|
|
|
+
|
|
|
+#### DNS
|
|
|
+
|
|
|
+In your DNS, you will need to add:
|
|
|
+
|
|
|
+- An `A` record for your server's public IP. e.g. `mail.MYDOMAIN.XYZ`
|
|
|
+- An `MX` record for your domain, pointing at your `A` record.
|
|
|
+- The DNS records from the file above. Specifically:
|
|
|
+ - The `monthYYYY._domainkey` `TXT` record for DKIM
|
|
|
+ - The `TXT` and `SPF` records in the root of your domain for SPF
|
|
|
+ - The `_dmarc` `TXT` record containing your DMARC record
|
|
|
+
|
|
|
+_Important_: The reverse DNS for your IP should match the `A` record you want to
|
|
|
+use. Without this, you will look spammy to other mail servers and may experience
|
|
|
+delivery problems.
|
|
|
+
|
|
|
+The entries generated in the `dns` file should work without modification, and
|
|
|
+should be added as-is unless you know what you are doing.
|
|
|
+
|
|
|
+#### Environment variables
|
|
|
+
|
|
|
+You need three environment variables set before you bring up the mail stack:
|
|
|
+
|
|
|
+- `MAIL_HOSTNAME` should be the hostname of your mail server, and should match
|
|
|
+ your reverse DNS
|
|
|
+- `SSL_DOMAIN` is the name of the directory in `/etc/letsencrypt/live` that
|
|
|
+ contains your SSL certificate.
|
|
|
+ - Normally this will match `MAIL_HOSTNAME` if your certificate just has one
|
|
|
+ host, but if you have multiple hosts in the same cert then it may be
|
|
|
+ something different.
|
|
|
+- `MYSQL_PASSWORD` is the password used to initialise and connect to the MariaDB
|
|
|
+ database. (The username will be `dovecot`)
|
|
|
+ - Once you have brought the stack up for the first time, you'll want to keep
|
|
|
+ this the same. To change it, you will need to connect to the database
|
|
|
+ directly and modify it as the root user.
|
|
|
+ - This can be anything you like, but it's best to randomly generate it.
|
|
|
+
|
|
|
+The easiest way to set these up is to add them to your `~/.bashrc`. e.g.:
|
|
|
+
|
|
|
+```bash
|
|
|
+export MAIL_HOSTNAME=mail.MYDOMAIN.XYZ
|
|
|
+export SSL_DOMAIN=mail.MYDOMAIN.XYZ
|
|
|
+export MYSQL_PASSWORD=some_secure_password
|
|
|
+```
|
|
|
+
|
|
|
+Don't forget to reload your `.bashrc` when done:
|
|
|
+
|
|
|
+```bash
|
|
|
+. ~/.bashrc
|
|
|
+```
|
|
|
+
|
|
|
+#### Building the stack
|
|
|
+
|
|
|
+The `docker-compose build` command will download all of the necessary base
|
|
|
+images and configure them. Run this inside your repository.
|
|
|
+
|
|
|
+You can then bring everything up with `docker-compose up -d`
|
|
|
+
|
|
|
+#### Creating your first user
|
|
|
+
|
|
|
+There are user-management scripts in the `bin` subdirectory, which call
|
|
|
+`docker-compose` so should be run from the repository root. These commands are
|
|
|
+fairly self-explanatory:
|
|
|
+
|
|
|
+- `list_users`
|
|
|
+- `add_user`
|
|
|
+- `set_user_password`
|
|
|
+- `delete_user`
|
|
|
+
|
|
|
+To create the first user you'll want to run:
|
|
|
+
|
|
|
+```bash
|
|
|
+bin/add_user me@MYDOMAIN.XYZ
|
|
|
+```
|
|
|
+
|
|
|
+You will be prompted for a password.
|
|
|
+
|
|
|
+#### Configuring Rainloop
|
|
|
+
|
|
|
+Rainloop webmail should be listening on your mail server now. You will need to
|
|
|
+set up your domain via the admin interface before you can log in:
|
|
|
+
|
|
|
+- Visit: `https://mail.YOURDOMAIN.XYZ/?admin`
|
|
|
+ - username: `admin`
|
|
|
+ - password: `12345`
|
|
|
+- Go to `security` and change the admin password!
|
|
|
+- Go to `domains` and add your domain:
|
|
|
+ - Click `Add Domain`
|
|
|
+ - Enter `YOURDOMAIN.XYZ` under `Name`
|
|
|
+ - In the `IMAP` section:
|
|
|
+ - Enter `dovecot` for `Server`
|
|
|
+ - Select `STARTTLS` for `Secure`
|
|
|
+ - Enter `10143` for `Port`
|
|
|
+ - In the `SMTP` section:
|
|
|
+ - Enter `haraka` for `Server`
|
|
|
+ - Select `STARTTLS` for `Secure`
|
|
|
+ - Enter `2525` for `Port`
|
|
|
+ - Check `Use authentication`
|
|
|
+ - Click `Test` - it should say everything is OK
|
|
|
+ - Click `Sieve configuration`
|
|
|
+ - Check `Allow sieve scripts` and `Allow custom user script`
|
|
|
+ - Enter `dovecot` for `Server`
|
|
|
+ - Leave `4190` for `Port`
|
|
|
+ - For `Secure` set `STARTTLS`
|
|
|
+ - Click `Test` again - it should test the sieve configuration and verify that
|
|
|
+ it is OK
|
|
|
+ - Click `Add`
|
|
|
+
|
|
|
+**TODO:** Add some screenshots!
|
|
|
+
|
|
|
+**NOTE:** The internal ports specified above are different to the ports
|
|
|
+externally published, which are the standard IMAP and SMTP ports. The internal
|
|
|
+ports are on numbers >1024 so that the processes can be run as a non-root user.
|
|
|
+
|
|
|
+This will have configured Rainloop to handle your domain, so that it knows how
|
|
|
+to send and receive mail from the rest of the stack.
|
|
|
+
|
|
|
+#### Logging in
|
|
|
+
|
|
|
+Visit `https://mail.MYDOMAIN.XYZ/` and log in as the user you created earlier.
|
|
|
+
|
|
|
+You may want to use the DKIM tester at (http://www.appmaildev.com/en/dkim) to
|
|
|
+verify that your setup is correctly signing messages.
|
|
|
+
|
|
|
+### Updating
|
|
|
+
|
|
|
+To update and rebuild the stack, run:
|
|
|
+
|
|
|
+```bash
|
|
|
+git pull
|
|
|
+docker-compose build --pull
|
|
|
+```
|
|
|
+
|
|
|
+## Important information and potential gotchas
|
|
|
+
|
|
|
+There are a couple of things that it helps to be aware of:
|
|
|
+
|
|
|
+### Where the data is stored
|
|
|
+
|
|
|
+Your mail and settings are stored in Docker volumes defined in
|
|
|
+`docker-compose.yml`. Please be careful when running commands such as
|
|
|
+`docker-compose down` (don't run it with the `-v` parameter) or `docker prune`
|
|
|
+as these may delete volumes, which will wipe out your mail!
|
|
|
+
|
|
|
+### Errors about volumes being already mounted
|
|
|
+
|
|
|
+If you rebuild any of the containers in the stack and then re-run
|
|
|
+`docker-compose up`, you may see errors about volumes already being mounted.
|
|
|
+When you rebuild, you must run `docker-compose down` before bringing it back up
|
|
|
+again.
|
|
|
+
|
|
|
+### 'Permission denied' errors for SSL certificates
|
|
|
+
|
|
|
+It may be that the programs running inside your containers can't read your SSL
|
|
|
+certificates, due to the fact that they run as their own user (e.g. users
|
|
|
+`dovecot` and `haraka`.) The SSL certificates are bind-mounted into the running
|
|
|
+containers and inherit the permissions that they have on disk.
|
|
|
+
|
|
|
+You may need to change the permissions on the files to support this. If you are
|
|
|
+confident that only you have access to the server, running
|
|
|
+`chmod a+r /etc/letsencrypt/archive/mail.YOURDOMAIN.XYZ/*` will work, but be
|
|
|
+aware of the security implications of doing this.
|
|
|
+
|
|
|
+### Multiple domains
|
|
|
+
|
|
|
+Multiple domains are supported. Simply add another user with `bin/add_user` and
|
|
|
+
|
|
|
+## Contributing
|
|
|
+
|
|
|
+Feel free to make a PR or open issues. Feedback is good.
|