Install & run from a prebuilt binary#
For when you already have — or want — just the opendray binary, with no
installer wizard touching your machine. This is the path for:
npm install -g opendray/npx opendray— the npm package ships the official Go release binary (see README → npm / npx).- Release downloads — grab
opendray_*_<os>_<arch>.tar.gzfrom the Releases page. - Scripted / ephemeral environments — CI runners, golden images, config management (Ansible, Nix, Docker), or any host where you already run your own Postgres and process supervisor.
The binary is the whole gateway — the web admin SPA is embedded, so there is no Node runtime, no separate static server, and nothing to build. What it does not do is set anything up for you. That is the trade: you bring a PostgreSQL database and a way to keep the process running, and in exchange nothing is installed, configured, or registered behind your back.
Want it all done for you instead? On a fresh Linux / macOS box, the one-line installer provisions Postgres, installs the AI CLIs, writes the config, and registers a service in ~5–10 minutes. See README → One-line installer or the manual getting-started.md walkthrough.
This guide takes you from "binary on PATH" to "running gateway" in five
steps, then shows how to keep it running as a service.
Step 1 — Get the binary#
Via npm (any OS with Node ≥ 18)#
[object Promise]The right platform binary (opendray-{linux,darwin}-{x64,arm64}) is selected
automatically via optionalDependencies — there is no postinstall hook and
no network call at install time. Do not pass --no-optional: it skips the
platform package and leaves the launcher with no binary to exec.
Via release archive#
[object Promise]Verify#
[object Promise]Supported platforms: Linux (x64, arm64) and macOS (x64, arm64). Native Windows is not packaged — use WSL2 and follow the Linux path.
Step 2 — Provide PostgreSQL 15+ with pgvector#
opendray stores everything (sessions, memory, audit log) in PostgreSQL, and
its memory subsystem needs the pgvector
extension. Supported server versions: 15, 16, 17.
If you already run Postgres, create a database and a CRUD-only role, then enable the extension once with a superuser:
[object Promise]Once the extension exists, opendray's CRUD-only role runs migrations without any further superuser access. Never point opendray at a superuser role for runtime — give it a project-scoped account and rotate its password out of band.
Step 3 — Configure#
opendray reads its config from a TOML file or purely from environment variables (12-factor) — env always wins over the file. The only hard requirement is the database URL; everything else has a default.
Option A — environment variables (good for containers / ephemeral hosts)#
[object Promise]| Variable | Required | Default | Purpose |
|---|---|---|---|
OPENDRAY_DATABASE_URL |
yes | — | Postgres DSN |
OPENDRAY_ADMIN_PASSWORD |
recommended | — | Web/mobile admin password |
OPENDRAY_ADMIN_USER |
no | admin |
Admin username |
OPENDRAY_LISTEN |
no | 127.0.0.1:8770 |
Bind address |
OPENDRAY_LOG_LEVEL |
no | info |
debug/info/warn/error |
OPENDRAY_LOG_FORMAT |
no | text |
text/json |
Run opendray serve with no -config flag and it loads entirely from the
environment.
Option B — config.toml#
[object Promise]The minimum to edit:
[object Promise]See config.example.toml for the fully annotated
file (logging, session idle detection, backups, vault, MCP). Pass it with
-config config.toml to the commands below. Keep secrets out of the TOML on
shared hosts — set OPENDRAY_DATABASE_URL / OPENDRAY_ADMIN_PASSWORD via env
and leave the file non-secret.
Step 4 — Apply the schema#
[object Promise]Idempotent — re-running is a no-op once the schema is current. This must
succeed before the first serve.
Step 5 — Run it#
[object Promise]This runs in the foreground (Ctrl-C stops it). You should now have:
| URL | What |
|---|---|
http://127.0.0.1:8770/admin/ |
Web admin — log in with admin + your password |
http://127.0.0.1:8770/api/v1/... |
REST + WebSocket API |
That is a complete, running gateway. For anything beyond a quick test, run it under a supervisor so it survives reboots and restarts on crash — next.
Run it as a service#
opendray serve is exactly what a service unit's start command should call.
opendray ships hardened, ready-to-use units; the steps below are the same as
README → Production deploy, which is the
authoritative reference (full bootstrap, sandboxing notes, reverse-proxy/TLS).
Linux — systemd#
The repo ships a hardened unit at
deploy/systemd/opendray.service
(runs migrate as ExecStartPre, secrets via an EnvironmentFile,
on-failure restart, syscall/filesystem sandboxing).
No systemd? (LXC without it, OpenRC, runit, s6, supervisord…) Point your
supervisor at opendray serve -config /etc/opendray/config.toml and run
opendray migrate once as a pre-start step. See
README → Production deploy §B.
macOS — launchd#
The repo ships a LaunchDaemon at
deploy/launchd/com.opendray.opendray.plist
(starts at boot, restarts on crash, logs to /usr/local/var/log/opendray/).
Restart: sudo launchctl kickstart -k system/com.opendray.opendray.
Unload: sudo launchctl bootout system/com.opendray.opendray.
Both units are documented in full — including the secrets layout and why
MemoryDenyWriteExecuteis left off — indeploy/README.md.
Keeping it updated#
How you update depends on how you installed:
Installed via npm — update with your package manager.
[object Promise]opendray updatewould replace the binary insidenode_modulesbehind npm's back and get clobbered on the next install, so don't use it here.Release download / wizard install — the binary self-updates in place (downloads the latest release, verifies its SHA-256, atomically swaps itself):
[object Promise]
Troubleshooting#
the matching platform package "opendray-…" was not installed
npm was run with --no-optional, or the install was interrupted. Re-run
npm install -g opendray (without --no-optional).
unsupported platform
The npm package covers Linux/macOS on x64/arm64 only. On other targets, build
from source — see quickstart.md.
config: database.url is empty
Neither OPENDRAY_DATABASE_URL nor [database].url is set. Set one (Step 3).
connection refused on migrate/serve
Postgres isn't running or the DSN is wrong. Confirm the server is up and the
host/port/credentials in your DSN are correct.
pgvector / extension "vector" is not available
The extension isn't installed on the server, or wasn't enabled in the
opendray database. Re-do Step 2 (install the OS package, then
CREATE EXTENSION vector as a superuser).
Port already in use
Change OPENDRAY_LISTEN (or listen in config.toml) to a free port.
Next steps#
- README → Production deploy — full deploy reference (systemd / launchd / own-supervisor, hardening, reverse proxy)
docs/operator-guide.md— ops: reverse-proxy/TLS topology, encrypted DB backups, data export/importdocs/integration-guide.md— build an external integration against the REST + WebSocket APIdocs/getting-started.md— the guided, all-in-one setup if you'd rather not assemble the pieces yourself