Last active
December 20, 2025 01:30
-
-
Save prem-prakash/17359f8a097f5bb31045891c2c4b80ec to your computer and use it in GitHub Desktop.
Stalwart in Coolify
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| services: | |
| stalwart: | |
| image: 'stalwartlabs/stalwart:latest' | |
| container_name: stalwart | |
| networks: | |
| - coolify | |
| ports: | |
| - '25:25' | |
| - '587:587' | |
| - '465:465' | |
| - '143:143' | |
| - '993:993' | |
| - '4190:4190' | |
| - '110:110' | |
| - '995:995' | |
| volumes: | |
| - 'stalwart_data:/opt/stalwart' | |
| - '/etc/localtime:/etc/localtime:ro' | |
| restart: unless-stopped | |
| labels: | |
| - traefik.enable=true | |
| - traefik.http.routers.stalwart-admin.rule=Host(`admin-mail.YOUR_DOMAIN.com`) | |
| - traefik.http.routers.stalwart-admin.entrypoints=https | |
| - traefik.http.routers.stalwart-admin.tls=true | |
| - traefik.http.services.stalwart-admin.loadbalancer.server.port=8080 | |
| volumes: | |
| stalwart_data: null | |
| networks: | |
| coolify: | |
| external: true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| authentication.fallback-admin.secret = "XXXXX" | |
| authentication.fallback-admin.user = "admin" | |
| directory.internal.store = "rocksdb" | |
| directory.internal.type = "internal" | |
| server.hostname = "mail.YOUR_DOMAIN.com" | |
| server.listener.http.bind = "[::]:8080" | |
| server.listener.http.protocol = "http" | |
| server.listener.https.bind = "[::]:443" | |
| server.listener.https.protocol = "http" | |
| server.listener.https.tls.implicit = true | |
| server.listener.imap.bind = "[::]:143" | |
| server.listener.imap.protocol = "imap" | |
| server.listener.imap.proxy.override = false | |
| server.listener.imap.socket.override = false | |
| server.listener.imap.tls.implicit = false | |
| server.listener.imap.tls.override = false | |
| server.listener.imaptls.bind = "[::]:993" | |
| server.listener.imaptls.protocol = "imap" | |
| server.listener.imaptls.tls.implicit = true | |
| server.listener.pop3.bind = "[::]:110" | |
| server.listener.pop3.protocol = "pop3" | |
| server.listener.pop3s.bind = "[::]:995" | |
| server.listener.pop3s.protocol = "pop3" | |
| server.listener.pop3s.tls.implicit = true | |
| server.listener.sieve.bind = "[::]:4190" | |
| server.listener.sieve.protocol = "managesieve" | |
| server.listener.smtp.bind = "[::]:25" | |
| server.listener.smtp.protocol = "smtp" | |
| server.listener.submission.bind = "[::]:587" | |
| server.listener.submission.protocol = "smtp" | |
| server.listener.submission.proxy.override = false | |
| server.listener.submission.socket.override = false | |
| server.listener.submission.tls.implicit = false | |
| server.listener.submission.tls.override = false | |
| server.listener.submissions.bind = "[::]:465" | |
| server.listener.submissions.protocol = "smtp" | |
| server.listener.submissions.tls.implicit = true | |
| server.max-connections = 8192 | |
| server.socket.backlog = 1024 | |
| server.socket.nodelay = true | |
| server.socket.reuse-addr = true | |
| server.socket.reuse-port = true | |
| storage.blob = "rocksdb" | |
| storage.data = "rocksdb" | |
| storage.directory = "internal" | |
| storage.fts = "rocksdb" | |
| storage.lookup = "rocksdb" | |
| store.rocksdb.compression = "lz4" | |
| store.rocksdb.path = "/opt/stalwart/data" | |
| store.rocksdb.type = "rocksdb" | |
| tracer.log.ansi = false | |
| tracer.log.enable = true | |
| tracer.log.level = "info" | |
| tracer.log.path = "/opt/stalwart/logs" | |
| tracer.log.prefix = "stalwart.log" | |
| tracer.log.rotate = "daily" | |
| tracer.log.type = "log" | |
| # this below will output logs to the docker output | |
| [tracer.console] | |
| enable = true | |
| type = "console" | |
| level = "trace" | |
| ansi = false | |
| # configure acme provider | |
| # Instead of adding this to the config I did this manually in the interface | |
| # In order to reload generated certificates I needed to run: | |
| # # stalwart-cli -u https://admin-mail.YOUR_DOMAIN.com server reload-certificates | |
| [acme."letsencrypt"] | |
| directory = "https://acme-v02.api.letsencrypt.org/directory" | |
| challenge = "dns-01" | |
| provider = "cloudflare" | |
| secret = "YOUR_CLOUDFLARE_TOKEN" | |
| domains = ["*.YOUR_DOMAIN.com", "YOUR_DOMAIN.com"] # wildcard covers mail/admin-mail | |
| cache = "%{BASE_PATH}%/etc/acme-letsencrypt" | |
| renew-before = "30d" | |
| default = true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| In `Domains` in the service config put: https://admin-mail.YOUR_DOMAIN.com:8080 | |
| In Stalwart you need to configure an ACME Provider (Server -> TLS -> Acme Providers) | |
| - directory id: any name | |
| - challenge type: dns-01 | |
| - contact email: any working email | |
| - subject name: mail.YOUR_DOMAIN.com | |
| - DNS Provider: Cloudflare | |
| - Secret: Cloudflare API Token Scoped to your domain YOUR_DOMAIN.com, with Edit DNS | |
| After changing this you usually will need to restart the docker service and run: | |
| # stalwart-cli -u https://admin-mail.YOUR_DOMAIN.com server reload-certificates |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment