Skip to content

Server Deployment

A server deployment runs a dedicated Oratorio backend and DotCraft AppServer on a Linux host for unattended source sync, PR review dispatch, and draft generation. The recommended entry point is the Oratorio CLI.

bash
curl -fsSL https://dotharness.github.io/oratorio/install.sh | bash
oratorio server init

The installer downloads the Linux x64 oratorio CLI from GitHub Releases and verifies the release checksum. The CLI then creates and manages a Docker Compose review stack for you.

What The CLI Creates

oratorio server init creates an isolated review stack:

text
oratorio-review/
  docker-compose.yml
  docker-compose.webhook.yml  # only when public webhook ingress is enabled
  Caddyfile                   # only when public webhook ingress is enabled
  .env
  oratorio.config.json
  workspace/
  secrets/

The stack contains:

  • one Oratorio backend container;
  • one dedicated DotCraft AppServer container for review work;
  • one shared /workspace mount used by both containers;
  • one server-side oratorio.config.json managed by the CLI.
  • an optional Caddy gateway that exposes only the GitHub webhook endpoint.

This review stack is intentionally separate from any DotCraft container you may already use for bots, chats, or other business workflows.

Key Constraint: Shared Filesystem

Oratorio creates Git worktrees and passes their absolute paths to DotCraft. Therefore Oratorio and DotCraft must see the same workspace filesystem at the same absolute path. The CLI-generated stack mounts the same host workspace/ directory into both containers at /workspace.

Multiple repositories do not require multiple containers. A single stack can review many repositories through explicit workspace routes:

bash
oratorio server add-repo github:owner/repo-a
oratorio server add-repo github:owner/repo-b

Each repository is cloned into workspace/<owner>__<repo> and mapped to /workspace/<owner>__<repo> in oratorio.config.json.

First Run

During oratorio server init, the CLI asks for:

  • DotCraft provider, model, and API key;
  • one or more GitHub repositories;
  • GitHub App ID and private key path or file;
  • optional GitHub App installation ID for the repository owner;
  • whether to enable Auto Review;
  • whether to enable GitHub write-back.
  • an optional public DNS name or IP address for GitHub webhook delivery.

The CLI uses your server's existing Git credentials for git clone; it does not write GitHub App installation tokens into Git remotes. GitHub App credentials are the only supported GitHub API authentication path for read sync, PR review, checks, comments, and delivery. Use --no-github-writes if the App should be read-only.

After the stack starts, the CLI prints the SSH tunnel command:

bash
ssh -N -L 5087:127.0.0.1:5087 user@your-server

In Oratorio Desktop, use Remote > SSH tunnel and choose a local SSH config alias such as your-server, or use Remote > URL after opening the tunnel manually. The tunneled backend URL is:

text
http://127.0.0.1:5087

Desktop tunnel mode uses the system ssh binary and your local SSH config, keys, or agent. It does not store SSH passwords or private key contents.

Enable GitHub Webhook Ingress

Keep the backend private and add the HTTPS gateway when GitHub must deliver comment commands or synchronization events:

bash
oratorio server webhook enable \
  --public-host webhooks.example.com \
  --acme-email ops@example.com

The command generates docker-compose.webhook.yml and Caddyfile, adds a 32-byte webhook secret to .env, validates ports 80 and 443, validates both container configurations, and starts the gateway. It recreates Oratorio so the backend receives the secret. A newly generated secret is printed once. To use a secret you already generated, put its single-line value in a file:

bash
oratorio server webhook enable \
  --public-host webhooks.example.com \
  --secret-file ./webhook-secret.txt

You can also enable ingress during initialization:

bash
oratorio server init --webhook-public-host webhooks.example.com

Interactive initialization lets you leave the host empty for a private deployment. Non-interactive --yes mode enables ingress only when --webhook-public-host is explicitly present.

Caddy uses normal automatic HTTPS for a DNS name. A globally routable public IP is also accepted; Caddy then requests a Let's Encrypt certificate with the shortlived ACME profile and renews it from its persistent certificate volume. Private, loopback, link-local, reserved, and URL-shaped values are rejected.

The public URL is:

text
https://<host-or-ip>/api/v1/sources/github/webhook

Only an exact POST to that path is proxied. GET, adjacent paths, health checks, and every other /api/v1/* path return 404 at the gateway.

CAUTION

Allow inbound TCP 80 and 443 in the host and cloud firewall, but do not open 5087, the AppServer port, or the dashboard port. Port 80 is used for ACME validation and HTTPS redirection, not as an HTTP webhook fallback.

The CLI does not change DNS, firewall rules, or GitHub App settings. In the GitHub App, enable the webhook, paste the printed secret, keep SSL verification enabled, and subscribe to Issue comments. See GitHub Integration for the complete checklist.

Operations

Common server commands:

bash
oratorio server doctor
oratorio server status
oratorio server logs --follow
oratorio server restart
oratorio server upgrade
oratorio server webhook status

doctor checks Docker, Docker Compose, Git, required secrets, repository checkouts, workspace routes, and Oratorio health. When ingress is enabled, it also validates the merged Compose model, Caddyfile, gateway container, secret presence, and listeners on ports 80 and 443. Secret values are never displayed.

status, logs, restart, and upgrade automatically use the webhook overlay when it exists. Disable only the public ingress with:

bash
oratorio server webhook disable

Disable stops and removes the gateway and its CLI-managed files. It preserves the webhook secret, Caddy certificate volumes, Oratorio, DotCraft, and SSH tunnel access.

Configuration Ownership

For server deployments, configuration is owned by the server-side CLI and files:

  • .env stores secrets such as model keys and the AppServer token;
  • secrets/ stores mounted files such as the GitHub App private key;
  • oratorio.config.json stores source lists, workspace routes, and automation policy, including GitHub App ID, private key path, writes setting, and optional installation profiles;
  • Oratorio Desktop remote mode treats server-admin configuration as read-only.

The generated Docker stack sets Oratorio:Settings:Writable=false, so tunneled Desktop sessions cannot accidentally write server-admin configuration even though the request appears to come from loopback.

Manual Compose Setup

Manual setup remains available for advanced operators. Fetch the Compose template and edit it yourself:

bash
mkdir oratorio && cd oratorio
curl -O https://raw.githubusercontent.com/DotHarness/oratorio/master/deploy/docker/docker-compose.yml
curl -O https://raw.githubusercontent.com/DotHarness/oratorio/master/deploy/docker/.env.example
cp .env.example .env

For more than one repository, prefer oratorio.config.json over long environment-variable arrays.

For a manual DNS-based webhook gateway, also download docker-compose.webhook.yml and Caddyfile, replace the example DNS name, set ORATORIO_GITHUB_WEBHOOK_SECRET in .env, then validate and start the merged stack:

bash
docker compose \
  -f docker-compose.yml \
  -f docker-compose.webhook.yml \
  config --quiet
docker compose \
  -f docker-compose.yml \
  -f docker-compose.webhook.yml \
  up -d

Use the CLI for public IP ingress so it generates the required short-lived certificate policy.

Further Reading

Apache License 2.0