{
  "schema": "leumas.docs.page/1",
  "id": "pkg:@leumas/imperium-server",
  "slug": "services/imperium-server",
  "kind": "capabilities",
  "bucket": "package",
  "title": "@leumas/imperium-server — host Imperium on your own infra",
  "name": "@leumas/imperium-server",
  "eyebrow": "host Imperium on your own infra",
  "chip": null,
  "summary": "Standalone, white-label Imperium production server — the packageable 'run your own Imperium ecosystem' edition. Reuses the @leumas/hosting core (resolve/serve/SEO/mode-endpoints/shield) behind a...",
  "keywords": [
    "imperium-server",
    "caddyfile",
    "shield",
    "imperium-server entitlements",
    "security posture",
    "imperium server api",
    "leumas imperium server",
    "wildcard"
  ],
  "audience": "both",
  "funnel": {
    "product": null,
    "cta": null
  },
  "body": "# @leumas/imperium-server — host Imperium on your own infra\n\nThe standalone, white-label edition of Imperium: point a wildcard domain at it and every subdomain\nresolves to its own config (`mode` + `data`) and renders. It is **the same engine the Leumas\nplatform runs** — `@leumas/hosting` — assembled into a small Express app, so a self-hosted instance\ngets identical resolve, publish gating, SEO, storage endpoints and anti-scrape behaviour.\n\n```\nvisitor → wildcard edge (Caddy) → imperium-server worker(s) → @leumas/hosting → your config store\n```\n\n## Quick start\n\n```bash\nnode bin/create-imperium.mjs --dir ./my-imperium --domain example.com\ncd ./my-imperium\nnode node_modules/@leumas/imperium-server/src/server.js\n```\n\nThe scaffolder creates the runtime layout, generates instance secrets, and seeds the shared\n`__global` layer plus one published site so the first boot serves a real page. Re-running it never\noverwrites existing configs.\n\n## What it serves\n\n| Surface | Path |\n|---|---|\n| Every subdomain's page | `GET *` — SEO injected into the SPA bundle (or a minimal shell without one) |\n| Config resolution | `GET /api/hosting/resolve?host=…` |\n| Custom view types | `GET /api/hosting/view-modes` (public — anonymous visitors need these to render `x-…` sites) |\n| Storage-backed modes | `GET /api/hosting/modes/:siteId/{folder,gallery,exe}/…` |\n| SEO | `/robots.txt`, `/sitemap.xml` (this host), `/sitemap-index.xml` (all servable sites) |\n| Probes | `/healthz`, `/readyz` |\n\nPublishing, editing and the member UI live in **Leumas Studio** — this server is the read/serve\nplane. Point both at the same store, or run Studio's appliance EXE alongside it.\n\n## Configuration\n\nAll optional except the base domain.\n\n| Env | Meaning |\n|---|---|\n| `PORT` | listen port (default `1000`) |\n| `IMPERIUM_BASE_DOMAIN` | the domain subdomains hang off (`example.com`) |\n| `IMPERIUM_WEB_DIST` | a built `leumas-web` bundle → full SPA rendering |\n| `LEUMAS_DATA_ROOT` | the config store (libSQL) — the connector reads this one |\n| `IMPERIUM_DATA_ROOT` | server-local runtime files (`license.json`) |\n| `IMPERIUM_STORAGE_ROOT` | per-site upload roots for folder/gallery/exe modes |\n| `IMPERIUM_PREVIEW_SECRET` | **must be identical across workers** or draft-preview links fail to verify |\n| `IMPERIUM_FOLDER_ROOTS` | `;`-separated absolute prefixes a `folder` site may read (self-host only) |\n| `IMPERIUM_RESOLVE_CACHE_MS` | resolve read-cache TTL (default `3000`, `0` disables) |\n| `IMPERIUM_ALLOW_LEGACY_CONFIGS` | serve pre-`firstParty` configs during a migration |\n| `LEUMAS_LICENSE_SERVER` | licensed appliance: entitlement policies come from the signed token |\n\n## Entitlements\n\nTwo modes, no configuration branching in your code:\n\n- **Self-host** — the instance's own `entitlement_policies` docs, layered over the committed\n  defaults, so hosting works out of the box.\n- **Licensed appliance** (`LEUMAS_LICENSE_SERVER`) — the policy ceiling is a Leumas-signed Ed25519\n  token verified **offline**; an unreachable platform never bricks the instance before the token's\n  own expiry. Membership assignment stays local to your instance.\n\nSet `IMPERIUM_NO_ENTITLEMENTS=1` to serve every published site without the per-owner capability\nre-check (single-tenant installs).\n\n## Scaling\n\n`deploy/Caddyfile` is a wildcard edge that forwards **all** of `*.example.com` to an identical\nworker pool, preserving the `Host` header — no per-site routes, ever. Start N copies on\n`1001…100N`, list them in the `reverse_proxy` block, and Caddy health-checks `/healthz`.\n\nEach worker is stateless apart from its store; the resolve cache is per-process and TTL-bounded, so\nworkers converge within `IMPERIUM_RESOLVE_CACHE_MS` of a publish.\n\n## Security posture\n\n- Configs serve only when **published** (hosted) or explicitly flagged **`firstParty`** (operator).\n- Storage endpoints are traversal-guarded and scoped to `storage/imperium/<siteId>/`; raw filesystem\n  roots are self-host-only and must be allowlisted via `IMPERIUM_FOLDER_ROOTS`.\n- Custom view types render inside a **sandboxed iframe** with no same-origin access.\n- The reverse proxy performs SSRF checks (private/loopback/metadata ranges denied, DNS-rebind pinned).\n- The optional per-site shield applies rate limits, user-agent denylists and honeypot paths at the edge.\n",
  "source": {
    "path": "shared/services/imperium-server/README.md",
    "blobSha": "",
    "commit": "",
    "committedAt": "",
    "provenance": "no-git",
    "bytes": 4635,
    "hash": "81df8d81d7bb9834b0ca928c08b63ae5582a2e93"
  },
  "urls": {
    "html": "/p/services/imperium-server",
    "json": "/docs/services/imperium-server.json",
    "md": "/docs/services/imperium-server.md"
  },
  "links": {
    "composes": [
      "pkg:@leumas/config-registry",
      "pkg:@leumas/entitlements",
      "pkg:@leumas/licensing",
      "pkg:@leumas/middleware",
      "pkg:@leumas/security"
    ],
    "usedBy": [],
    "product": [],
    "howTo": [
      "how-to:surveillance-enterprise"
    ],
    "skills": []
  },
  "exports": null
}
