Skip to main content

Server Setup

Use this path when ProPR should run on a shared host or production server.

Starting from a bare VPS?

If this is a fresh server, follow Secure VPS Deployment instead — it covers OS hardening, the host firewall, localhost port binding, and TLS in addition to the ProPR-specific steps below.

What Changes From Local Setup​

The Docker image flow is the same as Local Setup. The differences are:

  • Use a stable runtime directory such as /srv/propr.
  • Set public URLs in .env.
  • Put ProPR behind a reverse proxy or ingress.
  • Configure TLS at the proxy layer.
  • Optionally switch to an advanced intake mode (polling, or your own GitHub App webhook); the default hosted-App WebSocket routing needs no inbound endpoint.
  • Restrict access to the Docker socket and credential directories.
  • Back up data, logs, repositories, Redis, and SQLite state.

The server must be a Linux amd64 host that meets the system requirements; the launcher bind-mounts host paths and the Docker socket directly. For normal use, start with at least 8 GB RAM and 20 GB of free disk. A 2-vCPU, 4-GB host is suitable for a single-task evaluation when WORKER_CONCURRENCY=1.

Runtime Directory​

sudo mkdir -p /srv/propr/{data,logs,repos}
sudo chown -R "$USER" /srv/propr
cd /srv/propr

For the own-App path, propr github-app create writes the private key into this runtime directory with mode 0600. The default ProPR Connect path needs no key.

Public URLs​

Set the URLs in .env to your domain:

FRONTEND_URL=https://propr.example.com
API_PUBLIC_URL=https://propr.example.com
GH_OAUTH_CALLBACK_URL=https://propr.example.com/api/auth/github/callback

API_PUBLIC_URL otherwise defaults to http://localhost:4000, which breaks auth redirects and attachment links behind a proxy. The GitHub OAuth App callback URL must match.

GitHub Event Intake​

By default ProPR receives GitHub events through the hosted ProPR GitHub App over WebSocket routing (GITHUB_EVENT_INTAKE_MODE=routing_websocket). Events stream to ProPR over an outbound WebSocket with near-immediate delivery, so a server needs no inbound public URL for intake and no webhook secret — the recommended path for almost every server. Once the shared App is installed, propr relay enroll provisions the routing/relay credentials; see GitHub Authentication. Note that GH_WEBHOOK_SECRET applies only to the own-App webhook option below and is ignored in routing mode.

Two advanced intake modes are available when you have a specific reason to use them:

Advanced: Polling​

Set GITHUB_EVENT_INTAKE_MODE=polling to have ProPR pull labeled issues from the GitHub API on a fixed interval (POLLING_INTERVAL_MS, milliseconds; default 60000). Polling needs no inbound endpoint either, but it adds latency (up to one interval) and consumes the installation's API budget continuously — see Deployment.

Advanced: Your Own GitHub App Webhook​

Create and install a correctly configured App:

propr github-app create --root /srv/propr --public-url https://propr.example.com
# Over SSH, add --no-browser and follow the portable form / paste-back instructions.
propr start --root /srv/propr --restart

The command configures the webhook, secret, private key, installation, GitHub login, and GITHUB_EVENT_INTAKE_MODE=direct_webhook. Add --org your-org for organization ownership or --allow-workflow-changes to let agents edit CI files. See Create your own App for permissions, SSH instructions, and manual registration.

The webhook endpoint is POST /webhook on the API service (port 4000). Route it through your reverse proxy, for example with nginx. Use an exact-match location = /webhook so the proxy does not also forward prefix siblings such as /webhookadmin or /webhook-test to the API:

location = /webhook {
proxy_pass http://127.0.0.1:4000/webhook;
}

propr github-app create sets the webhook URL to https://propr.example.com/webhook and saves GitHub's matching signing secret automatically.

Start The Stack​

On the server, the CLI control plane is the simplest path (Node.js 22+). The guided propr setup wizard is the recommended bootstrap — it scaffolds the runtime directory, helps you pick a GitHub auth mode and issue intake (including the polling-vs-webhook choice covered above), and starts the stack:

sudo mkdir -p /srv/propr && sudo chown -R "$USER":"$USER" /srv/propr && cd /srv/propr
propr setup --root /srv/propr # guided, re-runnable bootstrap

