Compare commits

...
3 Commits
Author SHA1 Message Date
jschoubben 80d9e9a7e7 portainer: publish its software ports; the machine side is the mesh's to assign
9090:9000 and 9443:9443 were the predecessor's machine numbers written into the
definition. The manifest now says 9000 and 9443 and the mesh assigns the
machine ports on each node (the portainer slice of #173, which is stale).
2026-09-30 20:54:29 +02:00
jschoubben e0c5acd547 Merge pull request 'No definition names this installation' (#188) from feat/a-definition-names-no-installation into main 2026-09-30 18:49:38 +00:00
jschoubben 3476f1ebec No definition names this installation
keycloak, minio and n8n are told their names from their route bindings; mailu takes its domain, site
name, website and proxy address as settings and its front's name from its route, and the provisioner
reads the domain from the merged config; builder and route-proxy package the controller from the git
seat; the applications built outside the mesh say so per container; matrix says which of the world's
servers it means; the site module is named website, and the why prose no longer names a name (novox/hq
ADR 0155, issues 122 and 134). module check passes over all 77.
2026-09-30 20:49:21 +02:00
16 changed files with 111 additions and 42 deletions
+2 -1
View File
@@ -69,7 +69,8 @@
"kind": "image", "kind": "image",
"from": "Dockerfile", "from": "Dockerfile",
"context": { "context": {
"repository": "https://git.novox.be/novox/mesh-controller.git", "seat": "git",
"repository": "novox/mesh-controller",
"ref": "main" "ref": "main"
} }
} }
+5 -2
View File
@@ -27,7 +27,7 @@
"port": 35621, "port": 35621,
"protocol": "tcp", "protocol": "tcp",
"from": "mesh", "from": "mesh",
"why": "the de-spiegel site and its /contact endpoint over http; the public name de-spiegel.novox.be is a route grant, and route-proxy reaches it on this published port" "why": "the de-spiegel site and its /contact endpoint over http; its public name is a route grant, and route-proxy reaches it on this published port"
} }
], ],
"resources": [ "resources": [
@@ -61,7 +61,10 @@
"ports": [ "ports": [
"35621" "35621"
], ],
"secrets-in-environment": "the application's own code reads SMTP_AUTH_USER/PASS from the environment (de-spiegel server/index.js); converting is that repository's change" "secrets-in-environment": "the application's own code reads SMTP_AUTH_USER/PASS from the environment (de-spiegel server/index.js); converting is that repository's change",
"names-on-purpose": {
"registry-api.novox.be": "built outside the mesh, from the application's own repository, and pulled from the registry that built it; moves when that repository is a build source on the git seat (novox/hq ADR 0155, issue 122)"
}
} }
] ]
} }
+8 -2
View File
@@ -87,7 +87,10 @@
}, },
"ports": [ "ports": [
"80" "80"
] ],
"names-on-purpose": {
"registry-api.novox.be": "built outside the mesh, from the application's own repository, and pulled from the registry that built it; moves when that repository is a build source on the git seat (novox/hq ADR 0155, issue 122)"
}
}, },
{ {
"id": "api", "id": "api",
@@ -105,7 +108,10 @@
"ports": [ "ports": [
"9000" "9000"
], ],
"secrets-in-environment": "the application's own code reads MONGO_URL and MINIO_SECRET from the environment (invoicing-app server/src/config.js); converting is that repository's change" "secrets-in-environment": "the application's own code reads MONGO_URL and MINIO_SECRET from the environment (invoicing-app server/src/config.js); converting is that repository's change",
"names-on-purpose": {
"registry-api.novox.be": "built outside the mesh, from the application's own repository, and pulled from the registry that built it; moves when that repository is a build source on the git seat (novox/hq ADR 0155, issue 122)"
}
} }
] ]
} }
+17
View File
@@ -0,0 +1,17 @@
# mailu
Mail — Mailu, with its provisioner (the `smtp` provision) and tools, on the tool runtime.
## Settings
A definition names no mesh (novox/hq ADR 0112, ADR 0155), so the values that are this
installation's are settings on the assignment, `settings set mailu <file>`:
```json
{"domain": "…", "sitename": "…", "website": "https://…", "proxy-address": "…"}
```
`domain` is the mail domain (also the provisioner's, for a consumer's address); `sitename` and
`website` are shown by the web front; `proxy-address` is what `REAL_IP_FROM` trusts a real-IP
header from — the address the proxy forwards with. The front's own hostname is the name of its
`web` route, told to it by the mesh.
+4 -7
View File
@@ -127,14 +127,14 @@
"port": 7443, "port": 7443,
"protocol": "tcp", "protocol": "tcp",
"from": "mesh", "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" "why": "the web front over its own TLS (admin, webmail, API); its public name is a route grant reaching it here"
}, },
{ {
"name": "autoconfig", "name": "autoconfig",
"port": 4243, "port": 4243,
"protocol": "tcp", "protocol": "tcp",
"from": "mesh", "from": "mesh",
"why": "automx: mail client autoconfiguration; autoconfig/autodiscover/automx.novox.be are route grants reaching it here" "why": "automx: mail client autoconfiguration; the autoconfig, autodiscover and automx names are route grants reaching it here"
} }
], ],
"own-secrets": { "own-secrets": {
@@ -168,7 +168,7 @@
"type": "file", "type": "file",
"path": "${dir:state}/mailu.env", "path": "${dir:state}/mailu.env",
"mode": "0644", "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=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\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=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" "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"
}, },
{ {
"id": "secret-env", "id": "secret-env",
@@ -490,7 +490,6 @@
"MESH_MAILU_API_KEY_FILE": "/run/secrets/api-token", "MESH_MAILU_API_KEY_FILE": "/run/secrets/api-token",
"MESH_MAILU_IMAP_CONTAINER": "mailu-imap", "MESH_MAILU_IMAP_CONTAINER": "mailu-imap",
"MESH_MAILU_CONFIG_FILE": "/run/config/config.json", "MESH_MAILU_CONFIG_FILE": "/run/config/config.json",
"MESH_MAILU_DOMAIN": "novox.be",
"MESH_RECEIVES": "${dir:grants}/mesh.json" "MESH_RECEIVES": "${dir:grants}/mesh.json"
}, },
"restart-on": [ "restart-on": [
@@ -553,9 +552,7 @@
], ],
"serves": { "serves": {
"smtp": { "smtp": {
"port": 587, "port": 587
"domain": "novox.be",
"name": "mail.novox.be"
} }
}, },
"receives": { "receives": {
+18 -3
View File
@@ -13,17 +13,32 @@
// it to both ends; mailu sets exactly that password every run — so a rotation takes — and seals // it to both ends; mailu sets exactly that password every run — so a rotation takes — and seals
// nothing: the consumer already has its copy through the mesh's own channel. // nothing: the consumer already has its copy through the mesh's own channel.
import { readFileSync } from "node:fs";
import { runProvisioner, type Provision } from "@novox/mesh-sdk/provisioner"; import { runProvisioner, type Provision } from "@novox/mesh-sdk/provisioner";
import { MailuClient } from "../client.js"; import { MailuClient } from "../client.js";
const mailu = MailuClient.fromEnv(); const mailu = MailuClient.fromEnv();
// The mail server's own domain. From the environment the manifest composes, because the client's // The mail server's own domain: the operator's value, from the settings the mesh merges into this
// config file carries the admin API's coordinates, not the mail domain. // module's config file (`settings set mailu` with {"domain": …}; novox/hq ADR 0112, ADR 0155). A
// definition names no mesh, so it is never a literal in the manifest — and it used to be, as
// MESH_MAILU_DOMAIN, which is still read for a mesh that has not re-registered the manifest.
function domain(): string { function domain(): string {
const file = process.env.MESH_MAILU_CONFIG_FILE;
if (file) {
try {
const config = JSON.parse(readFileSync(file, "utf8")) as { domain?: unknown };
if (typeof config.domain === "string" && config.domain.trim() !== "") return config.domain.trim();
} catch {
// Unreadable or not JSON: fall through to the environment, and the error below names both.
}
}
const named = (process.env.MESH_MAILU_DOMAIN ?? "").trim(); const named = (process.env.MESH_MAILU_DOMAIN ?? "").trim();
if (named === "") { if (named === "") {
throw new Error("MESH_MAILU_DOMAIN is not set, so a consumer's address cannot be composed"); throw new Error(
"no mail domain is set, so a consumer's address cannot be composed — `settings set mailu <file>` " +
'with {"domain": "<the mail domain>"}',
);
} }
return named; return named;
} }
+17 -2
View File
@@ -55,7 +55,10 @@
"type": "file", "type": "file",
"path": "${dir:state}/conduit.toml", "path": "${dir:state}/conduit.toml",
"mode": "0644", "mode": "0644",
"content": "# Written by the mesh (modules/matrix). Conduit reads this file (CONDUIT_CONFIG); nothing comes\n# from the environment. server_name is the homeserver's permanent identity: every user id, room id\n# and signature in the database carries it, so it is the name this module is served under\n# (${bound:route:name-homeserver}) and never changes once a database exists.\n[global]\nserver_name = \"${bound:route:name-homeserver}\"\ndatabase_backend = \"rocksdb\"\ndatabase_path = \"/var/lib/matrix-conduit/\"\naddress = \"0.0.0.0\"\nport = 6167\nmax_request_size = 20000000\nallow_registration = false\nallow_federation = true\nallow_check_for_updates = true\ntrusted_servers = [\"matrix.org\"]\n" "content": "# Written by the mesh (modules/matrix). Conduit reads this file (CONDUIT_CONFIG); nothing comes\n# from the environment. server_name is the homeserver's permanent identity: every user id, room id\n# and signature in the database carries it, so it is the name this module is served under\n# (${bound:route:name-homeserver}) and never changes once a database exists.\n[global]\nserver_name = \"${bound:route:name-homeserver}\"\ndatabase_backend = \"rocksdb\"\ndatabase_path = \"/var/lib/matrix-conduit/\"\naddress = \"0.0.0.0\"\nport = 6167\nmax_request_size = 20000000\nallow_registration = false\nallow_federation = true\nallow_check_for_updates = true\ntrusted_servers = [\"matrix.org\"]\n",
"names-on-purpose": {
"matrix.org": "the federation's public key server, trusted by default; the world's, not this mesh's"
}
}, },
{ {
"id": "element-conf", "id": "element-conf",
@@ -63,7 +66,19 @@
"path": "${dir:state}/element.json", "path": "${dir:state}/element.json",
"mode": "0644", "mode": "0644",
"merge": "json", "merge": "json",
"content": "{\n \"default_server_name\": \"${bound:route:name-homeserver}\",\n \"default_server_config\": {\n \"m.homeserver\": {\n \"base_url\": \"https://${bound:route:name-homeserver}\"\n },\n \"m.identity_server\": {\n \"base_url\": \"https://vector.im\"\n }\n },\n \"brand\": \"Element\",\n \"integrations_ui_url\": \"https://scalar.vector.im/\",\n \"integrations_rest_url\": \"https://scalar.vector.im/api\",\n \"integrations_widgets_urls\": [\n \"https://scalar.vector.im/_matrix/integrations/v1\",\n \"https://scalar.vector.im/api\",\n \"https://scalar-staging.vector.im/_matrix/integrations/v1\",\n \"https://scalar-staging.vector.im/api\",\n \"https://scalar-staging.riot.im/scalar/api\"\n ],\n \"bug_report_endpoint_url\": \"https://element.io/bugreports/submit\",\n \"uisi_autorageshake_app\": \"element-auto-uisi\",\n \"show_labs_settings\": true,\n \"room_directory\": {\n \"servers\": [\n \"${bound:route:name-homeserver}\",\n \"matrix.org\",\n \"gitter.im\",\n \"libera.chat\"\n ]\n },\n \"enable_presence_by_hs_url\": {\n \"https://matrix.org\": false,\n \"https://matrix-client.matrix.org\": false\n },\n \"terms_and_conditions_links\": [\n {\n \"url\": \"https://element.io/privacy\",\n \"text\": \"Privacy Policy\"\n },\n {\n \"url\": \"https://element.io/cookie-policy\",\n \"text\": \"Cookie Policy\"\n }\n ],\n \"features\": {\n \"feature_video_rooms\": true,\n \"feature_rust_crypto\": true\n },\n \"element_call\": {\n \"url\": \"https://call.element.dev\"\n }\n}\n" "content": "{\n \"default_server_name\": \"${bound:route:name-homeserver}\",\n \"default_server_config\": {\n \"m.homeserver\": {\n \"base_url\": \"https://${bound:route:name-homeserver}\"\n },\n \"m.identity_server\": {\n \"base_url\": \"https://vector.im\"\n }\n },\n \"brand\": \"Element\",\n \"integrations_ui_url\": \"https://scalar.vector.im/\",\n \"integrations_rest_url\": \"https://scalar.vector.im/api\",\n \"integrations_widgets_urls\": [\n \"https://scalar.vector.im/_matrix/integrations/v1\",\n \"https://scalar.vector.im/api\",\n \"https://scalar-staging.vector.im/_matrix/integrations/v1\",\n \"https://scalar-staging.vector.im/api\",\n \"https://scalar-staging.riot.im/scalar/api\"\n ],\n \"bug_report_endpoint_url\": \"https://element.io/bugreports/submit\",\n \"uisi_autorageshake_app\": \"element-auto-uisi\",\n \"show_labs_settings\": true,\n \"room_directory\": {\n \"servers\": [\n \"${bound:route:name-homeserver}\",\n \"matrix.org\",\n \"gitter.im\",\n \"libera.chat\"\n ]\n },\n \"enable_presence_by_hs_url\": {\n \"https://matrix.org\": false,\n \"https://matrix-client.matrix.org\": false\n },\n \"terms_and_conditions_links\": [\n {\n \"url\": \"https://element.io/privacy\",\n \"text\": \"Privacy Policy\"\n },\n {\n \"url\": \"https://element.io/cookie-policy\",\n \"text\": \"Cookie Policy\"\n }\n ],\n \"features\": {\n \"feature_video_rooms\": true,\n \"feature_rust_crypto\": true\n },\n \"element_call\": {\n \"url\": \"https://call.element.dev\"\n }\n}\n",
"names-on-purpose": {
"matrix.org": "the public room directory and the federation's largest homeserver; the world's",
"matrix-client.matrix.org": "the same homeserver's client endpoint; the world's",
"vector.im": "Element's public identity server; the world's",
"scalar.vector.im": "Element's public integration manager; the world's",
"scalar-staging.vector.im": "Element's staging integration manager, named by the upstream default config; the world's",
"scalar-staging.riot.im": "the same, under its former name; the world's",
"element.io": "Element's bug reports, privacy and cookie pages; the world's",
"gitter.im": "a public room directory; the world's",
"libera.chat": "a public room directory; the world's",
"call.element.dev": "Element Call's public instance; the world's"
}
}, },
{ {
"id": "net", "id": "net",
+1 -2
View File
@@ -86,7 +86,7 @@
"type": "file", "type": "file",
"path": "/var/lib/minio/root.env", "path": "/var/lib/minio/root.env",
"mode": "0600", "mode": "0600",
"content": "MINIO_ROOT_USER=meshroot\n" "content": "MINIO_ROOT_USER=meshroot\nMINIO_BROWSER_REDIRECT_URL=https://${bound:route:name-console}\n"
}, },
{ {
"id": "data", "id": "data",
@@ -124,7 +124,6 @@
], ],
"env": { "env": {
"MINIO_ROOT_PASSWORD_FILE": "/run/secrets/root", "MINIO_ROOT_PASSWORD_FILE": "/run/secrets/root",
"MINIO_BROWSER_REDIRECT_URL": "https://files.novox.be",
"MINIO_REGION": "eu-west" "MINIO_REGION": "eu-west"
} }
}, },
+2 -2
View File
@@ -33,7 +33,7 @@
"port": 5682, "port": 5682,
"protocol": "tcp", "protocol": "tcp",
"from": "mesh", "from": "mesh",
"why": "the n8n editor and webhook endpoints over http; the public name n8n.novox.be is a route grant, and route-proxy reaches it on this published port" "why": "the n8n editor and webhook endpoints over http; its public name is a route grant, and route-proxy reaches it on this published port"
} }
], ],
"resources": [ "resources": [
@@ -55,7 +55,7 @@
"type": "file", "type": "file",
"path": "/var/lib/n8n/server.env", "path": "/var/lib/n8n/server.env",
"mode": "0600", "mode": "0600",
"content": "N8N_HOST=n8n.novox.be\nN8N_PORT=5678\nN8N_PROTOCOL=https\nWEBHOOK_URL=https://n8n.novox.be/\nN8N_BASIC_AUTH_ACTIVE=true\nN8N_BASIC_AUTH_USER=admin\nN8N_BASIC_AUTH_PASSWORD=${secret:basic-auth}\nNODE_FUNCTION_ALLOW_BUILTIN=*\nNODE_FUNCTION_ALLOW_EXTERNAL=*\nDB_TYPE=postgresdb\nDB_POSTGRESDB_HOST=${bound:postgres-database:at}\nDB_POSTGRESDB_PORT=${bound:postgres-database:port}\nDB_POSTGRESDB_DATABASE=${bound:postgres-database:as}\nDB_POSTGRESDB_USER=${bound:postgres-database:as}\nDB_POSTGRESDB_PASSWORD=${secret:postgres-database}\n" "content": "N8N_HOST=${bound:route:name}\nN8N_PORT=5678\nN8N_PROTOCOL=https\nWEBHOOK_URL=https://${bound:route:name}/\nN8N_BASIC_AUTH_ACTIVE=true\nN8N_BASIC_AUTH_USER=admin\nN8N_BASIC_AUTH_PASSWORD=${secret:basic-auth}\nNODE_FUNCTION_ALLOW_BUILTIN=*\nNODE_FUNCTION_ALLOW_EXTERNAL=*\nDB_TYPE=postgresdb\nDB_POSTGRESDB_HOST=${bound:postgres-database:at}\nDB_POSTGRESDB_PORT=${bound:postgres-database:port}\nDB_POSTGRESDB_DATABASE=${bound:postgres-database:as}\nDB_POSTGRESDB_USER=${bound:postgres-database:as}\nDB_POSTGRESDB_PASSWORD=${secret:postgres-database}\n"
}, },
{ {
"id": "net", "id": "net",
+1 -1
View File
@@ -26,7 +26,7 @@
"port": 9070, "port": 9070,
"protocol": "tcp", "protocol": "tcp",
"from": "mesh", "from": "mesh",
"why": "the document server over http; the public name office.novox.be is a route grant, and route-proxy reaches it on this published port" "why": "the document server over http; its public name is a route grant, and route-proxy reaches it on this published port"
} }
], ],
"resources": [ "resources": [
+5 -2
View File
@@ -23,7 +23,7 @@
"port": 4012, "port": 4012,
"protocol": "tcp", "protocol": "tcp",
"from": "mesh", "from": "mesh",
"why": "the eef photos client site over http; the public name eef.novox.be is a route grant, and route-proxy reaches it on this published port" "why": "the eef photos client site over http; its public name is a route grant, and route-proxy reaches it on this published port"
} }
], ],
"resources": [ "resources": [
@@ -46,7 +46,10 @@
"network": "photos-eef", "network": "photos-eef",
"ports": [ "ports": [
"80" "80"
] ],
"names-on-purpose": {
"registry-api.novox.be": "built outside the mesh, from the application's own repository, and pulled from the registry that built it; moves when that repository is a build source on the git seat (novox/hq ADR 0155, issue 122)"
}
} }
] ]
} }
+5 -2
View File
@@ -23,7 +23,7 @@
"port": 4013, "port": 4013,
"protocol": "tcp", "protocol": "tcp",
"from": "mesh", "from": "mesh",
"why": "the filip photos client site over http; the public name filip.novox.be is a route grant, and route-proxy reaches it on this published port" "why": "the filip photos client site over http; its public name is a route grant, and route-proxy reaches it on this published port"
} }
], ],
"resources": [ "resources": [
@@ -46,7 +46,10 @@
"network": "photos-filip", "network": "photos-filip",
"ports": [ "ports": [
"80" "80"
] ],
"names-on-purpose": {
"registry-api.novox.be": "built outside the mesh, from the application's own repository, and pulled from the registry that built it; moves when that repository is a build source on the git seat (novox/hq ADR 0155, issue 122)"
}
} }
] ]
} }
+9 -3
View File
@@ -43,7 +43,7 @@
"port": 4001, "port": 4001,
"protocol": "tcp", "protocol": "tcp",
"from": "mesh", "from": "mesh",
"why": "the admin client site over http; the public name photos.novox.be is a route grant, and route-proxy reaches it on this published port" "why": "the admin client site over http; its public name is a route grant, and route-proxy reaches it on this published port"
} }
], ],
"resources": [ "resources": [
@@ -77,7 +77,10 @@
"ports": [ "ports": [
"9000" "9000"
], ],
"secrets-in-environment": "the application's own code reads MONGO_URL and MINIO_SECRET from the environment (photos server/src/config.js); converting is that repository's change" "secrets-in-environment": "the application's own code reads MONGO_URL and MINIO_SECRET from the environment (photos server/src/config.js); converting is that repository's change",
"names-on-purpose": {
"registry-api.novox.be": "built outside the mesh, from the application's own repository, and pulled from the registry that built it; moves when that repository is a build source on the git seat (novox/hq ADR 0155, issue 122)"
}
}, },
{ {
"id": "admin-client", "id": "admin-client",
@@ -87,7 +90,10 @@
"network": "photos", "network": "photos",
"ports": [ "ports": [
"80" "80"
] ],
"names-on-purpose": {
"registry-api.novox.be": "built outside the mesh, from the application's own repository, and pulled from the registry that built it; moves when that repository is a build source on the git seat (novox/hq ADR 0155, issue 122)"
}
} }
] ]
} }
+4 -4
View File
@@ -8,10 +8,10 @@
"listens": [ "listens": [
{ {
"name": "web", "name": "web",
"port": 9090, "port": 9000,
"protocol": "tcp", "protocol": "tcp",
"from": "mesh", "from": "mesh",
"why": "the dashboard over http; portainer.novox.be is a route grant and the proxy reaches it here \u2014 the machine side of 9090:9000, the predecessor's number" "why": "the dashboard over http; its public name is a route grant and the proxy reaches it here"
}, },
{ {
"name": "web-tls", "name": "web-tls",
@@ -39,8 +39,8 @@
"name": "portainer", "name": "portainer",
"image": "portainer/portainer-ce@sha256:4d616db18cfeb5dd41a69c0958bc825c84483ea9cde1106eb82a5d26f3bd8b0e", "image": "portainer/portainer-ce@sha256:4d616db18cfeb5dd41a69c0958bc825c84483ea9cde1106eb82a5d26f3bd8b0e",
"ports": [ "ports": [
"9090:9000", "9000",
"9443:9443" "9443"
], ],
"volumes": [ "volumes": [
"${dir:data}:/data", "${dir:data}:/data",
+2 -1
View File
@@ -162,7 +162,8 @@
"kind": "image", "kind": "image",
"from": "Dockerfile", "from": "Dockerfile",
"context": { "context": {
"repository": "https://git.novox.be/novox/mesh-controller.git", "seat": "git",
"repository": "novox/mesh-controller",
"ref": "main" "ref": "main"
} }
}, },
@@ -1,5 +1,5 @@
{ {
"module": "novox.be", "module": "website",
"version": "1", "version": "1",
"capabilities": [ "capabilities": [
"container-runtime" "container-runtime"
@@ -14,7 +14,7 @@
} }
}, },
"binds": { "binds": {
"route": "/var/lib/novox.be/route.json" "route": "${dir:state}/route.json"
}, },
"listens": [ "listens": [
{ {
@@ -22,30 +22,33 @@
"port": 4000, "port": 4000,
"protocol": "tcp", "protocol": "tcp",
"from": "mesh", "from": "mesh",
"why": "the public website over http; the public name novox.be is a route grant, and route-proxy reaches it on this published port" "why": "the public website over http; its public name is a route grant, and route-proxy reaches it on this published port"
} }
], ],
"resources": [ "resources": [
{ {
"id": "state", "id": "state",
"type": "directory", "type": "directory",
"path": "/var/lib/novox.be", "mode": "0700",
"mode": "0700" "place": "."
}, },
{ {
"id": "net", "id": "net",
"type": "network", "type": "network",
"name": "novox-be" "name": "website"
}, },
{ {
"id": "server", "id": "server",
"type": "container", "type": "container",
"name": "novox-be", "name": "website",
"image": "registry-api.novox.be/novox/www@sha256:aa7ed20a293e1d7444c5c5d59b6d8bdb382bad159559a22e006810e379cae69c", "image": "registry-api.novox.be/novox/www@sha256:aa7ed20a293e1d7444c5c5d59b6d8bdb382bad159559a22e006810e379cae69c",
"network": "novox-be", "network": "novox-be",
"ports": [ "ports": [
"8080" "8080"
] ],
"names-on-purpose": {
"registry-api.novox.be": "built outside the mesh, from the application's own repository, and pulled from the registry that built it; moves when that repository is a build source on the git seat (novox/hq ADR 0155, issue 122)"
}
} }
] ]
} }