Install
Nexul runs as a self-hosted instance on your own machine or server. There are two ways to install it.
Option A: Docker Compose (recommended)
Section titled “Option A: Docker Compose (recommended)”This is the fastest path and starts everything you need: the server, the web UI, the logs stack, the automations host, and one runner on the same host. The stack pulls prebuilt images from GHCR rather than building from source — see Upgrade for how those images get updated later.
./install.sh # Linux / macOS.\install.ps1 # Windows, with Docker DesktopThe script:
- Installs Docker if it isn’t already present (
get.docker.comon Linux/macOS,wingetfor Docker Desktop on Windows). - Asks for a password for the logs UI. Leave it blank to generate one — it’s saved to
.enveither way, so re-running the script keeps the same password. - Pulls the stack’s images and starts it with
docker compose pullthendocker compose up -d. - Prints the URL of the setup wizard and the logs UI.
Re-running the script is safe: it keeps whatever logs password is already in .env, and it’s also how you upgrade — see Upgrade.
There’s nothing else to configure before you start. The server generates its own auth secret and the runner’s shared secret on first start and keeps them on its data volume. Everything else — the instance URL, the GitHub App, connectors — is collected the first time you open the web UI, in the setup wizard.
If you’d rather skip the script, docker compose up -d starts the same stack using the dev defaults baked into docker-compose.yml.
What’s in the stack
Section titled “What’s in the stack”| Service | Purpose |
|---|---|
server |
The API, the WebSocket endpoint for runners, and the MCP server |
web |
The React frontend, served by nginx on port 80 |
runner |
One bundled runner, named instance, that builds and deploys on the same host |
openobserve |
Logs, metrics, and traces — see Logs |
automations |
Runs the instance’s default automations |
The stack listens on plain HTTP on port 80. For a public domain, put a Cloudflare tunnel or your own TLS-terminating proxy in front of it, and enter the https:// address as the instance URL in the setup wizard. Every URL Nexul derives — OAuth callbacks, the runner install command, the MCP endpoint — comes from that saved instance URL rather than the incoming request, so the proxy doesn’t need to forward any extra headers.
Option B: single binary
Section titled “Option B: single binary”Download the nexul-server-<os>-<arch> tarball for your platform from the latest release, unpack it, and run it:
./nexul-serverThe single-binary build embeds the web frontend directly (via go:embed), so the server serves the frontend on / and the API on /api/* — no nginx and no Node.js needed at runtime. You can also build it yourself:
make build-single./dist/nexul-serverThe single binary doesn’t include a bundled runner or logs stack. Add runners from the web UI’s Runners page (see Runners), and point logs at any OTLP/HTTP backend with NEXUL_OTLP_ENDPOINT (details in Logs).
Next step
Section titled “Next step”However you installed it, open the printed URL to reach the setup wizard and connect your GitHub App. See Setup wizard for what each step asks for, and Upgrade for how to keep the instance current later.