DinD HostingManual
Overview/Manual/Run the platform
CHAPTER 14

Administration

Admins see three extra entries in the top bar — users, metrics and platform. This chapter covers each of them.

Admin role required

Everything on this page needs the admin role. Regular users do not see these pages; the matching API routes and MCP tools refuse them with requires the admin role.

Console language#

The console speaks English and Ukrainian. Every user picks a language with the selector in the top navigation (also on the login page); it is saved in the browser as dind.lang and, until a choice is made, taken from the browser's preferred languages (uk, uk-UA… → Ukrainian, anything else → English). Dates, times and numbers follow the language. Text that comes from the server — error details, ACME notes, validation messages — is shown as received, in English, in both languages.

Users#

users lists every account with its alias, email, role (a drop-down), status and two actions per row: manage and delete. + new user creates an account.

hosting.example.com/admin/users
Users
The Users page. (1) create an account, (2) change a role in place, (3) manage opens the user's daemons and password reset, (4) delete — disabled for admin rows.

Creating a user#

Field Rule
email the login name; unique
alias 2–15 characters a-z0-9; used for the user's daemon and site names; cannot clash with another user
password at least 8 characters

New accounts are regular users; change the role in the table afterwards. Over MCP, create_user takes the role directly:

create_user(email="mia@example.com", password="…", alias="mia", role="user")   # admin only

Creating a user provisions their world: a projects-<alias> daemon, a MinIO IAM user and the bucket <alias>-files. The account exists even if the MinIO step fails afterwards, so a hiccup never leaves a half-created user.

Manage and delete#

  • manage shows the user's daemons — kind, name, ip and status — and a reset password box (minimum 8 characters).
  • delete removes the user, their daemons and tokens. It is refused while the user still has projects (409 user has N project(s) — delete them first): delete or hand over the projects first. You cannot delete yourself, and admin rows have the button disabled. Audit and query history survive with the user reference cleared.
  • The very first admin, admin@platform.example, is created at first boot; its generated password is printed in the management log and stored in data/platform/secrets/panel.admin_password. Further admins can be promoted in the table or created with python -m app.cli create-admin --email … inside the management container.

Dedicated database daemon#

By default a user's databases run in the shared db daemon. For a user who needs stronger separation an admin can switch on a dedicated db-<alias> daemon. The console does not have a switch for this — use the API or an MCP tool:

bash
curl -fsS -X PATCH "$BASE/api/v1/users/$UID" -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' -d '{"own_db_dind": true}'
# MCP: set_user_db_dind(user_id=5, enabled=true)

Switching it off destroys data

Destroying a user's dedicated database daemon purges its data directory. Move or dump the databases first.

Metrics#

metrics shows platform-wide load: every container with samples (daemon, CPU % and memory, latest) for the selected range, and a per-user summary (daemons, total CPU, total memory). It reads the same sampler as the project charts — see Metrics & logs.

Platform#

The platform page has four blocks.

hosting.example.com/admin/platform
platform
The Platform page: health, settings, then certificates and maintenance below.

Health#

A component table (daemons, platform database, MinIO, Traefik, …) with a status each, and the platform's platform_id. The same data is returned by GET /api/v1/health and the MCP tool platform_health (ok or degraded).

Settings#

Setting Purpose Default
tls mode dev — local CA; prod — ACME certificates dev
lb public ip(s) comma-separated address(es) the platform is reachable at; pre-checks require a custom domain's record to equal one of them. Empty = "resolves" is enough empty
backup retention days delete backups older than this 14
backups to keep per scope keep at most this many per project/database 5
metrics raw retention days raw 15-second samples 14
metrics hourly retention days hourly roll-ups 90

Switching tls mode re-renders every route file.

Default container limits#

The default CPU and memory cap for app and database containers is a platform setting too — 2 CPUs and 4 GiB until changed. It is not in the console form; set it with the API (null removes a cap; the minimum is 0.01 CPU or 64 MiB):

bash
curl -fsS -X PUT "$BASE/api/v1/admin/settings" -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"default_limits": {"cpus": 2, "mem_bytes": 4294967296}}'

An app's own resources: in platform.yaml wins over the default.

Certificates (ACME)#

In prod mode, certificates come from an ACME CA configured here — no environment variables or restarts by hand.

Choice Notes
Let's Encrypt (production) the default; HTTP-01
Let's Encrypt (staging) for rehearsals; untrusted certificates, generous limits
ZeroSSL, Google Public CA need external account binding — a key id and an HMAC key
Custom ACME server any https:// directory URL whose chain is publicly trusted

You also set the contact email (the CA writes expiry notices there). A real address is required — the placeholder admin@platform.example is refused by every CA. EAB credentials are write-only.

Applying recreates Traefik

Saving ACME settings recreates the Traefik container: expect a few seconds of dropped connections. Changing the CA starts a new certificate set — every domain is issued again — because each CA/account keeps its own certificate store, so staging and production never mix.

Maintenance#

Three buttons run housekeeping on demand: prune old backups, prune old metrics, and run the domain/certificate watchdog now instead of waiting for its five-minute cycle.

Resource limits and isolation#

Limits exist at three levels, from coarse to fine:

  1. Platform default — the default limits setting above, applied to app and database containers.
  2. Per app — resources: in platform.yaml overrides the default for that app.
  3. Per-container metrics show who is close to a limit before it bites.

User isolation is a daemon per user for apps; databases are separate containers with their own credentials (in a shared or dedicated daemon). Build contexts are streamed over the daemon's socket per deploy and never bind-mounted, so sources never cross users.