Xiteng Site component labels
xiteng.site does not contain a hardcoded service list. A Docker container opts one or more
components into the public catalog with labels under this namespace:
labels:
- "xiteng.site.component.example.enabled=true"
- "xiteng.site.component.example.name=Example"
- "xiteng.site.component.example.description=What this component does."
- "xiteng.site.component.example.section=services"
- "xiteng.site.component.example.category=开发与协作"
- "xiteng.site.component.example.url=https://example.xiteng.site"
- "xiteng.site.component.example.endpoint=example.xiteng.site:443"
- "xiteng.site.component.example.access=sso"
- "xiteng.site.component.example.access-label=需要 Authentik"
- "xiteng.site.component.example.icon=EX"
- "xiteng.site.component.example.icon-url=https://example.xiteng.site/favicon.svg"
- "xiteng.site.component.example.accent=blue"
- "xiteng.site.component.example.order=100"
- "xiteng.site.component.example.navigation=new-tab"
- "xiteng.site.component.example.portal-link=native"
- "xiteng.site.component.example.monitor.enabled=true"
- "xiteng.site.component.example.monitor.url=http://example:8080/healthz"
Schema
| Field | Required | Values / behavior |
|---|---|---|
enabled |
yes | Only the exact value true publishes the component. |
name |
yes | Public display name. |
description |
recommended | Public description; never put secrets here. |
section |
yes | services or infrastructure. |
category |
recommended | Dynamic group heading. |
url |
no | Only HTTP(S) URLs are accepted. No URL renders a non-clickable card. |
endpoint |
no | Public protocol endpoint or connection hint. |
access |
yes | Machine-readable mode such as public, sso, mixed, access-key, ssh-key, local, or internal. |
access-label |
recommended | Human-readable access boundary shown on the card. |
icon |
no | Final fallback text or emoji, limited to eight characters. |
icon-url |
no | Preferred HTTP(S) icon URL. Without it, the UI tries /favicon.svg, /favicon.ico, then /favicon.png on the component origin before showing icon. |
accent |
no | red, green, yellow, blue, or ink. |
order |
no | Numeric order inside a section; defaults to 999. |
navigation |
no | new-tab (default for URLs), same-tab, or endpoint (default without a URL). |
portal-link |
no | embedded, native, or none; documents how the service returns to the Portal. |
monitor.enabled |
no | true enables the built-in HTTP GET probe. |
monitor.url |
when enabled | Internal HTTP(S) target. It is never returned by the public API. |
monitor.interval |
no | Check interval in seconds, default 60. |
monitor.failures |
no | Consecutive failures before down, default 3. |
monitor.timeout |
no | Request timeout in seconds, default 10. |
monitor.accept |
no | Accepted HTTP codes, default 200-299; comma-separated values and ranges are supported. |
The component id (example above) must be globally stable. One container may publish multiple
components by using multiple ids, which is useful for services such as SeaweedFS Web and its S3 API.
The registry reads container state and image names from Docker. It returns only the public fields above plus Compose project/service names, runtime status, sanitized monitor state, response time, last check time, and 24-hour availability. Internal monitor URLs, errors, environment variables, mounts, raw labels, Docker configuration, and secret values are never returned to the public site container.
Navigation contract
Components with a public HTTP(S) URL open in a new tab by default with noopener noreferrer, leaving the
Portal available in the original tab. Owned or officially customizable applications link back to
https://xiteng.site/?focus=<component-id>#services; the Portal clears incompatible filters, scrolls to the
component card, briefly highlights it, and then removes the focus query parameter. Protocol endpoints and
internal-only components remain non-clickable. Do not inject navigation into third-party HTML at the proxy.
Monitoring and lifecycle
The Registry is the only discovery and lifecycle control plane. It uses the stable component id as the
database primary key, so a component can never create multiple monitors. It performs bounded-concurrency
HTTP GET probes and stores state in site/data/registry.db:
active → missing → archived → purged
active: the component Label is currently present on a Docker container;missing: the container or Label disappeared, but catalog and monitor history remain for 30 days;archived: monitoring is paused and the component is hidden from the default public catalog;purged: an administrator explicitly removes the component and all of its monitoring data.
A component that returns with the same id before purge reuses its existing history. Raw checks are retained for 30 days; hourly and daily aggregates are retained for 365 days. Response bodies are never stored.
https://xiteng.site/admin and /api/admin/* are protected by Authentik ForwardAuth and additionally
require the exact username liooil; this check is repeated in the site backend and Key Vault. All other
users use /account and /api/account/*. The account page is the canonical self-service surface for
profile name/email, avatar resolution, password recovery, TOTP, Passkeys, Authentik sessions, and Provider
configuration constrained by the session's (issuer, sub) pair. Provider definition, model list, and an
optional credential are saved from one form. Backend credentials are encrypted by Key Vault; Frontend
credentials remain in the current browser's IndexedDB. Either mode can be saved and connectivity-tested in
the same action. The public homepage remains unauthenticated.
The admin page is the canonical control plane for human users, ordinary groups, password setup/recovery,
session revocation, authenticator status/reset, and a group-only application access matrix. The native
Authentik admin UI is hidden. TOTP and Passkey enrollment launches dedicated Authentik setup flows and
returns to /account; list, rename, delete, reset, and ownership checks remain in the Portal API. The account
page hashes the normalized email with SHA-256 in the browser, then loads Gravatar and Libravatar directly with
no referrer; a deterministic initials image remains visible while loading and on failure. Avatar bytes never
pass through the Portal backend. The Portal accesses Authentik with a server-only API token and
records every identity mutation in a local JSONL audit; password values are never logged. liuhome is
protected and currently contains liooil and ziyue; all managed non-public applications are restricted
to that group.
The default Authentik identification stage enables WebAuthn conditional UI. A discoverable Passkey can
authenticate directly on auth.xiteng.site; Authentik's default flow policies then skip both password and
the later MFA stage. Username/password plus TOTP remains available as a fallback, and new Passkeys are
enrolled with the default resident_key_requirement=preferred setup stage.
Host metrics
The internal metrics service publishes the sanitized /api/metrics payload used by the device status
cards. It reads host CPU and memory counters from a read-only /proc mount, root filesystem capacity
through a read-only bind on the same filesystem, and NVIDIA GPU telemetry through the utility driver
capability. The public payload is limited to:
- CPU usage, model, logical core count, and load averages;
- memory and root filesystem used/available/total values;
- GPU model, utilization, VRAM, temperature, and power;
- hostname and collection timestamp.
The metrics container has no Docker socket and no public router. The site server proxies its fixed
internal endpoint as /api/metrics; arbitrary host files and commands are not exposed.
PWA and icons
favicon.svg is the source artwork for browser and install icons. The PNG and ICO derivatives live in
icons/ and at favicon.ico. manifest.webmanifest enables standalone installation and shortcuts to the
service and infrastructure catalogs. sw.js caches only the public page shell and static artwork. Runtime
component/metrics APIs, Authentik paths, and all administration requests always use the network and are
never written to the PWA cache.
Setting enabled=false, removing the labels, or removing the container moves the component to missing
without changing index.html or app.js. The old homepage.* and kuma.* namespaces are no longer read;
new and existing components use only the xiteng.site.component.* schema.
Static edge caching is a separate, security-sensitive declaration and is intentionally not part of
the public component schema. A service can opt public, user-independent asset directories into the
shared cache with xiteng.site.cache.<policy>.* labels. See edge-cache/README.md for the schema;
never apply it to API, admin, callback, tokenized download, HTML, or user-content paths.