diff --git a/testserver/docker_mail/tasks/main.yaml b/testserver/docker_mail/tasks/main.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c9d324eeae4f03c95927ce028437498f0f374336 --- /dev/null +++ b/testserver/docker_mail/tasks/main.yaml @@ -0,0 +1,112 @@ +--- + +- include_tasks: ../functions/get_secret.yml + with_items: + - { path: "{{ basedir }}/secrets/mailu_secret_key", length: 32 } + - { path: "{{ basedir }}/secrets/mailu_admin_pass", length: 32 } + - { path: "{{ basedir }}/secrets/mailu_api_token", length: 32 } + - { path: "{{ basedir }}/secrets/mailu_db_pass", length: 28 } + - { path: "{{ basedir }}/secrets/roundcube_db_pass", length: 28 } + - { path: "{{ basedir }}/secrets/hyperkitty_api_key", length: 28 } + - { path: "{{ basedir }}/secrets/mailman_db_pass", length: 28 } + - { path: "{{ basedir }}/secrets/mailman_secret_key", length: 28 } + - { path: "{{ basedir }}/secrets/mailman_restapi_pass", length: 28 } + - { path: "{{ basedir }}/secrets/mysql_root_pass", length: 28 } + + +# - name: pakete installieren +# apt: +# pkg: ['logrotate'] +# update_cache: no +# state: present + + +- name: "create folder struct for {{ servicename }}" + file: + path: "{{ item }}" + state: "directory" + with_items: + - "{{ basedir }}" + - "{{ basedir }}/secrets" + - "{{ basedir }}/db" + - "{{ basedir }}/db-init" + - "{{ basedir }}/mailu" + - "{{ basedir }}/mailu/overrides" + - "{{ basedir }}/mailu/overrides/postfix" + - "{{ basedir }}/mailman-core" + - "{{ basedir }}/mailman-core/var" + - "{{ basedir }}/mailman-core/var/data" + - "{{ basedir }}/mailman-web" +# - "{{ basedir }}/mailman-db" + + +# - name: "create folder struct for {{ servicename }} with rights" +# file: +# path: "{{ item }}" +# state: "directory" +# owner: "5000" +# group: "5000" +# mode: "ugo+rwx" +# with_items: +# - "{{ basedir }}/data/crypt" +# - "{{ basedir }}/data/vmail" +# - "{{ basedir }}/data/vmail-index" + + + +- name: "deploy {{ servicename }} config files" + template: + dest: "{{ basedir }}/{{ item }}" + src: "{{ item }}" + mode: 0644 + with_items: + - docker-compose.yml + - mailu.env + - mailman.env + - mailman-nginx.conf + - db-init/mailman.sql + - db-init/roundcube.sql + - mailu/overrides/postfix/postfix.cf + register: config + +- name: "set local dns record" + become: true + blockinfile: + path: /etc/hosts + create: yes + block: | + {{ ext_ip4 }} mailserver.warpzone.ms + +# - name: deploy LogRotate configs +# template: +# src: "logrotate/{{item}}" +# dest: "/etc/logrotate.d/{{item}}" +# with_items: +# - mailman-core +# - mailman-web + + +# Start containers +- name: "stop {{ servicename }} docker" + community.docker.docker_compose_v2: + project_src: "{{ basedir }}" + state: absent + when: config.changed + +- name: "start {{ servicename }} docker" + community.docker.docker_compose_v2: + project_src: "{{ basedir }}" + state: present + + +# Start mailman containers +# - name: "stop {{ servicename }} (mailman) docker" +# community.docker.docker_compose_v2: +# project_src: "{{ basedir }}/docker-mailman" +# state: absent +# when: config_mailcow.changed + +# - name: "start {{ servicename }} (mailman) docker" +# community.docker.docker_compose_v2: +# project_src: "{{ basedir }}/docker-mailman" +# state: present diff --git a/testserver/docker_mail/templates/db-init/mailman.sql b/testserver/docker_mail/templates/db-init/mailman.sql new file mode 100644 index 0000000000000000000000000000000000000000..27ff11b022f639467d9da9686b81477be370d439 --- /dev/null +++ b/testserver/docker_mail/templates/db-init/mailman.sql @@ -0,0 +1,4 @@ +CREATE DATABASE IF NOT EXISTS mailman; +CREATE USER IF NOT EXISTS mailman@'%' IDENTIFIED BY '{{ mailman_db_pass }}'; +GRANT ALL ON mailman.* TO mailman@'%'; +FLUSH PRIVILEGES; diff --git a/testserver/docker_mail/templates/db-init/roundcube.sql b/testserver/docker_mail/templates/db-init/roundcube.sql new file mode 100644 index 0000000000000000000000000000000000000000..32e4983adfe2d9ae4976b9383d0feb1330c14e73 --- /dev/null +++ b/testserver/docker_mail/templates/db-init/roundcube.sql @@ -0,0 +1,4 @@ +CREATE DATABASE IF NOT EXISTS roundcube; +CREATE USER IF NOT EXISTS roundcube@'%' IDENTIFIED BY '{{ roundcube_db_pass }}'; +GRANT ALL ON roundcube.* TO roundcube@'%'; +FLUSH PRIVILEGES; diff --git a/testserver/docker_mail/templates/docker-compose.yml b/testserver/docker_mail/templates/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..5c1dd8128b05f5dc43f5dc52bd4a2d4e92e449dc --- /dev/null +++ b/testserver/docker_mail/templates/docker-compose.yml @@ -0,0 +1,218 @@ +version: '2.2' + +services: + + # External dependencies + redis: + image: redis:alpine + restart: always + volumes: + - "{{ basedir }}/mailu/redis:/data" + depends_on: + - resolver + dns: + - 192.168.203.254 + + # Certdumper + certdumper: + image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}traefik-certdumper:${MAILU_VERSION:-2.0} + restart: always + environment: + - DOMAIN={{ mailserver }} + - TRAEFIK_VERSION=v2 + volumes: + - "/srv/traefik:/traefik" + - "{{ basedir }}/mailu/certs:/output" + + # Core services + front: + image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}nginx:${MAILU_VERSION:-2.0} + restart: always + depends_on: + - db + - resolver + env_file: mailu.env + ports: + - "25:25" #smtp + - "465:465" #submissions + - "587:587" #submission + - "143:143" #imap + - "993:993" #imaps + volumes: + - "{{ basedir }}/mailu/certs:/certs" + - "{{ basedir }}/mailu/overrides/nginx:/overrides:ro" + labels: + - "traefik.enable=true" + - "traefik.http.routers.{{ servicename }}.entrypoints=websecure" + - "traefik.http.routers.{{ servicename }}.rule=Host(`{{ mailserver }}`)" + - "traefik.http.routers.{{ servicename }}.tls" + - "traefik.http.routers.{{ servicename }}.tls.certresolver=letsencrypt" + - "traefik.http.routers.{{ servicename }}.tls.domains[0].main={{ domain }}" + - "traefik.http.routers.{{ servicename }}.tls.domains[0].sans={{ mailserver }},imap.test-warpzone.de,smtp.test-warpzone.de" + - "traefik.http.routers.{{ servicename }}.service={{ servicename }}" + - "traefik.http.services.{{ servicename }}.loadbalancer.server.port=80" + networks: + - default + - web + dns: + - 192.168.203.254 + + resolver: + image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}unbound:${MAILU_VERSION:-2.0} + env_file: mailu.env + restart: always + networks: + default: + ipv4_address: 192.168.203.254 + + admin: + image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}admin:${MAILU_VERSION:-2.0} + restart: always + depends_on: + - db + - redis + - resolver + env_file: mailu.env + volumes: + - "{{ basedir }}/mailu/data:/data" + - "{{ basedir }}/mailu/dkim:/dkim" + dns: + - 192.168.203.254 + + imap: + image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}dovecot:${MAILU_VERSION:-2.0} + restart: always + depends_on: + - db + - front + - resolver + env_file: mailu.env + volumes: + - "{{ basedir }}/mailu/mail:/mail" + - "{{ basedir }}/mailu/overrides/dovecot:/overrides:ro" + dns: + - 192.168.203.254 + + smtp: + image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}postfix:${MAILU_VERSION:-2.0} + restart: always + depends_on: + - db + - front + - resolver + - mailman-core + env_file: mailu.env + volumes: + - "{{ basedir }}/mailu/mailqueue:/queue" + - "{{ basedir }}/mailu/overrides/postfix:/overrides:ro" + - "{{ basedir }}/mailman-core/var/data:/opt/mailman:ro" + dns: + - 192.168.203.254 + + oletools: + image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}oletools:${MAILU_VERSION:-2.0} + hostname: oletools + restart: always + depends_on: + - resolver + networks: + - noinet + dns: + - 192.168.203.254 + + antispam: + image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}rspamd:${MAILU_VERSION:-2.0} + hostname: antispam + restart: always + depends_on: + - front + - redis + - oletools + - resolver + env_file: mailu.env + volumes: + - "{{ basedir }}/mailu/filter:/var/lib/rspamd" + - "{{ basedir }}/mailu/overrides/rspamd:/overrides:ro" + networks: + default: + ipv4_address: 192.168.203.253 + noinet: + dns: + - 192.168.203.254 + + # Optional mailu services: Database + db: + image: mariadb:11.2 + command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci + restart: always + volumes: + - "{{ basedir }}/db:/var/lib/mysql" + - "{{ basedir }}/db-init:/docker-entrypoint-initdb.d:ro" + environment: + - MYSQL_DATABASE=mailu + - MYSQL_USER=mailu + - MYSQL_PASSWORD={{ mailu_db_pass }} + - MYSQL_ROOT_PASSWORD={{ mysql_root_pass }} + + # Optional mailu services: Webmail + webmail: + image: ${DOCKER_ORG:-ghcr.io/mailu}/${DOCKER_PREFIX:-}webmail:${MAILU_VERSION:-2.0} + restart: always + depends_on: + - front + env_file: mailu.env + volumes: + - "{{ basedir }}/mailu/webmail:/data" + - "{{ basedir }}/mailu/overrides/roundcube:/overrides:ro" + + # Additional Services: mailman + mailman-core: + image: maxking/mailman-core:0.4 + restart: always + env_file: mailman.env + depends_on: + - db + volumes: + - "{{ basedir }}/mailman-core:/opt/mailman:rw,z" + + mailman-web: + image: maxking/mailman-web:0.4 + restart: always + env_file: mailman.env + depends_on: + - db + volumes: + - "{{ basedir }}/mailman-web:/opt/mailman-web-data:rw,z" + + mailman-nginx: + image: nginx:1.25 + restart: always + depends_on: + - mailman-web + volumes: + - "{{ basedir }}/mailman-web/:/opt/mailman-web-data:ro,z" + - "{{ basedir }}/mailman-nginx.conf:/etc/nginx/conf.d/default.conf:ro" + labels: + - traefik.enable=true + - traefik.http.routers.{{ servicename }}-mailman.rule=Host(`{{ listserver }}`) + - traefik.http.routers.{{ servicename }}-mailman.entrypoints=websecure + - traefik.http.services.{{ servicename }}-mailman.loadbalancer.server.port=80 + networks: + - default + - web + +networks: + default: + driver: bridge + enable_ipv6: true + ipam: + driver: default + config: + # must be a ULA range + - subnet: fd00:dead:beef:25::/64 + - subnet: 192.168.203.0/24 + noinet: + driver: bridge + internal: true + web: + external: true diff --git a/testserver/docker_mail/templates/mailman-nginx.conf b/testserver/docker_mail/templates/mailman-nginx.conf new file mode 100644 index 0000000000000000000000000000000000000000..408ed688375938830043040f924c927180a82e36 --- /dev/null +++ b/testserver/docker_mail/templates/mailman-nginx.conf @@ -0,0 +1,25 @@ + +server { + + listen 80; + listen [::]:80; + + server_name listserver.warpzone.ms; + root /dev/null; + index index.html; + + location / { + # First attempt to serve request as file, then + + uwsgi_pass mailman-web:8080; + include uwsgi_params; + uwsgi_read_timeout 300; + } + + location /static { + + root /opt/mailman-web-data; + + } + +} \ No newline at end of file diff --git a/testserver/docker_mail/templates/mailman.env b/testserver/docker_mail/templates/mailman.env new file mode 100644 index 0000000000000000000000000000000000000000..7ade751389ef13db6a94193c0bd67c65314f6ace --- /dev/null +++ b/testserver/docker_mail/templates/mailman.env @@ -0,0 +1,32 @@ +# Admin User +MAILMAN_ADMIN_USER=listadmin +MAILMAN_ADMIN_EMAIL=listadmin@warpzone.ms + +# MTA to use +MTA=postfix + +# SMTP Host and Port +SMTP_HOST=smtp +SMTP_PORT=25 + +# External Domain for Mailman web Interface +SERVE_FROM_DOMAIN={{ listserver }} + +# Mailman Secret Key +SECRET_KEY={{ mailman_secret_key }} + +# Database for mailman and Hyperkitty +DATABASE_URL=mysql://mailman:{{ mailman_db_pass }}@db/mailman?charset=utf8mb4 + +# Internal hostname of the Mailman Core Container +MM_HOSTNAME=mailman-core + +# User and Password for Mailman API +MAILMAN_REST_USER=mailman +MAILMAN_REST_PASSWORD={{ mailman_restapi_pass }} + +# internal URL and API Key for Hyperkitty +HYPERKITTY_URL=http://mailman-web:8000/hyperkitty +HYPERKITTY_API_KEY={{ hyperkitty_api_key }} + + diff --git a/testserver/docker_mail/templates/mailu.env b/testserver/docker_mail/templates/mailu.env new file mode 100644 index 0000000000000000000000000000000000000000..208d611ee04c26ba56a5dddb9dbf4fdf3414e61d --- /dev/null +++ b/testserver/docker_mail/templates/mailu.env @@ -0,0 +1,181 @@ +################################### +# Additional Setings +################################### + +# Set Version +MAILU_VERSION=2.0.37 + +# enable IPv6 +SUBNET6=fd00:dead:beef:25::/64 + +# Autocreate Admin User +INITIAL_ADMIN_ACCOUNT=mailadmin +INITIAL_ADMIN_DOMAIN={{ domain }} +INITIAL_ADMIN_PW={{ mailu_admin_pass }} +INITIAL_ADMIN_MODE=ifmissing + +# force internel connect to rspamd with ipv4 +ANTISPAM_ADDRESS=192.168.203.253 + +# Use Mysql as Database +SQLALCHEMY_DATABASE_URI=mysql+mysqlconnector://mailu:{{ mailu_db_pass }}@db/mailu + +# Use Mysql as Database +SQLALCHEMY_DATABASE_URI_ROUNDCUBE=mysql://roundcube:{{ roundcube_db_pass }}@db/roundcube + +################################### +# Common configuration variables +################################### + +# Set to a randomly generated 16 bytes string +SECRET_KEY={{ mailu_secret_key }} + +# Subnet of the docker network. This should not conflict with any networks to which your system is connected. (Internal and external!) +SUBNET=192.168.203.0/24 + +# Main mail domain +DOMAIN={{ domain }} + +# Hostnames for this server, separated with comas +HOSTNAMES={{ mailserver }} + +# Postmaster local part (will append the main mail domain) +POSTMASTER=admin + +# Choose how secure connections will behave (value: letsencrypt, cert, notls, mail, mail-letsencrypt) +TLS_FLAVOR=mail + +# Authentication rate limit per IP (per /24 on ipv4 and /48 on ipv6) +AUTH_RATELIMIT_IP=60/hour + +# Authentication rate limit per user (regardless of the source-IP) +AUTH_RATELIMIT_USER=100/day + +# Opt-out of statistics, replace with "True" to opt out +DISABLE_STATISTICS=True + +################################### +# Optional features +################################### + +# Expose the admin interface (value: true, false) +ADMIN=true + +# Choose which webmail to run if any (values: roundcube, snappymail, none) +WEBMAIL=roundcube + +# Expose the API interface (value: true, false) +API=false + +# Dav server implementation (value: radicale, none) +WEBDAV=none + +# Antivirus solution (value: clamav, none) +ANTIVIRUS=none + +# Scan Macros solution (value: true, false) +SCAN_MACROS=true + +################################### +# Mail settings +################################### + +# Message size limit in bytes +# Default: accept messages up to 50MB +# Max attachment size will be 33% smaller +MESSAGE_SIZE_LIMIT=50000000 + +# Message rate limit (per user) +MESSAGE_RATELIMIT=200/day + +# Networks granted relay permissions +# Use this with care, all hosts in this networks will be able to send mail without authentication! +RELAYNETS= + +# Will relay all outgoing mails if configured +RELAYHOST= + +# Enable fetchmail +FETCHMAIL_ENABLED=False + +# Fetchmail delay +FETCHMAIL_DELAY=600 + +# Recipient delimiter, character used to delimiter localpart from custom address part +# must be set to + for mailman +RECIPIENT_DELIMITER=+ + +# DMARC rua and ruf email +DMARC_RUA=admin +DMARC_RUF=admin + +# Welcome email, enable and set a topic and body if you wish to send welcome +# emails to all users. +WELCOME=false +WELCOME_SUBJECT=Welcome to your new email account +WELCOME_BODY=Welcome to your new email account, if you can read this, then it is configured properly! + +# Maildir Compression +# choose compression-method, default: none (value: gz, bz2) +COMPRESSION= +# change compression-level, default: 6 (value: 1-9) +COMPRESSION_LEVEL= + +# IMAP full-text search is enabled by default. Set the following variable to off in order to disable the feature. +FULL_TEXT_SEARCH=on + +################################### +# Web settings +################################### + +# Path to redirect / to +WEBROOT_REDIRECT=/webmail + +# Path to the admin interface if enabled +WEB_ADMIN=/admin + +# Path to the webmail if enabled +WEB_WEBMAIL=/webmail + +# Path to the API interface if enabled +WEB_API= + +# Website name +SITENAME=warpzone mail + +# Linked Website URL +WEBSITE=https://listserver.{{ domain }} + + + +################################### +# Advanced settings +################################### + +# Docker-compose project name, this will prepended to containers names. +COMPOSE_PROJECT_NAME=mailu + +# Number of rounds used by the password hashing scheme +CREDENTIAL_ROUNDS=12 + +# Header to take the real ip from +REAL_IP_HEADER=X-Real-Ip + +# IPs for nginx set_real_ip_from (CIDR list separated by commas) +REAL_IP_FROM=0.0.0.0/0 + +# choose wether mailu bounces (no) or rejects (yes) mail when recipient is unknown (value: yes, no) +REJECT_UNLISTED_RECIPIENT= + +# Log level threshold in start.py (value: CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET) +LOG_LEVEL=WARNING + +# Timezone for the Mailu containers. See this link for all possible values https://en.wikipedia.org/wiki/List_of_tz_database_time_zones +TZ=Europe/Berlin + +# Default spam threshold used for new users +DEFAULT_SPAM_THRESHOLD=80 + +# API token required for authenticating to the RESTful API. +# This is a mandatory setting for using the RESTful API. +API_TOKEN={{ mailu_api_token }} diff --git a/testserver/docker_mail/templates/mailu/overrides/postfix/postfix.cf b/testserver/docker_mail/templates/mailu/overrides/postfix/postfix.cf new file mode 100644 index 0000000000000000000000000000000000000000..7c0123e79805c85732436ebb7c34c66ec48de90c --- /dev/null +++ b/testserver/docker_mail/templates/mailu/overrides/postfix/postfix.cf @@ -0,0 +1,14 @@ + +# Overrides for mailman3 integration +# see https://patrick.georgi.family/2019/01/12/combining-mailman-3-with-mailu/ + +always_add_missing_headers = yes +append_at_myorigin=no +append_dot_mydomain=no +local_header_rewrite_clients = permit_sasl_authenticated +owner_request_special = no +unknown_local_recipient_reject_code = 550 + +local_recipient_maps = regexp:/opt/mailman/postfix_lmtp +transport_maps = regexp:/opt/mailman/postfix_lmtp, lmdb:/etc/postfix/transport.map, \${podop}transport +virtual_mailbox_maps = regexp:/opt/mailman/postfix_lmtp, \${podop}mailbox diff --git a/testserver/docker_mail/templates/mailu/overrides/postfix/transport.map b/testserver/docker_mail/templates/mailu/overrides/postfix/transport.map new file mode 100644 index 0000000000000000000000000000000000000000..80a3d9e5e568fa2a380ebef229108794d66574f2 --- /dev/null +++ b/testserver/docker_mail/templates/mailu/overrides/postfix/transport.map @@ -0,0 +1,9 @@ +yahoo.com polite: +hotmail.com polite: +outlook.com polite: +exchange.com polite: +microsoft.com polite: +1und1.de polite: +t-online.de polite: +web.de polite: +gmail.com polite: