Security
Harmonic drives agents with real access to your repositories and machine, so who can reach it matters. Two settings decide that: an operator password and the host binding.
Operator password
Section titled “Operator password”One password gates the web UI; named API keys gate the REST API. Set it when you start:
harmonic start --password 'a long passphrase' # or the HARMONIC_PASSWORD env var- It’s stored hashed and persists: later starts without the flag keep it, they don’t revert to ungated.
- Setting a new value rotates it. Minimum length is 4 characters.
- To go back to ungated, clear it explicitly, and only on a local
binding:
harmonic start --password ''. - Signing in lasts until the server restarts. After a restart, including
harmonic restartand an upgrade, open tabs return to the Login screen. - Wrong passwords are rate limited. The first five wrong attempts get no delay. After that each wrong attempt waits longer, starting at 1 second and doubling up to 60 seconds. The limit is shared by everyone who can reach the server, not kept per IP address. A login sent while another is still waiting gets HTTP 429. The count resets after 15 minutes with no login attempts, or on a successful sign-in.
Host binding
Section titled “Host binding”--host | Reachable from | Use when |
|---|---|---|
0.0.0.0 (default) | Your whole network | You’ve set a password. |
127.0.0.1 | The local machine only | Local-only, no network exposure. |
Recommended setups
Section titled “Recommended setups”| Situation | Binding | Password |
|---|---|---|
| Just you, on your own machine | 127.0.0.1 | Optional |
| Reachable from other devices | 0.0.0.0 | Required |
| Behind a reverse proxy or tunnel | 127.0.0.1 | Required |
Reverse proxies
Section titled “Reverse proxies”Harmonic rejects a signed-in browser request with 403 when the page’s
Origin host matches neither the Host header nor the first
X-Forwarded-Host value. This covers the web UI and the live WebSocket
(/api/ws). Requests without an Origin header are not checked, and API
keys are not affected.
If your proxy rewrites Host, keep the original value. For nginx:
proxy_set_header Host $host;Or send the original host in X-Forwarded-Host:
proxy_set_header X-Forwarded-Host $host;See CLI and
Configuration for the --password and
--host options, and Settings & overrides for
in-app Permission Rules.
Browser access from another site
Section titled “Browser access from another site”A separately hosted page, such as a dashboard that reads activity with an
API key, needs its origin allowed before the browser will let it call the
REST API. List those origins in HARMONIC_CORS_ORIGINS, comma-separated:
HARMONIC_CORS_ORIGINS='https://viewer.example.com' harmonic start* allows any origin. Requests from an allowed origin still need an API
key, and Harmonic never allows credentialed cross-origin requests, so the
page can’t use your login session. Give such pages a Read Key, which can
view work but change nothing.
Create keys on the API page and choose Read only for a Read Key. It can read Tasks, Attempts, Workspaces and their Epics, maps, activity, Operations, Scheduled Jobs and Notifications, and can listen on the WebSocket, which is filtered to what the key may read. Everything else needs a full-access key.
Secret key backup
Section titled “Secret key backup”Workspace tokens for Forgejo and Jira are encrypted with an instance key
stored in secret.key in the data directory. If the data directory is lost or
corrupted, back up this file along with the database to recover. If the key
file is lost, all stored tokens become unreadable.
Server error references
Section titled “Server error references”When an unexpected server error occurs, the web UI shows a message like
internal server error (ref abc123def456). Search the Harmonic log (usually
~/.harmonic/harmonic.log or journalctl -u harmonic) for that ref ID to
find the logged error with its full stack trace.