{ "module": "mailu", "version": "1", "capabilities": [ "container-runtime" ], "requires": [ "postgres-database", "route", "secret" ], "contributes": { "postgres-database": { "name": "mailu" }, "route": { "web": { "label": "mail", "port": 7443, "scheme": "https", "insecure": true }, "acme": { "label": "mail", "path": "/.well-known/acme-challenge", "port": 7080, "priority": 100 }, "autoconfig": { "label": "autoconfig", "port": 4243 }, "autodiscover": { "label": "autodiscover", "port": 4243 }, "automx": { "label": "automx", "port": 4243 } } }, "binds": { "postgres-database": "/var/lib/mailu/database.json", "route": "/var/lib/mailu/route.json" }, "secrets": { "postgres-database": "/var/lib/mailu/database.secret", "secret": { "secret-key": "/var/lib/mailu/secret-key.secret", "admin": "/var/lib/mailu/admin.secret", "api-token": "/var/lib/mailu/api-token.secret" } }, "emits": [ "module.mailu.user.created", "module.mailu.user.deleted", "module.mailu.alias.created", "module.mailu.alias.deleted" ], "listens": [ { "port": 25, "protocol": "tcp", "from": "anywhere", "why": "mail from other mail servers", "fixed": true }, { "port": 110, "protocol": "tcp", "from": "anywhere", "why": "POP3, kept at parity with the predecessor; pruning legacy protocols is its own deliberate change", "fixed": true }, { "port": 143, "protocol": "tcp", "from": "anywhere", "why": "IMAP with STARTTLS, kept at parity", "fixed": true }, { "port": 465, "protocol": "tcp", "from": "anywhere", "why": "submission over TLS", "fixed": true }, { "port": 587, "protocol": "tcp", "from": "anywhere", "why": "submission; also what the smtp provision serves consumers", "fixed": true }, { "port": 993, "protocol": "tcp", "from": "anywhere", "why": "IMAP over TLS", "fixed": true }, { "port": 995, "protocol": "tcp", "from": "anywhere", "why": "POP3 over TLS, kept at parity", "fixed": true }, { "port": 7080, "protocol": "tcp", "from": "mesh", "why": "the web front over http; only the ACME HTTP-01 passthrough is routed here \u2014 everything else 301s to https and would loop a proxy" }, { "port": 7443, "protocol": "tcp", "from": "mesh", "why": "the web front over its own TLS (admin, webmail, API); the public name mail.novox.be is a route grant reaching it here" }, { "port": 4243, "protocol": "tcp", "from": "mesh", "why": "automx: mail client autoconfiguration; autoconfig/autodiscover/automx.novox.be are route grants reaching it here" } ], "own-secrets": { "broker": "/var/lib/mesh/mailu/broker" }, "resources": [ { "id": "mesh-state", "type": "directory", "path": "/var/lib/mesh/mailu", "mode": "0700" }, { "id": "state", "type": "directory", "path": "/var/lib/mailu", "mode": "0700" }, { "id": "grants", "type": "directory", "path": "/var/lib/mailu/grants", "mode": "0700" }, { "id": "data-automx", "type": "directory", "path": "/services/mailu/data/automx", "mode": "0700" }, { "id": "config-env", "type": "file", "path": "/var/lib/mailu/mailu.env", "mode": "0644", "content": "PORTS=25,80,443,465,993,995,4190,110,143,587\nDOMAIN=novox.be\nHOSTNAMES=mail.novox.be\nPOSTMASTER=admin\nSITENAME=Novox\nWEBSITE=https://novox.be\nTLS_FLAVOR=letsencrypt\nSUBNET=192.168.203.0/24\nCOMPOSE_PROJECT_NAME=mailu\nHOST_ADMIN=mailu-admin\nHOST_ANTISPAM=mailu-antispam:11332\nHOST_IMAP=mailu-imap\nHOST_SMTP=mailu-smtp\nHOST_WEBMAIL=mailu-webmail\nHOST_WEBDAV=mailu-webdav:5232\nHOST_REDIS=mailu-redis\nHOST_FRONT=mailu-front\nREDIS_ADDRESS=mailu-redis\nANTIVIRUS=clamav\nWEBMAIL=roundcube\nWEBDAV=radicale\nFETCHMAIL_ENABLED=True\nFETCHMAIL_DELAY=600\nADMIN=true\nWEB_ADMIN=/admin\nWEB_WEBMAIL=/webmail\nWEBROOT_REDIRECT=/webmail\nWEBMAIL_ADDRESS=webmail\nAPI=true\nWEB_API=/api\nAUTH_RATELIMIT_IP=6000/hour\nAUTH_RATELIMIT_USER=1000/day\nCREDENTIAL_ROUNDS=12\nPASSWORD_SCHEME=PBKDF2\nDISABLE_STATISTICS=True\nMESSAGE_SIZE_LIMIT=50000000\nMESSAGE_RATELIMIT=200/day\nRECIPIENT_DELIMITER=+\nPOSTFIX_MYNETWORKS=127.0.0.0/8 [::1]/128\nRELAYNETS=\nRELAYHOST=\nREJECT_UNLISTED_RECIPIENT=\nDB_FLAVOR=postgresql\nINITIAL_ADMIN_ACCOUNT=admin\nINITIAL_ADMIN_DOMAIN=novox.be\nINITIAL_ADMIN_MODE=ifmissing\nSMTP_PORT=25\nSMTPS_PORT=465\nSUBMISSION_PORT=587\nPOP3_PORT=110\nPOP3S_PORT=995\nIMAP_PORT=143\nIMAPS_PORT=993\nHTTP_PORT=7080\nHTTPS_PORT=7443\nAUTOMX_PORT=4243\nAMX_SMTP_ADDRESS=mail.novox.be\nAMX_SMTP_PORT=587\nAMX_IMAP_ADDRESS=mail.novox.be\nAMX_IMAP_PORT=143\nAMX_MAIL_DOMAINS=novox.be\nDMARC_RUA=admin\nDMARC_RUF=admin\nLETSENCRYPT_SHORTCHAIN=True\nTZ=Etc/UTC\nLOG_LEVEL=INFO\nWELCOME=false\nREAL_IP_HEADER=X-Real-IP\nREAL_IP_FROM=142.132.152.141\nCOMPRESSION=\nCOMPRESS_LEVEL=\nCOMPRESSION_LEVEL=\nBIND_ADDRESS4=127.0.0.1\nBIND_ADDRESS6=::1\nMAILU_VERSION=1.9\nDOCKER_ORG=mailu\nDOCKER_PREFIX=\nWELCOME_SUBJECT=Welcome to your new email account\nWELCOME_BODY=Welcome to your new email account, if you can read this, then it is configured properly!\n" }, { "id": "secret-env", "type": "file", "path": "/var/lib/mailu/secret.env", "mode": "0600", "content": "SECRET_KEY=${secret:secret-key}\n" }, { "id": "database-env", "type": "file", "path": "/var/lib/mailu/database.env", "mode": "0600", "content": "DB_FLAVOR=postgresql\nDB_HOST=${bound:postgres-database:at}:${bound:postgres-database:port}\nDB_USER=${bound:postgres-database:as}\nDB_NAME=${bound:postgres-database:as}\nDB_PW=${secret:postgres-database}\n" }, { "id": "admin-env", "type": "file", "path": "/var/lib/mailu/admin.env", "mode": "0600", "content": "INITIAL_ADMIN_PW=${secret:admin}\nAPI_TOKEN=${secret:api-token}\n" }, { "id": "data-certs", "type": "directory", "path": "/services/mailu/data/certs", "mode": "0700" }, { "id": "data-data", "type": "directory", "path": "/services/mailu/data/data", "mode": "0700" }, { "id": "data-dkim", "type": "directory", "path": "/services/mailu/data/dkim", "mode": "0700" }, { "id": "data-mail", "type": "directory", "path": "/services/mailu/data/mail", "mode": "0700" }, { "id": "data-mailqueue", "type": "directory", "path": "/services/mailu/data/mailqueue", "mode": "0700" }, { "id": "data-filter", "type": "directory", "path": "/services/mailu/data/filter", "mode": "0700" }, { "id": "data-clamav", "type": "directory", "path": "/services/mailu/data/clamav", "mode": "0700" }, { "id": "data-redis", "type": "directory", "path": "/services/mailu/data/redis", "mode": "0700" }, { "id": "data-webmail", "type": "directory", "path": "/services/mailu/data/webmail", "mode": "0700" }, { "id": "data-dav", "type": "directory", "path": "/services/mailu/data/dav", "mode": "0700" }, { "id": "data-fetchmail", "type": "directory", "path": "/services/mailu/data/data/fetchmail", "mode": "0700" }, { "id": "data-overrides-nginx", "type": "directory", "path": "/services/mailu/data/overrides/nginx", "mode": "0700" }, { "id": "data-overrides-dovecot", "type": "directory", "path": "/services/mailu/data/overrides/dovecot", "mode": "0700" }, { "id": "data-overrides-postfix", "type": "directory", "path": "/services/mailu/data/overrides/postfix", "mode": "0700" }, { "id": "data-overrides-rspamd", "type": "directory", "path": "/services/mailu/data/overrides/rspamd", "mode": "0700" }, { "id": "data-overrides-roundcube", "type": "directory", "path": "/services/mailu/data/overrides/roundcube", "mode": "0700" }, { "id": "net", "type": "network", "name": "mailu" }, { "id": "resolver", "type": "container", "name": "mailu-resolver", "image": "ghcr.io/mailu/unbound@sha256:3a0fdfb364a63f4f9259526e013c1ef40f5f14de3621ce1560804b3a5909584a", "network": "mailu", "env-file": [ "/var/lib/mailu/mailu.env", "/var/lib/mailu/secret.env" ], "secrets-in-environment": "mailu-admin honours SECRET_KEY_FILE, DB_PW_FILE and API_TOKEN_FILE (configuration.py) but INITIAL_ADMIN_PW is env-only (start.py); the remaining containers' need for SECRET_KEY is unverified" }, { "id": "redis", "type": "container", "name": "mailu-redis", "image": "redis@sha256:4bed291aa5efb9f0d77b76ff7d4ab71eee410962965d052552db1fb80576431d", "network": "mailu", "volumes": [ "/services/mailu/data/redis:/data" ] }, { "id": "admin", "type": "container", "name": "mailu-admin", "image": "ghcr.io/mailu/admin@sha256:6dbfdadc4a9590dcb7652357b505200115b689b74008653bbf369e4599a3be5a", "network": "mailu", "env-file": [ "/var/lib/mailu/mailu.env", "/var/lib/mailu/secret.env", "/var/lib/mailu/database.env", "/var/lib/mailu/admin.env" ], "volumes": [ "/services/mailu/data/data:/data", "/services/mailu/data/dkim:/dkim" ], "secrets-in-environment": "mailu-admin honours SECRET_KEY_FILE, DB_PW_FILE and API_TOKEN_FILE (configuration.py) but INITIAL_ADMIN_PW is env-only (start.py); the remaining containers' need for SECRET_KEY is unverified" }, { "id": "imap", "type": "container", "name": "mailu-imap", "image": "ghcr.io/mailu/dovecot@sha256:7f0ed5db996fbdc00adc5c5e38a08492e04f7eb4a9fbd66a03aa9a28ddf23993", "network": "mailu", "env-file": [ "/var/lib/mailu/mailu.env" ], "volumes": [ "/services/mailu/data/mail:/mail", "/services/mailu/data/overrides/dovecot:/overrides:ro" ] }, { "id": "smtp", "type": "container", "name": "mailu-smtp", "image": "ghcr.io/mailu/postfix@sha256:e2e49f39e53b80eac9e7a2f18d9df11edeb4914fd62dbba89b3155e8e034f62e", "network": "mailu", "env-file": [ "/var/lib/mailu/mailu.env" ], "volumes": [ "/services/mailu/data/mailqueue:/queue", "/services/mailu/data/overrides/postfix:/overrides:ro" ] }, { "id": "antispam", "type": "container", "name": "mailu-antispam", "image": "ghcr.io/mailu/rspamd@sha256:ff3666d8a61f17d309c5c6f6bcf4d40470b82299ca706ac650301175bb1a079d", "network": "mailu", "env-file": [ "/var/lib/mailu/mailu.env" ], "volumes": [ "/services/mailu/data/filter:/var/lib/rspamd", "/services/mailu/data/overrides/rspamd:/etc/rspamd/override.d:ro" ] }, { "id": "antivirus", "type": "container", "name": "mailu-antivirus", "image": "clamav/clamav-debian@sha256:b12ef8fefddbba7d88de59bea8a32622f365339154adf02d38fd089112e6745a", "network": "mailu", "volumes": [ "/services/mailu/data/clamav:/var/lib/clamav" ] }, { "id": "webmail", "type": "container", "name": "mailu-webmail", "image": "ghcr.io/mailu/webmail@sha256:bdbee44cdb05a4658f0e3b62cc448de55ca8f8aea172279fda594826144c04f6", "network": "mailu", "env-file": [ "/var/lib/mailu/mailu.env", "/var/lib/mailu/secret.env" ], "volumes": [ "/services/mailu/data/webmail:/data", "/services/mailu/data/overrides/roundcube:/overrides:ro" ], "secrets-in-environment": "mailu-admin honours SECRET_KEY_FILE, DB_PW_FILE and API_TOKEN_FILE (configuration.py) but INITIAL_ADMIN_PW is env-only (start.py); the remaining containers' need for SECRET_KEY is unverified" }, { "id": "webdav", "type": "container", "name": "mailu-webdav", "image": "ghcr.io/mailu/radicale@sha256:690ed6edf189dfef100a5a8b37c195ebf5d9241ac5f23f2f44b8b7b75726e3de", "network": "mailu", "env-file": [ "/var/lib/mailu/mailu.env", "/var/lib/mailu/secret.env" ], "volumes": [ "/services/mailu/data/dav:/data" ], "secrets-in-environment": "mailu-admin honours SECRET_KEY_FILE, DB_PW_FILE and API_TOKEN_FILE (configuration.py) but INITIAL_ADMIN_PW is env-only (start.py); the remaining containers' need for SECRET_KEY is unverified" }, { "id": "fetchmail", "type": "container", "name": "mailu-fetchmail", "image": "ghcr.io/mailu/fetchmail@sha256:f881c8412d3bbe73d638469b48321558d6403a9d45bfa043c1e52c752103d42d", "network": "mailu", "env-file": [ "/var/lib/mailu/mailu.env", "/var/lib/mailu/secret.env" ], "volumes": [ "/services/mailu/data/data/fetchmail:/data" ], "secrets-in-environment": "mailu-admin honours SECRET_KEY_FILE, DB_PW_FILE and API_TOKEN_FILE (configuration.py) but INITIAL_ADMIN_PW is env-only (start.py); the remaining containers' need for SECRET_KEY is unverified" }, { "id": "front", "type": "container", "name": "mailu-front", "image": "ghcr.io/mailu/nginx@sha256:36f98897cd1bc9d27628bbb4e04bdf60147af2ec7507d6da77f002c4f256896d", "network": "mailu", "env-file": [ "/var/lib/mailu/mailu.env" ], "ports": [ "25", "110", "143", "465", "587", "993", "995", "7080:80", "7443:443" ], "volumes": [ "/services/mailu/data/certs:/certs", "/services/mailu/data/overrides/nginx:/overrides:ro" ] }, { "id": "runtime-config", "type": "file", "path": "/var/lib/mesh/mailu/config.json", "mode": "0600", "content": "{}\n", "merge": "json" }, { "id": "runtime", "type": "container", "name": "mesh-mailu", "network": "mailu", "volumes": [ "/var/lib/mesh/mailu/broker:/run/secrets/broker:ro", "/var/lib/mailu/api-token.secret:/run/secrets/api-token:ro", "/var/lib/mailu/grants:/var/lib/mailu/grants:ro", "/var/lib/mesh/mailu/config.json:/run/config/config.json:ro", "/var/run/docker.sock:/var/run/docker.sock" ], "env": { "MESH_BROKER_FILE": "/run/secrets/broker", "MESH_MAILU_URL": "http://mailu-admin/api/v1", "MESH_MAILU_API_KEY_FILE": "/run/secrets/api-token", "MESH_MAILU_IMAP_CONTAINER": "mailu-imap", "MESH_MAILU_CONFIG_FILE": "/run/config/config.json", "MESH_MAILU_DOMAIN": "novox.be", "MESH_RECEIVES": "/var/lib/mailu/grants/mesh.json" }, "restart-on": [ "runtime-config" ], "artifact": "runtime" }, { "id": "automx", "type": "container", "name": "mailu-automx", "artifact": "automx", "network": "mailu", "env-file": [ "/var/lib/mailu/mailu.env" ], "ports": [ "4243" ], "volumes": [ "/services/mailu/data/automx:/data" ] } ], "build": { "on": [ { "arg": "BUILD_BASE", "module": "mesh-tools", "artifact": "build" }, { "arg": "RUNTIME_BASE", "module": "mesh-tools", "artifact": "runtime" }, { "arg": "PYTHON_BASE", "image": "python@sha256:25f3cfeaceca14921366af4d1240b56457ef46273bdb508c7b0e8f469f6fd228" } ], "artifacts": [ { "name": "runtime", "kind": "image", "from": "Dockerfile" }, { "name": "automx", "kind": "image", "from": "automx/Dockerfile" } ] }, "provides": [ { "name": "smtp", "scope": "mesh" } ], "serves": { "smtp": { "port": 587, "domain": "novox.be" } }, "receives": { "smtp": "/var/lib/mailu/grants/mesh.json" }, "grants": { "smtp": "/var/lib/mailu/grants" } }