Skip to content

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.

One password gates the web UI; named API keys gate the REST API. Set it when you start:

Terminal window
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 restart and 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.
--hostReachable fromUse when
0.0.0.0 (default)Your whole networkYou’ve set a password.
127.0.0.1The local machine onlyLocal-only, no network exposure.
SituationBindingPassword
Just you, on your own machine127.0.0.1Optional
Reachable from other devices0.0.0.0Required
Behind a reverse proxy or tunnel127.0.0.1Required

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.

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:

Terminal window
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.

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.

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.