|
|
|
@@ -5,6 +5,10 @@
|
|
|
|
|
"policy": "record",
|
|
|
|
|
"why": "people's mail: any change to how its containers are declared recreates them together in one send, and the mail is down for everyone until they are up again — a person chooses the moment (hq ADR 0242, issue 295)"
|
|
|
|
|
},
|
|
|
|
|
"unhealthy": {
|
|
|
|
|
"severity": "urgent",
|
|
|
|
|
"why": "while mailu is broken, mail is refused or stuck for everyone with a mailbox here (hq ADR 0355, issue 687)"
|
|
|
|
|
},
|
|
|
|
|
"capabilities": [
|
|
|
|
|
"container-runtime"
|
|
|
|
|
],
|
|
|
|
@@ -56,6 +60,19 @@
|
|
|
|
|
"api-token": "${dir:state}/api-token.secret"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"tools": [
|
|
|
|
|
"mailu_list_users",
|
|
|
|
|
"mailu_create_user",
|
|
|
|
|
"mailu_change_password",
|
|
|
|
|
"mailu_delete_user",
|
|
|
|
|
"mailu_list_aliases",
|
|
|
|
|
"mailu_create_alias",
|
|
|
|
|
"mailu_delete_alias",
|
|
|
|
|
"mailu_list_domains",
|
|
|
|
|
"mailu_read_mail",
|
|
|
|
|
"mailu_search_mail",
|
|
|
|
|
"mailu_health"
|
|
|
|
|
],
|
|
|
|
|
"emits": [
|
|
|
|
|
"user.created",
|
|
|
|
|
"user.deleted",
|
|
|
|
@@ -198,12 +215,6 @@
|
|
|
|
|
"class": "rebuildable",
|
|
|
|
|
"why": "certificates, issued again"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "automx",
|
|
|
|
|
"path": "${dir:data-automx}",
|
|
|
|
|
"class": "rebuildable",
|
|
|
|
|
"why": "client autoconfiguration, written again"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "fetchmail",
|
|
|
|
|
"path": "${dir:data-fetchmail}",
|
|
|
|
@@ -231,136 +242,188 @@
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"config": {
|
|
|
|
|
"domain": {
|
|
|
|
|
"type": "string",
|
|
|
|
|
"description": "The mail domain Mailu serves, such as example.org: its first mail domain, the postmaster's and the one consumers send as; the operator's, with no default (novox/hq ADR 0112).",
|
|
|
|
|
"trusted": true,
|
|
|
|
|
"required": true
|
|
|
|
|
},
|
|
|
|
|
"proxy-address": {
|
|
|
|
|
"type": "string",
|
|
|
|
|
"description": "The address of the reverse proxy in front of Mailu, whose X-Real-IP header Mailu believes; the operator's, with no default.",
|
|
|
|
|
"trusted": true,
|
|
|
|
|
"required": true
|
|
|
|
|
},
|
|
|
|
|
"sitename": {
|
|
|
|
|
"type": "string",
|
|
|
|
|
"description": "The name Mailu's web pages show for the mail service; the operator's, with no default.",
|
|
|
|
|
"trusted": true,
|
|
|
|
|
"required": true
|
|
|
|
|
},
|
|
|
|
|
"website": {
|
|
|
|
|
"type": "string",
|
|
|
|
|
"description": "The address of the website Mailu's web pages link to, as a URL; the operator's, with no default.",
|
|
|
|
|
"trusted": true,
|
|
|
|
|
"required": true
|
|
|
|
|
},
|
|
|
|
|
"url": {
|
|
|
|
|
"type": "string",
|
|
|
|
|
"description": "The address the module's tools reach Mailu's API at, as a URL; empty leaves them to MESH_MAILU_URL.",
|
|
|
|
|
"trusted": true,
|
|
|
|
|
"default": ""
|
|
|
|
|
},
|
|
|
|
|
"container": {
|
|
|
|
|
"type": "string",
|
|
|
|
|
"description": "The name of the container holding Mailu's mailboxes, which the module's tools read mail in; empty is mailu-imap.",
|
|
|
|
|
"trusted": true,
|
|
|
|
|
"default": ""
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"resources": [
|
|
|
|
|
{
|
|
|
|
|
"id": "mesh-state",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"place": "mesh"
|
|
|
|
|
"place": "mesh",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "state",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"place": "."
|
|
|
|
|
"place": ".",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "grants",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "data-automx",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700"
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "config-env",
|
|
|
|
|
"type": "file",
|
|
|
|
|
"path": "${dir:state}/mailu.env",
|
|
|
|
|
"mode": "0644",
|
|
|
|
|
"content": "ADMIN_ADDRESS=mailu-admin\nANTISPAM_ADDRESS=mailu-antispam\nANTIVIRUS_ADDRESS=mailu-antivirus\nIMAP_ADDRESS=mailu-imap\nSMTP_ADDRESS=mailu-smtp\nFRONT_ADDRESS=mailu-front\nWEBMAIL_ADDRESS=mailu-webmail\nWEBDAV_ADDRESS=mailu-webdav\nREDIS_ADDRESS=mailu-redis\nPORTS=25,80,443,465,993,995,4190,110,143,587\nDOMAIN=${setting:domain}\nHOSTNAMES=${bound:route:name-web}\nPOSTMASTER=admin\nSITENAME=${setting:sitename}\nWEBSITE=${setting:website}\nTLS_FLAVOR=letsencrypt\nSUBNET=192.168.203.0/24\nCOMPOSE_PROJECT_NAME=mailu\nANTIVIRUS=clamav\nWEBMAIL=roundcube\nWEBDAV=radicale\nFETCHMAIL_ENABLED=True\nFETCHMAIL_DELAY=600\nADMIN=true\nWEB_ADMIN=/admin\nWEB_WEBMAIL=/webmail\nWEBROOT_REDIRECT=/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=${setting:domain}\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=${bound:route:name-web}\nAMX_SMTP_PORT=587\nAMX_IMAP_ADDRESS=${bound:route:name-web}\nAMX_IMAP_PORT=143\nAMX_MAIL_DOMAINS=${setting:domain}\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=${setting:proxy-address}\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"
|
|
|
|
|
"template": "files/mailu.env"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "secret-env",
|
|
|
|
|
"type": "file",
|
|
|
|
|
"path": "${dir:state}/secret.env",
|
|
|
|
|
"mode": "0600",
|
|
|
|
|
"content": "SECRET_KEY=${secret:secret-key}\n"
|
|
|
|
|
"template": "files/secret.env"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "database-env",
|
|
|
|
|
"type": "file",
|
|
|
|
|
"path": "${dir:state}/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"
|
|
|
|
|
"template": "files/database.env"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "admin-env",
|
|
|
|
|
"type": "file",
|
|
|
|
|
"path": "${dir:state}/admin.env",
|
|
|
|
|
"mode": "0600",
|
|
|
|
|
"content": "INITIAL_ADMIN_PW=${secret:admin}\nAPI_TOKEN=${secret:api-token}\n"
|
|
|
|
|
"template": "files/admin.env"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "data-certs",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700"
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "data-data",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700"
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "data-dkim",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700"
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "data-mail",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700"
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "data-mailqueue",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0755"
|
|
|
|
|
"mode": "0755",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "data-filter",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700"
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "data-clamav",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700"
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "data-redis",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700"
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "data-webmail",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700"
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "data-dav",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700"
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "data-fetchmail",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700"
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "data-overrides-nginx",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700"
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "data-overrides-dovecot",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700"
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "data-overrides-postfix",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700"
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "data-overrides-rspamd",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700"
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "data-overrides-roundcube",
|
|
|
|
|
"type": "directory",
|
|
|
|
|
"mode": "0700"
|
|
|
|
|
"mode": "0700",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "net",
|
|
|
|
@@ -371,7 +434,7 @@
|
|
|
|
|
"id": "resolver",
|
|
|
|
|
"type": "container",
|
|
|
|
|
"name": "mailu-resolver",
|
|
|
|
|
"image": "ghcr.io/mailu/unbound@sha256:3a0fdfb364a63f4f9259526e013c1ef40f5f14de3621ce1560804b3a5909584a",
|
|
|
|
|
"image": "ghcr.io/mailu/unbound@sha256:2c037bc5c988b5c0ab7e1b6e6ffa762e14ba1e45c96281ac87f8b9be8eee8b6e",
|
|
|
|
|
"health": {
|
|
|
|
|
"kind": "runtime"
|
|
|
|
|
},
|
|
|
|
@@ -443,7 +506,12 @@
|
|
|
|
|
"name": "mailu-smtp",
|
|
|
|
|
"image": "ghcr.io/mailu/postfix@sha256:e2e49f39e53b80eac9e7a2f18d9df11edeb4914fd62dbba89b3155e8e034f62e",
|
|
|
|
|
"health": {
|
|
|
|
|
"kind": "runtime"
|
|
|
|
|
"kind": "tool",
|
|
|
|
|
"tool": "mailu_health",
|
|
|
|
|
"interval": "60s",
|
|
|
|
|
"timeout": "30s",
|
|
|
|
|
"looks": 3,
|
|
|
|
|
"grace": "120s"
|
|
|
|
|
},
|
|
|
|
|
"network": "mailu",
|
|
|
|
|
"env-file": [
|
|
|
|
@@ -560,7 +628,12 @@
|
|
|
|
|
"name": "mailu-front",
|
|
|
|
|
"image": "ghcr.io/mailu/nginx@sha256:36f98897cd1bc9d27628bbb4e04bdf60147af2ec7507d6da77f002c4f256896d",
|
|
|
|
|
"health": {
|
|
|
|
|
"kind": "runtime"
|
|
|
|
|
"kind": "exec",
|
|
|
|
|
"command": "curl -m3 -skfLo /dev/null http://127.0.0.1:10204/health && kill -0 $(cat /run/dovecot/master.pid) && python3 -c \"import smtplib; s = smtplib.SMTP('127.0.0.1', 25, timeout=5); s.ehlo('health'); s.quit()\" && openssl x509 -checkend 1209600 -noout -in /certs/letsencrypt/live/mailu/nginx-chain.pem",
|
|
|
|
|
"interval": "60s",
|
|
|
|
|
"timeout": "15s",
|
|
|
|
|
"looks": 3,
|
|
|
|
|
"grace": "120s"
|
|
|
|
|
},
|
|
|
|
|
"network": "mailu",
|
|
|
|
|
"env-file": [
|
|
|
|
@@ -591,14 +664,29 @@
|
|
|
|
|
"type": "file",
|
|
|
|
|
"path": "${dir:mesh-state}/config.json",
|
|
|
|
|
"mode": "0600",
|
|
|
|
|
"content": "{}\n",
|
|
|
|
|
"template": "files/config.json",
|
|
|
|
|
"takes-config": ["domain", "proxy-address", "sitename", "website", "url", "container"],
|
|
|
|
|
"merge": "json"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "program-automx",
|
|
|
|
|
"type": "archive",
|
|
|
|
|
"path": "${dir:state}/automx",
|
|
|
|
|
"artifact": "automx",
|
|
|
|
|
"unknown": "program"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"id": "automx",
|
|
|
|
|
"type": "container",
|
|
|
|
|
"name": "mailu-automx",
|
|
|
|
|
"artifact": "automx",
|
|
|
|
|
"artifact": "alpine",
|
|
|
|
|
"health": {
|
|
|
|
|
"kind": "http",
|
|
|
|
|
"endpoint": "autoconfig",
|
|
|
|
|
"path": "/",
|
|
|
|
|
"status": 200,
|
|
|
|
|
"body": "Show Thunderbird-style"
|
|
|
|
|
},
|
|
|
|
|
"network": "mailu",
|
|
|
|
|
"env-file": [
|
|
|
|
|
"${dir:state}/mailu.env"
|
|
|
|
@@ -607,17 +695,18 @@
|
|
|
|
|
"4243"
|
|
|
|
|
],
|
|
|
|
|
"volumes": [
|
|
|
|
|
"${dir:data-automx}:/data"
|
|
|
|
|
"${dir:state}/automx:/opt/mesh:ro"
|
|
|
|
|
],
|
|
|
|
|
"args": [
|
|
|
|
|
"/opt/mesh/automx"
|
|
|
|
|
],
|
|
|
|
|
"restart-on": [
|
|
|
|
|
"program-automx",
|
|
|
|
|
"config-env"
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"build": {
|
|
|
|
|
"on": [
|
|
|
|
|
{
|
|
|
|
|
"arg": "PYTHON_BASE",
|
|
|
|
|
"image": "python@sha256:25f3cfeaceca14921366af4d1240b56457ef46273bdb508c7b0e8f469f6fd228"
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"artifacts": [
|
|
|
|
|
{
|
|
|
|
|
"name": "code",
|
|
|
|
@@ -637,14 +726,28 @@
|
|
|
|
|
"MESH_MAILU_URL": "http://127.0.0.1:${port:8080}/api/v1",
|
|
|
|
|
"MESH_MAILU_API_KEY_FILE": "${dir:state}/api-token.secret",
|
|
|
|
|
"MESH_MAILU_IMAP_CONTAINER": "mailu-imap",
|
|
|
|
|
"MESH_MAILU_SMTP_CONTAINER": "mailu-smtp",
|
|
|
|
|
"MESH_MAILU_CONFIG_FILE": "${dir:mesh-state}/config.json",
|
|
|
|
|
"MESH_RECEIVES": "${dir:grants}/mesh.json"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"name": "automx",
|
|
|
|
|
"kind": "image",
|
|
|
|
|
"from": "automx/Dockerfile"
|
|
|
|
|
"kind": "bundle",
|
|
|
|
|
"language": "go",
|
|
|
|
|
"system": "alpine",
|
|
|
|
|
"from": "cmd/automx",
|
|
|
|
|
"binary": "automx"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"name": "alpine",
|
|
|
|
|
"kind": "upstream",
|
|
|
|
|
"from": "alpine@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"name": "files",
|
|
|
|
|
"kind": "archive",
|
|
|
|
|
"from": "files"
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
@@ -661,7 +764,7 @@
|
|
|
|
|
"serves": {
|
|
|
|
|
"smtp": {
|
|
|
|
|
"port": 587,
|
|
|
|
|
"domain": "${setting:domain}"
|
|
|
|
|
"domain": "${config:domain}"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"receives": {
|
|
|
|
@@ -673,7 +776,7 @@
|
|
|
|
|
"jails": [
|
|
|
|
|
{
|
|
|
|
|
"name": "mailu-front",
|
|
|
|
|
"failregex": "^.*(?:imap|pop3|submission|managesieve)-login: .*\\(auth failed, \\d+ attempts(?: in \\d+ secs)?\\):.*rip=<HOST>(?:,|$)",
|
|
|
|
|
"failregex": "^.*(?:imap|pop3|submission|managesieve)-login: .*\\(auth failed, \\d+ attempts(?: in \\d+ secs)?\\):.*rip=<HOST>(?:,|$)\n ^.*client login failed: \"AUTH not supported\" while in http auth state, client: <HOST>, server: \\S+:25,",
|
|
|
|
|
"jail": "backend = systemd\njournalmatch = CONTAINER_NAME=mailu-front\nport = smtp,submission,submissions,imap,imaps,pop3,pop3s\nmaxretry = 3\nfindtime = 1d\nbantime = 1d"
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|