mirror of
https://github.com/docker-mailserver/docker-mailserver.git
synced 2025-08-03 17:44:49 +02:00
docs(refactor): Large refactor + additions + fixes
Consistency pass, formatting cleanup and fixes, introduce admonitions, add front-matter. --- docs: Add front-matter --- docs: Fix and format links - Some links were invalid (eg files moved or renamed) - Some were valid but had invalid section headers (content removed or migrated) - Some use `http://` instead of `https://` when the website supports a secure connection. - Some already used the `[name][reference]` convention but often with a number that wasn't as useful for maintenance. - All referenced docs needed URLs replaced. Opted for the `[name][reference]` approach to group them all clearly at the bottom of the doc, especially with the relative URLs and in some cases many duplicate entries. - All `tomav` references from the original repo prior to switch to an organization have been corrected. - Minor cosmetic changes to the `name` part of the URL, such as for referencing issues to be consistent. - Some small changes to text body, usually due to duplicate URL reference that was unnecessary (open relay, youtous) - Switched other links to use the `[name][reference]` format when there was a large group of URLs such as wikipedia or kubernetes. Github repos that reference projects related to `docker-mailserver` also got placed here so they're noticed better by maintainers. This also helped quite a bit with `mermaid` external links that are very long. - There was a Github Wiki supported syntax in use `[[name | link]]` for `fetchmail` page that isn't compatible by default with MkDocs (needs a plugin), converted to `[name][reference]` instead since it's a relative link. --- docs: Update commit link for LDAP override script Logic moved to another file, keeping the permalink commit reference so it's unaffected by any changes in the file referenced in future. --- docs: Heading corrections Consistency pass. Helps with the Table of Contents (top-right UI) aka Document Outline. docs: codefence cleanup --- docs: misc cleanup --- docs: Add Admonitions Switches `<details>` usage for collapsible admonitions (`???`) while other text content is switched to the visually more distinct admoniton (`!!!` or `???+`) style. This does affect editor syntax highlighting a bit and markdown linting as it's custom non-standard markdown syntax.
This commit is contained in:
parent
f13df19b87
commit
021e942c4c
30 changed files with 1369 additions and 1027 deletions
|
@ -1,17 +1,35 @@
|
|||
Fail2ban is installed automatically and bans IP addresses for 3 hours after 3 failed attempts in 10 minutes by default. If you want to change this, you can easily edit [config/fail2ban-jail.cf](https://github.com/tomav/docker-mailserver/blob/master/config/fail2ban-jail.cf).
|
||||
You can do the same with the values from fail2ban.conf, e.g dbpurgeage. In that case you need to edit [config/fail2ban-fail2ban.cf](https://github.com/tomav/docker-mailserver/blob/master/config/fail2ban-fail2ban.cf)
|
||||
---
|
||||
title: 'Security | Fail2Ban'
|
||||
hide:
|
||||
- toc # Hide Table of Contents for this page
|
||||
---
|
||||
|
||||
__Important__: The mail container must be launched with the NET_ADMIN capability in order to be able to install the iptable rules that actually ban IP addresses. Thus either include `--cap-add=NET_ADMIN` in the docker run commandline or the equivalent docker-compose.yml:
|
||||
```
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
```
|
||||
If you don't you will see errors of the form
|
||||
```
|
||||
Fail2Ban is installed automatically and bans IP addresses for 3 hours after 3 failed attempts in 10 minutes by default. If you want to change this, you can easily edit [`config/fail2ban-jail.cf`][github-file-f2bjail].
|
||||
|
||||
You can do the same with the values from `fail2ban.conf`, e.g `dbpurgeage`. In that case you need to edit [`config/fail2ban-fail2ban.cf`][github-file-f2bconfig].
|
||||
|
||||
!!! attention
|
||||
The mail container must be launched with the `NET_ADMIN` capability in order to be able to install the iptable rules that actually ban IP addresses.
|
||||
|
||||
Thus either include `--cap-add=NET_ADMIN` in the docker run commandline or the equivalent `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
```
|
||||
|
||||
If you don't you will see errors the form of:
|
||||
|
||||
```log
|
||||
iptables -w -X f2b-postfix -- stderr: "getsockopt failed strangely: Operation not permitted\niptables v1.4.21: can't initialize iptabl
|
||||
es table `filter': Permission denied (you must be root)\nPerhaps iptables or your kernel needs to be upgraded.\niptables v1.4.21: can'
|
||||
t initialize iptables table `filter': Permission denied (you must be root)\nPerhaps iptables or your kernel needs to be upgraded.\n"
|
||||
2016-06-01 00:53:51,284 fail2ban.action [678]: ERROR iptables -w -D INPUT -p tcp -m multiport --dports smtp,465,submission -
|
||||
j f2b-postfix
|
||||
```
|
||||
You can also manage and list the banned IPs with the [setup.sh](https://github.com/tomav/docker-mailserver/wiki/Setup-docker-mailserver-using-the-script-setup.sh) script.
|
||||
|
||||
You can also manage and list the banned IPs with the [`setup.sh`][docs-setupsh] script.
|
||||
|
||||
[docs-setupsh]: ../setup.sh.md
|
||||
[github-file-f2bjail]: https://github.com/docker-mailserver/docker-mailserver/blob/master/config/fail2ban-jail.cf
|
||||
[github-file-f2bconfig]: https://github.com/docker-mailserver/docker-mailserver/blob/master/config/fail2ban-fail2ban.cf
|
||||
|
|
|
@ -1,112 +1,140 @@
|
|||
---
|
||||
title: 'Security | TLS (aka SSL)'
|
||||
---
|
||||
|
||||
There are multiple options to enable SSL:
|
||||
|
||||
* using [letsencrypt](#lets-encrypt-recommended) (recommended)
|
||||
* using [Caddy](#caddy)
|
||||
* using [Traefik](#traefik)
|
||||
* using [self-signed certificates](#self-signed-certificates-testing-only) with the provided tool
|
||||
* using [your own certificates](#custom-certificate-files)
|
||||
- Using [letsencrypt](#lets-encrypt-recommended) (recommended)
|
||||
- Using [Caddy](#caddy)
|
||||
- Using [Traefik](#traefik)
|
||||
- Using [self-signed certificates](#self-signed-certificates-testing-only) with the provided tool
|
||||
- Using [your own certificates](#custom-certificate-files)
|
||||
|
||||
After installation, you can test your setup with:
|
||||
- [checktls.com](https://www.checktls.com/TestReceiver)
|
||||
- [testssl.sh](https://github.com/drwetter/testssl.sh)
|
||||
|
||||
### Let's encrypt (recommended)
|
||||
- [`checktls.com`](https://www.checktls.com/TestReceiver)
|
||||
- [`testssl.sh`](https://github.com/drwetter/testssl.sh)
|
||||
|
||||
## Let's Encrypt (Recommended)
|
||||
|
||||
To enable Let's Encrypt on your mail server, you have to:
|
||||
|
||||
* get your certificate using [letsencrypt client](https://github.com/letsencrypt/letsencrypt)
|
||||
* add an environment variable `SSL_TYPE` with value `letsencrypt` (see `docker-compose.yml.dist`)
|
||||
* mount your whole `letsencrypt` folder to `/etc/letsencrypt`
|
||||
* the certs folder name located in `letsencrypt/live/` must be the `fqdn` of your container responding to the `hostname` command. The full qualified domain name (`fqdn`) inside the docker container is built combining the `hostname` and `domainname` values of the docker-compose file, e. g.: hostname: `mail`; domainname: `myserver.tld`; fqdn: `mail.myserver.tld`
|
||||
- Get your certificate using [letsencrypt client](https://github.com/letsencrypt/letsencrypt)
|
||||
- Add an environment variable `SSL_TYPE` with value `letsencrypt` (see [`docker-compose.yml`][github-file-compose])
|
||||
- Mount your whole `letsencrypt` folder to `/etc/letsencrypt`
|
||||
- The certs folder name located in `letsencrypt/live/` must be the `fqdn` of your container responding to the `hostname` command. The `fqdn` (full qualified domain name) inside the docker container is built combining the `hostname` and `domainname` values of the `docker-compose` file, eg:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
mail:
|
||||
hostname: mail
|
||||
domainname: myserver.tld
|
||||
fqdn: mail.myserver.tld
|
||||
```
|
||||
|
||||
You don't have anything else to do. Enjoy.
|
||||
|
||||
### Example using Docker for Let's Encrypt
|
||||
|
||||
1. Make a directory to store your letsencrypt logs and configs. In my case:
|
||||
|
||||
#### Example using docker for letsencrypt
|
||||
Make a directory to store your letsencrypt logs and configs.
|
||||
```sh
|
||||
mkdir -p /home/ubuntu/docker/letsencrypt
|
||||
cd /home/ubuntu/docker/letsencrypt
|
||||
```
|
||||
|
||||
In my case
|
||||
```
|
||||
mkdir -p /home/ubuntu/docker/letsencrypt
|
||||
cd /home/ubuntu/docker/letsencrypt
|
||||
2. Now get the certificate (modify `mail.myserver.tld`) and following the certbot instructions.
|
||||
|
||||
3. This will need access to port 80 from the internet, adjust your firewall if needed:
|
||||
|
||||
```sh
|
||||
docker run --rm -it \
|
||||
-v $PWD/log/:/var/log/letsencrypt/ \
|
||||
-v $PWD/etc/:/etc/letsencrypt/ \
|
||||
-p 80:80 \
|
||||
certbot/certbot certonly --standalone -d mail.myserver.tld
|
||||
```
|
||||
|
||||
4. You can now mount `/home/ubuntu/docker/letsencrypt/etc/` in `/etc/letsencrypt` of `docker-mailserver`.
|
||||
|
||||
To renew your certificate just run (this will need access to port 443 from the internet, adjust your firewall if needed):
|
||||
|
||||
```sh
|
||||
docker run --rm -it \
|
||||
-v $PWD/log/:/var/log/letsencrypt/ \
|
||||
-v $PWD/etc/:/etc/letsencrypt/ \
|
||||
-p 80:80 \
|
||||
-p 443:443 \
|
||||
certbot/certbot renew
|
||||
```
|
||||
|
||||
### Example using Docker, `nginx-proxy` and `letsencrypt-nginx-proxy-companion`
|
||||
|
||||
If you are running a web server already, it is non-trivial to generate a Let's Encrypt certificate for your mail server using `certbot`, because port 80 is already occupied. In the following example, we show how `docker-mailserver` can be run alongside the docker containers `nginx-proxy` and `letsencrypt-nginx-proxy-companion`.
|
||||
|
||||
There are several ways to start `nginx-proxy` and `letsencrypt-nginx-proxy-companion`. Any method should be suitable here.
|
||||
|
||||
For example start `nginx-proxy` as in the `letsencrypt-nginx-proxy-companion` [documentation](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion):
|
||||
|
||||
```sh
|
||||
docker run --detach \
|
||||
--name nginx-proxy \
|
||||
--restart always \
|
||||
--publish 80:80 \
|
||||
--publish 443:443 \
|
||||
--volume /server/letsencrypt/etc:/etc/nginx/certs:ro \
|
||||
--volume /etc/nginx/vhost.d \
|
||||
--volume /usr/share/nginx/html \
|
||||
--volume /var/run/docker.sock:/tmp/docker.sock:ro \
|
||||
jwilder/nginx-proxy
|
||||
```
|
||||
|
||||
Now get the certificate (modify ```mail.myserver.tld```) and following the certbot instructions.
|
||||
This will need access to port 80 from the internet, adjust your firewall if needed
|
||||
```
|
||||
docker run --rm -ti -v $PWD/log/:/var/log/letsencrypt/ -v $PWD/etc/:/etc/letsencrypt/ -p 80:80 certbot/certbot certonly --standalone -d mail.myserver.tld
|
||||
```
|
||||
You can now mount /home/ubuntu/docker/letsencrypt/etc/ in /etc/letsencrypt of ```docker-mailserver```
|
||||
Then start `nginx-proxy-letsencrypt`:
|
||||
|
||||
To renew your certificate just run (this will need access to port 443 from the internet, adjust your firewall if needed)
|
||||
```
|
||||
docker run --rm -ti -v $PWD/log/:/var/log/letsencrypt/ -v $PWD/etc/:/etc/letsencrypt/ -p 80:80 -p 443:443 certbot/certbot renew
|
||||
```sh
|
||||
docker run --detach \
|
||||
--name nginx-proxy-letsencrypt \
|
||||
--restart always \
|
||||
--volume /server/letsencrypt/etc:/etc/nginx/certs:rw \
|
||||
--volumes-from nginx-proxy \
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock:ro \
|
||||
jrcs/letsencrypt-nginx-proxy-companion
|
||||
```
|
||||
|
||||
#### Example using docker, nginx-proxy and letsencrypt-nginx-proxy-companion ####
|
||||
If you are running a web server already, it is non-trivial to generate a Let's Encrypt certificate for your mail server using ```certbot```, because port 80 is already occupied. In the following example, we show how ```docker-mailserver``` can be run alongside the docker containers ```nginx-proxy``` and ```letsencrypt-nginx-proxy-companion```.
|
||||
|
||||
There are several ways to start ```nginx-proxy``` and ```letsencrypt-nginx-proxy-companion```. Any method should be suitable here. For example start ```nginx-proxy``` as in the ```letsencrypt-nginx-proxy-companion``` [documentation](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion):
|
||||
|
||||
```
|
||||
docker run --detach \
|
||||
--name nginx-proxy \
|
||||
--restart always \
|
||||
--publish 80:80 \
|
||||
--publish 443:443 \
|
||||
--volume /server/letsencrypt/etc:/etc/nginx/certs:ro \
|
||||
--volume /etc/nginx/vhost.d \
|
||||
--volume /usr/share/nginx/html \
|
||||
--volume /var/run/docker.sock:/tmp/docker.sock:ro \
|
||||
jwilder/nginx-proxy
|
||||
```
|
||||
|
||||
Then start ```nginx-proxy-letsencrypt```:
|
||||
```
|
||||
docker run --detach \
|
||||
--name nginx-proxy-letsencrypt \
|
||||
--restart always \
|
||||
--volume /server/letsencrypt/etc:/etc/nginx/certs:rw \
|
||||
--volumes-from nginx-proxy \
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock:ro \
|
||||
jrcs/letsencrypt-nginx-proxy-companion
|
||||
```
|
||||
Start the rest of your web server containers as usual.
|
||||
|
||||
Start another container for your ```mail.myserver.tld```. This will generate a Let's Encrypt certificate for your domain, which can be used by ```docker-mailserver```. It will also run a web server on port 80 at that address.:
|
||||
```
|
||||
Start another container for your `mail.myserver.tld`. This will generate a Let's Encrypt certificate for your domain, which can be used by `docker-mailserver`. It will also run a web server on port 80 at that address:
|
||||
|
||||
```sh
|
||||
docker run -d \
|
||||
--name webmail \
|
||||
-e "VIRTUAL_HOST=mail.myserver.tld" \
|
||||
-e "LETSENCRYPT_HOST=mail.myserver.tld" \
|
||||
-e "LETSENCRYPT_EMAIL=foo@bar.com" \
|
||||
library/nginx
|
||||
```
|
||||
You may want to add ```-e LETSENCRYPT_TEST=true``` to the above while testing to avoid the Let's Encrypt certificate generation rate limits.
|
||||
|
||||
Finally, start the mailserver with the docker-compose.yml
|
||||
Make sure your mount path to the letsencrypt certificates is correct.
|
||||
Inside your /path/to/mailserver/docker-compose.yml ( for the mailserver from this repo ) make sure volumes look like below example;
|
||||
|
||||
```
|
||||
volumes:
|
||||
- maildata:/var/mail
|
||||
- mailstate:/var/mail-state
|
||||
- ./config/:/tmp/docker-mailserver/
|
||||
- /server/letsencrypt/etc:/etc/letsencrypt/live
|
||||
--name webmail \
|
||||
-e "VIRTUAL_HOST=mail.myserver.tld" \
|
||||
-e "LETSENCRYPT_HOST=mail.myserver.tld" \
|
||||
-e "LETSENCRYPT_EMAIL=foo@bar.com" \
|
||||
library/nginx
|
||||
```
|
||||
|
||||
Then
|
||||
You may want to add `-e LETSENCRYPT_TEST=true` to the above while testing to avoid the Let's Encrypt certificate generation rate limits.
|
||||
|
||||
/path/to/mailserver/docker-compose up -d mail
|
||||
Finally, start the mailserver with the `docker-compose.yml`. Make sure your mount path to the letsencrypt certificates is correct.
|
||||
|
||||
Inside your `/path/to/mailserver/docker-compose.yml` (for the mailserver from this repo) make sure volumes look like below example:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- maildata:/var/mail
|
||||
- mailstate:/var/mail-state
|
||||
- ./config/:/tmp/docker-mailserver/
|
||||
- /server/letsencrypt/etc:/etc/letsencrypt/live
|
||||
```
|
||||
|
||||
#### Example using docker, nginx-proxy and letsencrypt-nginx-proxy-companion with docker-compose
|
||||
The following docker-compose.yml is the basic setup you need for using letsencrypt-nginx-proxy-companion. It is mainly derived from its own wiki/documenation.
|
||||
Then: `/path/to/mailserver/docker-compose up -d mail`
|
||||
|
||||
```YAML
|
||||
### Example using Docker, `nginx-proxy` and `letsencrypt-nginx-proxy-companion` with `docker-compose`
|
||||
|
||||
The following `docker-compose.yml` is the basic setup you need for using `letsencrypt-nginx-proxy-companion`. It is mainly derived from its own wiki/documenation.
|
||||
|
||||
```yaml
|
||||
version: "2"
|
||||
|
||||
services:
|
||||
|
@ -156,9 +184,9 @@ networks:
|
|||
name: nginx-proxy
|
||||
```
|
||||
|
||||
The second part of the setup is the actual mail container. So, in another folder, create another docker-compose.yml with the following content (Removed all ENV variables for this example):
|
||||
The second part of the setup is the actual mail container. So, in another folder, create another `docker-compose.yml` with the following content (Removed all ENV variables for this example):
|
||||
|
||||
``` YAML
|
||||
```yaml
|
||||
version: '2'
|
||||
services:
|
||||
mail:
|
||||
|
@ -192,60 +220,62 @@ services:
|
|||
networks:
|
||||
- proxy-tier
|
||||
restart: always
|
||||
|
||||
|
||||
networks:
|
||||
proxy-tier:
|
||||
external:
|
||||
name: nginx-proxy
|
||||
|
||||
```
|
||||
|
||||
The mail container needs to have the letsencrypt certificate folder mounted as a volume. No further changes are needed. The second container is a dummy-sidecar we need, because the mail-container do not expose any web-ports. Set your ENV variables as you need. (VIRTUAL_HOST and LETSENCRYPT_HOST are mandandory, see documentation)
|
||||
The mail container needs to have the letsencrypt certificate folder mounted as a volume. No further changes are needed. The second container is a dummy-sidecar we need, because the mail-container do not expose any web-ports. Set your ENV variables as you need. (`VIRTUAL_HOST` and `LETSENCRYPT_HOST` are mandandory, see documentation)
|
||||
|
||||
### Example using the Let's Encrypt Certificates on a Synology NAS
|
||||
|
||||
#### Example using the letsencrypt certificates on a Synology NAS
|
||||
Version 6.2 and later of the Synology NAS DSM OS now come with an interface to generate and renew letencrypt certificates. Navigation into your DSM control panel and go to Security, then click on the tab Certificate to generate and manage letsencrypt certificates.
|
||||
|
||||
Version 6.2 and later of the Synology NAS DSM OS now come with an interface to generate and renew letencrypt certificates. Navigation into your DSM control panel and go to Security, then click on the tab Certificate to generate and manage letsencrypt certificates. Amongst other things, you can use these to secure your mail server. DSM locates the generated certificates in a folder below ```/usr/syno/etc/certificate/_archive/```. Navigate to that folder and note the 6 character random folder name of the certificate you'd like to use. Then, add the following to your ```docker-compose.yml``` declaration file:
|
||||
Amongst other things, you can use these to secure your mail server. DSM locates the generated certificates in a folder below `/usr/syno/etc/certificate/_archive/`.
|
||||
|
||||
```
|
||||
Navigate to that folder and note the 6 character random folder name of the certificate you'd like to use. Then, add the following to your `docker-compose.yml` declaration file:
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- /usr/syno/etc/certificate/_archive/YOUR_FOLDER/:/tmp/ssl
|
||||
...
|
||||
- /usr/syno/etc/certificate/_archive/<your-folder>/:/tmp/ssl
|
||||
environment:
|
||||
- SSL_TYPE=manual
|
||||
- SSL_CERT_PATH=/tmp/ssl/fullchain.pem
|
||||
- SSL_KEY_PATH=/tmp/ssl/privkey.pem
|
||||
|
||||
- SSL_TYPE=manual
|
||||
- SSL_CERT_PATH=/tmp/ssl/fullchain.pem
|
||||
- SSL_KEY_PATH=/tmp/ssl/privkey.pem
|
||||
```
|
||||
|
||||
DSM-generated letsencrypt certificates get auto-renewed every three months.
|
||||
|
||||
### Caddy
|
||||
## Caddy
|
||||
|
||||
If you are using Caddy to renew your certificates, please note that only RSA certificates work. Read [issue 1440](https://github.com/tomav/docker-mailserver/issues/1440) for details. In short for Caddy v1 the Caddyfile should look something like:
|
||||
If you are using Caddy to renew your certificates, please note that only RSA certificates work. Read [#1440][github-issue-1440] for details. In short for Caddy v1 the `Caddyfile` should look something like:
|
||||
|
||||
```
|
||||
```caddyfile
|
||||
https://mail.domain.com {
|
||||
tls yourcurrentemail@gmail.com {
|
||||
key_type rsa2048
|
||||
}
|
||||
tls yourcurrentemail@gmail.com {
|
||||
key_type rsa2048
|
||||
}
|
||||
}
|
||||
```
|
||||
For Caddy v2 you can specify the key_type in your server's global settings, which would end up looking something like this if you're using a Caddyfile:
|
||||
```
|
||||
{
|
||||
debug
|
||||
admin localhost:2019
|
||||
http_port 80
|
||||
https_port 443
|
||||
default_sni mywebserver.com
|
||||
key_type rsa4096
|
||||
|
||||
For Caddy v2 you can specify the `key_type` in your server's global settings, which would end up looking something like this if you're using a `Caddyfile`:
|
||||
|
||||
```caddyfile
|
||||
{
|
||||
debug
|
||||
admin localhost:2019
|
||||
http_port 80
|
||||
https_port 443
|
||||
default_sni mywebserver.com
|
||||
key_type rsa4096
|
||||
}
|
||||
````
|
||||
```
|
||||
|
||||
If you are instead using a json config for Caddy v2, you can set it in your site's TLS automation policies:
|
||||
|
||||
```
|
||||
```json
|
||||
{
|
||||
"apps": {
|
||||
"http": {
|
||||
|
@ -309,8 +339,10 @@ If you are instead using a json config for Caddy v2, you can set it in your site
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
The generated certificates can be mounted:
|
||||
```
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- ${CADDY_DATA_DIR}/certificates/acme-v02.api.letsencrypt.org-directory/mail.domain.com/mail.domain.com.crt:/etc/letsencrypt/live/mail.domain.com/fullchain.pem
|
||||
- ${CADDY_DATA_DIR}/certificates/acme-v02.api.letsencrypt.org-directory/mail.domain.com/mail.domain.com.key:/etc/letsencrypt/live/mail.domain.com/privkey.pem
|
||||
|
@ -318,32 +350,32 @@ volumes:
|
|||
|
||||
EC certificates fail in the TLS handshake:
|
||||
|
||||
```
|
||||
```log
|
||||
CONNECTED(00000003)
|
||||
140342221178112:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:ssl/record/rec_layer_s3.c:1543:SSL alert number 40
|
||||
no peer certificate available
|
||||
No client certificate CA names sent
|
||||
```
|
||||
|
||||
### Traefik
|
||||
## Traefik
|
||||
|
||||
[Traefik](https://github.com/containous/traefik) is an open-source Edge Router which handles ACME protocol using [lego](https://github.com/go-acme/lego).
|
||||
|
||||
Traefik can request certificates for domains through the ACME protocol (see [Traefik's documentation about its ACME negotiation & storage mechanism](https://docs.traefik.io/https/acme/)). Traefik's router will take care of renewals, challenge negotiations, etc.
|
||||
|
||||
##### Traefik v2
|
||||
### Traefik v2
|
||||
|
||||
(For Traefik v1 see [next section](#traefik-v1))
|
||||
|
||||
Traefik's V2 storage format is natively supported if the `acme.json` store is mounted into the container at `/etc/letsencrypt/acme.json`. The file is also monitored for changes and will trigger a reload of the mail services. Lookup of the certificate domain happens in the following order:
|
||||
|
||||
1. $SSL_DOMAIN
|
||||
2. $HOSTNAME
|
||||
3. $DOMAINNAME
|
||||
1. `$SSL_DOMAIN`
|
||||
2. `$HOSTNAME`
|
||||
3. `$DOMAINNAME`
|
||||
|
||||
This allows for support of wild card certificates: `"SSL_DOMAIN=*.example.com"`. Here is an example setup for [docker-compose](https://docs.docker.com/compose/):
|
||||
This allows for support of wild card certificates: `SSL_DOMAIN=*.example.com`. Here is an example setup for [`docker-compose`](https://docs.docker.com/compose/):
|
||||
|
||||
``` YAML
|
||||
```yaml
|
||||
version: '3.8'
|
||||
services:
|
||||
mail:
|
||||
|
@ -384,127 +416,150 @@ services:
|
|||
|
||||
This setup only comes with one caveat: The domain has to be configured on another service for traefik to actually request it from lets-encrypt (`whoami` in this case).
|
||||
|
||||
##### Traefik V1
|
||||
### Traefik v1
|
||||
|
||||
If you are using Traefik v1, you might want to _push_ your Traefik-managed certificates to the mailserver container, in order to reuse them. Not an easy task, but fortunately, [youtous/mailserver-traefik](https://github.com/youtous/docker-mailserver-traefik) is a certificate renewal service for docker-mailserver.
|
||||
If you are using Traefik v1, you might want to _push_ your Traefik-managed certificates to the mailserver container, in order to reuse them. Not an easy task, but fortunately, [`youtous/mailserver-traefik`][youtous-mailtraefik] is a certificate renewal service for `docker-mailserver`.
|
||||
|
||||
Depending of your Traefik configuration, certificates may be stored using a file or a KV Store (consul, etcd...) Either way, certificates will be renewed by Traefik, then automatically pushed to the mailserver thanks to the cert-renewer service. Finally, dovecot and postfix will be restarted.
|
||||
Depending of your Traefik configuration, certificates may be stored using a file or a KV Store (consul, etcd...) Either way, certificates will be renewed by Traefik, then automatically pushed to the mailserver thanks to the `cert-renewer` service. Finally, dovecot and postfix will be restarted.
|
||||
|
||||
Documentation: https://github.com/youtous/docker-mailserver-traefik
|
||||
|
||||
|
||||
### Self-signed certificates (testing only)
|
||||
## Self-Signed Certificates (Testing Only)
|
||||
|
||||
You can easily generate a self-signed SSL certificate by using the following command:
|
||||
|
||||
docker run -ti --rm -v "$(pwd)"/config/ssl:/tmp/docker-mailserver/ssl -h mail.my-domain.com -t tvial/docker-mailserver generate-ssl-certificate
|
||||
```sh
|
||||
docker run -it --rm -v "$(pwd)"/config/ssl:/tmp/docker-mailserver/ssl -h mail.my-domain.com -t tvial/docker-mailserver generate-ssl-certificate
|
||||
|
||||
# Press enter
|
||||
# Enter a password when needed
|
||||
# Fill information like Country, Organisation name
|
||||
# Fill "my-domain.com" as FQDN for CA, and "mail.my-domain.com" for the certificate.
|
||||
# They HAVE to be different, otherwise you'll get a `TXT_DB error number 2`
|
||||
# Don't fill extras
|
||||
# Enter same password when needed
|
||||
# Sign the certificate? [y/n]:y
|
||||
# 1 out of 1 certificate requests certified, commit? [y/n]y
|
||||
# Press enter
|
||||
# Enter a password when needed
|
||||
# Fill information like Country, Organisation name
|
||||
# Fill "my-domain.com" as FQDN for CA, and "mail.my-domain.com" for the certificate.
|
||||
# They HAVE to be different, otherwise you'll get a `TXT_DB error number 2`
|
||||
# Don't fill extras
|
||||
# Enter same password when needed
|
||||
# Sign the certificate? [y/n]:y
|
||||
# 1 out of 1 certificate requests certified, commit? [y/n]y
|
||||
|
||||
# will generate:
|
||||
# config/ssl/mail.my-domain.com-key.pem (used in postfix)
|
||||
# config/ssl/mail.my-domain.com-req.pem (only used to generate other files)
|
||||
# config/ssl/mail.my-domain.com-cert.pem (used in postfix)
|
||||
# config/ssl/mail.my-domain.com-combined.pem (used in courier)
|
||||
# config/ssl/demoCA/cacert.pem (certificate authority)
|
||||
# will generate:
|
||||
# config/ssl/mail.my-domain.com-key.pem (used in postfix)
|
||||
# config/ssl/mail.my-domain.com-req.pem (only used to generate other files)
|
||||
# config/ssl/mail.my-domain.com-cert.pem (used in postfix)
|
||||
# config/ssl/mail.my-domain.com-combined.pem (used in courier)
|
||||
# config/ssl/demoCA/cacert.pem (certificate authority)
|
||||
```
|
||||
|
||||
Note that the certificate will be generate for the container `fqdn`, that is passed as `-h` argument.
|
||||
Check the following page for more information regarding [postfix and SSL/TLS configuration](http://www.mad-hacking.net/documentation/linux/applications/mail/using-ssl-tls-postfix-courier.xml).
|
||||
!!! note
|
||||
The certificate will be generate for the container `fqdn`, that is passed as `-h` argument.
|
||||
|
||||
Check the following page for more information regarding [postfix and SSL/TLS configuration](http://www.mad-hacking.net/documentation/linux/applications/mail/using-ssl-tls-postfix-courier.xml).
|
||||
|
||||
To use the certificate:
|
||||
|
||||
* add `SSL_TYPE=self-signed` to your container environment variables
|
||||
* if a matching certificate (files listed above) is found in `config/ssl`, it will be automatically setup in postfix and dovecot. You just have to place them in `config/ssl` folder.
|
||||
- Add `SSL_TYPE=self-signed` to your container environment variables
|
||||
- If a matching certificate (files listed above) is found in `config/ssl`, it will be automatically setup in postfix and dovecot. You just have to place them in `config/ssl` folder.
|
||||
|
||||
### Custom certificate files
|
||||
## Custom Certificate Files
|
||||
|
||||
You can also provide your own certificate files. Add these entries to your `docker-compose.yml`:
|
||||
|
||||
volumes:
|
||||
- /etc/ssl:/tmp/ssl:ro
|
||||
environment:
|
||||
- SSL_TYPE=manual
|
||||
- SSL_CERT_PATH=/tmp/ssl/cert/public.crt
|
||||
- SSL_KEY_PATH=/tmp/ssl/private/private.key
|
||||
```yaml
|
||||
volumes:
|
||||
- /etc/ssl:/tmp/ssl:ro
|
||||
environment:
|
||||
- SSL_TYPE=manual
|
||||
- SSL_CERT_PATH=/tmp/ssl/cert/public.crt
|
||||
- SSL_KEY_PATH=/tmp/ssl/private/private.key
|
||||
```
|
||||
|
||||
This will mount the path where your ssl certificates reside as read-only under `/tmp/ssl`. Then all you have to do is to specify the location of your private key and the certificate.
|
||||
|
||||
Please note that you may have to restart your mailserver once the certificates change.
|
||||
!!! note
|
||||
You may have to restart your mailserver once the certificates change.
|
||||
|
||||
### Testing certificate
|
||||
## Testing a Certificate is Valid
|
||||
|
||||
From your host:
|
||||
- From your host:
|
||||
|
||||
docker exec mail openssl s_client -connect 0.0.0.0:25 -starttls smtp -CApath /etc/ssl/certs/
|
||||
```sh
|
||||
docker exec mail openssl s_client \
|
||||
-connect 0.0.0.0:25 \
|
||||
-starttls smtp \
|
||||
-CApath /etc/ssl/certs/
|
||||
```
|
||||
|
||||
or
|
||||
- Or:
|
||||
|
||||
docker exec mail openssl s_client -connect 0.0.0.0:143 -starttls imap -CApath /etc/ssl/certs/
|
||||
```sh
|
||||
docker exec mail openssl s_client \
|
||||
-connect 0.0.0.0:143 \
|
||||
-starttls imap \
|
||||
-CApath /etc/ssl/certs/
|
||||
```
|
||||
|
||||
|
||||
And you should see the certificate chain, the server certificate and:
|
||||
|
||||
Verify return code: 0 (ok)
|
||||
And you should see the certificate chain, the server certificate and: `Verify return code: 0 (ok)`
|
||||
|
||||
In addition, to verify certificate dates:
|
||||
|
||||
docker exec mail openssl s_client -connect 0.0.0.0:25 -starttls smtp -CApath /etc/ssl/certs/ 2>/dev/null | openssl x509 -noout -dates
|
||||
```sh
|
||||
docker exec mail openssl s_client \
|
||||
-connect 0.0.0.0:25 \
|
||||
-starttls smtp \
|
||||
-CApath /etc/ssl/certs/ \
|
||||
2>/dev/null | openssl x509 -noout -dates
|
||||
```
|
||||
|
||||
|
||||
### Plain text access
|
||||
## Plain-Text Access
|
||||
|
||||
Not recommended for purposes other than testing.
|
||||
|
||||
Just add this to config/dovecot.cf:
|
||||
Just add this to `config/dovecot.cf`:
|
||||
|
||||
```
|
||||
```cf
|
||||
ssl = yes
|
||||
disable_plaintext_auth=no
|
||||
```
|
||||
|
||||
These options in conjunction mean:
|
||||
|
||||
```
|
||||
ssl=yes and disable_plaintext_auth=no: SSL/TLS is offered to the client, but the client isn't required to use it. The client is allowed to login with plaintext authentication even when SSL/TLS isn't enabled on the connection. This is insecure, because the plaintext password is exposed to the internet.
|
||||
```
|
||||
- SSL/TLS is offered to the client, but the client isn't required to use it.
|
||||
- The client is allowed to login with plaintext authentication even when SSL/TLS isn't enabled on the connection.
|
||||
- **This is insecure**, because the plaintext password is exposed to the internet.
|
||||
|
||||
### Importing certificates obtained via another source
|
||||
If you have another source for SSL/TLS certificates you can import them into the server via an external script. The external script can be found here: [external certificate import script](https://github.com/hanscees/dockerscripts/blob/master/scripts/tomav-renew-certs)
|
||||
## Importing Certificates Obtained via Another Source
|
||||
|
||||
If you have another source for SSL/TLS certificates you can import them into the server via an external script. The external script can be found here: [external certificate import script][hanscees-renewcerts].
|
||||
|
||||
The steps to follow are these:
|
||||
1. Transport the new certificates to ./config/sll (/tmp/ssl in the container)
|
||||
2. You should provide fullchain.key and privkey.pem
|
||||
3. Place the script in ./config/ (or /tmp/docker-mailserver/ inside the container)
|
||||
4. Make the script executable (chmod +x tomav-renew-certs.sh )
|
||||
5. Run the script: docker exec mail /tmp/docker-mailserver/tomav-renew-certs.sh
|
||||
|
||||
1. Transport the new certificates to `./config/ssl` (`/tmp/ssl` in the container)
|
||||
2. You should provide `fullchain.key` and `privkey.pem`
|
||||
3. Place the script in `./config/` (or `/tmp/docker-mailserver/` inside the container)
|
||||
4. Make the script executable (`chmod +x tomav-renew-certs.sh`)
|
||||
5. Run the script: `docker exec mail /tmp/docker-mailserver/tomav-renew-certs.sh`
|
||||
|
||||
If an error occurs the script will inform you. If not you will see both postfix and dovecot restart.
|
||||
|
||||
After the certificates have been loaded you can check the certificate:
|
||||
After the certificates have been loaded you can check the certificate:
|
||||
|
||||
```
|
||||
```sh
|
||||
openssl s_client \
|
||||
-servername mail.mydomain.net \
|
||||
-connect 192.168.0.72:465 \
|
||||
2>/dev/null | openssl x509
|
||||
|
||||
openssl s_client -servername mail.mydomain.net -connect 192.168.0.72:465 2>/dev/null | openssl x509
|
||||
|
||||
# or
|
||||
|
||||
openssl s_client -servername mail.mydomain.net -connect mail.mydomain.net:465 2>/dev/null | openssl x509
|
||||
# or
|
||||
|
||||
openssl s_client \
|
||||
-servername mail.mydomain.net \
|
||||
-connect mail.mydomain.net:465 \
|
||||
2>/dev/null | openssl x509
|
||||
```
|
||||
|
||||
Or you can check how long the new certificate is valid with commands like:
|
||||
```
|
||||
|
||||
```sh
|
||||
export SITE_URL="mail.mydomain.net"
|
||||
export SITE_IP_URL="192.168.0.72" ## can also be mail.mydomain.net
|
||||
export SITE_SSL_PORT="465" ##imap port dovecot
|
||||
export SITE_IP_URL="192.168.0.72" # can also be `mail.mydomain.net`
|
||||
export SITE_SSL_PORT="993" # imap port dovecot
|
||||
|
||||
##works: check if certificate will expire in two weeks
|
||||
#2 weeks is 1209600 seconds
|
||||
|
@ -513,39 +568,39 @@ export SITE_SSL_PORT="465" ##imap port dovecot
|
|||
#15 weeks is 9072000
|
||||
|
||||
certcheck_2weeks=`openssl s_client -connect ${SITE_IP_URL}:${SITE_SSL_PORT} \
|
||||
-servername ${SITE_URL} 2> /dev/null | openssl x509 -noout -checkend 1209600`
|
||||
-servername ${SITE_URL} 2> /dev/null | openssl x509 -noout -checkend 1209600`
|
||||
|
||||
####################################
|
||||
#notes: output can be
|
||||
#notes: output can be
|
||||
#Certificate will not expire
|
||||
#Certificate will expire
|
||||
####################
|
||||
|
||||
```
|
||||
|
||||
What does the script that imports the certificates do:
|
||||
1. Check if there are new certs in the /tmp/ssl folder
|
||||
2. check with the ssl cert fingerprint if they differ from the current certificates
|
||||
3. if so it will copy the certs to the right places
|
||||
4. and restart postfix and dovecot
|
||||
|
||||
You can ofcourse run the script by cron once a week or something. In that way you could automate cert renewal. If you do so it is probably wise to run an automated check on certificate expiry as well. Such a check could look something like this:
|
||||
```
|
||||
1. Check if there are new certs in the `/tmp/ssl` folder.
|
||||
2. Check with the ssl cert fingerprint if they differ from the current certificates.
|
||||
3. If so it will copy the certs to the right places.
|
||||
4. And restart postfix and dovecot.
|
||||
|
||||
You can of course run the script by cron once a week or something. In that way you could automate cert renewal. If you do so it is probably wise to run an automated check on certificate expiry as well. Such a check could look something like this:
|
||||
|
||||
```sh
|
||||
## code below will alert if certificate expires in less than two weeks
|
||||
## please adjust varables!
|
||||
## make sure the mail -s command works! Test!
|
||||
|
||||
export SITE_URL="mail.mydomain.net"
|
||||
export SITE_IP_URL="192.168.2.72" ## can also be mail.mydomain.net
|
||||
export SITE_SSL_PORT="465" ##imap port dovecot
|
||||
export SITE_IP_URL="192.168.2.72" # can also be `mail.mydomain.net`
|
||||
export SITE_SSL_PORT="993" # imap port dovecot
|
||||
export ALERT_EMAIL_ADDR="bill@gates321boom.com"
|
||||
|
||||
certcheck_2weeks=`openssl s_client -connect ${SITE_IP_URL}:${SITE_SSL_PORT} \
|
||||
-servername ${SITE_URL} 2> /dev/null | openssl x509 -noout -checkend 1209600`
|
||||
-servername ${SITE_URL} 2> /dev/null | openssl x509 -noout -checkend 1209600`
|
||||
|
||||
####################################
|
||||
#notes: output can be
|
||||
#notes: output can be
|
||||
#Certificate will not expire
|
||||
#Certificate will expire
|
||||
####################
|
||||
|
@ -555,27 +610,17 @@ certcheck_2weeks=`openssl s_client -connect ${SITE_IP_URL}:${SITE_SSL_PORT} \
|
|||
##automated check you might run by cron or something
|
||||
## does tls/ssl certificate expire within two weeks?
|
||||
|
||||
if [ "$certcheck_2weeks" = "Certificate will not expire" ]; then
|
||||
echo "all is wel, certwatch 2 weeks says $certcheck_2weeks"
|
||||
else
|
||||
echo "Cert seems to be expiring pretty soon, within two weeks: $certcheck_2weeks"
|
||||
echo "we will send an alert email and log as well"
|
||||
logger Certwatch: cert $SITE_URL will expire in two weeks
|
||||
echo "Certwatch: cert $SITE_URL will expire in two weeks" | mail -s "cert $SITE_URL expires in two weeks " $ALERT_EMAIL_ADDR
|
||||
if [ "$certcheck_2weeks" = "Certificate will not expire" ]; then
|
||||
echo "all is well, certwatch 2 weeks says $certcheck_2weeks"
|
||||
else
|
||||
echo "Cert seems to be expiring pretty soon, within two weeks: $certcheck_2weeks"
|
||||
echo "we will send an alert email and log as well"
|
||||
logger Certwatch: cert $SITE_URL will expire in two weeks
|
||||
echo "Certwatch: cert $SITE_URL will expire in two weeks" | mail -s "cert $SITE_URL expires in two weeks " $ALERT_EMAIL_ADDR
|
||||
fi
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[github-file-compose]: https://github.com/docker-mailserver/docker-mailserver/blob/master/docker-compose.yml
|
||||
[github-issue-1440]: https://github.com/docker-mailserver/docker-mailserver/issues/1440
|
||||
[hanscees-renewcerts]: https://github.com/hanscees/dockerscripts/blob/master/scripts/tomav-renew-certs
|
||||
[youtous-mailtraefik]: https://github.com/youtous/docker-mailserver-traefik
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
---
|
||||
title: 'Security | Understanding the Ports'
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
Prefer Implicit TLS ports, they're more secure and if you use a Reverse Proxy, should be less hassle (although it's probably wiser to expose these ports directly to `docker-mailserver`).
|
||||
|
||||
## Overview of email ports
|
||||
## Overview of Email Ports
|
||||
|
||||
| Protocol | Explicit TLS<sup>1</sup> | Implicit TLS | Purpose |
|
||||
|----------|--------------------------|-----------------|----------------------|
|
||||
|
@ -11,56 +15,54 @@ Prefer Implicit TLS ports, they're more secure and if you use a Reverse Proxy, s
|
|||
| POP3 | 110 | 995 | Retrieval |
|
||||
| IMAP4 | 143 | 993 | Retrieval |
|
||||
|
||||
1. A connection *may* be secured over TLS when both ends support `STARTTLS`. On ports 110, 143 and 587, `docker-mailserver` will reject a connection that cannot be secured. Port 25 is [required](https://serverfault.com/questions/623692/is-it-still-wrong-to-require-starttls-on-incoming-smtp-messages) to support insecure connections.
|
||||
1. A connection *may* be secured over TLS when both ends support `STARTTLS`. On ports 110, 143 and 587, `docker-mailserver` will reject a connection that cannot be secured. Port 25 is [required][ref-port25-mandatory] to support insecure connections.
|
||||
2. Receives email, `docker-mailserver` additionally filters for spam and viruses. For submitting email to the server to be sent to third-parties, you should prefer the *submission* ports(465, 587) - which require authentication. Unless a relay host is configured(eg SendGrid), outgoing email will leave the server via port 25(thus outbound traffic must not be blocked by your provider or firewall).
|
||||
3. A *submission* port since 2018 ([RFC 8314](https://tools.ietf.org/html/rfc8314)). Previously a secure variant of port 25.
|
||||
3. A *submission* port since 2018 ([RFC 8314][rfc-8314]). Previously a secure variant of port 25.
|
||||
|
||||
### What ports should I use? (SMTP)
|
||||
### What Ports Should I Use? (SMTP)
|
||||
|
||||
[](https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgc3ViZ3JhcGggeW91ci1zZXJ2ZXIgW1wiWW91ciBTZXJ2ZXJcIl1cbiAgICAgICAgaW5fMjUoMjUpIC0tPiBzZXJ2ZXJcbiAgICAgICAgaW5fNDY1KDQ2NSkgLS0-IHNlcnZlclxuICAgICAgICBzZXJ2ZXIoKFwiZG9ja2VyLW1haWxzZXJ2ZXI8YnIvPmhlbGxvQHdvcmxkLmNvbVwiKSlcbiAgICAgICAgc2VydmVyIC0tLSBvdXRfMjUoMjUpXG4gICAgICAgIHNlcnZlciAtLS0gb3V0XzQ2NSg0NjUpXG4gICAgZW5kXG5cbiAgICB0aGlyZC1wYXJ0eShcIlRoaXJkLXBhcnR5PGJyLz4oc2VuZGluZyB5b3UgZW1haWwpXCIpIC0tLXxcIlJlY2VpdmUgZW1haWwgZm9yPGJyLz5oZWxsb0B3b3JsZC5jb21cInwgaW5fMjVcblxuICAgIHN1YmdyYXBoIGNsaWVudHMgW1wiQ2xpZW50cyAoTVVBKVwiXVxuICAgICAgICBtdWEtY2xpZW50KFRodW5kZXJiaXJkLDxici8-V2VibWFpbCw8YnIvPk11dHQsPGJyLz5ldGMpXG4gICAgICAgIG11YS1zZXJ2aWNlKEJhY2tlbmQgc29mdHdhcmU8YnIvPm9uIGFub3RoZXIgc2VydmVyKVxuICAgIGVuZFxuICAgIGNsaWVudHMgLS0tfFwiU2VuZCBlbWFpbCBhczxici8-aGVsbG9Ad29ybGQuY29tXCJ8IGluXzQ2NVxuXG4gICAgb3V0XzI1KDI1KSAtLT58XCJEaXJlY3Q8YnIvPkRlbGl2ZXJ5XCJ8IHRpbl8yNVxuICAgIG91dF80NjUoNDY1KSAtLT4gcmVsYXkoXCJNVEE8YnIvPlJlbGF5IFNlcnZlclwiKSAtLT4gdGluXzI1KDI1KVxuXG4gICAgc3ViZ3JhcGggdGhpcmQtcGFydHktc2VydmVyW1wiVGhpcmQtcGFydHkgU2VydmVyXCJdXG4gICAgICAgIHRoaXJkLXBhcnR5LW10YShcIk1UQTxici8-ZnJpZW5kQGV4YW1wbGUuY29tXCIpXG4gICAgICAgIHRpbl8yNSgyNSkgLS0-IHRoaXJkLXBhcnR5LW10YVxuICAgIGVuZCIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0In0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9)
|
||||
[![Best Practice - Ports (SMTP)][asset-external-mermaid-smtp]][ref-mermaid-live-smtp]
|
||||
|
||||
<details>
|
||||
<summary>Flowchart - Mermaid.js source:</summary>
|
||||
??? "Flowchart - Mermaid.js source:"
|
||||
|
||||
View in the [Live Editor](https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgc3ViZ3JhcGggeW91ci1zZXJ2ZXIgW1wiWW91ciBTZXJ2ZXJcIl1cbiAgICAgICAgaW5fMjUoMjUpIC0tPiBzZXJ2ZXJcbiAgICAgICAgaW5fNDY1KDQ2NSkgLS0-IHNlcnZlclxuICAgICAgICBzZXJ2ZXIoKFwiZG9ja2VyLW1haWxzZXJ2ZXI8YnIvPmhlbGxvQHdvcmxkLmNvbVwiKSlcbiAgICAgICAgc2VydmVyIC0tLSBvdXRfMjUoMjUpXG4gICAgICAgIHNlcnZlciAtLS0gb3V0XzQ2NSg0NjUpXG4gICAgZW5kXG5cbiAgICB0aGlyZC1wYXJ0eShcIlRoaXJkLXBhcnR5PGJyLz4oc2VuZGluZyB5b3UgZW1haWwpXCIpIC0tLXxcIlJlY2VpdmUgZW1haWwgZm9yPGJyLz5oZWxsb0B3b3JsZC5jb21cInwgaW5fMjVcblxuICAgIHN1YmdyYXBoIGNsaWVudHMgW1wiQ2xpZW50cyAoTVVBKVwiXVxuICAgICAgICBtdWEtY2xpZW50KFRodW5kZXJiaXJkLDxici8-V2VibWFpbCw8YnIvPk11dHQsPGJyLz5ldGMpXG4gICAgICAgIG11YS1zZXJ2aWNlKEJhY2tlbmQgc29mdHdhcmU8YnIvPm9uIGFub3RoZXIgc2VydmVyKVxuICAgIGVuZFxuICAgIGNsaWVudHMgLS0tfFwiU2VuZCBlbWFpbCBhczxici8-aGVsbG9Ad29ybGQuY29tXCJ8IGluXzQ2NVxuXG4gICAgb3V0XzI1KDI1KSAtLT58XCJEaXJlY3Q8YnIvPkRlbGl2ZXJ5XCJ8IHRpbl8yNVxuICAgIG91dF80NjUoNDY1KSAtLT4gcmVsYXkoXCJNVEE8YnIvPlJlbGF5IFNlcnZlclwiKSAtLT4gdGluXzI1KDI1KVxuXG4gICAgc3ViZ3JhcGggdGhpcmQtcGFydHktc2VydmVyW1wiVGhpcmQtcGFydHkgU2VydmVyXCJdXG4gICAgICAgIHRoaXJkLXBhcnR5LW10YShcIk1UQTxici8-ZnJpZW5kQGV4YW1wbGUuY29tXCIpXG4gICAgICAgIHRpbl8yNSgyNSkgLS0-IHRoaXJkLXBhcnR5LW10YVxuICAgIGVuZCIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0In0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9).
|
||||
View in the [Live Editor][ref-mermaid-live-smtp].
|
||||
|
||||
```
|
||||
flowchart LR
|
||||
subgraph your-server ["Your Server"]
|
||||
in_25(25) --> server
|
||||
in_465(465) --> server
|
||||
server(("docker-mailserver<br/>hello@world.com"))
|
||||
server --- out_25(25)
|
||||
server --- out_465(465)
|
||||
end
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph your-server ["Your Server"]
|
||||
in_25(25) --> server
|
||||
in_465(465) --> server
|
||||
server(("docker-mailserver<br/>hello@world.com"))
|
||||
server --- out_25(25)
|
||||
server --- out_465(465)
|
||||
end
|
||||
|
||||
third-party("Third-party<br/>(sending you email)") ---|"Receive email for<br/>hello@world.com"| in_25
|
||||
third-party("Third-party<br/>(sending you email)") ---|"Receive email for<br/>hello@world.com"| in_25
|
||||
|
||||
subgraph clients ["Clients (MUA)"]
|
||||
mua-client(Thunderbird,<br/>Webmail,<br/>Mutt,<br/>etc)
|
||||
mua-service(Backend software<br/>on another server)
|
||||
end
|
||||
clients ---|"Send email as<br/>hello@world.com"| in_465
|
||||
subgraph clients ["Clients (MUA)"]
|
||||
mua-client(Thunderbird,<br/>Webmail,<br/>Mutt,<br/>etc)
|
||||
mua-service(Backend software<br/>on another server)
|
||||
end
|
||||
clients ---|"Send email as<br/>hello@world.com"| in_465
|
||||
|
||||
out_25(25) -->|"Direct<br/>Delivery"| tin_25
|
||||
out_465(465) --> relay("MTA<br/>Relay Server") --> tin_25(25)
|
||||
out_25(25) -->|"Direct<br/>Delivery"| tin_25
|
||||
out_465(465) --> relay("MTA<br/>Relay Server") --> tin_25(25)
|
||||
|
||||
subgraph third-party-server["Third-party Server"]
|
||||
third-party-mta("MTA<br/>friend@example.com")
|
||||
tin_25(25) --> third-party-mta
|
||||
end
|
||||
```
|
||||
subgraph third-party-server["Third-party Server"]
|
||||
third-party-mta("MTA<br/>friend@example.com")
|
||||
tin_25(25) --> third-party-mta
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
</details>
|
||||
#### Inbound Traffic (On the left)
|
||||
|
||||
|
||||
#### Inbound Traffic (On the left):
|
||||
- **Port 25:** Think of this like a physical mailbox, it is open to receive email from anyone who wants to. `docker-mailserver` will actively filter email delivered on this port for spam or viruses and refuse mail from known bad sources. While you could also use this port internally to send email outbound without requiring authentication, you really should prefer the *Submission* ports(587, 465).
|
||||
- **Port 465(*and 587*):** This is the equivalent of a post office box where you would send email to be delivered on your behalf(`docker-mailserver` is that metaphorical post office, aka the MTA). Unlike port 25, these two ports are known as the *Submission* ports and require a valid email account on the server with a password to be able to send email to anyone outside of the server(an MTA you do not control, eg Outlook or Gmail). Prefer port 465 which provides Implicit TLS.
|
||||
|
||||
#### Outbound Traffic (On the Right):
|
||||
#### Outbound Traffic (On the Right)
|
||||
|
||||
- **Port 25:** Send the email directly to the given email address MTA as possible. Like your own `docker-mailserver` port 25, this is the standard port for receiving email on, thus email will almost always arrive to the final MTA on this port. Note that, there may be additional MTAs further in the chain, but this would be the public facing one representing that email address.
|
||||
- **Port 465(*and 587*):** SMTP Relays are a popular choice to hand-off delivery of email through. Services like SendGrid are useful for bulk email(marketing) or when your webhost or ISP are preventing you from using standard ports like port 25 to send out email(which can be abused by spammers).
|
||||
|
||||
|
@ -70,11 +72,11 @@ flowchart LR
|
|||
|
||||
#### Explicit TLS (aka Opportunistic TLS) - Opt-in Encryption
|
||||
|
||||
Communication on these ports begin in [cleartext](https://www.denimgroup.com/resources/blog/2007/10/cleartext-vs-pl/), indicating support for `STARTTLS`. If both client and server support `STARTTLS` the connection will be secured over TLS, otherwise no encryption will be used.
|
||||
Communication on these ports begin in [cleartext][ref-clear-vs-plain], indicating support for `STARTTLS`. If both client and server support `STARTTLS` the connection will be secured over TLS, otherwise no encryption will be used.
|
||||
|
||||
Support for `STARTTLS` is not always implemented correctly, which can lead to leaking credentials(client sending too early) prior to a TLS connection being established. Third-parties such as some ISPs have also been known to intercept the `STARTTLS` exchange, modifying network traffic to prevent establishing a secure connection.
|
||||
|
||||
Due to these security concerns, [RFC 8314 (Section 4.1)](https://tools.ietf.org/html/rfc8314#section-4.1) encourages you to **prefer Implicit TLS ports where possible**.
|
||||
Due to these security concerns, [RFC 8314 (Section 4.1)][rfc-8314-s41] encourages you to **prefer Implicit TLS ports where possible**.
|
||||
|
||||
#### Implicit TLS - Enforced Encryption
|
||||
|
||||
|
@ -86,12 +88,21 @@ Additionally, referring to port 465 as *SMTPS* would be incorrect, as it is a su
|
|||
|
||||
## Security
|
||||
|
||||
**TODO:** *This section should provide any related configuration advice, and probably expand on and link to resources about DANE, DNSSEC, MTA-STS and STARTTLS Policy list, with advice on how to configure/setup these added security layers.*
|
||||
!!! todo
|
||||
This section should provide any related configuration advice, and probably expand on and link to resources about DANE, DNSSEC, MTA-STS and STARTTLS Policy list, with advice on how to configure/setup these added security layers.
|
||||
|
||||
**TODO:** *A related section or page on ciphers used may be useful, although less important for users to be concerned about.*
|
||||
!!! todo
|
||||
A related section or page on ciphers used may be useful, although less important for users to be concerned about.
|
||||
|
||||
### TLS connections on mail servers, compared to web browsers
|
||||
|
||||
Unlike with HTTP where a web browser client communicates directly with the server providing a website, a secure TLS connection as discussed below is not the equivalent safety that HTTPS provides when the transit of email (receiving or sending) is sent through third-parties, as the secure connection is only between two machines, any additional machines (MTAs) between the MUA and the MDA depends on them establishing secure connections between one another successfully.
|
||||
|
||||
Other machines that facilitate a connection that generally aren't taken into account can exist between a client and server, such as those where your connection passes through your ISP provider are capable of compromising a cleartext connection through interception.
|
||||
Other machines that facilitate a connection that generally aren't taken into account can exist between a client and server, such as those where your connection passes through your ISP provider are capable of compromising a cleartext connection through interception.
|
||||
|
||||
[asset-external-mermaid-smtp]: https://mermaid.ink/img/eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgc3ViZ3JhcGggeW91ci1zZXJ2ZXIgW1wiWW91ciBTZXJ2ZXJcIl1cbiAgICAgICAgaW5fMjUoMjUpIC0tPiBzZXJ2ZXJcbiAgICAgICAgaW5fNDY1KDQ2NSkgLS0-IHNlcnZlclxuICAgICAgICBzZXJ2ZXIoKFwiZG9ja2VyLW1haWxzZXJ2ZXI8YnIvPmhlbGxvQHdvcmxkLmNvbVwiKSlcbiAgICAgICAgc2VydmVyIC0tLSBvdXRfMjUoMjUpXG4gICAgICAgIHNlcnZlciAtLS0gb3V0XzQ2NSg0NjUpXG4gICAgZW5kXG5cbiAgICB0aGlyZC1wYXJ0eShcIlRoaXJkLXBhcnR5PGJyLz4oc2VuZGluZyB5b3UgZW1haWwpXCIpIC0tLXxcIlJlY2VpdmUgZW1haWwgZm9yPGJyLz5oZWxsb0B3b3JsZC5jb21cInwgaW5fMjVcblxuICAgIHN1YmdyYXBoIGNsaWVudHMgW1wiQ2xpZW50cyAoTVVBKVwiXVxuICAgICAgICBtdWEtY2xpZW50KFRodW5kZXJiaXJkLDxici8-V2VibWFpbCw8YnIvPk11dHQsPGJyLz5ldGMpXG4gICAgICAgIG11YS1zZXJ2aWNlKEJhY2tlbmQgc29mdHdhcmU8YnIvPm9uIGFub3RoZXIgc2VydmVyKVxuICAgIGVuZFxuICAgIGNsaWVudHMgLS0tfFwiU2VuZCBlbWFpbCBhczxici8-aGVsbG9Ad29ybGQuY29tXCJ8IGluXzQ2NVxuXG4gICAgb3V0XzI1KDI1KSAtLT58XCJEaXJlY3Q8YnIvPkRlbGl2ZXJ5XCJ8IHRpbl8yNVxuICAgIG91dF80NjUoNDY1KSAtLT4gcmVsYXkoXCJNVEE8YnIvPlJlbGF5IFNlcnZlclwiKSAtLT4gdGluXzI1KDI1KVxuXG4gICAgc3ViZ3JhcGggdGhpcmQtcGFydHktc2VydmVyW1wiVGhpcmQtcGFydHkgU2VydmVyXCJdXG4gICAgICAgIHRoaXJkLXBhcnR5LW10YShcIk1UQTxici8-ZnJpZW5kQGV4YW1wbGUuY29tXCIpXG4gICAgICAgIHRpbl8yNSgyNSkgLS0-IHRoaXJkLXBhcnR5LW10YVxuICAgIGVuZCIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0In0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9
|
||||
[ref-clear-vs-plain]: https://www.denimgroup.com/resources/blog/2007/10/cleartext-vs-pl
|
||||
[ref-port25-mandatory]: https://serverfault.com/questions/623692/is-it-still-wrong-to-require-starttls-on-incoming-smtp-messages
|
||||
[ref-mermaid-live-smtp]: https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZmxvd2NoYXJ0IExSXG4gICAgc3ViZ3JhcGggeW91ci1zZXJ2ZXIgW1wiWW91ciBTZXJ2ZXJcIl1cbiAgICAgICAgaW5fMjUoMjUpIC0tPiBzZXJ2ZXJcbiAgICAgICAgaW5fNDY1KDQ2NSkgLS0-IHNlcnZlclxuICAgICAgICBzZXJ2ZXIoKFwiZG9ja2VyLW1haWxzZXJ2ZXI8YnIvPmhlbGxvQHdvcmxkLmNvbVwiKSlcbiAgICAgICAgc2VydmVyIC0tLSBvdXRfMjUoMjUpXG4gICAgICAgIHNlcnZlciAtLS0gb3V0XzQ2NSg0NjUpXG4gICAgZW5kXG5cbiAgICB0aGlyZC1wYXJ0eShcIlRoaXJkLXBhcnR5PGJyLz4oc2VuZGluZyB5b3UgZW1haWwpXCIpIC0tLXxcIlJlY2VpdmUgZW1haWwgZm9yPGJyLz5oZWxsb0B3b3JsZC5jb21cInwgaW5fMjVcblxuICAgIHN1YmdyYXBoIGNsaWVudHMgW1wiQ2xpZW50cyAoTVVBKVwiXVxuICAgICAgICBtdWEtY2xpZW50KFRodW5kZXJiaXJkLDxici8-V2VibWFpbCw8YnIvPk11dHQsPGJyLz5ldGMpXG4gICAgICAgIG11YS1zZXJ2aWNlKEJhY2tlbmQgc29mdHdhcmU8YnIvPm9uIGFub3RoZXIgc2VydmVyKVxuICAgIGVuZFxuICAgIGNsaWVudHMgLS0tfFwiU2VuZCBlbWFpbCBhczxici8-aGVsbG9Ad29ybGQuY29tXCJ8IGluXzQ2NVxuXG4gICAgb3V0XzI1KDI1KSAtLT58XCJEaXJlY3Q8YnIvPkRlbGl2ZXJ5XCJ8IHRpbl8yNVxuICAgIG91dF80NjUoNDY1KSAtLT4gcmVsYXkoXCJNVEE8YnIvPlJlbGF5IFNlcnZlclwiKSAtLT4gdGluXzI1KDI1KVxuXG4gICAgc3ViZ3JhcGggdGhpcmQtcGFydHktc2VydmVyW1wiVGhpcmQtcGFydHkgU2VydmVyXCJdXG4gICAgICAgIHRoaXJkLXBhcnR5LW10YShcIk1UQTxici8-ZnJpZW5kQGV4YW1wbGUuY29tXCIpXG4gICAgICAgIHRpbl8yNSgyNSkgLS0-IHRoaXJkLXBhcnR5LW10YVxuICAgIGVuZCIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0In0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9
|
||||
[rfc-8314]: https://tools.ietf.org/html/rfc8314
|
||||
[rfc-8314-s41]: https://tools.ietf.org/html/rfc8314#section-4.1
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue