feat: add Hermes WebUI provisioning and English Dragon HD Omni voices
Rebuild & Deploy / rebuild (push) Successful in 2m17s
Rebuild & Deploy / rebuild (push) Successful in 2m17s
This commit is contained in:
1 parent
47cc9c88a0
commit
6b8d55fc92
59 files changed
+1175
-70
No files matched your search
@@ -79,6 +79,80 @@ For colocated FastAPI integration use `Depends(control.current_user)` and
|
||||
this application's `app.state.accounts`/settings. Separate services use the
|
||||
secret-authenticated internal endpoints instead.
|
||||
|
||||
## Hermes LAN access and migration
|
||||
|
||||
User containers use Docker **host networking** for outbound access to the same
|
||||
LAN resources as Unraid. The control service must also run with host networking
|
||||
(as in the deployment script). Each Hermes API binds **127.0.0.1 only**, on its
|
||||
own persistent port; no LAN-facing API publication or Docker port bindings.
|
||||
|
||||
`HERMES_API_PORT_RANGE` defaults to `20000-29999`. Reserve this TCP range for
|
||||
Hermes. Allocation skips ports already bound on the host and assignments are
|
||||
stored in the protected `api-ports.json` under `HOPE_HERMES_DATA_DIR`. Run only
|
||||
one control process against this runtime root. Assignments survive restarts and
|
||||
account deletion alongside retained data; changing the range affects only new
|
||||
assignments. An unrelated process taking an assigned port is an operator error;
|
||||
provisioning fails rather than silently changing the account endpoint.
|
||||
|
||||
Deploy/restart the updated control service to migrate existing accounts:
|
||||
startup schedules **all accounts**, including ready ones. Provisioning replaces
|
||||
owned legacy bridge containers with host-networked containers, retaining the
|
||||
account name, API key, home, workspace and non-listener configuration. Only the
|
||||
API host/port settings in the persisted YAML are updated. Owned legacy networks
|
||||
are removed. Expect brief per-account downtime; failed startup is retriable with
|
||||
the retained state. The normal reconcile loop also rejects legacy containers as
|
||||
not ready and schedules provisioning. This is not a live deployment receipt.
|
||||
|
||||
**Security tradeoff:** host networking removes per-user network namespace
|
||||
isolation. Containers can reach host-loopback services and other account API
|
||||
ports (authentication is still required). Loopback-only binding prevents direct
|
||||
LAN access to the Hermes API, but is not isolation from other host-networked
|
||||
containers. File separation, nonroot execution, capability drops and resource
|
||||
limits remain. This controls the Hermes API listener, **not arbitrary tool
|
||||
processes**: terminal/browser tools can open their own LAN-facing unprivileged
|
||||
ports. Strict outbound-only enforcement needs a separate host ingress firewall
|
||||
policy; host networking alone cannot guarantee that. Host networking does not
|
||||
bypass LAN ACLs or configure mDNS/DNS.
|
||||
|
||||
## Per-account Hermes WebUI
|
||||
|
||||
Build `hermes-webui.Dockerfile` as `hope-hermes-webui:62e4d7b`. This packages the
|
||||
pinned nesquena/hermes-webui revision with the existing pinned Hermes image and
|
||||
uses `bootstrap.py --foreground --no-browser --skip-agent-install` as a supervised
|
||||
second service. Both gateway and WebUI exit/restart together on service failure.
|
||||
|
||||
Enable in the protected control runtime environment:
|
||||
|
||||
```dotenv
|
||||
HOPE_WEBUI_ENABLED=true
|
||||
HERMES_IMAGE=hope-hermes-webui:62e4d7b
|
||||
HERMES_WEBUI_HOST=192.168.86.2
|
||||
HERMES_WEBUI_PORT_RANGE=30000-30999
|
||||
```
|
||||
|
||||
Each user gets a persistent port recorded in `webui-ports.json`, a separate random
|
||||
browser password in `<runtime-root>/<full-account-id>/webui-password` (0600), and
|
||||
private WebUI state and self-signed TLS certificate under the retained home.
|
||||
User-selected WebUI passwords have **no minimum length**; only blank/whitespace
|
||||
and multiline values are rejected to keep authentication enabled. After changing
|
||||
the protected password file, recreate that account container to update its env.
|
||||
Passwords are **not** Hope login passwords. An operator can retrieve the intended
|
||||
account's password over trusted SSH; never print all credentials or Docker envs.
|
||||
Certificates have the configured LAN IP SAN; clients must trust the self-signed
|
||||
certificate. Only WebUI binds the configured LAN IP; gateway APIs remain loopback.
|
||||
No router forwarding/public internet access is configured. No firewall changes
|
||||
are needed if the allocated LAN listener is already reachable.
|
||||
|
||||
Browser chat uses that account's authenticated gateway and runs API, preserving
|
||||
its execution boundary/concurrency limit. Both API readiness and **HTTPS** WebUI
|
||||
health must pass. Separate cookie names prevent collisions between ports, but
|
||||
ports on the same IP are not a cookie isolation boundary: for stronger isolation,
|
||||
use per-account hostnames. WebUI grants its authenticated owner powerful access
|
||||
to account files/configuration/tools. Source/dependency installers are disabled
|
||||
at runtime. Recreating an existing container preserves state, keys, API ports,
|
||||
WebUI ports and browser passwords. CI builds the pinned WebUI image for future
|
||||
accounts; keep the above environment enabled across control redeployments.
|
||||
|
||||
## Provisioner interface
|
||||
|
||||
`create_app(settings: Settings, provisioner=...)` supports offline injection.
|
||||
|
||||
Reference in new issue
Block a user