Integrate Mailu in Swag with certbot

I’m integrating a Mailu mailserver into an existing docker-compose.yml using Swag reverse proxy and have a question how to configure Webmail/IMAP/SMTP via SSL correctly.

The Swag reverse proxy forwards HTTPS trafic to HTTP port 80 of the Mailu front container in Swag config file config/nginx/proxy-confs/mailu.subdomain.conf. How does this work for IMAP and SMTP ports? Should I forward IMAP/SMTP ports to the Mailu front or Swag container? Should I share the SSL certificate between Mailu front and Swag containers?

According to the Mailu reverse proxy documentation describes:

You must not disable Mailu reverse proxy by removing the front section from the docker-compose.yml.
front is handling authentication and is also proxying e.g. SMTP and IMAP. A basic HTTP reverse proxy as described in this document is not sufficient for this.

Then the documentation stops. How can I properly handle IMAP and SMTP via SSL?

The default generated Mailu docker-compose.yml front container is:

  front:
    image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}nginx:${MAILU_VERSION:-local}
    restart: always
    env_file: mailu.env
    logging:
      driver: json-file
    ports:
      - "0.0.0.0:80:80"
      - "0.0.0.0:443:443"
      - "0.0.0.0:25:25"
      - "0.0.0.0:465:465"
      - "0.0.0.0:587:587"
      - "0.0.0.0:110:110"
      - "0.0.0.0:995:995"
      - "0.0.0.0:143:143"
      - "0.0.0.0:993:993"
    volumes:
      - "/mailu/certs:/certs"
      - "/mailu/overrides/nginx:/overrides:ro"

Does anyone have a docker-compose.yml example or suggestions? Thanks!

I found the answers myself to get Mailu - Swag configuration up and running:

Swag configuration

Make sure Swag is already configured with SSL Certbot.

Enable Mailu proxy by remove .samples from filename config/nginx/proxy-confs/mailu.subdomain.conf.samples.

This enables a proxy from port 80/443 at domain mailu.* to the Mailu front container at port 80.

## Version 2021/05/18
# make sure that your dns has a cname set for mailu and that your mailu front container is named front

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name mailu.*;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    location / {
        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app front;
        set $upstream_port 80;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;

    }
}

docker-compose.yml

  # Mailu container
  front:
    image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}nginx:${MAILU_VERSION:-local}
    restart: always
    env_file: mailu.env
    logging:
      driver: json-file
    ports:
      # - "0.0.0.0:80:80"     # Do not enable port 80 and 443 as they are in use by Swag reverse proxy!
      # - "0.0.0.0:443:443"
      - "0.0.0.0:25:25"       # SMTP relaying (transmission email server to email server)
      - "0.0.0.0:465:465"     # SMTP (Some websites refers this as deprecated)
      - "0.0.0.0:587:587"     # SMTP secure (out)
      # - "0.0.0.0:110:110"   # POP3 client plain  # Not used in my setup
      # - "0.0.0.0:995:995"   # POP3 client secure # Not used in my setup
      - "0.0.0.0:143:143"     # IMAP client plain
      - "0.0.0.0:993:993"     # IMAP client secure

  # Other containers here such as redis, admin, imap, smtp, antispam, webmail etc

  # Reverse proxy (store environment variables in .env file)
  swag:
    image: ghcr.io/linuxserver/swag:version-1.17.0
    container_name: swag
    restart: always
    ports:
      - 80:80
      - 443:443
    cap_add:
      - NET_ADMIN
    environment:
      - PUID=$DOCKER_UID
      - PGID=$DOCKER_GID
      - EMAIL=${SWAG_EMAIL}
      - URL=${ROOT_DOMAIN}
      - SUBDOMAINS=${SWAG_SUBDOMAINS}
      - VALIDATION=${SWAG_VALIDATION}
      - DNSPLUGIN=${SWAG_DNSPLUGIN}
      - PROPAGATION=${SWAG_PROPAGATION}
      - ONLY_SUBDOMAINS=${SWAG_ONLY_SUBDOMAINS}
      - TZ=${TZ}
    volumes:
      - ${VOLUME_DIR}/swag/config:/config

# Create bridge network and make sure the subnet matches with mailu.env variable SUBNET
networks:
  default:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 192.168.203.0/24

Port forwarding to the Mailu server on all ports above, including 80 and 443.

The answer to my question is:

  • Swag handles port 80 and 443 with certbot SSL certificate. (In my case a wildcard)
  • Mailu uses it’s own built-in certbot on all other non-plain front container with:

Mailu front container: core/nginx/letsencrypt.py

command = [
    "certbot",
    "-n", "--agree-tos", # non-interactive
    "-d", os.environ["HOSTNAMES"],
    "-m", "{}@{}".format(os.environ["POSTMASTER"], os.environ["DOMAIN"]),
    "certonly", "--standalone",
    "--cert-name", "mailu",
    "--preferred-challenges", "http", "--http-01-port", "8008",
    "--keep-until-expiring",
    "--rsa-key-size", "4096",
    "--config-dir", "/certs/letsencrypt",
    "--post-hook", "/config.py"
]

SSL verification is done via the front Nginx HTTP server at port 8008 which is routed via the Swag proxy. That’s the trick how two certbots can work concurrent without claiming port 443 twice.

Add DNS entries as listed on https://mail.example.com/admin/ui/domain/details/example.com

Configure mail client such as Thunderbird automatically detects IMAP and SMTP server configuration. :slight_smile:

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.