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.
curl -fsSL https://dotharness.github.io/oratorio/install.sh | bash
oratorio server initThe 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:
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
/workspacemount used by both containers; - one server-side
oratorio.config.jsonmanaged 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:
oratorio server add-repo github:owner/repo-a
oratorio server add-repo github:owner/repo-bEach 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:
ssh -N -L 5087:127.0.0.1:5087 user@your-serverIn 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:
http://127.0.0.1:5087Desktop 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:
oratorio server webhook enable \
--public-host webhooks.example.com \
--acme-email ops@example.comThe 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:
oratorio server webhook enable \
--public-host webhooks.example.com \
--secret-file ./webhook-secret.txtYou can also enable ingress during initialization:
oratorio server init --webhook-public-host webhooks.example.comInteractive 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:
https://<host-or-ip>/api/v1/sources/github/webhookOnly 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:
oratorio server doctor
oratorio server status
oratorio server logs --follow
oratorio server restart
oratorio server upgrade
oratorio server webhook statusdoctor 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:
oratorio server webhook disableDisable 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:
.envstores secrets such as model keys and the AppServer token;secrets/stores mounted files such as the GitHub App private key;oratorio.config.jsonstores 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:
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 .envFor 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:
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 -dUse the CLI for public IP ingress so it generates the required short-lived certificate policy.