Operations
Self-hosting
Morrow has no hosted service — every instance runs on infrastructure the operator provisions and controls.
Docker
shell
docker run -e MORROW_API_KEY=secret -v morrow-data:/data -p 3000:3000 ghcr.io/jekyo/morrow:latestAll profile directories, the SQLite database, and other durable state live under /data inside the container. Mount a named volume or bind mount there — without it, everything is lost when the container is removed.
Environment variables
| Variable | Default | What it does |
|---|---|---|
| MORROW_API_KEY | (none — required) | The single bearer key gating every request. Required — the server refuses to start without it. |
| MORROW_PORT | 3000 | Port the HTTP/websocket server listens on. |
| MORROW_DATA_DIR | /data | Where profile directories, the SQLite database, and other on-disk state live. |
| MORROW_MAX_PROFILES | 5 | How many profiles may be running (browser processes launched) at once. |
| MORROW_LAUNCH_TIMEOUT | 60 | Seconds to wait for a profile's browser to finish launching before failing. |
| MORROW_DEV_ORIGINS | (unset) | Dev-only: extra hosts (comma-separated, no protocol/port) allowed to load /_next/* assets when running npm run dev from something other than localhost — a LAN IP, hostname, or tunnel. Not used in production. |
Deploying with jekyo
Morrow's own repo is set up to deploy with jekyo, a Docker-compose-to-k3s deployment tool — write a jekyo.yaml pointing at the published image, mount a persistent volume for /data, and set MORROW_API_KEY as a secret. Any container host that gives you a persistent volume and a TLS-terminating reverse proxy in front works the same way — jekyo is a convenience, not a requirement.
Security posture
- Single API key. One
MORROW_API_KEYgates the whole instance — every profile, session, and stored artifact. There is currently no per-user or per-profile access separation. - Run behind TLS. Terminate TLS in front of Morrow (nginx, Caddy, or similar) so the API key and profile data are never sent in the clear. Morrow is not hardened for direct exposure to the open internet.
- Encryption at rest is the operator's responsibility today. Morrow does not encrypt the
/datavolume itself. If encryption at rest is required, provide it at the disk or volume level on the host. - Avoid exposing the Playwright/viewer WebSocket endpoints publicly — the API key travels as a query parameter there and may be logged by upstream infrastructure.
- Keep the host, its dependencies, and the Morrow version itself up to date.
Full security policy
Reporting a vulnerability, supported versions, and the complete operating checklist live in SECURITY.md.