Self-hosting (Docker)
Total time: ~30 minutes. PLUR Enterprise runs in Docker Compose behind Caddy; works on public internet (auto-TLS) or intranet (your own cert).
Prerequisites
Section titled “Prerequisites”- Linux server (Ubuntu 22.04+ recommended)
- Docker Engine 24+ and Docker Compose v2
- ≥ 2 vCPU, ≥ 4 GB RAM, ≥ 20 GB disk
- Ports 80 and 443 reachable from your users
- A hostname or IP (public domain or internal)
- GitHub Container Registry access (provided by the PLUR team)
1. Authenticate with GHCR
Section titled “1. Authenticate with GHCR”Create a GitHub Personal Access Token with read:packages scope at github.com/settings/tokens, then:
echo YOUR_GITHUB_TOKEN | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdin2. Download deployment files
Section titled “2. Download deployment files”mkdir -p /opt/plur-enterprise && cd /opt/plur-enterpriseYou need these files (released as a tarball or via the PLUR team):
docker-compose.prod.ymlCaddyfile.example.env.exampledocker/init.sqldocker/02-plur-app-role.shdocker/02-plur-app-role.sql3. Configure
Section titled “3. Configure”cp .env.example .env$EDITOR .envRequired values:
| Variable | Example | Notes |
|---|---|---|
PLUR_PUBLIC_URL | https://plur.your-org.com | Public-facing URL |
PLUR_DATABASE_URL | postgresql://plur_app:...@postgres:5432/plur | App role only |
PLUR_JWT_SECRET | <openssl rand -hex 32> | Token signing |
PLUR_ADMIN_EMAIL | you@your-org.com | First admin |
PLUR_ADMIN_PASSWORD | <one-time> | Forced to change at first login |
PLUR_SMTP_* | optional | If unset, runs in stub mode (logs to console) |
Optional auth (configure later from /admin/sso):
| Variable | Notes |
|---|---|
PLUR_GITHUB_CLIENT_ID / _SECRET | GitHub OAuth |
PLUR_GITLAB_CLIENT_ID / _SECRET / _URL | GitLab OAuth (self-hosted GitLab works) |
PLUR_OIDC_* | OIDC SSO — Google, Okta, Microsoft Entra |
PLUR_SAML_* | SAML 2.0 — older enterprise IdPs |
4. Configure Caddy
Section titled “4. Configure Caddy”cp Caddyfile.example Caddyfile$EDITOR CaddyfileFor public domains, the default config gets free TLS from Let’s Encrypt. For intranet, swap the auto-TLS for tls /path/to/cert.pem /path/to/key.pem.
5. Start
Section titled “5. Start”docker compose -f docker-compose.prod.yml up -dWhat this starts:
postgres— Postgres 16 with Apache AGE.plur-enterprise— the Node server.caddy— TLS termination + reverse proxy.
First start runs migrations and creates the admin user from the env vars.
6. Verify
Section titled “6. Verify”curl https://plur.your-org.com/statusExpected:
{ "status": "ok", "version": "0.x.y", "database": "ok", "graph": "ok", "uptime_s": 12}Log in to /admin with the email + password from .env. You’ll be forced to change the password and (optionally) enable 2FA on first login.
7. Configure auth
Section titled “7. Configure auth”Go to /admin/sso and add at least one IdP for browser users (OIDC/SAML/GitHub OAuth/GitLab OAuth). For agents (Claude Code, Cursor, OpenClaw), issue API keys from /me/api-keys — see Authentication for the right method per client.
Operational tasks
Section titled “Operational tasks”Backups
Section titled “Backups”Daily Postgres dumps run inside the container — see docker/backup.sh. Push them off-host with PLUR_BACKUP_S3_URL or a sidecar.
Updates
Section titled “Updates”cd /opt/plur-enterprisedocker compose pulldocker compose -f docker-compose.prod.yml up -dMigrations are idempotent and run automatically on container start.
Postgres role hardening
Section titled “Postgres role hardening”The compose stack creates two roles automatically: plur_test (bootstrap superuser, used only for extension install and role creation) and plur_app (least-privilege, used at runtime). The full grant list lives in docker/02-plur-app-role.sql. The runtime DSN should always point at plur_app, not plur_test. See Postgres & backups.
Structured JSON via pino. Tail:
docker compose logs -f plur-enterpriseAudit events go to the audit_log table; query via the admin dashboard or directly with SQL.
Production hosting tracked in GitHub
Section titled “Production hosting tracked in GitHub”Full production deployment (auto-restart policies, off-host backup S3 push, monitoring exporters) is tracked in issue #79. The Docker Compose path described here is the documented baseline.