home-hosted 0.8.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +9 -5
- package/README.md +50 -14
- package/dist/cli.js +1331 -282
- package/dist/cli.js.map +1 -1
- package/docs/DDNS.md +2 -1
- package/docs/NOTIFICATIONS.md +72 -20
- package/docs/SERVERS.md +20 -1
- package/docs/UI_CREATION.md +22 -7
- package/docs/branding/logo.svg +33 -0
- package/docs/branding/social-preview.png +0 -0
- package/package.json +27 -24
- package/uis/stock/dist/assets/de-DL4xkOYj.js +1 -0
- package/uis/stock/dist/assets/es-CKj-v3FY.js +1 -0
- package/uis/stock/dist/assets/fr-72WremqT.js +1 -0
- package/uis/stock/dist/assets/index-BNSSU69y.js +47 -0
- package/uis/stock/dist/assets/index-GxTN2fYn.css +2 -0
- package/uis/stock/dist/assets/ja-BU4XyMbC.js +1 -0
- package/uis/stock/dist/assets/ko-Db8xtJ0N.js +1 -0
- package/uis/stock/dist/assets/ru-Bs8KXP2O.js +1 -0
- package/uis/stock/dist/assets/vi-DdQD4h7B.js +1 -0
- package/uis/stock/dist/assets/zh-CN-DIrw2Ubv.js +1 -0
- package/uis/stock/dist/favicon.ico +0 -0
- package/uis/stock/dist/favicon.svg +14 -0
- package/uis/stock/dist/index.html +6 -2
- package/uis/stock/dist/ui.json +3 -3
- package/uis/stock/dist/assets/de-DQxDtYp2.js +0 -1
- package/uis/stock/dist/assets/es-BP0qzCTU.js +0 -1
- package/uis/stock/dist/assets/fr-DHCvxiys.js +0 -1
- package/uis/stock/dist/assets/index-C02FUAwz.js +0 -46
- package/uis/stock/dist/assets/index-Skf2FzpK.css +0 -2
- package/uis/stock/dist/assets/ja-DseIeS1D.js +0 -1
- package/uis/stock/dist/assets/ko-Dcu2b6c2.js +0 -1
- package/uis/stock/dist/assets/ru-DaAAVw09.js +0 -1
- package/uis/stock/dist/assets/vi-D780h-t9.js +0 -1
- package/uis/stock/dist/assets/zh-CN-C8OC-N1b.js +0 -1
package/AGENTS.md
CHANGED
|
@@ -10,8 +10,8 @@ level: `settings.json` (listener, auth, TLS policy, host vitals, backups, revers
|
|
|
10
10
|
`.ui/`, `.logs/` (the panel console), `.proxy/` (the engine, its generated config and nanny state), and
|
|
11
11
|
`run.json` (the live daemon's pid/url/token, 0600). Every workspace owns `.hh/<id>/`: `settings.json`
|
|
12
12
|
(server defaults, log retention, notifications, DDNS), `servers.config.json`, `.secrets.json` (0600:
|
|
13
|
-
Telegram
|
|
14
|
-
is sealed, because it is the one thing replayed to a third party), `.logs/` (per server, `<id>.log`
|
|
13
|
+
Telegram bot tokens, one per destination, plus DDNS credentials sealed with AES-256-GCM under
|
|
14
|
+
`HHOSTED_DDNS_SECRET` — only DDNS is sealed, because it is the one thing replayed to a third party), `.logs/` (per server, `<id>.log`
|
|
15
15
|
plus `<id>.log.1` when it rotates), and `.state/` (nanny state, its 0600 spawn spec until read,
|
|
16
16
|
`ddns.json`). A home still on the 0.6.x layout is **refused** by `ensureLayout()`, which names the file
|
|
17
17
|
and tells the person to install the latest 0.7.x; 0.8.0 does not relocate it. **The package ships no
|
|
@@ -39,7 +39,7 @@ Where knowledge lives, and when to reach for each:
|
|
|
39
39
|
| [`.agentDocs/COMPATIBILITY.md`](.agentDocs/COMPATIBILITY.md) | config and UI compatibility, migrations |
|
|
40
40
|
| [`.agentDocs/RELEASING.md`](.agentDocs/RELEASING.md) | how a release is cut, and which version to dispatch |
|
|
41
41
|
| [`docs/SERVERS.md`](docs/SERVERS.md) | entries, port conflicts, persistent entries |
|
|
42
|
-
| [`docs/NOTIFICATIONS.md`](docs/NOTIFICATIONS.md) | Telegram
|
|
42
|
+
| [`docs/NOTIFICATIONS.md`](docs/NOTIFICATIONS.md) | notification destinations: Telegram, webhooks, shared defaults |
|
|
43
43
|
| [`docs/DDNS.md`](docs/DDNS.md) | dynamic-DNS providers and hostnames |
|
|
44
44
|
| [`docs/REVERSE_PROXY.md`](docs/REVERSE_PROXY.md) | the Caddy engine, routes, certificates |
|
|
45
45
|
| [`docs/UI_CREATION.md`](docs/UI_CREATION.md) | the contract for a new UI |
|
|
@@ -56,6 +56,8 @@ pnpm run start # up --foreground (systemd, docker, a foregro
|
|
|
56
56
|
pnpm exec tsx src/cli.ts logs # the panel's own console output (--lines, --follow, --json)
|
|
57
57
|
pnpm dev # tsx-watch panel :6000 + the stock UI's Vite :6001, state in .dev-state/
|
|
58
58
|
pnpm dev --ui noc-console # the same, for another UI; --port/--ui-port override
|
|
59
|
+
pnpm dev --home /tmp/hh-dev # state elsewhere; HHOSTED_HOME is IGNORED here, and the real
|
|
60
|
+
# ~/.home-hosted is refused. Dev password: `dev`
|
|
59
61
|
pnpm run build # dist/cli.js + the stock UI (uis/stock/dist)
|
|
60
62
|
pnpm run build:uis # every UI under uis/, zipped into uis/dist/ (release assets)
|
|
61
63
|
pnpm run build:locales # i18n/sheets/*.csv -> the git-ignored i18n/generated/*.json (also
|
|
@@ -69,7 +71,8 @@ pnpm run set-password # non-interactive through HHOSTED_PASSWORD
|
|
|
69
71
|
pnpm run set-token # --generate prints a new API token once
|
|
70
72
|
pnpm run migrate # bring the config up to this release's schema
|
|
71
73
|
pnpm exec tsx src/cli.ts init # scaffold a project (interactive; --yes for defaults)
|
|
72
|
-
pnpm run media # regenerate docs/media
|
|
74
|
+
pnpm run media # regenerate docs/media; needs `pnpm exec playwright install chromium`
|
|
75
|
+
# once (browser only; `gif` alone does not)
|
|
73
76
|
```
|
|
74
77
|
|
|
75
78
|
The published bin is `home-hosted`, with an `hh` alias: both names run the same CLI.
|
|
@@ -128,7 +131,8 @@ These prevent defects if broken. The *why* for the non-obvious ones is in
|
|
|
128
131
|
**refuses** a commit that changed a shipped UI without raising it (a UI's `test/` and its own
|
|
129
132
|
`README.md` are exempt — neither is in the built asset).
|
|
130
133
|
`src/shared/**` is a UI build input, so a runtime contract needs the bump too — the hook does not
|
|
131
|
-
inspect that commit.
|
|
134
|
+
inspect that commit. **`tag` and `unix` are build provenance**, stamped into `dist/ui.json` by
|
|
135
|
+
`build-uis.mjs`; never committed to `public/ui.json`.
|
|
132
136
|
- **Paths.** `dataRoot` is state, under `dataRoot/.hh`; `projectDir` is the base for relative entry
|
|
133
137
|
paths. `{…}` and `${ENV}` expand in config — the full list is the table in
|
|
134
138
|
[`docs/SERVERS.md`](docs/SERVERS.md), which is what to keep in step. No package-relative state.
|
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<img src="docs/branding/logo.svg" alt="home-hosted" width="128" height="128">
|
|
4
|
+
|
|
5
|
+
# home-hosted
|
|
4
6
|
|
|
5
7
|
**The control panel for everything you self-host at home.**
|
|
6
8
|
|
|
@@ -81,7 +83,8 @@ some arguments, and the environment you give it:
|
|
|
81
83
|
```
|
|
82
84
|
|
|
83
85
|
<sub>Manage them from the panel, `home-hosted start|stop <id>` from a shell, `home-hosted status --json`,
|
|
84
|
-
or `GET /api/state`; `GET /healthz` is the same status line for your own monitor, no session needed
|
|
86
|
+
or `GET /api/state`; `GET /healthz` is the same status line for your own monitor, no session needed —
|
|
87
|
+
`503` when an autostart server has crashed or a running one is failing its health check.</sub>
|
|
85
88
|
|
|
86
89
|
---
|
|
87
90
|
|
|
@@ -267,17 +270,17 @@ can be told what to be: *"Help me build a UI for home-hosted: nostalgic game the
|
|
|
267
270
|
| 🗂 **Workspaces** | One panel, many scopes: pick a workspace in the header and it owns its servers, secrets, logs and settings. Create, rename and delete them there. Panel-wide things — listener, auth, host vitals, backups, TLS, UI — stay in **Global settings**. |
|
|
268
271
|
| 🚦 **Lifecycle** | Start, stop, restart from the panel or the API; `autostart` entries come up with it. |
|
|
269
272
|
| 📝 **Hand edits welcome** | Change a workspace's `servers.config.json` in an editor, a `git checkout` or a config tool: the panel notices within seconds, no restart. A file it cannot read is reported in the panel, and the running servers are left alone. |
|
|
270
|
-
| ♻️ **Auto-restart** | Exponential backoff on crash, with the counter reset once a process stays up. |
|
|
273
|
+
| ♻️ **Auto-restart** | Exponential backoff on crash, with the counter reset once a process stays up. The budget is remembered across a restart of the panel. |
|
|
271
274
|
| 🩺 **Health that acts** | TCP or HTTP probes per server: warn on the card, force a restart after a timeout, check ports before starting — and [follow or replace](./docs/SERVERS.md#when-a-program-restarts-itself) a program that restarts itself. |
|
|
272
275
|
| 🔗 **Ordered startup** | `dependsOn` waits for a dependency to be *healthy* — not merely spawned. `stop-all`/`down` stop dependents before their dependencies; stopping one server names the dependents it leaves running. [SERVERS.md](./docs/SERVERS.md#field-reference) |
|
|
273
276
|
| 📜 **Logs** | Live per-server stream, buffer plus rotated files on disk, search, filter to one stream, download, one click to clear. |
|
|
274
277
|
| 📈 **Resources** | CPU and RSS of the whole process tree, with an optional memory ceiling that triggers a restart. |
|
|
275
278
|
| 🌡️ **Host vitals** | Load, memory, swap, disk and CPU temperature, with thresholds that notify once and again on recovery. |
|
|
276
279
|
| 🤖 **Token API** | Scripts and agents drive it with `Authorization: Bearer` — no browser, no session. [↑](#-agents-scripts-and-tools) |
|
|
277
|
-
| 🔔 **Notifications** | Telegram on crash, unhealthy, forced restart, recovery, host thresholds and DNS changes
|
|
280
|
+
| 🔔 **Notifications** | One list of **destinations** — Telegram chats and webhooks (ntfy, Discord, Slack, your own endpoint) — on crash, unhealthy, forced restart, recovery, host thresholds and DNS changes. The event toggles and throttle are set once, and each destination may inherit them or carry its own. [Setup here](./docs/NOTIFICATIONS.md). |
|
|
278
281
|
| 🌐 **Dynamic DNS** | Keep hostnames pointed at your public IP — Cloudflare, Namecheap, Spaceship, Porkbun, GoDaddy, Gandi and more. [DDNS.md](./docs/DDNS.md) |
|
|
279
282
|
| 🔀 **Reverse proxy** | One engine in front of everything, with automatic HTTPS: `git.example.com` → a Gitea entry, `media.example.com` → a service on another box, `panel.example.com` → the panel. Caddy, installed and supervised by the panel. [REVERSE_PROXY.md](./docs/REVERSE_PROXY.md) |
|
|
280
|
-
| 💾 **Backups** |
|
|
283
|
+
| 💾 **Backups** | Global settings, TLS, workspaces, and inside each one its settings, servers, secrets and declared data — plain `.zip`, or AES-256 with a password. Each secret is picked separately, and a restore can be customized. |
|
|
281
284
|
| 🌍 **Nine languages** | English, Vietnamese, Chinese, Japanese, Spanish, Korean, Russian, French, German — picked on the login page or in **Global settings → Language**, kept per browser. |
|
|
282
285
|
| 🎨 **BYOU — Bring Your Own UI** | Upload a static build, `ui-update` to follow its releases, `ui-revert` to go back. [UI_CREATION.md](./docs/UI_CREATION.md) |
|
|
283
286
|
| 🔐 **Security** | Cookie sessions, API tokens, scrypt hashes, per-IP lockout, optional TLS, and a refusal to expose itself without a password. |
|
|
@@ -464,10 +467,15 @@ Everything binds `127.0.0.1` until you say otherwise.
|
|
|
464
467
|
|
|
465
468
|
## 🔔 Notifications
|
|
466
469
|
|
|
467
|
-
|
|
470
|
+
A message when something happens while you are not looking: a server that gave up restarting, a
|
|
468
471
|
failing health check, a forced restart, a recovery, a host threshold (disk, memory, swap, load,
|
|
469
|
-
temperature), or a dynamic DNS change.
|
|
470
|
-
|
|
472
|
+
temperature), or a dynamic DNS change.
|
|
473
|
+
|
|
474
|
+
Every alert goes to a list of **destinations** — a Telegram chat, a webhook, or several of each. The
|
|
475
|
+
event toggles and the throttle are set **once**, and each destination either inherits them or carries
|
|
476
|
+
its own. Rate-limited per destination, server *and* reason. Bot tokens and webhook credentials stay in
|
|
477
|
+
the secrets file, never in a config. **Two minutes of setup:
|
|
478
|
+
[NOTIFICATIONS.md](./docs/NOTIFICATIONS.md).**
|
|
471
479
|
|
|
472
480
|
---
|
|
473
481
|
|
|
@@ -485,11 +493,38 @@ Provider tokens stay in the workspace's secrets file. **Providers and the config
|
|
|
485
493
|
|
|
486
494
|
**Global settings → Backups** archives the panel's own settings, its secrets and the TLS pair — plus
|
|
487
495
|
every workspace you pick. It is two-level: the top of *Create backup…* lists the global items and
|
|
488
|
-
each workspace; opening
|
|
489
|
-
directory its entries declare, and you can drop any single piece.
|
|
490
|
-
an archive before anything is written. Either way it is an
|
|
491
|
-
password, restored per path. Known build output and
|
|
492
|
-
`.next`, framework caches) are skipped per entry;
|
|
496
|
+
each workspace; opening one lists its **settings**, **servers**, its **secrets** and every data
|
|
497
|
+
directory its entries declare, and you can drop any single piece. Each secret has its own checkbox.
|
|
498
|
+
*Restore…* shows the same list from an archive before anything is written. Either way it is an
|
|
499
|
+
ordinary `.zip`, or WinZip AES-256 with a password, restored per path. Known build output and
|
|
500
|
+
dependency directories (`node_modules`, `dist`, `.next`, framework caches) are skipped per entry;
|
|
501
|
+
`backupIgnoreGenerated: false` captures them anyway.
|
|
502
|
+
|
|
503
|
+
**Automatic backups** write one archive on a schedule you set — the page asks in hours; the config
|
|
504
|
+
stores `intervalMs` — with a retention of its own (`Keep automatic`). The two counts are independent: `Keep` bounds the archives you take by hand,
|
|
505
|
+
and a scheduled pass never prunes one of yours to make room for its own. Both live in the same
|
|
506
|
+
directory, and an automatic archive is named `auto-…` so you can tell them apart — a name you drop
|
|
507
|
+
in by hand with that prefix is treated as one, so do not use it.
|
|
508
|
+
|
|
509
|
+
<details>
|
|
510
|
+
<summary><b>🔑 Restoring a secret</b></summary>
|
|
511
|
+
|
|
512
|
+
An archive records **which release wrote it and the config schema it understood**; a restore refuses
|
|
513
|
+
a newer schema outright rather than restoring the parts it recognizes.
|
|
514
|
+
|
|
515
|
+
Ticking a **single secret** merges by field: it lands and the others in that file are left alone. So
|
|
516
|
+
restoring the Telegram token does not clear the DDNS credentials. Ticking the whole **Secrets** entry
|
|
517
|
+
replaces the file with the archive's copy instead, which is what makes the two worth telling apart.
|
|
518
|
+
|
|
519
|
+
Two things to know before restoring onto a machine already in use:
|
|
520
|
+
|
|
521
|
+
- **The password hash and API token hash are secrets like any other.** Restoring them reinstates the
|
|
522
|
+
old machine's password and long-lived token, so anyone holding that token keeps access. Leave them
|
|
523
|
+
unticked, or rotate afterwards with `pnpm run set-token --generate`.
|
|
524
|
+
- **`HHOSTED_DDNS_SECRET` is not in the archive.** DDNS credentials travel sealed under it, so a host
|
|
525
|
+
with a different value cannot open them. Supply the same secret, or re-enter the credentials.
|
|
526
|
+
|
|
527
|
+
</details>
|
|
493
528
|
|
|
494
529
|
<details>
|
|
495
530
|
<summary><b>🚚 One archive is a whole setup</b></summary>
|
|
@@ -649,6 +684,7 @@ src/cli.ts the command line; one file per command under src/cli/
|
|
|
649
684
|
src/index.ts the control plane itself, used by `up --foreground`
|
|
650
685
|
uis/ UIs: `stock` (shipped in the package) and alternatives — any framework, static output
|
|
651
686
|
bin/ the published entry point
|
|
687
|
+
docs/branding/ logo, icons and the social preview; the SVGs are the source, `pnpm run brand` renders them
|
|
652
688
|
docs/ topic docs, UI examples and the README's media
|
|
653
689
|
scripts/ builds, typechecks, media capture, release helpers
|
|
654
690
|
test/ the vitest suite
|
|
@@ -665,7 +701,7 @@ plus types; `pnpm test` is vitest; `pnpm run media` regenerates the GIF above.
|
|
|
665
701
|
| if you want to… | read |
|
|
666
702
|
| --- | --- |
|
|
667
703
|
| declare a server: every field, placeholders, port conflicts | [SERVERS.md](./docs/SERVERS.md) |
|
|
668
|
-
| get Telegram alerts working end to end | [NOTIFICATIONS.md](./docs/NOTIFICATIONS.md) |
|
|
704
|
+
| get Telegram or webhook alerts working end to end | [NOTIFICATIONS.md](./docs/NOTIFICATIONS.md) |
|
|
669
705
|
| expose the stack behind one hostname, with HTTPS | [REVERSE_PROXY.md](./docs/REVERSE_PROXY.md) |
|
|
670
706
|
| build a UI against the API | [UI_CREATION.md](./docs/UI_CREATION.md) |
|
|
671
707
|
| change the internals: architecture and the rules | [AGENTS.md](./AGENTS.md) |
|