novox/hq 04-ISSUES/026. Four modules mounted fourteen host paths that no resource declared — the mail spool, the databases, the object store's data. Each would be created by the container runtime as root, with a mode nobody chose, so `owner` and `mode` went unapplied on exactly the directories that matter. The worse half: a directory the mesh declared and no longer wants is kept rather than removed when it holds anything the mesh did not put there. That rule is the answer to what happens to data when a module goes away, and it is written in terms of declared directories. An undeclared one is not covered. So the one rule guarding against data loss reached the configuration directories, which are cheap to lose, and missed the data directories, which are why the rule exists. The cause is worth naming. These manifests were written by reading the arrangement being replaced and carrying its compose files across — service, image, ports, volumes, environment. The container shape can express all of that, which is what made the transliteration feel like progress. A shape that can express a compose file gets filled in like one, and a volume line borrowed from compose declares no owner, no mode and no intent. Declared parent-first, because the host applies in the order written and does not sort. The check is mechanical now, because a person comparing volumes against directories by hand is the process that produced this. Still open, and bigger: whether these paths are where a module's data should live at all. They were inherited whole, and they decide what a person backs up.
276 lines
6.8 KiB
JSON
276 lines
6.8 KiB
JSON
{
|
|
"module": "mailu",
|
|
"version": "1",
|
|
"capabilities": [
|
|
"container-runtime"
|
|
],
|
|
"listens": [
|
|
{
|
|
"port": 25,
|
|
"protocol": "tcp",
|
|
"from": "anywhere",
|
|
"why": "mail from other mail servers"
|
|
},
|
|
{
|
|
"port": 465,
|
|
"protocol": "tcp",
|
|
"from": "anywhere",
|
|
"why": "submission over TLS"
|
|
},
|
|
{
|
|
"port": 587,
|
|
"protocol": "tcp",
|
|
"from": "anywhere",
|
|
"why": "submission"
|
|
},
|
|
{
|
|
"port": 993,
|
|
"protocol": "tcp",
|
|
"from": "anywhere",
|
|
"why": "IMAP over TLS"
|
|
},
|
|
{
|
|
"port": 7080,
|
|
"protocol": "tcp",
|
|
"from": "mesh",
|
|
"why": "the web interface, behind a proxy"
|
|
}
|
|
],
|
|
"own-secrets": {
|
|
"secret-key": "/var/lib/mailu/secret-key.secret",
|
|
"database": "/var/lib/mailu/database.secret",
|
|
"admin": "/var/lib/mailu/admin.secret"
|
|
},
|
|
"resources": [
|
|
{
|
|
"id": "state",
|
|
"type": "directory",
|
|
"path": "/var/lib/mailu",
|
|
"mode": "0700"
|
|
},
|
|
{
|
|
"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": "POSTGRES_USER=mailu\nPOSTGRES_DB=mailu\nPOSTGRES_PASSWORD=${secret:database}\nDB_USER=mailu\nDB_NAME=mailu\nDB_PW=${secret:database}\n"
|
|
},
|
|
{
|
|
"id": "admin-env",
|
|
"type": "file",
|
|
"path": "/var/lib/mailu/admin.env",
|
|
"mode": "0600",
|
|
"content": "INITIAL_ADMIN_PW=${secret:admin}\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-filter",
|
|
"type": "directory",
|
|
"path": "/services/mailu/data/filter",
|
|
"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-redis",
|
|
"type": "directory",
|
|
"path": "/services/mailu/data/redis",
|
|
"mode": "0700"
|
|
},
|
|
{
|
|
"id": "data-webmail",
|
|
"type": "directory",
|
|
"path": "/services/mailu/data/webmail",
|
|
"mode": "0700"
|
|
},
|
|
{
|
|
"id": "data-dovecot",
|
|
"type": "directory",
|
|
"path": "/services/mailu/data/overrides/dovecot",
|
|
"mode": "0700"
|
|
},
|
|
{
|
|
"id": "data-nginx",
|
|
"type": "directory",
|
|
"path": "/services/mailu/data/overrides/nginx",
|
|
"mode": "0700"
|
|
},
|
|
{
|
|
"id": "data-pgdata",
|
|
"type": "directory",
|
|
"path": "/services/mailu/data/data/psql_admindb/pgdata",
|
|
"mode": "0700"
|
|
},
|
|
{
|
|
"id": "net",
|
|
"type": "network",
|
|
"name": "mailu"
|
|
},
|
|
{
|
|
"id": "resolver",
|
|
"type": "container",
|
|
"name": "mailu-resolver",
|
|
"image": "ghcr.io/mailu/unbound@sha256:142aaad82ad1b0d5b59a5f1303778dba61a3e0a540f5d969c48862bcc99f6f5d",
|
|
"network": "mailu",
|
|
"env-file": [
|
|
"/var/lib/mailu/secret.env"
|
|
]
|
|
},
|
|
{
|
|
"id": "redis",
|
|
"type": "container",
|
|
"name": "mailu-redis",
|
|
"image": "redis@sha256:1db42ccef14898aa29bae778452d567534b59c107129cbc1163fb552de184d3c",
|
|
"network": "mailu",
|
|
"volumes": [
|
|
"/services/mailu/data/redis:/data"
|
|
]
|
|
},
|
|
{
|
|
"id": "admindb",
|
|
"type": "container",
|
|
"name": "mailu-admindb",
|
|
"image": "postgres@sha256:7456ef82e5f5bc43d997f4781bbd7c0d6389bff397564649a356e206ba473aee",
|
|
"network": "mailu",
|
|
"env": {
|
|
"PGDATA": "/var/lib/postgresql/data/pgdata"
|
|
},
|
|
"env-file": [
|
|
"/var/lib/mailu/database.env"
|
|
],
|
|
"volumes": [
|
|
"/services/mailu/data/data/psql_admindb/pgdata:/var/lib/postgresql/data/pgdata"
|
|
]
|
|
},
|
|
{
|
|
"id": "admin",
|
|
"type": "container",
|
|
"name": "mailu-admin",
|
|
"image": "ghcr.io/mailu/admin@sha256:dcac20e9cbdad560faef9653b1b5ac0d9266f4098dc00f0e7f0d35f4e70ed8f1",
|
|
"network": "mailu",
|
|
"env-file": [
|
|
"/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"
|
|
]
|
|
},
|
|
{
|
|
"id": "imap",
|
|
"type": "container",
|
|
"name": "mailu-imap",
|
|
"image": "ghcr.io/mailu/dovecot@sha256:46d18ba51032be8ebd6841aa49c1ef8762c729038c5fd86a081b5b884d478af9",
|
|
"network": "mailu",
|
|
"env-file": [
|
|
"/var/lib/mailu/secret.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:bbf882880f68849511710b35237a933f3fe80c4b28bf48ff20205dbd1f1433d7",
|
|
"network": "mailu",
|
|
"env-file": [
|
|
"/var/lib/mailu/secret.env"
|
|
],
|
|
"volumes": [
|
|
"/services/mailu/data/mailqueue:/queue"
|
|
]
|
|
},
|
|
{
|
|
"id": "antispam",
|
|
"type": "container",
|
|
"name": "mailu-antispam",
|
|
"image": "ghcr.io/mailu/rspamd@sha256:e87ab93dd252cc69499caa5317dd10d445fd4291a7ecf6bca09793c7d475a0c8",
|
|
"network": "mailu",
|
|
"env-file": [
|
|
"/var/lib/mailu/secret.env"
|
|
],
|
|
"volumes": [
|
|
"/services/mailu/data/filter:/var/lib/rspamd"
|
|
]
|
|
},
|
|
{
|
|
"id": "webmail",
|
|
"type": "container",
|
|
"name": "mailu-webmail",
|
|
"image": "ghcr.io/mailu/webmail@sha256:076b720fc766e58a97321cdb700e887c2008d6d323685fe59f323088333059dc",
|
|
"network": "mailu",
|
|
"env-file": [
|
|
"/var/lib/mailu/secret.env"
|
|
],
|
|
"volumes": [
|
|
"/services/mailu/data/webmail:/data"
|
|
]
|
|
},
|
|
{
|
|
"id": "front",
|
|
"type": "container",
|
|
"name": "mailu-front",
|
|
"image": "ghcr.io/mailu/nginx@sha256:09f28ab6d36367fcacc7994f7021f132ac845bdc05f04bf80906102d11aaa057",
|
|
"network": "mailu",
|
|
"env-file": [
|
|
"/var/lib/mailu/secret.env"
|
|
],
|
|
"ports": [
|
|
"25:25",
|
|
"465:465",
|
|
"587:587",
|
|
"993:993",
|
|
"7080:80"
|
|
],
|
|
"volumes": [
|
|
"/services/mailu/data/certs:/certs",
|
|
"/services/mailu/data/overrides/nginx:/overrides:ro"
|
|
],
|
|
"restart-on": [
|
|
"imap",
|
|
"smtp",
|
|
"admin"
|
|
]
|
|
}
|
|
]
|
|
}
|