docker-mailserver/docs/content/examples/tutorials/mailserver-behind-proxy.md
Brennan Kinney a0ee472501
docs(chore): Normalize for consistency (#2206)
"Brief" summary/overview of changes. See the PR discussion or individual commits from the PR for more details.

---

Only applies to the `docs/content/**` content (_and `setup` command_). `target/` and `test/` can be normalized at a later date.

* Normalize to `example.com`

- Domains normalized to `example.com`: `mywebserver.com`, `myserver.tld`, `domain.com`, `domain.tld`, `mydomain.net`, `my-domain.tld`, `my-domain.com`, `example.org`, `whoami.com`.
- Alternative domains normalized to `not-example.com`: `otherdomain.com`, `otherdomain.tld`, `domain2.tld`, `mybackupmx.com`, `whoareyou.org`.
- Email addresses normalized to `admin@example.com` (in `ssl.md`): `foo@bar.com`, `yourcurrentemail@gmail.com`, `email@email.com`, `admin@domain.tld`.
- Email addresses normalized to `external-account@gmail.com`: `bill@gates321boom.com`, `external@gmail.com`, `myemail@gmail.com`, `real-email-address@external-domain.com`.
- **`faq.md`:** A FAQ entry title with `sample.domain.com` changed to `subdomain.example.com`.
- **`mail-fetchmail.md`:** Config examples with FQDNs for `imap`/`pop3` used `example.com` domain for a third-party, changed to `gmail.com` as more familiar third-party/external MTA.

* Normalize config volume path

- Normalizing local config path references to `./docker-data/dms/config/`: `./config/`, `config/`, \``config`\`, `/etc/` (_volume mount src path prefix_).
- Normalize DMS volume paths to `docker-data/dms/mail-{data,state,log}`: `./mail`, `./mail-state` `./data/mail`, `./data/state`, `./data/logs`, `./data/maildata`, `./data/mailstate`, `./data/maillogs`, (_dropped/converted data volumes: `maildata`, `mailstate`_).
- Other docker images also adopt the `docker-data/{service name}/` prefix.

* `ssl.md` - Use `dms/custom-certs` where appropriate.

* Apply normalizations to README and example `docker-compose.yml`

---

Common terms, sometimes interchangeably used or now invalid depending on context: `mail`, `mail container`, `mail server`, `mail-server`, `mailserver`,`docker-mailserver`, `Docker Mailserver`.

Rough transformations applied to most matches (_conditionally, depending on context_):

- 'Docker Mailserver' => '`docker-mailserver`'
- 'mail container' => '`docker-mailserver`' (_optionally retaining ' container'_)
- 'mail server' => 'mail-server' / '`docker-mailserver`'
- 'mail-server' => '`docker-mailserver`'
- 'mailserver' => 'mail-server' / '`docker-mailserver`'

Additionally I checked `docker run` (_plus `exec`, `logs`, etc, sub-commands_) and `docker-compose` commands. Often finding usage of `mail` instead of the expected `mailserver`

Additionally changes `mailserver` hostname in k8s to `mail` to align with other non-k8s examples.

---

* drive-by revisions

Mostly minor revisions or improvements to docs that aren't related to normalization effort.
2021-09-23 11:29:37 +12:00

5.2 KiB

title
Tutorials | Mail-Server behind a Proxy

Using docker-mailserver behind a Proxy

Information

If you are hiding your container behind a proxy service you might have discovered that the proxied requests from now on contain the proxy IP as the request origin. Whilst this behavior is technical correct it produces certain problems on the containers behind the proxy as they cannot distinguish the real origin of the requests anymore.

To solve this problem on TCP connections we can make use of the proxy protocol. Compared to other workarounds that exist (X-Forwarded-For which only works for HTTP requests or Tproxy that requires you to recompile your kernel) the proxy protocol:

  • It is protocol agnostic (can work with any layer 7 protocols, even when encrypted).
  • It does not require any infrastructure changes.
  • NAT-ing firewalls have no impact it.
  • It is scalable.

There is only one condition: both endpoints of the connection MUST be compatible with proxy protocol.

Luckily dovecot and postfix are both Proxy-Protocol ready softwares so it depends only on your used reverse-proxy / loadbalancer.

Configuration of the used Proxy Software

The configuration depends on the used proxy system. I will provide the configuration examples of traefik v2 using IMAP and SMTP with implicit TLS.

Feel free to add your configuration if you achieved the same goal using different proxy software below:

??? "Traefik v2"

Truncated configuration of traefik itself:

```yaml
version: '3.8'
services:
  reverse-proxy:
    image: docker.io/traefik:latest # v2.5
    container_name: docker-traefik
    restart: always
    command:
      - "--providers.docker"
      - "--providers.docker.exposedbydefault=false"
      - "--providers.docker.network=proxy"
      - "--entrypoints.web.address=:80"
      - "--entryPoints.websecure.address=:443"
      - "--entryPoints.smtp.address=:25"
      - "--entryPoints.smtp-ssl.address=:465"
      - "--entryPoints.imap-ssl.address=:993"
      - "--entryPoints.sieve.address=:4190"
    ports:
      - "25:25"
      - "465:465"
      - "993:993"
      - "4190:4190"
[...]
```

Truncated list of necessary labels on the `docker-mailserver` container:

```yaml
version: '3.8'
services:
  mailserver:
    image: docker.io/mailserver/docker-mailserver:latest
    container_name: mailserver
    hostname: mail
    domainname: example.com
    restart: always
    networks:
      - proxy
    labels:
      - "traefik.enable=true"
      - "traefik.tcp.routers.smtp.rule=HostSNI(`*`)"
      - "traefik.tcp.routers.smtp.entrypoints=smtp"
      - "traefik.tcp.routers.smtp.service=smtp"
      - "traefik.tcp.services.smtp.loadbalancer.server.port=25"
      - "traefik.tcp.services.smtp.loadbalancer.proxyProtocol.version=1"
      - "traefik.tcp.routers.smtp-ssl.rule=HostSNI(`*`)"
      - "traefik.tcp.routers.smtp-ssl.tls=false"
      - "traefik.tcp.routers.smtp-ssl.entrypoints=smtp-ssl"
      - "traefik.tcp.routers.smtp-ssl.service=smtp-ssl"
      - "traefik.tcp.services.smtp-ssl.loadbalancer.server.port=465"
      - "traefik.tcp.services.smtp-ssl.loadbalancer.proxyProtocol.version=1"
      - "traefik.tcp.routers.imap-ssl.rule=HostSNI(`*`)"
      - "traefik.tcp.routers.imap-ssl.entrypoints=imap-ssl"
      - "traefik.tcp.routers.imap-ssl.service=imap-ssl"
      - "traefik.tcp.services.imap-ssl.loadbalancer.server.port=10993"
      - "traefik.tcp.services.imap-ssl.loadbalancer.proxyProtocol.version=2"
      - "traefik.tcp.routers.sieve.rule=HostSNI(`*`)"
      - "traefik.tcp.routers.sieve.entrypoints=sieve"
      - "traefik.tcp.routers.sieve.service=sieve"
      - "traefik.tcp.services.sieve.loadbalancer.server.port=4190"
[...]
```

Keep in mind that it is necessary to use port `10993` here. More information below at `dovecot` configuration.

Configuration of the Backend (dovecot and postfix)

The following changes can be achieved completely by adding the content to the appropriate files by using the projects function to overwrite config files.

Changes for postfix can be applied by adding the following content to docker-data/dms/config/postfix-main.cf:

postscreen_upstream_proxy_protocol = haproxy

and to docker-data/dms/config/postfix-master.cf:

submission/inet/smtpd_upstream_proxy_protocol=haproxy
smtps/inet/smtpd_upstream_proxy_protocol=haproxy

Changes for dovecot can be applied by adding the following content to docker-data/dms/config/dovecot.cf:

haproxy_trusted_networks = <your-proxy-ip>, <optional-cidr-notation>
haproxy_timeout = 3 secs
service imap-login {
  inet_listener imaps {
    haproxy = yes
    ssl = yes
    port = 10993
  }
}

!!! note Port 10993 is used here to avoid conflicts with internal systems like postscreen and amavis as they will exchange messages on the default port and obviously have a different origin then compared to the proxy.