Over SSH, run propr setup --no-tui if your terminal lacks raw-mode support; setup then prompts line-by-line. Choosing ProPR Connect (default ProPR GitHub App) at the auth step enrolls the shared App automatically (logging you in if needed, then writing the relay/routing credentials to .env), so no separate propr relay enroll is needed. For your own App, choose Custom GitHub App → Create it for me, or I already have one to enter existing credentials. Setup is safe to re-run after editing public URLs or switching intake mode: it skips already-satisfied steps and never overwrites .env or deletes data.

Manual / Advanced Flow​

To control each step yourself (useful for scripted provisioning and CI), run the underlying commands directly:

sudo mkdir -p /srv/propr && sudo chown -R "$USER":"$USER" /srv/propr && cd /srv/propr
propr init stack # scaffold .env + data/ logs/ repos/
# configure GitHub auth in .env before `propr check` — see below
propr check
propr start --no-tui

Configure GitHub auth in .env before propr check: by default the shared, hosted App via propr relay enroll (no private key), or run propr github-app create --public-url https://propr.example.com for your own App. See GitHub Authentication for the full walkthrough.

propr status, propr stop, and propr start --restart manage the running stack. Prefer a container-only host? Use the launcher below instead.

Alternative: Start The Launcher​

Use the same launcher command as local setup, but run it from /srv/propr or your chosen server directory. All PROPR_* and HOST_* paths must be absolute; the launcher does not expand ~.

To reuse an existing Antigravity account, authenticate on the host with agy login; the launcher mounts HOST_ANTIGRAVITY_DIR="$HOME/.gemini" for its runs. Alternatively, omit that provider host path and choose Log in to a new account after adding Antigravity in the Web UI. For existing OpenCode credentials and Mistral Vibe preparation (including the host prompt cache directory, /tmp/propr-vibe-prompts-$(id -u) by default), see Local Setup.

docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$PWD/.env:/app/.env:ro" \
-e PROPR_ENV_FILE="$PWD/.env" \
-e PROPR_DATA_DIR="$PWD/data" \
-e PROPR_LOGS_DIR="$PWD/logs" \
-e PROPR_REPOS_DIR="$PWD/repos" \
-e HOST_CLAUDE_DIR="$HOME/.claude" \
-e HOST_CODEX_DIR="$HOME/.codex" \
-e HOST_ANTIGRAVITY_DIR="$HOME/.gemini" \
-e HOST_OPENCODE_XDG_DIR="$HOME/.config/opencode" \
-e HOST_OPENCODE_DATA_DIR="$HOME/.local/share/opencode" \
-e HOST_VIBE_DIR="$HOME/.vibe" \
-e HOST_VIBE_PROMPT_CACHE_DIR="/tmp/propr-vibe-prompts-$(id -u)" \
-e VIBE_PROMPT_CACHE_DIR=/tmp/propr-vibe-prompts \
propr/launcher:latest

Omit the OpenCode and Vibe lines if you do not enable those agents. If you run your own GitHub App, set HOST_GH_PRIVATE_KEY in .env to the absolute host path of the .pem; the launcher bind-mounts it into the app containers. To update later, run docker pull propr/launcher:latest and re-run the same command.

Finish In The Web UI​

After the stack is reachable:

  1. Add repositories.
  2. Configure AI Agents.
  3. Review label and PR settings.
  4. Run one small test task.

Each step works from the Web UI or from the ProPR CLI against the public API URL — useful for scripted provisioning:

npm install -g propr-cli
propr remote https://propr.example.com # the API origin behind your proxy
propr login <personal-access-token>
propr repo add owner/repo
propr agent add my-claude -t claude -m opus5 -d opus5
propr remote-status

CLI authentication uses GitHub Bearer tokens and is enabled by default (ENABLE_BEARER_AUTH=true).

Before opening the server to traffic, harden the host and deployment: Secure VPS Deployment covers OS hardening, the host firewall, localhost port binding, and TLS, and Advanced VPS Hardening removes public inbound traffic entirely with a Cloudflare Tunnel and an SSO gate. For ongoing server care, see Maintenance And Troubleshooting.