# Table of Contents

- [Table of Contents](#table-of-contents)
  - [Introduction](#introduction)
  - [Folder Structure](#folder-structure)
  - [Usage](#usage)
    - [Step-by-Step](#step-by-step)
    - [Env File](#env-file)
    - [Development](#development)
- [Setup](#setup)
  - [Certificate](#certificate)
  - [haproxy](#haproxy)
  - [postfix](#postfix)
  - [dovecot](#dovecot)
  - [rspamd](#rspamd)
  - [Misc: transparent proxy](#misc-transparent-proxy)
- [Sources](#sources)
- [TODO](#todo)

## Introduction
This little project enables you to deploy a functioning mailserver. The setup contains a significant amount of hard-coded config and need to be changed as required (postfix, dovecot, etc). Dynamic variables are to be found in template.env.

This docker covers the following items:
- Mailserver with postfix and dovecot setup.
- Database (mariadb) which is partially setup with init files and with other docker machines.
- An rspamd component for simple spamfiltering.
- Roundcubemail which provides E-Mail access.
- haproxy for testing purposes (optional)
- prometheus and grafana for an amazing monitoring solution (optional)

## Folder Structure
- Folders:
  - data: All necessary configuration files and scripts for the docker instances.
  - dockerfiles: contains all the dockerfiles setups.
  - ini: QoL mariadb client files, used in conjuction with makefile.
  - persist-data: For persistent data, only used for desting.
  - scripts: Scripts for testing and other misc stuff
- Files:
  - docker-compose.yaml: Deploy the setup with it.
  - .env: configuration files, it's required.

## Usage
For the scope of this project, we've simplified the deploy of this setup. You only required make installed and you can deploy the whole setup with a simple command:
- make docker_init_prod

### Step-by-Step
1. Clone this repo in its entierty.
2. make sure you have all necessary make, docker and docker-compose component installed.
3. compy template.env to .env and adjust as needed.
4. make docker_init_prod


### Env File
We store our secrets in the `.env` file. The `.env` file is also used for our docker setup with docker-compose. In the directory there is a `template.env` file with all the necessary variables. Just copy this file, rename it to `.env` and adjust the values to your environment.

That should be it.

### Development
The development makes only sense locally. While there are some restrictions with the mail capabilities, it's still helpful to be able to develope it locally. The development architecture provides a haproxy setup and haproxy docker. For it to work you need the setup up `10.0.0.0/24`to your lo device. 
- make docker_init_devl

# Setup
## Certificate
Certificate is set up with lego. A setup will be provided to allow certificate renewal with certbot and an apache2 webserver but no automated renewal was configured.

**haproxy setup addition**
```shell
frontend frt-http
  mode http
  bind 54.37.73.59:80
  
  acl letsencrypt-acl path_beg /.well-known/acme-challenge/
  http-response set-header Strict-Transport-Security "max-age=16000000; preload;"

  redirect scheme https if !letsencrypt-acl 
  use_backend letsencrypt-backend if letsencrypt-acl
  
  default_backend nothing


backend letsencrypt-backend
  mode http
  server lego 127.0.0.1:82 maxconn 10

```

**apache setup**
```shell
# cat /etc/apache2/sites-available/000-default.conf 
<VirtualHost 127.0.0.1:82>
	ServerAdmin foo.bar@foobar.com
	DocumentRoot /var/www/html

  Alias /.well-known/acme-challenge/ /var/www/html/.well-known/acme-challenge/
  <Directory "/var/www/html/letsencrypt/.well-known/acme-challenge/">
      Options None
      AllowOverride None
      ForceType text/plain
      RedirectMatch 404 "^(?!/\.well-known/acme-challenge/[\w-]{43}$)"
  </Directory>

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
```

**certbot command**
```shell
certbot certonly --webroot -w /var/www/html -d mail.fqdn.com --non-interactive --agree-tos --email foo.bar@foobar.com --http-01-port=80
```

There are many tutorials on how to set up autoamted certificate renewals. This won't be covered with this documentation.

## haproxy
For a mailservice the ideal setup for a loadbalancer is to relay the client ip to the backend devices. That's necessary if the implementation of malicious behaviour should be limited. One example would be repeated SASL Logins should be limited to a certain amount of time.
For that to work source client information need to be relayed to the backend hosts. There are two ways to do it. The hard way is with firewall rules and network table manipulation. The easier way is to use the proxy-protocol.

In this situation we've decided to use the proxy protocol. The draw back is, that it only works for the postfix and dovecot instance. Following adjustments need to be done for it to work properly:

- haproxy adjustments
- postfix config adjustments
- dovecot config adjustments
- additional IP on lo, because 127.0.0.1 is not allowed

**host settings**
```shell
ip addr add 10.0.1.0/24 dev lo scope host
```

**haproxy.conf**
Following a sample configuration. Simply add "send-proxy" behind a backend server to relay client information to the service in the backend.
```shell
backend bck-smtp-587
	mode tcp
	balance leastconn
	
	server smtp1 10.0.0.21:587 send-proxy check
```

**main.cf**
- simply adding upstream proxy protocol support is enough for it to work

```shell
mynetworks = 127.0.0.0/8 10.0.0.0/24 10.0.1.0/24 [::ffff:127.0.0.0]/104 [::1]/128
postscreen_upstream_proxy_protocol = haproxy
```

**10-master.conf**
- Each listener that gets data from haproxy needs the "haproxy = yes" option enabled
- trusted haproxy network needs to be setup
 
```shell
inet_listener imaps {
  haproxy = yes
  port = 993
  ssl = yes
}

# ...

haproxy_trusted_networks = 10.0.0.0/24, 10.0.1.0/24
```

## postfix
All the related files can be found in `data/mailserver/conf/etc/`. Specifically following fodlers are important for postfix setup:
- main.cf: Contains the main configuration for receiving and handling mails
- master.cf: contains important configurations for all ports
- sql-folder: all crud operations

Postfix is a well known SMTP server and widely used. There is no breakdown of the settings used. All necessary information can be found on the official [postfix website](https://www.postfix.org/documentation.html).

## dovecot
All the related files can be found in `data/(mailserver/conf/etc/dovecot-conf-d` and `data/(mailserver/conf/etc/dovecot`.
- dovecot: contains the basic dovecot.conf file which simply includes all the other files and dovecot-sql.conf which is the CRUD operation for the database.
- dovecot-conf.d: Contains all the necessary configurations for all ports.

Dovecot is a well known IMAP server and widely used. Just like with postfix the settings won't explained. The official [dovecot website](https://doc.dovecot.org/) contains all the necessary information.

## rspamd
All the related fiels can be found in `data/mailserver/rspamd/` and `data/mailserver/redis/`.
- rspamd: contains the whole configuration set. 

Rspamd is a very well known spamfilter that is widely used. Noteworth is that rspamd listens on a ip other than localhost, because postifx and rspamd are two docker instances. We've added a simple running version of rspamd. Just with the other components the (rspamd website)[https://rspamd.com/doc/] contains all the necessary information.

Below are gtube strings. These strings are used to test a spamfilter. Sending an e-mail with such a string in the body should trigger the appropriate response/log entry. 
https://rspamd.com/doc/gtube_patterns.html

pattern	action	enabled
XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X	reject	Yes
YJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X	add header	No
ZJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X	rewrite subject	No
AJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X	no action	No

## Misc: transparent proxy
With this method you can achieve transparent proxy on host level with using fairly deep linux capabilities. This methos is not the most recommended one, because it requries haproxy to be run as root user.

```shell
iptables -t mangle -N DIVERT
iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT
iptables -t mangle -A DIVERT -j MARK --set-mark 1
iptables -t mangle -A DIVERT -j ACCEPT

ip rule add fwmark 1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100
```

# Sources 
|Docker|Service|Source|
|-|-|-|
|mailserver|Postfix, Dovecot|https://github.com/technicalguru/docker-mailserver-postfix|
|webmail|Roundcube|https://roundcube.net/|

All the other docker images are sourced from the official docker website.

# TODO
- Change DB to PostgreSQL
- Split Mailserver into seperate mailservices
  - dovecot
  - postfix
- Add automated dkim configuration
- add amavis/spammassassin docker
- Add working haproxy docker
  - Transparent proxying is a requirement
