From fb3087f897083b49e46ebbdd69403fb372bf87ae Mon Sep 17 00:00:00 2001 From: karmacoma Date: Sat, 27 Dec 2025 02:43:30 +0100 Subject: [PATCH] switched to docker-mailserver --- .env | 1 - .gitignore | 85 ----- LICENSE | 22 ++ README.md | 61 ---- SECURITY.md | 42 --- coolify.md | 48 --- docker-compose.coolify.yml | 696 ----------------------------------- docker-compose.yml | 717 ++----------------------------------- generate_config.sh | 517 -------------------------- readme.md | 63 ++++ 10 files changed, 121 insertions(+), 2131 deletions(-) delete mode 120000 .env delete mode 100644 .gitignore create mode 100644 LICENSE delete mode 100644 README.md delete mode 100644 SECURITY.md delete mode 100644 coolify.md delete mode 100644 docker-compose.coolify.yml delete mode 100755 generate_config.sh create mode 100644 readme.md diff --git a/.env b/.env deleted file mode 120000 index 9400869..0000000 --- a/.env +++ /dev/null @@ -1 +0,0 @@ -mailcow.conf \ No newline at end of file diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 5e05448..0000000 --- a/.gitignore +++ /dev/null @@ -1,85 +0,0 @@ -!data/conf/nginx/dynmaps.conf -!data/conf/nginx/meta_exporter.conf -!data/conf/nginx/site.conf -!/**/.gitkeep -*.iml -.idea -.vscode/* -data/assets/ssl-example/* -data/assets/ssl/* -data/conf/borgmatic/ -data/conf/clamav/whitelist.ign2 -data/conf/dovecot/acl_anyone -data/conf/dovecot/dovecot-master.passwd -data/conf/dovecot/dovecot-master.userdb -data/conf/dovecot/extra.conf -data/conf/dovecot/mail_replica.conf -data/conf/dovecot/global_sieve_* -data/conf/dovecot/last_login -data/conf/dovecot/lua -data/conf/dovecot/mail_plugins* -data/conf/dovecot/shared_namespace.conf -data/conf/dovecot/sni.conf -data/conf/dovecot/sogo-sso.conf -data/conf/dovecot/sogo_trusted_ip.conf -data/conf/dovecot/sql -data/conf/dovecot/conf.d/fts.conf -data/conf/nextcloud-*.bak -data/conf/nginx/*.active -data/conf/nginx/*.bak -data/conf/nginx/*.conf -data/conf/nginx/*.custom -data/conf/phpfpm/sogo-sso/sogo-sso.pass -data/conf/portainer/ -data/conf/postfix/allow_mailcow_local.regexp -data/conf/postfix/custom_postscreen_whitelist.cidr -data/conf/postfix/custom_transport.pcre -data/conf/postfix/extra.cf -data/conf/postfix/sni.map -data/conf/postfix/sni.map.db -data/conf/postfix/sql -data/conf/postfix/dns_blocklists.cf -data/conf/postfix/dnsbl_reply.map -data/conf/rspamd/custom/* -data/conf/rspamd/local.d/* -data/conf/rspamd/override.d/* -data/conf/sogo/custom-theme.js -data/conf/sogo/plist_ldap -data/conf/sogo/plist_ldap.sh -data/conf/sogo/sieve.creds -data/conf/sogo/cron.creds -data/conf/sogo/custom-fulllogo.svg -data/conf/sogo/custom-shortlogo.svg -data/conf/sogo/custom-fulllogo.png -data/gitea/ -data/gogs/ -data/hooks/dovecot/* -data/hooks/phpfpm/* -data/hooks/postfix/* -data/hooks/rspamd/* -data/hooks/sogo/* -data/hooks/unbound/* -data/web/templates/cache/* -!data/web/templates/cache/.gitkeep -data/web/.well-known/acme-challenge -data/web/css/build/0081-custom-mailcow.css -data/web/inc/vars.local.inc.php -data/web/inc/app_info.inc.php -data/web/nextcloud*/ -data/web/rc*/ -docker-compose.override.yml -mailcow.conf -mailcow.conf_backup -rebuild-images.sh -refresh_images.sh -update_diffs/ -create_cold_standby.sh -!data/conf/nginx/mailcow_auth.conf -data/conf/postfix/postfix-tlspol -.github -data -helper-scripts -scripts -.editorconfig -CODE_OF_CONDUCT.md -CONTRIBUTING.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..791be1f --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 40288f1..0000000 --- a/README.md +++ /dev/null @@ -1,61 +0,0 @@ -# mailcow: dockerized - 🐮 + 🐋 = 💕 - -[![Translation status](https://translate.mailcow.email/widgets/mailcow-dockerized/-/translation/svg-badge.svg)](https://translate.mailcow.email/engage/mailcow-dockerized/) -[![Twitter URL](https://img.shields.io/twitter/url/https/twitter.com/mailcow_email.svg?style=social&label=Follow%20%40mailcow_email)](https://twitter.com/mailcow_email) -![Mastodon Follow](https://img.shields.io/mastodon/follow/109388212176073348?domain=https%3A%2F%2Fmailcow.social&label=Follow%20%40doncow%40mailcow.social&link=https%3A%2F%2Fmailcow.social%2F%40doncow) - - -## Want to support mailcow? - -Please [consider a support contract with Servercow](https://www.servercow.de/mailcow?lang=en#support) to support further development. _We_ support _you_ while _you_ support _us_. :) - -You can also [get a SAL](https://www.servercow.de/mailcow?lang=en#sal) which is a one-time payment with no liabilities or returning fees. - -Or just spread the word: moo. - -## Many thanks to our GitHub Sponsors ❤️ -A big thank you to everyone supporting us on GitHub Sponsors—your contributions mean the world to us! Special thanks to the following amazing supporters: - -### 100$/Month Sponsors - - - -### 50$/Month Sponsors - - -## Info, documentation and support - -Please see [the official documentation](https://docs.mailcow.email/) for installation and support instructions. 🐄 - -🐛 **If you found a critical security issue, please mail us to [info at servercow.de](mailto:info@servercow.de).** - -## Cowmunity - -[mailcow community](https://community.mailcow.email) - -[Telegram mailcow channel](https://telegram.me/mailcow) - -[Telegram mailcow Off-Topic channel](https://t.me/mailcowOfftopic) - -[Official 𝕏 (Twitter) Account](https://twitter.com/mailcow_email) - -[Official Mastodon Account](https://mailcow.social/@doncow) - -Telegram desktop clients are available for [multiple platforms](https://desktop.telegram.org). You can search the groups history for keywords. - -## Misc - -**Important**: mailcow makes use of various open-source software. Please assure you agree with their license before using mailcow. -Any part of mailcow itself is released under **GNU General Public License, Version 3**. - -mailcow is a registered word mark of The Infrastructure Company GmbH, Parkstr. 42, 47877 Willich, Germany. - -The project is managed and maintained by The Infrastructure Company GmbH. - -Originated from @andryyy (André) diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index de63ca3..0000000 --- a/SECURITY.md +++ /dev/null @@ -1,42 +0,0 @@ -# Security Policies and Procedures - -This document outlines security procedures and general policies for the _mailcow: dockerized_ project as found on [mailcow-dockerized](https://github.com/mailcow/mailcow-dockerized). - - * [Reporting a Vulnerability](#reporting-a-vulnerability) - * [Disclosure Policy](#disclosure-policy) - * [Comments on this Policy](#comments-on-this-policy) - -## Reporting a Vulnerability - -The mailcow team and community take all security vulnerabilities -seriously. Thank you for improving the security of our open source -software. We appreciate your efforts and responsible disclosure and will -make every effort to acknowledge your contributions. - -Report security vulnerabilities by emailing the mailcow team at: - - info at servercow.de - -mailcow team will acknowledge your email as soon as possible, and will -send a more detailed response afterwards indicating the next steps in -handling your report. After the initial reply to your report, the mailcow -team will endeavor to keep you informed of the progress towards a fix and -full announcement, and may ask for additional information or guidance. - -Report security vulnerabilities in third-party modules to the person or -team maintaining the module. - -## Disclosure Policy - -When the mailcow team receives a security bug report, they will assign it -to a primary handler. This person will coordinate the fix and release -process, involving the following steps: - - * Confirm the problem and determine the affected versions. - * Audit code to find any potential similar problems. - * Prepare fixes for all releases still under maintenance. - -## Comments on this Policy - -If you have suggestions on how this process could be improved please submit a -pull request. diff --git a/coolify.md b/coolify.md deleted file mode 100644 index 6c70231..0000000 --- a/coolify.md +++ /dev/null @@ -1,48 +0,0 @@ -# Deploying mailcow-dockerized with Coolify + Traefik - -This repository ships the upstream `mailcow-dockerized` stack plus a single Coolify-ready compose file (`docker-compose.coolify.yml`) that already contains the Traefik wiring for `mail.karmacoma.dev`. Mail protocols (SMTP/IMAP/POP3/Sieve) stay bound directly on the host; only HTTP/HTTPS are proxied by Traefik. - -Official docs to keep handy: -- mailcow: https://docs.mailcow.email/ -- Reverse proxy notes (mailcow): https://docs.mailcow.email/post_installation/reverse-proxy/ -- Coolify: https://docs.coolify.io/ - -## Prerequisites -- DNS already points `mail.karmacoma.dev` A/AAAA and MX to this host; PTR records match. -- Host firewall allows TCP 25, 465, 587, 993, 995, 143, 110, 4190 and UDP/TCP 53 for DNS resolver traffic. Ports 80/443 stay open but will be used by Traefik. -- Coolify is running with its built-in Traefik proxy. Note the proxy network name (UI: Infrastructure → Networks or `docker network ls`), typically `coolify-proxy`. - -## Prepare configuration -1. From the repo root, generate the base config if you have not already: - ```sh - ./generate_config.sh - ``` -2. Edit `mailcow.conf`: - - `MAILCOW_HOSTNAME=mail.karmacoma.dev` - - Leave `HTTP_PORT=80` and `HTTPS_PORT=443` (Traefik attaches via Docker network, not host binds). - - Ensure `HTTP_REDIRECT=n` so ACME HTTP-01 works through Traefik. - - Keep `SKIP_LETS_ENCRYPT=n` so mailcow issues its own cert for mail protocols. - - Optionally set `TRUSTED_PROXIES=172.16.0.0/12` (defaulted in the compose) to trust Coolify's proxy IP range. -3. Create a small `.env` (or set in Coolify) for the Traefik network if the default differs: - ```sh - echo "TRAEFIK_NETWORK=coolify-proxy" > .env - ``` - -## Coolify deployment steps -1. Add a new **Docker Compose** service in Coolify pointing to this repository/branch. -2. Compose file: select only `docker-compose.coolify.yml` (it already includes the upstream stack plus Traefik labels/network). -3. Environment file: point Coolify to `mailcow.conf` (and `.env` if you created one), or copy its contents into the UI env editor. -4. No additional ports need to be declared for HTTP/HTTPS—Traefik handles routing. Mail ports remain published as defined in the compose. -5. Deploy. First start will pull all mailcow images and generate certificates in `data/assets/ssl`. - -## Routing behavior -- Traefik forwards HTTP on entrypoint `web` to `nginx-mailcow` port 80 and enforces an HTTPS redirect. -- Traefik passes through TLS on entrypoint `websecure` to `nginx-mailcow` port 443 so mailcow presents its own certificate (also used by Postfix/Dovecot/SOGo). -- Other mail protocols continue to bind to the host as defined in the compose. - -## Post-deploy checks -- Browse https://mail.karmacoma.dev and ensure the UI loads through Traefik. -- Verify certificates exist in `data/assets/ssl/` and that Postfix/Dovecot advertise the correct hostname. -- Send/receive a test message and confirm DNSBL lookups work (unbound container must resolve outbound DNS). - -If you need to adjust anything later, edit `mailcow.conf` or tweak `docker-compose.coolify.yml` and redeploy from Coolify. diff --git a/docker-compose.coolify.yml b/docker-compose.coolify.yml deleted file mode 100644 index 43fc12f..0000000 --- a/docker-compose.coolify.yml +++ /dev/null @@ -1,696 +0,0 @@ -services: - - unbound-mailcow: - image: ghcr.io/mailcow/unbound:1.24 - environment: - - TZ=${TZ} - - SKIP_UNBOUND_HEALTHCHECK=${SKIP_UNBOUND_HEALTHCHECK:-n} - volumes: - - ./data/hooks/unbound:/hooks:Z - - ./data/conf/unbound/unbound.conf:/etc/unbound/unbound.conf:ro,Z - restart: always - tty: true - networks: - mailcow-network: - ipv4_address: ${IPV4_NETWORK:-172.22.1}.254 - aliases: - - unbound - - mysql-mailcow: - image: mariadb:10.11 - depends_on: - - unbound-mailcow - - netfilter-mailcow - stop_grace_period: 45s - volumes: - - mysql-vol-1:/var/lib/mysql/ - - mysql-socket-vol-1:/var/run/mysqld/:z - - ./data/conf/mysql/:/etc/mysql/conf.d/:ro,Z - environment: - - TZ=${TZ} - - MYSQL_ROOT_PASSWORD=${DBROOT} - - MYSQL_DATABASE=${DBNAME} - - MYSQL_USER=${DBUSER} - - MYSQL_PASSWORD=${DBPASS} - - MYSQL_INITDB_SKIP_TZINFO=1 - restart: always - ports: - - "${SQL_PORT:-127.0.0.1:13306}:3306" - networks: - mailcow-network: - aliases: - - mysql - - redis-mailcow: - image: redis:7.4.6-alpine - entrypoint: ["/bin/sh","/redis-conf.sh"] - volumes: - - redis-vol-1:/data/ - - ./data/conf/redis/redis-conf.sh:/redis-conf.sh:z - restart: always - depends_on: - - netfilter-mailcow - ports: - - "${REDIS_PORT:-127.0.0.1:7654}:6379" - environment: - - TZ=${TZ} - - REDISPASS=${REDISPASS} - - REDISMASTERPASS=${REDISMASTERPASS:-} - sysctls: - - net.core.somaxconn=4096 - networks: - mailcow-network: - ipv4_address: ${IPV4_NETWORK:-172.22.1}.249 - aliases: - - redis - - clamd-mailcow: - image: ghcr.io/mailcow/clamd:1.71 - restart: always - depends_on: - unbound-mailcow: - condition: service_healthy - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - environment: - - TZ=${TZ} - - SKIP_CLAMD=${SKIP_CLAMD:-n} - volumes: - - ./data/conf/clamav/:/etc/clamav/:Z - - clamd-db-vol-1:/var/lib/clamav - networks: - mailcow-network: - aliases: - - clamd - - rspamd-mailcow: - image: ghcr.io/mailcow/rspamd:2.4 - stop_grace_period: 30s - depends_on: - - dovecot-mailcow - - clamd-mailcow - environment: - - TZ=${TZ} - - IPV4_NETWORK=${IPV4_NETWORK:-172.22.1} - - IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - - SPAMHAUS_DQS_KEY=${SPAMHAUS_DQS_KEY:-} - volumes: - - ./data/hooks/rspamd:/hooks:Z - - ./data/conf/rspamd/custom/:/etc/rspamd/custom:z - - ./data/conf/rspamd/override.d/:/etc/rspamd/override.d:Z - - ./data/conf/rspamd/local.d/:/etc/rspamd/local.d:Z - - ./data/conf/rspamd/plugins.d/:/etc/rspamd/plugins.d:Z - - ./data/conf/rspamd/lua/:/etc/rspamd/lua/:ro,Z - - ./data/conf/rspamd/rspamd.conf.local:/etc/rspamd/rspamd.conf.local:Z - - ./data/conf/rspamd/rspamd.conf.override:/etc/rspamd/rspamd.conf.override:Z - - rspamd-vol-1:/var/lib/rspamd - restart: always - hostname: rspamd - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - networks: - mailcow-network: - aliases: - - rspamd - - php-fpm-mailcow: - image: ghcr.io/mailcow/phpfpm:8.2.29 - command: "php-fpm -d date.timezone=${TZ} -d expose_php=0" - depends_on: - - redis-mailcow - volumes: - - ./data/hooks/phpfpm:/hooks:Z - - ./data/web:/web:z - - ./data/conf/rspamd/dynmaps:/dynmaps:ro,z - - ./data/conf/rspamd/custom/:/rspamd_custom_maps:z - - ./data/conf/dovecot/auth/mailcowauth.php:/mailcowauth/mailcowauth.php:z - - ./data/web/inc/functions.inc.php:/mailcowauth/functions.inc.php:z - - ./data/web/inc/functions.auth.inc.php:/mailcowauth/functions.auth.inc.php:z - - ./data/web/inc/sessions.inc.php:/mailcowauth/sessions.inc.php:z - - ./data/web/inc/functions.mailbox.inc.php:/mailcowauth/functions.mailbox.inc.php:z - - ./data/web/inc/functions.ratelimit.inc.php:/mailcowauth/functions.ratelimit.inc.php:z - - ./data/web/inc/functions.acl.inc.php:/mailcowauth/functions.acl.inc.php:z - - rspamd-vol-1:/var/lib/rspamd - - mysql-socket-vol-1:/var/run/mysqld/:z - - ./data/conf/sogo/:/etc/sogo/:z - - ./data/conf/rspamd/meta_exporter:/meta_exporter:ro,z - - ./data/conf/phpfpm/crons:/crons:z - - ./data/conf/phpfpm/sogo-sso/:/etc/sogo-sso/:z - - ./data/conf/phpfpm/php-fpm.d/pools.conf:/usr/local/etc/php-fpm.d/z-pools.conf:Z - - ./data/conf/phpfpm/php-conf.d/opcache-recommended.ini:/usr/local/etc/php/conf.d/opcache-recommended.ini:Z - - ./data/conf/phpfpm/php-conf.d/upload.ini:/usr/local/etc/php/conf.d/upload.ini:Z - - ./data/conf/phpfpm/php-conf.d/other.ini:/usr/local/etc/php/conf.d/zzz-other.ini:Z - - ./data/conf/dovecot/global_sieve_before:/global_sieve/before:z - - ./data/conf/dovecot/global_sieve_after:/global_sieve/after:z - - ./data/assets/templates:/tpls:z - - ./data/conf/nginx/:/etc/nginx/conf.d/:z - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - environment: - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - - LOG_LINES=${LOG_LINES:-9999} - - TZ=${TZ} - - DBNAME=${DBNAME} - - DBUSER=${DBUSER} - - DBPASS=${DBPASS} - - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - - MAILCOW_PASS_SCHEME=${MAILCOW_PASS_SCHEME:-BLF-CRYPT} - - IMAP_PORT=${IMAP_PORT:-143} - - IMAPS_PORT=${IMAPS_PORT:-993} - - POP_PORT=${POP_PORT:-110} - - POPS_PORT=${POPS_PORT:-995} - - SIEVE_PORT=${SIEVE_PORT:-4190} - - IPV4_NETWORK=${IPV4_NETWORK:-172.22.1} - - IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64} - - SUBMISSION_PORT=${SUBMISSION_PORT:-587} - - SMTPS_PORT=${SMTPS_PORT:-465} - - SMTP_PORT=${SMTP_PORT:-25} - - API_KEY=${API_KEY:-invalid} - - API_KEY_READ_ONLY=${API_KEY_READ_ONLY:-invalid} - - API_ALLOW_FROM=${API_ALLOW_FROM:-invalid} - - COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME:-mailcow-dockerized} - - SKIP_FTS=${SKIP_FTS:-y} - - SKIP_CLAMD=${SKIP_CLAMD:-n} - - SKIP_OLEFY=${SKIP_OLEFY:-n} - - SKIP_SOGO=${SKIP_SOGO:-n} - - ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n} - - MASTER=${MASTER:-y} - - DEV_MODE=${DEV_MODE:-n} - - DEMO_MODE=${DEMO_MODE:-n} - - WEBAUTHN_ONLY_TRUSTED_VENDORS=${WEBAUTHN_ONLY_TRUSTED_VENDORS:-n} - - CLUSTERMODE=${CLUSTERMODE:-} - - ADDITIONAL_SERVER_NAMES=${ADDITIONAL_SERVER_NAMES:-} - restart: always - labels: - ofelia.enabled: "true" - ofelia.job-exec.phpfpm_keycloak_sync.schedule: "0 * * * * *" - ofelia.job-exec.phpfpm_keycloak_sync.no-overlap: "true" - ofelia.job-exec.phpfpm_keycloak_sync.command: "/bin/bash -c \"php /crons/keycloak-sync.php || exit 0\"" - ofelia.job-exec.phpfpm_ldap_sync.schedule: "0 * * * * *" - ofelia.job-exec.phpfpm_ldap_sync.no-overlap: "true" - ofelia.job-exec.phpfpm_ldap_sync.command: "/bin/bash -c \"php /crons/ldap-sync.php || exit 0\"" - networks: - mailcow-network: - aliases: - - phpfpm - - sogo-mailcow: - image: ghcr.io/mailcow/sogo:5.12.4 - environment: - - DBNAME=${DBNAME} - - DBUSER=${DBUSER} - - DBPASS=${DBPASS} - - TZ=${TZ} - - LOG_LINES=${LOG_LINES:-9999} - - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - - MAILCOW_PASS_SCHEME=${MAILCOW_PASS_SCHEME:-BLF-CRYPT} - - ACL_ANYONE=${ACL_ANYONE:-disallow} - - ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n} - - IPV4_NETWORK=${IPV4_NETWORK:-172.22.1} - - SOGO_EXPIRE_SESSION=${SOGO_EXPIRE_SESSION:-480} - - SOGO_URL_ENCRYPTION_KEY=${SOGO_URL_ENCRYPTION_KEY:-SOGoSuperSecret0} - - SKIP_SOGO=${SKIP_SOGO:-n} - - MASTER=${MASTER:-y} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - volumes: - - ./data/hooks/sogo:/hooks:Z - - ./data/conf/sogo/:/etc/sogo/:z - - ./data/web/inc/init_db.inc.php:/init_db.inc.php:z - - ./data/conf/sogo/custom-favicon.ico:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo.ico:z - - ./data/conf/sogo/custom-shortlogo.svg:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo-compact.svg:z - - ./data/conf/sogo/custom-fulllogo.svg:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo-full.svg:z - - ./data/conf/sogo/custom-fulllogo.png:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo-logo.png:z - - ./data/conf/sogo/custom-theme.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/theme.js:z - - ./data/conf/sogo/custom-sogo.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/custom-sogo.js:z - - mysql-socket-vol-1:/var/run/mysqld/:z - - sogo-web-vol-1:/sogo_web - - sogo-userdata-backup-vol-1:/sogo_backup - labels: - ofelia.enabled: "true" - ofelia.job-exec.sogo_sessions.schedule: "0 * * * * *" - ofelia.job-exec.sogo_sessions.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool -v expire-sessions $${SOGO_EXPIRE_SESSION} || exit 0\"" - ofelia.job-exec.sogo_ealarms.schedule: "0 * * * * *" - ofelia.job-exec.sogo_ealarms.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-ealarms-notify -p /etc/sogo/cron.creds || exit 0\"" - ofelia.job-exec.sogo_eautoreply.schedule: "0 */5 * * * *" - ofelia.job-exec.sogo_eautoreply.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool update-autoreply -p /etc/sogo/sieve.creds || exit 0\"" - ofelia.job-exec.sogo_backup.schedule: "0 0 0 * * *" - ofelia.job-exec.sogo_backup.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool backup /sogo_backup ALL || exit 0\"" - restart: always - networks: - mailcow-network: - ipv4_address: ${IPV4_NETWORK:-172.22.1}.248 - aliases: - - sogo - - dovecot-mailcow: - image: ghcr.io/mailcow/dovecot:2.3.21.1 - depends_on: - - mysql-mailcow - - netfilter-mailcow - - redis-mailcow - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - cap_add: - - NET_BIND_SERVICE - volumes: - - ./data/hooks/dovecot:/hooks:Z - - ./data/conf/dovecot:/etc/dovecot:z - - ./data/assets/ssl:/etc/ssl/mail/:ro,z - - ./data/conf/sogo/:/etc/sogo/:z - - ./data/conf/phpfpm/sogo-sso/:/etc/phpfpm/:z - - vmail-vol-1:/var/vmail - - vmail-index-vol-1:/var/vmail_index - - crypt-vol-1:/mail_crypt/ - - ./data/conf/rspamd/custom/:/etc/rspamd/custom:z - - ./data/assets/templates:/templates:z - - rspamd-vol-1:/var/lib/rspamd - - mysql-socket-vol-1:/var/run/mysqld/:z - environment: - - DOVECOT_MASTER_USER=${DOVECOT_MASTER_USER:-} - - DOVECOT_MASTER_PASS=${DOVECOT_MASTER_PASS:-} - - MAILCOW_REPLICA_IP=${MAILCOW_REPLICA_IP:-} - - DOVEADM_REPLICA_PORT=${DOVEADM_REPLICA_PORT:-} - - LOG_LINES=${LOG_LINES:-9999} - - DBNAME=${DBNAME} - - DBUSER=${DBUSER} - - DBPASS=${DBPASS} - - TZ=${TZ} - - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - - MAILCOW_PASS_SCHEME=${MAILCOW_PASS_SCHEME:-BLF-CRYPT} - - IPV4_NETWORK=${IPV4_NETWORK:-172.22.1} - - ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n} - - MAILDIR_GC_TIME=${MAILDIR_GC_TIME:-7200} - - ACL_ANYONE=${ACL_ANYONE:-disallow} - - SKIP_FTS=${SKIP_FTS:-y} - - FTS_HEAP=${FTS_HEAP:-512} - - FTS_PROCS=${FTS_PROCS:-3} - - MAILDIR_SUB=${MAILDIR_SUB:-} - - MASTER=${MASTER:-y} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - - COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME:-mailcow-dockerized} - ports: - - "${DOVEADM_PORT:-127.0.0.1:19991}:12345" - - "${IMAP_PORT:-143}:143" - - "${IMAPS_PORT:-993}:993" - - "${POP_PORT:-110}:110" - - "${POPS_PORT:-995}:995" - - "${SIEVE_PORT:-4190}:4190" - restart: always - tty: true - labels: - ofelia.enabled: "true" - ofelia.job-exec.dovecot_imapsync_runner.schedule: "0 * * * * *" - ofelia.job-exec.dovecot_imapsync_runner.no-overlap: "true" - ofelia.job-exec.dovecot_imapsync_runner.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu nobody /usr/local/bin/imapsync_runner.pl || exit 0\"" - ofelia.job-exec.dovecot_trim_logs.schedule: "0 * * * * *" - ofelia.job-exec.dovecot_trim_logs.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu vmail /usr/local/bin/trim_logs.sh || exit 0\"" - ofelia.job-exec.dovecot_quarantine.schedule: "0 */20 * * * *" - ofelia.job-exec.dovecot_quarantine.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu vmail /usr/local/bin/quarantine_notify.py || exit 0\"" - ofelia.job-exec.dovecot_clean_q_aged.schedule: "0 0 0 * * *" - ofelia.job-exec.dovecot_clean_q_aged.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu vmail /usr/local/bin/clean_q_aged.sh || exit 0\"" - ofelia.job-exec.dovecot_maildir_gc.schedule: "0 */30 * * * *" - ofelia.job-exec.dovecot_maildir_gc.command: "/bin/bash -c \"source /source_env.sh ; /usr/local/bin/gosu vmail /usr/local/bin/maildir_gc.sh\"" - ofelia.job-exec.dovecot_sarules.schedule: "@every 24h" - ofelia.job-exec.dovecot_sarules.command: "/bin/bash -c \"/usr/local/bin/sa-rules.sh\"" - ofelia.job-exec.dovecot_fts.schedule: "0 0 0 * * *" - ofelia.job-exec.dovecot_fts.command: "/bin/bash -c \"/usr/local/bin/gosu vmail /usr/local/bin/optimize-fts.sh\"" - ofelia.job-exec.dovecot_repl_health.schedule: "0 */5 * * * *" - ofelia.job-exec.dovecot_repl_health.command: "/bin/bash -c \"/usr/local/bin/gosu vmail /usr/local/bin/repl_health.sh\"" - ulimits: - nproc: 65535 - nofile: - soft: 20000 - hard: 40000 - networks: - mailcow-network: - ipv4_address: ${IPV4_NETWORK:-172.22.1}.250 - aliases: - - dovecot - - postfix-mailcow: - image: ghcr.io/mailcow/postfix:3.7.11 - depends_on: - mysql-mailcow: - condition: service_started - unbound-mailcow: - condition: service_healthy - postfix-tlspol-mailcow: - condition: service_started - volumes: - - ./data/hooks/postfix:/hooks:Z - - ./data/conf/postfix:/opt/postfix/conf:z - - ./data/assets/ssl:/etc/ssl/mail/:ro,z - - postfix-vol-1:/var/spool/postfix - - crypt-vol-1:/var/lib/zeyple - - rspamd-vol-1:/var/lib/rspamd - - mysql-socket-vol-1:/var/run/mysqld/:z - environment: - - LOG_LINES=${LOG_LINES:-9999} - - TZ=${TZ} - - DBNAME=${DBNAME} - - DBUSER=${DBUSER} - - DBPASS=${DBPASS} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - - SPAMHAUS_DQS_KEY=${SPAMHAUS_DQS_KEY:-} - cap_add: - - NET_BIND_SERVICE - ports: - - "${SMTP_PORT:-25}:25" - - "${SMTPS_PORT:-465}:465" - - "${SUBMISSION_PORT:-587}:587" - restart: always - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - networks: - mailcow-network: - ipv4_address: ${IPV4_NETWORK:-172.22.1}.253 - aliases: - - postfix - - postfix-tlspol-mailcow: - image: ghcr.io/mailcow/postfix-tlspol:1.8.22 - depends_on: - unbound-mailcow: - condition: service_healthy - volumes: - - postfix-tlspol-vol-1:/var/lib/postfix-tlspol - environment: - - LOG_LINES=${LOG_LINES:-9999} - - TZ=${TZ} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - - DEV_MODE=${DEV_MODE:-n} - restart: always - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - networks: - mailcow-network: - aliases: - - postfix-tlspol - - memcached-mailcow: - image: memcached:alpine - restart: always - environment: - - TZ=${TZ} - networks: - mailcow-network: - aliases: - - memcached - - nginx-mailcow: - depends_on: - - redis-mailcow - - php-fpm-mailcow - - sogo-mailcow - - rspamd-mailcow - image: ghcr.io/mailcow/nginx:1.05 - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - environment: - - HTTPS_PORT=${HTTPS_PORT:-443} - - HTTP_PORT=${HTTP_PORT:-80} - - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - - ADDITIONAL_SERVER_NAMES=${ADDITIONAL_SERVER_NAMES:-} - - TZ=${TZ} - - SKIP_SOGO=${SKIP_SOGO:-n} - - SKIP_RSPAMD=${SKIP_RSPAMD:-n} - - ENABLE_IPV6=${ENABLE_IPV6:-true} - - HTTP_REDIRECT=${HTTP_REDIRECT:-n} - - PHPFPMHOST=${PHPFPMHOST:-} - - SOGOHOST=${SOGOHOST:-} - - RSPAMDHOST=${RSPAMDHOST:-} - - REDISHOST=${REDISHOST:-} - - IPV4_NETWORK=${IPV4_NETWORK:-172.22.1} - - NGINX_USE_PROXY_PROTOCOL=${NGINX_USE_PROXY_PROTOCOL:-n} - - TRUSTED_PROXIES=${TRUSTED_PROXIES:-172.16.0.0/12} - volumes: - - ./data/web:/web:ro,z - - ./data/conf/rspamd/dynmaps:/dynmaps:ro,z - - ./data/assets/ssl/:/etc/ssl/mail/:ro,z - - ./data/conf/nginx/:/etc/nginx/conf.d/:z - - ./data/conf/rspamd/meta_exporter:/meta_exporter:ro,z - - ./data/conf/dovecot/auth/mailcowauth.php:/mailcowauth/mailcowauth.php:z - - ./data/web/inc/functions.inc.php:/mailcowauth/functions.inc.php:z - - ./data/web/inc/functions.auth.inc.php:/mailcowauth/functions.auth.inc.php:z - - ./data/web/inc/sessions.inc.php:/mailcowauth/sessions.inc.php:z - - sogo-web-vol-1:/usr/lib/GNUstep/SOGo/ - ports: [] - restart: always - networks: - mailcow-network: - aliases: - - nginx - traefik-proxy: {} - labels: - traefik.enable: "true" - traefik.docker.network: ${TRAEFIK_NETWORK:-coolify} - - traefik.http.routers.mailcow-http.rule: Host(`mail.karmacoma.dev`) - traefik.http.routers.mailcow-http.entrypoints: web - traefik.http.routers.mailcow-http.service: mailcow-http - traefik.http.middlewares.mailcow-https-redirect.redirectscheme.scheme: https - traefik.http.routers.mailcow-http.middlewares: mailcow-https-redirect - traefik.http.services.mailcow-http.loadbalancer.server.port: 80 - traefik.http.routers.mailcow-https.rule: Host(`mail.karmacoma.dev`) - traefik.http.routers.mailcow-https.entrypoints: websecure - traefik.http.routers.mailcow-https.tls: "true" - traefik.http.routers.mailcow-https.service: mailcow-http - - acme-mailcow: - depends_on: - nginx-mailcow: - condition: service_started - unbound-mailcow: - condition: service_healthy - image: ghcr.io/mailcow/acme:1.94 - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - environment: - - LOG_LINES=${LOG_LINES:-9999} - - ADDITIONAL_SAN=${ADDITIONAL_SAN} - - AUTODISCOVER_SAN=${AUTODISCOVER_SAN:-y} - - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - - DBNAME=${DBNAME} - - DBUSER=${DBUSER} - - DBPASS=${DBPASS} - - SKIP_LETS_ENCRYPT=${SKIP_LETS_ENCRYPT:-n} - - COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME:-mailcow-dockerized} - - DIRECTORY_URL=${DIRECTORY_URL:-} - - ENABLE_SSL_SNI=${ENABLE_SSL_SNI:-n} - - SKIP_IP_CHECK=${SKIP_IP_CHECK:-n} - - SKIP_HTTP_VERIFICATION=${SKIP_HTTP_VERIFICATION:-n} - - ONLY_MAILCOW_HOSTNAME=${ONLY_MAILCOW_HOSTNAME:-n} - - LE_STAGING=${LE_STAGING:-n} - - TZ=${TZ} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - - SNAT_TO_SOURCE=${SNAT_TO_SOURCE:-n} - - SNAT6_TO_SOURCE=${SNAT6_TO_SOURCE:-n} - volumes: - - ./data/web/.well-known/acme-challenge:/var/www/acme:z - - ./data/assets/ssl:/var/lib/acme/:z - - ./data/assets/ssl-example:/var/lib/ssl-example/:ro,Z - - mysql-socket-vol-1:/var/run/mysqld/:z - restart: always - networks: - mailcow-network: - aliases: - - acme - - netfilter-mailcow: - image: ghcr.io/mailcow/netfilter:1.63 - stop_grace_period: 30s - restart: always - privileged: true - environment: - - TZ=${TZ} - - IPV4_NETWORK=${IPV4_NETWORK:-172.22.1} - - IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64} - - SNAT_TO_SOURCE=${SNAT_TO_SOURCE:-n} - - SNAT6_TO_SOURCE=${SNAT6_TO_SOURCE:-n} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - - MAILCOW_REPLICA_IP=${MAILCOW_REPLICA_IP:-} - - DISABLE_NETFILTER_ISOLATION_RULE=${DISABLE_NETFILTER_ISOLATION_RULE:-n} - network_mode: "host" - volumes: - - /lib/modules:/lib/modules:ro - - watchdog-mailcow: - image: ghcr.io/mailcow/watchdog:2.09 - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - tmpfs: - - /tmp - volumes: - - rspamd-vol-1:/var/lib/rspamd - - mysql-socket-vol-1:/var/run/mysqld/:z - - postfix-vol-1:/var/spool/postfix - - ./data/assets/ssl:/etc/ssl/mail/:ro,z - restart: always - depends_on: - - postfix-mailcow - - dovecot-mailcow - - mysql-mailcow - - acme-mailcow - - redis-mailcow - environment: - - IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64} - - LOG_LINES=${LOG_LINES:-9999} - - TZ=${TZ} - - DBNAME=${DBNAME} - - DBUSER=${DBUSER} - - DBPASS=${DBPASS} - - DBROOT=${DBROOT} - - USE_WATCHDOG=${USE_WATCHDOG:-n} - - WATCHDOG_NOTIFY_EMAIL=${WATCHDOG_NOTIFY_EMAIL:-} - - WATCHDOG_NOTIFY_BAN=${WATCHDOG_NOTIFY_BAN:-y} - - WATCHDOG_NOTIFY_START=${WATCHDOG_NOTIFY_START:-y} - - WATCHDOG_SUBJECT=${WATCHDOG_SUBJECT:-Watchdog ALERT} - - WATCHDOG_NOTIFY_WEBHOOK=${WATCHDOG_NOTIFY_WEBHOOK:-} - - WATCHDOG_NOTIFY_WEBHOOK_BODY=${WATCHDOG_NOTIFY_WEBHOOK_BODY:-} - - WATCHDOG_EXTERNAL_CHECKS=${WATCHDOG_EXTERNAL_CHECKS:-n} - - WATCHDOG_MYSQL_REPLICATION_CHECKS=${WATCHDOG_MYSQL_REPLICATION_CHECKS:-n} - - WATCHDOG_VERBOSE=${WATCHDOG_VERBOSE:-n} - - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - - COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME:-mailcow-dockerized} - - IPV4_NETWORK=${IPV4_NETWORK:-172.22.1} - - IP_BY_DOCKER_API=${IP_BY_DOCKER_API:-0} - - CHECK_UNBOUND=${CHECK_UNBOUND:-1} - - SKIP_CLAMD=${SKIP_CLAMD:-n} - - SKIP_OLEFY=${SKIP_OLEFY:-n} - - SKIP_LETS_ENCRYPT=${SKIP_LETS_ENCRYPT:-n} - - SKIP_SOGO=${SKIP_SOGO:-n} - - HTTPS_PORT=${HTTPS_PORT:-443} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - - EXTERNAL_CHECKS_THRESHOLD=${EXTERNAL_CHECKS_THRESHOLD:-1} - - NGINX_THRESHOLD=${NGINX_THRESHOLD:-5} - - UNBOUND_THRESHOLD=${UNBOUND_THRESHOLD:-5} - - REDIS_THRESHOLD=${REDIS_THRESHOLD:-5} - - MYSQL_THRESHOLD=${MYSQL_THRESHOLD:-5} - - MYSQL_REPLICATION_THRESHOLD=${MYSQL_REPLICATION_THRESHOLD:-1} - - SOGO_THRESHOLD=${SOGO_THRESHOLD:-3} - - POSTFIX_THRESHOLD=${POSTFIX_THRESHOLD:-8} - - POSTFIX_TLSPOL_THRESHOLD=${POSTFIX_TLSPOL_THRESHOLD:-8} - - CLAMD_THRESHOLD=${CLAMD_THRESHOLD:-15} - - DOVECOT_THRESHOLD=${DOVECOT_THRESHOLD:-12} - - DOVECOT_REPL_THRESHOLD=${DOVECOT_REPL_THRESHOLD:-20} - - PHPFPM_THRESHOLD=${PHPFPM_THRESHOLD:-5} - - RATELIMIT_THRESHOLD=${RATELIMIT_THRESHOLD:-1} - - FAIL2BAN_THRESHOLD=${FAIL2BAN_THRESHOLD:-1} - - ACME_THRESHOLD=${ACME_THRESHOLD:-1} - - RSPAMD_THRESHOLD=${RSPAMD_THRESHOLD:-5} - - OLEFY_THRESHOLD=${OLEFY_THRESHOLD:-5} - - MAILQ_THRESHOLD=${MAILQ_THRESHOLD:-20} - - MAILQ_CRIT=${MAILQ_CRIT:-30} - - DEV_MODE=${DEV_MODE:-n} - networks: - mailcow-network: - aliases: - - watchdog - - dockerapi-mailcow: - image: ghcr.io/mailcow/dockerapi:2.11 - security_opt: - - label=disable - restart: always - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - environment: - - DBROOT=${DBROOT} - - TZ=${TZ} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - networks: - mailcow-network: - aliases: - - dockerapi - - olefy-mailcow: - image: ghcr.io/mailcow/olefy:1.15 - restart: always - environment: - - TZ=${TZ} - - OLEFY_BINDADDRESS=0.0.0.0 - - OLEFY_BINDPORT=10055 - - OLEFY_TMPDIR=/tmp - - OLEFY_PYTHON_PATH=/usr/bin/python3 - - OLEFY_OLEVBA_PATH=/usr/bin/olevba - - OLEFY_LOGLVL=20 - - OLEFY_MINLENGTH=500 - - OLEFY_DEL_TMP=1 - - SKIP_OLEFY=${SKIP_OLEFY:-n} - networks: - mailcow-network: - aliases: - - olefy - - ofelia-mailcow: - image: mcuadros/ofelia:latest - restart: always - command: daemon --docker -f label=com.docker.compose.project=${COMPOSE_PROJECT_NAME} - environment: - - TZ=${TZ} - - COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME} - depends_on: - - sogo-mailcow - - dovecot-mailcow - labels: - ofelia.enabled: "true" - security_opt: - - label=disable - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - networks: - mailcow-network: - aliases: - - ofelia - -networks: - mailcow-network: - driver: bridge - driver_opts: - com.docker.network.bridge.name: br-mailcow - enable_ipv6: ${ENABLE_IPV6:-true} - ipam: - driver: default - config: - - subnet: ${IPV4_NETWORK:-172.22.1}.0/24 - - subnet: ${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64} - -volumes: - vmail-vol-1: - vmail-index-vol-1: - mysql-vol-1: - mysql-socket-vol-1: - redis-vol-1: - rspamd-vol-1: - postfix-vol-1: - postfix-tlspol-vol-1: - crypt-vol-1: - sogo-web-vol-1: - sogo-userdata-backup-vol-1: - clamd-db-vol-1: diff --git a/docker-compose.yml b/docker-compose.yml index ae9a18d..b16e06a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,683 +1,38 @@ services: + mailserver: + image: ghcr.io/docker-mailserver/docker-mailserver:latest + container_name: mailserver + # Provide the FQDN of your mail server here (Your DNS MX record should point to this value) + hostname: mail.karmacoma.dev + ports: + - "25:25" + - "465:465" + - "587:587" + - "993:993" + volumes: + - ./docker-data/dms/mail-data/:/var/mail/ + - ./docker-data/dms/mail-state/:/var/mail-state/ + - ./docker-data/dms/mail-logs/:/var/log/mail/ + - ./docker-data/dms/config/:/tmp/docker-mailserver/ + - /etc/localtime:/etc/localtime:ro + environment: + - ENABLE_RSPAMD=1 + - ENABLE_CLAMAV=1 + - ENABLE_FAIL2BAN=1 + cap_add: + - NET_ADMIN # For Fail2Ban to work + restart: always - unbound-mailcow: - image: ghcr.io/mailcow/unbound:1.24 - environment: - - TZ=${TZ} - - SKIP_UNBOUND_HEALTHCHECK=${SKIP_UNBOUND_HEALTHCHECK:-n} - volumes: - - ./data/hooks/unbound:/hooks:Z - - ./data/conf/unbound/unbound.conf:/etc/unbound/unbound.conf:ro,Z - restart: always - tty: true - networks: - mailcow-network: - ipv4_address: ${IPV4_NETWORK:-172.22.1}.254 - aliases: - - unbound - - mysql-mailcow: - image: mariadb:10.11 - depends_on: - - unbound-mailcow - - netfilter-mailcow - stop_grace_period: 45s - volumes: - - mysql-vol-1:/var/lib/mysql/ - - mysql-socket-vol-1:/var/run/mysqld/:z - - ./data/conf/mysql/:/etc/mysql/conf.d/:ro,Z - environment: - - TZ=${TZ} - - MYSQL_ROOT_PASSWORD=${DBROOT} - - MYSQL_DATABASE=${DBNAME} - - MYSQL_USER=${DBUSER} - - MYSQL_PASSWORD=${DBPASS} - - MYSQL_INITDB_SKIP_TZINFO=1 - restart: always - ports: - - "${SQL_PORT:-127.0.0.1:13306}:3306" - networks: - mailcow-network: - aliases: - - mysql - - redis-mailcow: - image: redis:7.4.6-alpine - entrypoint: ["/bin/sh","/redis-conf.sh"] - volumes: - - redis-vol-1:/data/ - - ./data/conf/redis/redis-conf.sh:/redis-conf.sh:z - restart: always - depends_on: - - netfilter-mailcow - ports: - - "${REDIS_PORT:-127.0.0.1:7654}:6379" - environment: - - TZ=${TZ} - - REDISPASS=${REDISPASS} - - REDISMASTERPASS=${REDISMASTERPASS:-} - sysctls: - - net.core.somaxconn=4096 - networks: - mailcow-network: - ipv4_address: ${IPV4_NETWORK:-172.22.1}.249 - aliases: - - redis - - clamd-mailcow: - image: ghcr.io/mailcow/clamd:1.71 - restart: always - depends_on: - unbound-mailcow: - condition: service_healthy - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - environment: - - TZ=${TZ} - - SKIP_CLAMD=${SKIP_CLAMD:-n} - volumes: - - ./data/conf/clamav/:/etc/clamav/:Z - - clamd-db-vol-1:/var/lib/clamav - networks: - mailcow-network: - aliases: - - clamd - - rspamd-mailcow: - image: ghcr.io/mailcow/rspamd:2.4 - stop_grace_period: 30s - depends_on: - - dovecot-mailcow - - clamd-mailcow - environment: - - TZ=${TZ} - - IPV4_NETWORK=${IPV4_NETWORK:-172.22.1} - - IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - - SPAMHAUS_DQS_KEY=${SPAMHAUS_DQS_KEY:-} - volumes: - - ./data/hooks/rspamd:/hooks:Z - - ./data/conf/rspamd/custom/:/etc/rspamd/custom:z - - ./data/conf/rspamd/override.d/:/etc/rspamd/override.d:Z - - ./data/conf/rspamd/local.d/:/etc/rspamd/local.d:Z - - ./data/conf/rspamd/plugins.d/:/etc/rspamd/plugins.d:Z - - ./data/conf/rspamd/lua/:/etc/rspamd/lua/:ro,Z - - ./data/conf/rspamd/rspamd.conf.local:/etc/rspamd/rspamd.conf.local:Z - - ./data/conf/rspamd/rspamd.conf.override:/etc/rspamd/rspamd.conf.override:Z - - rspamd-vol-1:/var/lib/rspamd - restart: always - hostname: rspamd - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - networks: - mailcow-network: - aliases: - - rspamd - - php-fpm-mailcow: - image: ghcr.io/mailcow/phpfpm:8.2.29 - command: "php-fpm -d date.timezone=${TZ} -d expose_php=0" - depends_on: - - redis-mailcow - volumes: - - ./data/hooks/phpfpm:/hooks:Z - - ./data/web:/web:z - - ./data/conf/rspamd/dynmaps:/dynmaps:ro,z - - ./data/conf/rspamd/custom/:/rspamd_custom_maps:z - - ./data/conf/dovecot/auth/mailcowauth.php:/mailcowauth/mailcowauth.php:z - - ./data/web/inc/functions.inc.php:/mailcowauth/functions.inc.php:z - - ./data/web/inc/functions.auth.inc.php:/mailcowauth/functions.auth.inc.php:z - - ./data/web/inc/sessions.inc.php:/mailcowauth/sessions.inc.php:z - - ./data/web/inc/functions.mailbox.inc.php:/mailcowauth/functions.mailbox.inc.php:z - - ./data/web/inc/functions.ratelimit.inc.php:/mailcowauth/functions.ratelimit.inc.php:z - - ./data/web/inc/functions.acl.inc.php:/mailcowauth/functions.acl.inc.php:z - - rspamd-vol-1:/var/lib/rspamd - - mysql-socket-vol-1:/var/run/mysqld/:z - - ./data/conf/sogo/:/etc/sogo/:z - - ./data/conf/rspamd/meta_exporter:/meta_exporter:ro,z - - ./data/conf/phpfpm/crons:/crons:z - - ./data/conf/phpfpm/sogo-sso/:/etc/sogo-sso/:z - - ./data/conf/phpfpm/php-fpm.d/pools.conf:/usr/local/etc/php-fpm.d/z-pools.conf:Z - - ./data/conf/phpfpm/php-conf.d/opcache-recommended.ini:/usr/local/etc/php/conf.d/opcache-recommended.ini:Z - - ./data/conf/phpfpm/php-conf.d/upload.ini:/usr/local/etc/php/conf.d/upload.ini:Z - - ./data/conf/phpfpm/php-conf.d/other.ini:/usr/local/etc/php/conf.d/zzz-other.ini:Z - - ./data/conf/dovecot/global_sieve_before:/global_sieve/before:z - - ./data/conf/dovecot/global_sieve_after:/global_sieve/after:z - - ./data/assets/templates:/tpls:z - - ./data/conf/nginx/:/etc/nginx/conf.d/:z - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - environment: - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - - LOG_LINES=${LOG_LINES:-9999} - - TZ=${TZ} - - DBNAME=${DBNAME} - - DBUSER=${DBUSER} - - DBPASS=${DBPASS} - - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - - MAILCOW_PASS_SCHEME=${MAILCOW_PASS_SCHEME:-BLF-CRYPT} - - IMAP_PORT=${IMAP_PORT:-143} - - IMAPS_PORT=${IMAPS_PORT:-993} - - POP_PORT=${POP_PORT:-110} - - POPS_PORT=${POPS_PORT:-995} - - SIEVE_PORT=${SIEVE_PORT:-4190} - - IPV4_NETWORK=${IPV4_NETWORK:-172.22.1} - - IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64} - - SUBMISSION_PORT=${SUBMISSION_PORT:-587} - - SMTPS_PORT=${SMTPS_PORT:-465} - - SMTP_PORT=${SMTP_PORT:-25} - - API_KEY=${API_KEY:-invalid} - - API_KEY_READ_ONLY=${API_KEY_READ_ONLY:-invalid} - - API_ALLOW_FROM=${API_ALLOW_FROM:-invalid} - - COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME:-mailcow-dockerized} - - SKIP_FTS=${SKIP_FTS:-y} - - SKIP_CLAMD=${SKIP_CLAMD:-n} - - SKIP_OLEFY=${SKIP_OLEFY:-n} - - SKIP_SOGO=${SKIP_SOGO:-n} - - ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n} - - MASTER=${MASTER:-y} - - DEV_MODE=${DEV_MODE:-n} - - DEMO_MODE=${DEMO_MODE:-n} - - WEBAUTHN_ONLY_TRUSTED_VENDORS=${WEBAUTHN_ONLY_TRUSTED_VENDORS:-n} - - CLUSTERMODE=${CLUSTERMODE:-} - - ADDITIONAL_SERVER_NAMES=${ADDITIONAL_SERVER_NAMES:-} - restart: always - labels: - ofelia.enabled: "true" - ofelia.job-exec.phpfpm_keycloak_sync.schedule: "0 * * * * *" - ofelia.job-exec.phpfpm_keycloak_sync.no-overlap: "true" - ofelia.job-exec.phpfpm_keycloak_sync.command: "/bin/bash -c \"php /crons/keycloak-sync.php || exit 0\"" - ofelia.job-exec.phpfpm_ldap_sync.schedule: "0 * * * * *" - ofelia.job-exec.phpfpm_ldap_sync.no-overlap: "true" - ofelia.job-exec.phpfpm_ldap_sync.command: "/bin/bash -c \"php /crons/ldap-sync.php || exit 0\"" - networks: - mailcow-network: - aliases: - - phpfpm - - sogo-mailcow: - image: ghcr.io/mailcow/sogo:5.12.4 - environment: - - DBNAME=${DBNAME} - - DBUSER=${DBUSER} - - DBPASS=${DBPASS} - - TZ=${TZ} - - LOG_LINES=${LOG_LINES:-9999} - - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - - MAILCOW_PASS_SCHEME=${MAILCOW_PASS_SCHEME:-BLF-CRYPT} - - ACL_ANYONE=${ACL_ANYONE:-disallow} - - ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n} - - IPV4_NETWORK=${IPV4_NETWORK:-172.22.1} - - SOGO_EXPIRE_SESSION=${SOGO_EXPIRE_SESSION:-480} - - SOGO_URL_ENCRYPTION_KEY=${SOGO_URL_ENCRYPTION_KEY:-SOGoSuperSecret0} - - SKIP_SOGO=${SKIP_SOGO:-n} - - MASTER=${MASTER:-y} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - volumes: - - ./data/hooks/sogo:/hooks:Z - - ./data/conf/sogo/:/etc/sogo/:z - - ./data/web/inc/init_db.inc.php:/init_db.inc.php:z - - ./data/conf/sogo/custom-favicon.ico:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo.ico:z - - ./data/conf/sogo/custom-shortlogo.svg:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo-compact.svg:z - - ./data/conf/sogo/custom-fulllogo.svg:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo-full.svg:z - - ./data/conf/sogo/custom-fulllogo.png:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo-logo.png:z - - ./data/conf/sogo/custom-theme.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/theme.js:z - - ./data/conf/sogo/custom-sogo.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/custom-sogo.js:z - - mysql-socket-vol-1:/var/run/mysqld/:z - - sogo-web-vol-1:/sogo_web - - sogo-userdata-backup-vol-1:/sogo_backup - labels: - ofelia.enabled: "true" - ofelia.job-exec.sogo_sessions.schedule: "0 * * * * *" - ofelia.job-exec.sogo_sessions.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool -v expire-sessions $${SOGO_EXPIRE_SESSION} || exit 0\"" - ofelia.job-exec.sogo_ealarms.schedule: "0 * * * * *" - ofelia.job-exec.sogo_ealarms.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-ealarms-notify -p /etc/sogo/cron.creds || exit 0\"" - ofelia.job-exec.sogo_eautoreply.schedule: "0 */5 * * * *" - ofelia.job-exec.sogo_eautoreply.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool update-autoreply -p /etc/sogo/sieve.creds || exit 0\"" - ofelia.job-exec.sogo_backup.schedule: "0 0 0 * * *" - ofelia.job-exec.sogo_backup.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool backup /sogo_backup ALL || exit 0\"" - restart: always - networks: - mailcow-network: - ipv4_address: ${IPV4_NETWORK:-172.22.1}.248 - aliases: - - sogo - - dovecot-mailcow: - image: ghcr.io/mailcow/dovecot:2.3.21.1 - depends_on: - - mysql-mailcow - - netfilter-mailcow - - redis-mailcow - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - cap_add: - - NET_BIND_SERVICE - volumes: - - ./data/hooks/dovecot:/hooks:Z - - ./data/conf/dovecot:/etc/dovecot:z - - ./data/assets/ssl:/etc/ssl/mail/:ro,z - - ./data/conf/sogo/:/etc/sogo/:z - - ./data/conf/phpfpm/sogo-sso/:/etc/phpfpm/:z - - vmail-vol-1:/var/vmail - - vmail-index-vol-1:/var/vmail_index - - crypt-vol-1:/mail_crypt/ - - ./data/conf/rspamd/custom/:/etc/rspamd/custom:z - - ./data/assets/templates:/templates:z - - rspamd-vol-1:/var/lib/rspamd - - mysql-socket-vol-1:/var/run/mysqld/:z - environment: - - DOVECOT_MASTER_USER=${DOVECOT_MASTER_USER:-} - - DOVECOT_MASTER_PASS=${DOVECOT_MASTER_PASS:-} - - MAILCOW_REPLICA_IP=${MAILCOW_REPLICA_IP:-} - - DOVEADM_REPLICA_PORT=${DOVEADM_REPLICA_PORT:-} - - LOG_LINES=${LOG_LINES:-9999} - - DBNAME=${DBNAME} - - DBUSER=${DBUSER} - - DBPASS=${DBPASS} - - TZ=${TZ} - - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - - MAILCOW_PASS_SCHEME=${MAILCOW_PASS_SCHEME:-BLF-CRYPT} - - IPV4_NETWORK=${IPV4_NETWORK:-172.22.1} - - ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n} - - MAILDIR_GC_TIME=${MAILDIR_GC_TIME:-7200} - - ACL_ANYONE=${ACL_ANYONE:-disallow} - - SKIP_FTS=${SKIP_FTS:-y} - - FTS_HEAP=${FTS_HEAP:-512} - - FTS_PROCS=${FTS_PROCS:-3} - - MAILDIR_SUB=${MAILDIR_SUB:-} - - MASTER=${MASTER:-y} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - - COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME:-mailcow-dockerized} - ports: - - "${DOVEADM_PORT:-127.0.0.1:19991}:12345" - - "${IMAP_PORT:-143}:143" - - "${IMAPS_PORT:-993}:993" - - "${POP_PORT:-110}:110" - - "${POPS_PORT:-995}:995" - - "${SIEVE_PORT:-4190}:4190" - restart: always - tty: true - labels: - ofelia.enabled: "true" - ofelia.job-exec.dovecot_imapsync_runner.schedule: "0 * * * * *" - ofelia.job-exec.dovecot_imapsync_runner.no-overlap: "true" - ofelia.job-exec.dovecot_imapsync_runner.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu nobody /usr/local/bin/imapsync_runner.pl || exit 0\"" - ofelia.job-exec.dovecot_trim_logs.schedule: "0 * * * * *" - ofelia.job-exec.dovecot_trim_logs.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu vmail /usr/local/bin/trim_logs.sh || exit 0\"" - ofelia.job-exec.dovecot_quarantine.schedule: "0 */20 * * * *" - ofelia.job-exec.dovecot_quarantine.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu vmail /usr/local/bin/quarantine_notify.py || exit 0\"" - ofelia.job-exec.dovecot_clean_q_aged.schedule: "0 0 0 * * *" - ofelia.job-exec.dovecot_clean_q_aged.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu vmail /usr/local/bin/clean_q_aged.sh || exit 0\"" - ofelia.job-exec.dovecot_maildir_gc.schedule: "0 */30 * * * *" - ofelia.job-exec.dovecot_maildir_gc.command: "/bin/bash -c \"source /source_env.sh ; /usr/local/bin/gosu vmail /usr/local/bin/maildir_gc.sh\"" - ofelia.job-exec.dovecot_sarules.schedule: "@every 24h" - ofelia.job-exec.dovecot_sarules.command: "/bin/bash -c \"/usr/local/bin/sa-rules.sh\"" - ofelia.job-exec.dovecot_fts.schedule: "0 0 0 * * *" - ofelia.job-exec.dovecot_fts.command: "/bin/bash -c \"/usr/local/bin/gosu vmail /usr/local/bin/optimize-fts.sh\"" - ofelia.job-exec.dovecot_repl_health.schedule: "0 */5 * * * *" - ofelia.job-exec.dovecot_repl_health.command: "/bin/bash -c \"/usr/local/bin/gosu vmail /usr/local/bin/repl_health.sh\"" - ulimits: - nproc: 65535 - nofile: - soft: 20000 - hard: 40000 - networks: - mailcow-network: - ipv4_address: ${IPV4_NETWORK:-172.22.1}.250 - aliases: - - dovecot - - postfix-mailcow: - image: ghcr.io/mailcow/postfix:3.7.11 - depends_on: - mysql-mailcow: - condition: service_started - unbound-mailcow: - condition: service_healthy - postfix-tlspol-mailcow: - condition: service_started - volumes: - - ./data/hooks/postfix:/hooks:Z - - ./data/conf/postfix:/opt/postfix/conf:z - - ./data/assets/ssl:/etc/ssl/mail/:ro,z - - postfix-vol-1:/var/spool/postfix - - crypt-vol-1:/var/lib/zeyple - - rspamd-vol-1:/var/lib/rspamd - - mysql-socket-vol-1:/var/run/mysqld/:z - environment: - - LOG_LINES=${LOG_LINES:-9999} - - TZ=${TZ} - - DBNAME=${DBNAME} - - DBUSER=${DBUSER} - - DBPASS=${DBPASS} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - - SPAMHAUS_DQS_KEY=${SPAMHAUS_DQS_KEY:-} - cap_add: - - NET_BIND_SERVICE - ports: - - "${SMTP_PORT:-25}:25" - - "${SMTPS_PORT:-465}:465" - - "${SUBMISSION_PORT:-587}:587" - restart: always - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - networks: - mailcow-network: - ipv4_address: ${IPV4_NETWORK:-172.22.1}.253 - aliases: - - postfix - - postfix-tlspol-mailcow: - image: ghcr.io/mailcow/postfix-tlspol:1.8.22 - depends_on: - unbound-mailcow: - condition: service_healthy - volumes: - - postfix-tlspol-vol-1:/var/lib/postfix-tlspol - environment: - - LOG_LINES=${LOG_LINES:-9999} - - TZ=${TZ} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - - DEV_MODE=${DEV_MODE:-n} - restart: always - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - networks: - mailcow-network: - aliases: - - postfix-tlspol - - memcached-mailcow: - image: memcached:alpine - restart: always - environment: - - TZ=${TZ} - networks: - mailcow-network: - aliases: - - memcached - - nginx-mailcow: - depends_on: - - redis-mailcow - - php-fpm-mailcow - - sogo-mailcow - - rspamd-mailcow - image: ghcr.io/mailcow/nginx:1.05 - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - environment: - - HTTPS_PORT=${HTTPS_PORT:-443} - - HTTP_PORT=${HTTP_PORT:-80} - - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - - ADDITIONAL_SERVER_NAMES=${ADDITIONAL_SERVER_NAMES:-} - - TZ=${TZ} - - SKIP_SOGO=${SKIP_SOGO:-n} - - SKIP_RSPAMD=${SKIP_RSPAMD:-n} - - ENABLE_IPV6=${ENABLE_IPV6:-true} - - HTTP_REDIRECT=${HTTP_REDIRECT:-n} - - PHPFPMHOST=${PHPFPMHOST:-} - - SOGOHOST=${SOGOHOST:-} - - RSPAMDHOST=${RSPAMDHOST:-} - - REDISHOST=${REDISHOST:-} - - IPV4_NETWORK=${IPV4_NETWORK:-172.22.1} - - NGINX_USE_PROXY_PROTOCOL=${NGINX_USE_PROXY_PROTOCOL:-n} - - TRUSTED_PROXIES=${TRUSTED_PROXIES:-} - volumes: - - ./data/web:/web:ro,z - - ./data/conf/rspamd/dynmaps:/dynmaps:ro,z - - ./data/assets/ssl/:/etc/ssl/mail/:ro,z - - ./data/conf/nginx/:/etc/nginx/conf.d/:z - - ./data/conf/rspamd/meta_exporter:/meta_exporter:ro,z - - ./data/conf/dovecot/auth/mailcowauth.php:/mailcowauth/mailcowauth.php:z - - ./data/web/inc/functions.inc.php:/mailcowauth/functions.inc.php:z - - ./data/web/inc/functions.auth.inc.php:/mailcowauth/functions.auth.inc.php:z - - ./data/web/inc/sessions.inc.php:/mailcowauth/sessions.inc.php:z - - sogo-web-vol-1:/usr/lib/GNUstep/SOGo/ - ports: - - "${HTTPS_BIND:-}:${HTTPS_PORT:-443}:${HTTPS_PORT:-443}" - - "${HTTP_BIND:-}:${HTTP_PORT:-80}:${HTTP_PORT:-80}" - restart: always - networks: - mailcow-network: - aliases: - - nginx - - acme-mailcow: - depends_on: - nginx-mailcow: - condition: service_started - unbound-mailcow: - condition: service_healthy - image: ghcr.io/mailcow/acme:1.94 - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - environment: - - LOG_LINES=${LOG_LINES:-9999} - - ADDITIONAL_SAN=${ADDITIONAL_SAN} - - AUTODISCOVER_SAN=${AUTODISCOVER_SAN:-y} - - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - - DBNAME=${DBNAME} - - DBUSER=${DBUSER} - - DBPASS=${DBPASS} - - SKIP_LETS_ENCRYPT=${SKIP_LETS_ENCRYPT:-n} - - COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME:-mailcow-dockerized} - - DIRECTORY_URL=${DIRECTORY_URL:-} - - ENABLE_SSL_SNI=${ENABLE_SSL_SNI:-n} - - SKIP_IP_CHECK=${SKIP_IP_CHECK:-n} - - SKIP_HTTP_VERIFICATION=${SKIP_HTTP_VERIFICATION:-n} - - ONLY_MAILCOW_HOSTNAME=${ONLY_MAILCOW_HOSTNAME:-n} - - LE_STAGING=${LE_STAGING:-n} - - TZ=${TZ} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - - SNAT_TO_SOURCE=${SNAT_TO_SOURCE:-n} - - SNAT6_TO_SOURCE=${SNAT6_TO_SOURCE:-n} - volumes: - - ./data/web/.well-known/acme-challenge:/var/www/acme:z - - ./data/assets/ssl:/var/lib/acme/:z - - ./data/assets/ssl-example:/var/lib/ssl-example/:ro,Z - - mysql-socket-vol-1:/var/run/mysqld/:z - restart: always - networks: - mailcow-network: - aliases: - - acme - - netfilter-mailcow: - image: ghcr.io/mailcow/netfilter:1.63 - stop_grace_period: 30s - restart: always - privileged: true - environment: - - TZ=${TZ} - - IPV4_NETWORK=${IPV4_NETWORK:-172.22.1} - - IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64} - - SNAT_TO_SOURCE=${SNAT_TO_SOURCE:-n} - - SNAT6_TO_SOURCE=${SNAT6_TO_SOURCE:-n} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - - MAILCOW_REPLICA_IP=${MAILCOW_REPLICA_IP:-} - - DISABLE_NETFILTER_ISOLATION_RULE=${DISABLE_NETFILTER_ISOLATION_RULE:-n} - network_mode: "host" - volumes: - - /lib/modules:/lib/modules:ro - - watchdog-mailcow: - image: ghcr.io/mailcow/watchdog:2.09 - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - tmpfs: - - /tmp - volumes: - - rspamd-vol-1:/var/lib/rspamd - - mysql-socket-vol-1:/var/run/mysqld/:z - - postfix-vol-1:/var/spool/postfix - - ./data/assets/ssl:/etc/ssl/mail/:ro,z - restart: always - depends_on: - - postfix-mailcow - - dovecot-mailcow - - mysql-mailcow - - acme-mailcow - - redis-mailcow - environment: - - IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64} - - LOG_LINES=${LOG_LINES:-9999} - - TZ=${TZ} - - DBNAME=${DBNAME} - - DBUSER=${DBUSER} - - DBPASS=${DBPASS} - - DBROOT=${DBROOT} - - USE_WATCHDOG=${USE_WATCHDOG:-n} - - WATCHDOG_NOTIFY_EMAIL=${WATCHDOG_NOTIFY_EMAIL:-} - - WATCHDOG_NOTIFY_BAN=${WATCHDOG_NOTIFY_BAN:-y} - - WATCHDOG_NOTIFY_START=${WATCHDOG_NOTIFY_START:-y} - - WATCHDOG_SUBJECT=${WATCHDOG_SUBJECT:-Watchdog ALERT} - - WATCHDOG_NOTIFY_WEBHOOK=${WATCHDOG_NOTIFY_WEBHOOK:-} - - WATCHDOG_NOTIFY_WEBHOOK_BODY=${WATCHDOG_NOTIFY_WEBHOOK_BODY:-} - - WATCHDOG_EXTERNAL_CHECKS=${WATCHDOG_EXTERNAL_CHECKS:-n} - - WATCHDOG_MYSQL_REPLICATION_CHECKS=${WATCHDOG_MYSQL_REPLICATION_CHECKS:-n} - - WATCHDOG_VERBOSE=${WATCHDOG_VERBOSE:-n} - - MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - - COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME:-mailcow-dockerized} - - IPV4_NETWORK=${IPV4_NETWORK:-172.22.1} - - IP_BY_DOCKER_API=${IP_BY_DOCKER_API:-0} - - CHECK_UNBOUND=${CHECK_UNBOUND:-1} - - SKIP_CLAMD=${SKIP_CLAMD:-n} - - SKIP_OLEFY=${SKIP_OLEFY:-n} - - SKIP_LETS_ENCRYPT=${SKIP_LETS_ENCRYPT:-n} - - SKIP_SOGO=${SKIP_SOGO:-n} - - HTTPS_PORT=${HTTPS_PORT:-443} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - - EXTERNAL_CHECKS_THRESHOLD=${EXTERNAL_CHECKS_THRESHOLD:-1} - - NGINX_THRESHOLD=${NGINX_THRESHOLD:-5} - - UNBOUND_THRESHOLD=${UNBOUND_THRESHOLD:-5} - - REDIS_THRESHOLD=${REDIS_THRESHOLD:-5} - - MYSQL_THRESHOLD=${MYSQL_THRESHOLD:-5} - - MYSQL_REPLICATION_THRESHOLD=${MYSQL_REPLICATION_THRESHOLD:-1} - - SOGO_THRESHOLD=${SOGO_THRESHOLD:-3} - - POSTFIX_THRESHOLD=${POSTFIX_THRESHOLD:-8} - - POSTFIX_TLSPOL_THRESHOLD=${POSTFIX_TLSPOL_THRESHOLD:-8} - - CLAMD_THRESHOLD=${CLAMD_THRESHOLD:-15} - - DOVECOT_THRESHOLD=${DOVECOT_THRESHOLD:-12} - - DOVECOT_REPL_THRESHOLD=${DOVECOT_REPL_THRESHOLD:-20} - - PHPFPM_THRESHOLD=${PHPFPM_THRESHOLD:-5} - - RATELIMIT_THRESHOLD=${RATELIMIT_THRESHOLD:-1} - - FAIL2BAN_THRESHOLD=${FAIL2BAN_THRESHOLD:-1} - - ACME_THRESHOLD=${ACME_THRESHOLD:-1} - - RSPAMD_THRESHOLD=${RSPAMD_THRESHOLD:-5} - - OLEFY_THRESHOLD=${OLEFY_THRESHOLD:-5} - - MAILQ_THRESHOLD=${MAILQ_THRESHOLD:-20} - - MAILQ_CRIT=${MAILQ_CRIT:-30} - - DEV_MODE=${DEV_MODE:-n} - networks: - mailcow-network: - aliases: - - watchdog - - dockerapi-mailcow: - image: ghcr.io/mailcow/dockerapi:2.11 - security_opt: - - label=disable - restart: always - dns: - - ${IPV4_NETWORK:-172.22.1}.254 - environment: - - DBROOT=${DBROOT} - - TZ=${TZ} - - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - - REDISPASS=${REDISPASS} - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - networks: - mailcow-network: - aliases: - - dockerapi - - olefy-mailcow: - image: ghcr.io/mailcow/olefy:1.15 - restart: always - environment: - - TZ=${TZ} - - OLEFY_BINDADDRESS=0.0.0.0 - - OLEFY_BINDPORT=10055 - - OLEFY_TMPDIR=/tmp - - OLEFY_PYTHON_PATH=/usr/bin/python3 - - OLEFY_OLEVBA_PATH=/usr/bin/olevba - - OLEFY_LOGLVL=20 - - OLEFY_MINLENGTH=500 - - OLEFY_DEL_TMP=1 - - SKIP_OLEFY=${SKIP_OLEFY:-n} - networks: - mailcow-network: - aliases: - - olefy - - ofelia-mailcow: - image: mcuadros/ofelia:latest - restart: always - command: daemon --docker -f label=com.docker.compose.project=${COMPOSE_PROJECT_NAME} - environment: - - TZ=${TZ} - - COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME} - depends_on: - - sogo-mailcow - - dovecot-mailcow - labels: - ofelia.enabled: "true" - security_opt: - - label=disable - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - networks: - mailcow-network: - aliases: - - ofelia - -networks: - mailcow-network: - driver: bridge - driver_opts: - com.docker.network.bridge.name: br-mailcow - enable_ipv6: ${ENABLE_IPV6:-true} - ipam: - driver: default - config: - - subnet: ${IPV4_NETWORK:-172.22.1}.0/24 - - subnet: ${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64} - -volumes: - vmail-vol-1: - vmail-index-vol-1: - mysql-vol-1: - mysql-socket-vol-1: - redis-vol-1: - rspamd-vol-1: - postfix-vol-1: - postfix-tlspol-vol-1: - crypt-vol-1: - sogo-web-vol-1: - sogo-userdata-backup-vol-1: - clamd-db-vol-1: + webmail: + image: ghcr.io/the-djmaze/snappymail:latest + container_name: webmail + depends_on: + - mailserver + ports: + - "8080:80" + environment: + # Log to stdout so container logs are visible in Coolify and docker logs + - SNAPPYMAIL_LOG_TO_STDOUT=1 + volumes: + - ./docker-data/snappymail/:/snappymail/data/ + restart: unless-stopped \ No newline at end of file diff --git a/generate_config.sh b/generate_config.sh deleted file mode 100755 index 393d2fc..0000000 --- a/generate_config.sh +++ /dev/null @@ -1,517 +0,0 @@ -#!/usr/bin/env bash - -# Ensure the script is run from the directory that contains a link of .env -# Resolve the directory this script lives in for consistent behavior when invoked from elsewhere -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" >/dev/null 2>&1 && pwd)" - -# Ensure script is executed in the mailcow installation directory by checking for a .env symlink that points to mailcow.conf -if [ ! -L "${PWD}/.env" ]; then - echo -e "\e[33mPlease run this script from the mailcow installation directory.\e[0m" - echo -e " \e[36mcd /path/to/mailcow && ./generate_config.sh\e[0m" - exit 1 -fi - -# Verify the .env symlink points to a mailcow.conf file -env_target="$(readlink -f "${PWD}/.env" 2>/dev/null || true)" -if [ -z "$env_target" ] || [ "$(basename "$env_target")" != "mailcow.conf" ]; then - echo -e "\e[31mThe found .env symlink does not point to a mailcow.conf file.\e[0m" - echo -e "\e[33mPlease create a symbolic link .env -> mailcow.conf inside the mailcow directory and run this script there.\e[0m" - echo -e "\e[33mNote: 'ln -s mailcow.conf .env' will create the symlink even if mailcow.conf does not yet exist.\e[0m" - echo -e " \e[36mcd /path/to/mailcow && ln -s mailcow.conf .env && ./generate_config.sh\e[0m" - exit 1 -fi - -# Load mailcow Generic Scripts -source _modules/scripts/core.sh -source _modules/scripts/ipv6_controller.sh - -set -o pipefail - -get_installed_tools -get_docker_version - -if [[ $docker_version -lt 24 ]]; then - echo -e "\e[31mCannot find Docker with a Version higher or equals 24.0.0\e[0m" - echo -e "\e[33mmailcow needs a newer Docker version to work properly...\e[0m" - echo -e "\e[31mPlease update your Docker installation... exiting\e[0m" - exit 1 -fi - -detect_bad_asn - -### If generate_config.sh is started with --dev or -d it will not check out nightly or master branch and will keep on the current branch -if [[ ${1} == "--dev" || ${1} == "-d" ]]; then - SKIP_BRANCH=y -else - SKIP_BRANCH=n -fi - -if [ -f mailcow.conf ]; then - read -r -p "A config file exists and will be overwritten, are you sure you want to continue? [y/N] " response - case $response in - [yY][eE][sS]|[yY]) - mv mailcow.conf mailcow.conf_backup - chmod 600 mailcow.conf_backup - ;; - *) - exit 1 - ;; - esac -fi - -echo "Press enter to confirm the detected value '[value]' where applicable or enter a custom value." -while [ -z "${MAILCOW_HOSTNAME}" ]; do - read -p "Mail server hostname (FQDN) - this is not your mail domain, but your mail servers hostname: " -e MAILCOW_HOSTNAME - DOTS=${MAILCOW_HOSTNAME//[^.]}; - if [ ${#DOTS} -lt 1 ]; then - echo -e "\e[31mMAILCOW_HOSTNAME (${MAILCOW_HOSTNAME}) is not a FQDN!\e[0m" - sleep 1 - echo "Please change it to a FQDN and redeploy the stack with docker(-)compose up -d" - exit 1 - elif [[ "${MAILCOW_HOSTNAME: -1}" == "." ]]; then - echo "MAILCOW_HOSTNAME (${MAILCOW_HOSTNAME}) is ending with a dot. This is not a valid FQDN!" - exit 1 - elif [ ${#DOTS} -eq 1 ]; then - echo -e "\e[33mMAILCOW_HOSTNAME (${MAILCOW_HOSTNAME}) does not contain a Subdomain. This is not fully tested and may cause issues.\e[0m" - echo "Find more information about why this message exists here: https://github.com/mailcow/mailcow-dockerized/issues/1572" - read -r -p "Do you want to proceed anyway? [y/N] " response - if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then - echo "OK. Procceding." - else - echo "OK. Exiting." - exit 1 - fi - fi -done - -if [ -a /etc/timezone ]; then - DETECTED_TZ=$(cat /etc/timezone) -elif [ -a /etc/localtime ]; then - DETECTED_TZ=$(readlink /etc/localtime|sed -n 's|^.*zoneinfo/||p') -fi - -while [ -z "${MAILCOW_TZ}" ]; do - if [ -z "${DETECTED_TZ}" ]; then - read -p "Timezone: " -e MAILCOW_TZ - else - read -p "Timezone [${DETECTED_TZ}]: " -e MAILCOW_TZ - [ -z "${MAILCOW_TZ}" ] && MAILCOW_TZ=${DETECTED_TZ} - fi -done - -MEM_TOTAL=$(awk '/MemTotal/ {print $2}' /proc/meminfo) - -if [ -z "${SKIP_CLAMD}" ]; then - if [ "${MEM_TOTAL}" -le "2621440" ]; then - echo "Installed memory is <= 2.5 GiB. It is recommended to disable ClamAV to prevent out-of-memory situations." - echo "ClamAV can be re-enabled by setting SKIP_CLAMD=n in mailcow.conf." - read -r -p "Do you want to disable ClamAV now? [Y/n] " response - case $response in - [nN][oO]|[nN]) - SKIP_CLAMD=n - ;; - *) - SKIP_CLAMD=y - ;; - esac - else - SKIP_CLAMD=n - fi -fi - -if [[ ${SKIP_BRANCH} != y ]]; then - echo "Which branch of mailcow do you want to use?" - echo "" - echo "Available Branches:" - echo "- master branch (stable updates) | default, recommended [1]" - echo "- nightly branch (unstable updates, testing) | not-production ready [2]" - echo "- legacy branch (supported until February 2026) | deprecated, security updates only [3]" - sleep 1 - - while [ -z "${MAILCOW_BRANCH}" ]; do - read -r -p "Choose the Branch with it's number [1/2/3] " branch - case $branch in - [3]) - MAILCOW_BRANCH="legacy" - ;; - [2]) - MAILCOW_BRANCH="nightly" - ;; - *) - MAILCOW_BRANCH="master" - ;; - esac - done - - git fetch --all - git checkout -f "$MAILCOW_BRANCH" - -elif [[ ${SKIP_BRANCH} == y ]]; then - echo -e "\033[33mEnabled Dev Mode.\033[0m" - echo -e "\033[33mNot checking out a different branch!\033[0m" - MAILCOW_BRANCH=$(git rev-parse --short $(git rev-parse @{upstream})) - -else - echo -e "\033[31mCould not determine branch input..." - echo -e "\033[31mExiting." - exit 1 -fi - -if [ ! -z "${MAILCOW_BRANCH}" ]; then - git_branch=${MAILCOW_BRANCH} -fi - -configure_ipv6 - -[ ! -f ./data/conf/rspamd/override.d/worker-controller-password.inc ] && echo '# Placeholder' > ./data/conf/rspamd/override.d/worker-controller-password.inc - -cat << EOF > mailcow.conf -# ------------------------------ -# mailcow web ui configuration -# ------------------------------ -# example.org is _not_ a valid hostname, use a fqdn here. -# Default admin user is "admin" -# Default password is "moohoo" -MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} - -# Password hash algorithm -# Only certain password hash algorithm are supported. For a fully list of supported schemes, -# see https://docs.mailcow.email/models/model-passwd/ -MAILCOW_PASS_SCHEME=BLF-CRYPT - -# ------------------------------ -# SQL database configuration -# ------------------------------ -DBNAME=mailcow -DBUSER=mailcow - -# Please use long, random alphanumeric strings (A-Za-z0-9) -DBPASS=$(LC_ALL=C /dev/null | head -c 28) -DBROOT=$(LC_ALL=C /dev/null | head -c 28) - -# ------------------------------ -# REDIS configuration -# ------------------------------ -REDISPASS=$(LC_ALL=C /dev/null | head -c 28) - -# ------------------------------ -# HTTP/S Bindings -# ------------------------------ - -# You should use HTTPS, but in case of SSL offloaded reverse proxies: -# Might be important: This will also change the binding within the container. -# If you use a proxy within Docker, point it to the ports you set below. -# Do _not_ use IP:PORT in HTTP(S)_BIND or HTTP(S)_PORT -# IMPORTANT: Do not use port 8081, 9081, 9082 or 65510! -# Example: HTTP_BIND=1.2.3.4 -# For IPv4 leave it as it is: HTTP_BIND= & HTTPS_PORT= -# For IPv6 see https://docs.mailcow.email/post_installation/firststeps-ip_bindings/ -HTTP_PORT=80 -HTTP_BIND= - -HTTPS_PORT=443 -HTTPS_BIND= - -# Redirect HTTP connections to HTTPS - y/n -HTTP_REDIRECT=y - -# ------------------------------ -# Other bindings -# ------------------------------ -# You should leave that alone -# Format: 11.22.33.44:25 or 12.34.56.78:465 etc. -SMTP_PORT=25 -SMTPS_PORT=465 -SUBMISSION_PORT=587 -IMAP_PORT=143 -IMAPS_PORT=993 -POP_PORT=110 -POPS_PORT=995 -SIEVE_PORT=4190 -DOVEADM_PORT=127.0.0.1:19991 -SQL_PORT=127.0.0.1:13306 -REDIS_PORT=127.0.0.1:7654 - -# Your timezone -# See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for a list of timezones -# Use the column named 'TZ identifier' + pay attention for the column named 'Notes' -TZ=${MAILCOW_TZ} - -# Fixed project name -# Please use lowercase letters only -COMPOSE_PROJECT_NAME=mailcowdockerized - -# Used Docker Compose version -# Switch here between native (compose plugin) and standalone -# For more information take a look at the mailcow docs regarding the configuration options. -# Normally this should be untouched but if you decided to use either of those you can switch it manually here. -# Please be aware that at least one of those variants should be installed on your machine or mailcow will fail. -DOCKER_COMPOSE_VERSION=${COMPOSE_VERSION} - -# Set this to "allow" to enable the anyone pseudo user. Disabled by default. -# When enabled, ACL can be created, that apply to "All authenticated users" -# This should probably only be activated on mail hosts, that are used exclusively by one organisation. -# Otherwise a user might share data with too many other users. -ACL_ANYONE=disallow - -# Garbage collector cleanup -# Deleted domains and mailboxes are moved to /var/vmail/_garbage/timestamp_sanitizedstring -# How long should objects remain in the garbage until they are being deleted? (value in minutes) -# Check interval is hourly -MAILDIR_GC_TIME=7200 - -# Additional SAN for the certificate -# -# You can use wildcard records to create specific names for every domain you add to mailcow. -# Example: Add domains "example.com" and "example.net" to mailcow, change ADDITIONAL_SAN to a value like: -#ADDITIONAL_SAN=imap.*,smtp.* -# This will expand the certificate to "imap.example.com", "smtp.example.com", "imap.example.net", "smtp.example.net" -# plus every domain you add in the future. -# -# You can also just add static names... -#ADDITIONAL_SAN=srv1.example.net -# ...or combine wildcard and static names: -#ADDITIONAL_SAN=imap.*,srv1.example.com -ADDITIONAL_SAN= - -# Obtain certificates for autodiscover.* and autoconfig.* domains. -# This can be useful to switch off in case you are in a scenario where a reverse proxy already handles those. -# There are mixed scenarios where ports 80,443 are occupied and you do not want to share certs -# between services. So acme-mailcow obtains for maildomains and all web-things get handled -# in the reverse proxy. -AUTODISCOVER_SAN=y - -# Additional server names for mailcow UI -# -# Specify alternative addresses for the mailcow UI to respond to -# This is useful when you set mail.* as ADDITIONAL_SAN and want to make sure mail.maildomain.com will always point to the mailcow UI. -# If the server name does not match a known site, Nginx decides by best-guess and may redirect users to the wrong web root. -# You can understand this as server_name directive in Nginx. -# Comma separated list without spaces! Example: ADDITIONAL_SERVER_NAMES=a.b.c,d.e.f -ADDITIONAL_SERVER_NAMES= - -# Skip running ACME (acme-mailcow, Let's Encrypt certs) - y/n -SKIP_LETS_ENCRYPT=n - -# Create separate certificates for all domains - y/n -# this will allow adding more than 100 domains, but some email clients will not be able to connect with alternative hostnames -# see https://doc.dovecot.org/admin_manual/ssl/sni_support -ENABLE_SSL_SNI=n - -# Skip IPv4 check in ACME container - y/n -SKIP_IP_CHECK=n - -# Skip HTTP verification in ACME container - y/n -SKIP_HTTP_VERIFICATION=n - -# Skip Unbound (DNS Resolver) Healthchecks (NOT Recommended!) - y/n -SKIP_UNBOUND_HEALTHCHECK=n - -# Skip ClamAV (clamd-mailcow) anti-virus (Rspamd will auto-detect a missing ClamAV container) - y/n -SKIP_CLAMD=${SKIP_CLAMD} - -# Skip Olefy (olefy-mailcow) anti-virus for Office documents (Rspamd will auto-detect a missing Olefy container) - y/n -SKIP_OLEFY=n - -# Skip SOGo: Will disable SOGo integration and therefore webmail, DAV protocols and ActiveSync support (experimental, unsupported, not fully implemented) - y/n -SKIP_SOGO=n - -# Skip FTS (Fulltext Search) for Dovecot on low-memory, low-threaded systems or if you simply want to disable it. -# Dovecot inside mailcow use Flatcurve as FTS Backend. -SKIP_FTS=n - -# Dovecot Indexing (FTS) Process maximum heap size in MB, there is no recommendation, please see Dovecot docs. -# Flatcurve (Xapian backend) is used as the FTS Indexer. It is supposed to be efficient in CPU and RAM consumption. -# However: Please always monitor your Resource consumption! -FTS_HEAP=128 - -# Controls how many processes the Dovecot indexing process can spawn at max. -# Too many indexing processes can use a lot of CPU and Disk I/O. -# Please visit: https://doc.dovecot.org/configuration_manual/service_configuration/#indexer-worker for more information -FTS_PROCS=1 - -# Allow admins to log into SOGo as email user (without any password) -ALLOW_ADMIN_EMAIL_LOGIN=n - -# Enable watchdog (watchdog-mailcow) to restart unhealthy containers -USE_WATCHDOG=y - -# Send watchdog notifications by mail (sent from watchdog@MAILCOW_HOSTNAME) -# CAUTION: -# 1. You should use external recipients -# 2. Mails are sent unsigned (no DKIM) -# 3. If you use DMARC, create a separate DMARC policy ("v=DMARC1; p=none;" in _dmarc.MAILCOW_HOSTNAME) -# Multiple rcpts allowed, NO quotation marks, NO spaces -#WATCHDOG_NOTIFY_EMAIL=a@example.com,b@example.com,c@example.com -#WATCHDOG_NOTIFY_EMAIL= - -# Send notifications to a webhook URL that receives a POST request with the content type "application/json". -# You can use this to send notifications to services like Discord, Slack and others. -#WATCHDOG_NOTIFY_WEBHOOK=https://discord.com/api/webhooks/XXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -# JSON body included in the webhook POST request. Needs to be in single quotes. -# Following variables are available: SUBJECT, BODY -#WATCHDOG_NOTIFY_WEBHOOK_BODY='{"username": "mailcow Watchdog", "content": "**${SUBJECT}**\n${BODY}"}' - -# Notify about banned IP (includes whois lookup) -WATCHDOG_NOTIFY_BAN=n - -# Send a notification when the watchdog is started. -WATCHDOG_NOTIFY_START=y - -# Subject for watchdog mails. Defaults to "Watchdog ALERT" followed by the error message. -#WATCHDOG_SUBJECT= - -# Checks if mailcow is an open relay. Requires a SAL. More checks will follow. -# https://www.servercow.de/mailcow?lang=en -# https://www.servercow.de/mailcow?lang=de -# No data is collected. Opt-in and anonymous. -# Will only work with unmodified mailcow setups. -WATCHDOG_EXTERNAL_CHECKS=n - -# Enable watchdog verbose logging -WATCHDOG_VERBOSE=n - -# Max log lines per service to keep in Redis logs -LOG_LINES=9999 - -# Internal IPv4 /24 subnet, format n.n.n (expands to n.n.n.0/24) -# Use private IPv4 addresses only, see https://en.wikipedia.org/wiki/Private_network#Private_IPv4_addresses -IPV4_NETWORK=172.22.1 - -# Internal IPv6 subnet in fc00::/7 -# Use private IPv6 addresses only, see https://en.wikipedia.org/wiki/Private_network#Private_IPv6_addresses -IPV6_NETWORK=fd4d:6169:6c63:6f77::/64 - -# Use this IPv4 for outgoing connections (SNAT) -#SNAT_TO_SOURCE= - -# Use this IPv6 for outgoing connections (SNAT) -#SNAT6_TO_SOURCE= - -# Create or override an API key for the web UI -# You _must_ define API_ALLOW_FROM, which is a comma separated list of IPs -# An API key defined as API_KEY has read-write access -# An API key defined as API_KEY_READ_ONLY has read-only access -# Allowed chars for API_KEY and API_KEY_READ_ONLY: a-z, A-Z, 0-9, - -# You can define API_KEY and/or API_KEY_READ_ONLY - -#API_KEY= -#API_KEY_READ_ONLY= -#API_ALLOW_FROM=172.22.1.1,127.0.0.1 - -# mail_home is ~/Maildir -MAILDIR_SUB=Maildir - -# SOGo session timeout in minutes -SOGO_EXPIRE_SESSION=480 - -# SOGo URL encryption key (exactly 16 characters, limited to A–Z, a–z, 0–9) -# This key is used to encrypt email addresses within SOGo URLs -SOGO_URL_ENCRYPTION_KEY=$(LC_ALL=C /dev/null | head -c 16) - -# DOVECOT_MASTER_USER and DOVECOT_MASTER_PASS must both be provided. No special chars. -# Empty by default to auto-generate master user and password on start. -# User expands to DOVECOT_MASTER_USER@mailcow.local -# LEAVE EMPTY IF UNSURE -DOVECOT_MASTER_USER= -# LEAVE EMPTY IF UNSURE -DOVECOT_MASTER_PASS= - -# WebAuthn device manufacturer verification -# After setting WEBAUTHN_ONLY_TRUSTED_VENDORS=y only devices from trusted manufacturers are allowed -# root certificates can be placed for validation under mailcow-dockerized/data/web/inc/lib/WebAuthn/rootCertificates -WEBAUTHN_ONLY_TRUSTED_VENDORS=n - -# Spamhaus Data Query Service Key -# Optional: Leave empty for none -# Enter your key here if you are using a blocked ASN (OVH, AWS, Cloudflare e.g) for the unregistered Spamhaus Blocklist. -# If empty, it will completely disable Spamhaus blocklists if it detects that you are running on a server using a blocked AS. -# Otherwise it will work normally. -SPAMHAUS_DQS_KEY= - -# IPv6 Controller Section -# This variable controls the usage of IPv6 within mailcow. -# Can either be true or false | Defaults to true -# WARNING: MAKE SURE TO PROPERLY CONFIGURE IPv6 ON YOUR HOST FIRST BEFORE ENABLING THIS AS FAULTY CONFIGURATIONS CAN LEAD TO OPEN RELAYS! -# A COMPLETE DOCKER STACK REBUILD (compose down && compose up -d) IS NEEDED TO APPLY THIS. -ENABLE_IPV6=${IPV6_BOOL} - -# Prevent netfilter from setting an iptables/nftables rule to isolate the mailcow docker network - y/n -# CAUTION: Disabling this may expose container ports to other neighbors on the same subnet, even if the ports are bound to localhost -DISABLE_NETFILTER_ISOLATION_RULE=n -EOF - -mkdir -p data/assets/ssl - -chmod 600 mailcow.conf - -# copy but don't overwrite existing certificate -echo "Generating snake-oil certificate..." -# Making Willich more popular -openssl req -x509 -newkey rsa:4096 -keyout data/assets/ssl-example/key.pem -out data/assets/ssl-example/cert.pem -days 365 -subj "/C=DE/ST=NRW/L=Willich/O=mailcow/OU=mailcow/CN=${MAILCOW_HOSTNAME}" -sha256 -nodes -echo "Copying snake-oil certificate..." -cp -n -d data/assets/ssl-example/*.pem data/assets/ssl/ - -# Set app_info.inc.php -case ${git_branch} in - master) - mailcow_git_version=$(git describe --tags `git rev-list --tags --max-count=1`) - ;; - nightly) - mailcow_git_version=$(git rev-parse --short $(git rev-parse @{upstream})) - mailcow_last_git_version="" - ;; - legacy) - mailcow_git_version=$(git rev-parse --short $(git rev-parse @{upstream})) - mailcow_last_git_version="" - ;; - *) - mailcow_git_version=$(git rev-parse --short HEAD) - mailcow_last_git_version="" - ;; -esac -# if [ ${git_branch} == "master" ]; then -# mailcow_git_version=$(git describe --tags `git rev-list --tags --max-count=1`) -# elif [ ${git_branch} == "nightly" ]; then -# mailcow_git_version=$(git rev-parse --short $(git rev-parse @{upstream})) -# mailcow_last_git_version="" -# else -# mailcow_git_version=$(git rev-parse --short HEAD) -# mailcow_last_git_version="" -# fi - -if [[ $SKIP_BRANCH != "y" ]]; then -mailcow_git_commit=$(git rev-parse origin/${git_branch}) -mailcow_git_commit_date=$(git log -1 --format=%ci @{upstream} ) -else -mailcow_git_commit=$(git rev-parse ${git_branch}) -mailcow_git_commit_date=$(git log -1 --format=%ci @{upstream} ) -git_branch=$(git rev-parse --abbrev-ref HEAD) -fi - -if [ $? -eq 0 ]; then - echo ' data/web/inc/app_info.inc.php - echo ' $MAILCOW_GIT_VERSION="'$mailcow_git_version'";' >> data/web/inc/app_info.inc.php - echo ' $MAILCOW_LAST_GIT_VERSION="";' >> data/web/inc/app_info.inc.php - echo ' $MAILCOW_GIT_OWNER="mailcow";' >> data/web/inc/app_info.inc.php - echo ' $MAILCOW_GIT_REPO="mailcow-dockerized";' >> data/web/inc/app_info.inc.php - echo ' $MAILCOW_GIT_URL="https://github.com/mailcow/mailcow-dockerized";' >> data/web/inc/app_info.inc.php - echo ' $MAILCOW_GIT_COMMIT="'$mailcow_git_commit'";' >> data/web/inc/app_info.inc.php - echo ' $MAILCOW_GIT_COMMIT_DATE="'$mailcow_git_commit_date'";' >> data/web/inc/app_info.inc.php - echo ' $MAILCOW_BRANCH="'$git_branch'";' >> data/web/inc/app_info.inc.php - echo ' $MAILCOW_UPDATEDAT='$(date +%s)';' >> data/web/inc/app_info.inc.php - echo '?>' >> data/web/inc/app_info.inc.php -else - echo ' data/web/inc/app_info.inc.php - echo ' $MAILCOW_GIT_VERSION="'$mailcow_git_version'";' >> data/web/inc/app_info.inc.php - echo ' $MAILCOW_LAST_GIT_VERSION="";' >> data/web/inc/app_info.inc.php - echo ' $MAILCOW_GIT_OWNER="mailcow";' >> data/web/inc/app_info.inc.php - echo ' $MAILCOW_GIT_REPO="mailcow-dockerized";' >> data/web/inc/app_info.inc.php - echo ' $MAILCOW_GIT_URL="https://github.com/mailcow/mailcow-dockerized";' >> data/web/inc/app_info.inc.php - echo ' $MAILCOW_GIT_COMMIT="";' >> data/web/inc/app_info.inc.php - echo ' $MAILCOW_GIT_COMMIT_DATE="";' >> data/web/inc/app_info.inc.php - echo ' $MAILCOW_BRANCH="'$git_branch'";' >> data/web/inc/app_info.inc.php - echo ' $MAILCOW_UPDATEDAT='$(date +%s)';' >> data/web/inc/app_info.inc.php - echo '?>' >> data/web/inc/app_info.inc.php - echo -e "\e[33mCannot determine current git repository version...\e[0m" -fi diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..91e6063 --- /dev/null +++ b/readme.md @@ -0,0 +1,63 @@ +# Mail Stack on Coolify with OIDC Webmail + +This stack pairs **docker-mailserver** with **SnappyMail** as a modern webmail UI that can sit behind your OIDC provider. Deploy it through Coolify with this repository. + +## Components +- docker-mailserver: SMTP/IMAP server with spam/AV/Fail2Ban enabled. +- SnappyMail: lightweight webmail with OAuth2/OIDC login support. + +## Prerequisites +- DNS: `MX` record to `mail.your-domain.tld`, plus `A`/`AAAA` for both `mail.your-domain.tld` and `webmail.your-domain.tld`. +- TLS: issue certificates (Coolify can request via Traefik/Let’s Encrypt if you publish through it). +- SMTP ports 25/465/587 and IMAP 993 open to the internet. +- An OIDC provider (e.g., Authentik, Keycloak, Azure AD) with a client ready to configure. + +## Deploy with Coolify +1. **Create an application from this repo** in Coolify and choose “Docker Compose”. +2. **Volumes**: Coolify will create them from the compose file paths. Ensure the persistent paths below map to durable storage: + - `./docker-data/dms/mail-data/`, `./docker-data/dms/mail-state/`, `./docker-data/dms/mail-logs/`, `./docker-data/dms/config/` + - `./docker-data/snappymail/` +3. **Environment**: adjust `hostname` for the mailserver and expose any extra docker-mailserver envs you need (aliases, relays, etc.). +4. **Networking**: publish ports 25/465/587/993 for mail delivery. Expose port 8080 from the `webmail` service to the internet (ideally behind HTTPS via Coolify/Traefik). If you front it with Traefik, set the appropriate labels and disable the direct `ports` stanza. +5. **Deploy** the stack. Coolify will start `mailserver` and `webmail` containers. + +## Bootstrap docker-mailserver +Run these once after the containers are healthy (from the host or via Coolify shell): + +```bash +docker compose exec mailserver setup email add user@your-domain.tld "SuperSecretPassword" +docker compose exec mailserver setup alias add postmaster@your-domain.tld user@your-domain.tld +``` + +Add DNS TXT records for SPF/DKIM/DMARC using docker-mailserver guidance, then reload: + +```bash +docker compose exec mailserver setup reload +``` + +## Configure SnappyMail for IMAP/SMTP +1. Open the admin panel at `https://webmail.your-domain.tld/?admin` (default admin password is shown on first run; change it immediately). +2. Set **IMAP** host to `mailserver`, port `993`, security **SSL/TLS**. +3. Set **SMTP** host to `mailserver`, port `587`, security **STARTTLS**, authentication **Use user credentials**. +4. Save and test with one of the mail accounts you created above. + +## Enable OIDC in SnappyMail +SnappyMail supports OAuth2/OIDC providers. Configure it in the admin UI: +1. In **Admin → Domains/Auth → OAuth**, add a **Custom / Generic OIDC** provider. +2. When prompted, SnappyMail shows a **Redirect URI**; copy this exact value into your OIDC client configuration. +3. In your OIDC provider, create a public/confidential client with these basics: + - **Grant type**: Authorization Code with PKCE (preferred) or standard code. + - **Scopes**: `openid email profile`. + - **Redirect URI**: the one SnappyMail displayed. +4. Back in SnappyMail, fill the provider fields: + - **Authorization endpoint** and **Token endpoint** from your IdP. + - **UserInfo endpoint** (for email/subject mapping). + - **Client ID/Secret** matching the client you created. + - **Login attribute mapping**: map email/subject to the mailbox name (e.g., `email` → `user@your-domain.tld`). +5. Save and test “Login with ”. Successful OIDC login should drop you into the mailbox without prompting for a separate password. + +## Operating tips +- Back up `./docker-data/` regularly; it holds mail, state, and SnappyMail config. +- Use Coolify health checks to surface container issues; restart policies are already defined in the compose file. +- For HTTPS, prefer running `webmail` behind Coolify’s Traefik with automatic certificates instead of exposing port 8080 directly. +- If you rotate OIDC credentials, update them in SnappyMail admin immediately to avoid login failures.