> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tierity.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Self-hosting

> Run Tierity on your own infrastructure with Docker Compose. Your scanner credentials and findings never leave your network.

## Prerequisites

* A Linux or macOS host with **Docker** 24+ and **Docker Compose** v2.20+
* 2 CPU cores and 4 GB of memory or more
* A hostname for Tierity, and ports 80 and 443 open if you want an automatic HTTPS certificate

The stack includes PostgreSQL and Redis, so you don't need to run them separately.

## Install

The installer asks a few questions, writes `docker-compose.yml` and `.env` files, and starts Tierity:

```bash theme={null}
curl -fsSL https://tierity.com/resources/self-host.sh | bash
```

> [!TIP]
>
> Read a script before piping it to your shell: `curl -fsSL https://tierity.com/resources/self-host.sh -o self-host.sh && less self-host.sh`.

It asks for:

| Question | Default |
| - | - |
| Install directory | `~/pwnbook` |
| License key | Blank (free plan) |
| Sign-in mode | Local (email and password) or WorkOS |
| Admin email and password | For local sign-in |
| Base URL | `http://localhost:8080` |
| Frontend and API ports | `8080` and `3001` |
| Email (Resend) settings | Optional, for invitations and notifications |

When it finishes, open the base URL and sign in with the admin account.

> [!NOTE]
>
> Some names in the installed stack, such as the `~/pwnbook` directory, the `armisticegroup/pwnbook` images and `PWNBOOK_*` variables, still use Tierity's former name. They're kept so existing installs keep working.

## What runs

| Service | Purpose |
| - | - |
| `frontend` | The web app, which also proxies API requests to the backend |
| `backend` | The API, background syncs and scheduled jobs |
| `postgres` | The database |
| `redis` | The job queue |
| `caddy` | Reverse proxy with automatic HTTPS |
| `runner` | Optional, started with `--profile runner`: runs scans on this host. See Config → Runners. |

Database migrations run automatically when the backend starts.

## Sign-in modes

Set with `AUTH_PROVIDER` in `backend/.env`:

| Mode | Value | Use when |
| - | - | - |
| **Local** | `local` | You want email and password sign-in with no external services. The default. |
| **WorkOS** | `workos` | You want the email code, password and SSO flow from Tierity Cloud. Needs a WorkOS account. |
| **OIDC** | `oidc` | You want everyone to sign in through your own OpenID Connect identity provider. |

**Local**

```bash theme={null}
AUTH_PROVIDER=local
ADMIN_EMAIL=you@example.com
ADMIN_PASSWORD=change-me
```

The admin account is created on first start. If no admin is configured, Tierity opens a setup wizard instead.

**WorkOS**

In the [WorkOS dashboard](https://dashboard.workos.com), create an application and add your redirect URI, then:

```bash theme={null}
AUTH_PROVIDER=workos
WORKOS_API_KEY=sk_...
WORKOS_CLIENT_ID=client_...
WORKOS_REDIRECT_URI=https://tierity.example.com/auth/callback
```

**OIDC**

Register Tierity as a client in your identity provider with the redirect URI `https://tierity.example.com/auth/oidc/callback`, then:

```bash theme={null}
AUTH_PROVIDER=oidc
OIDC_ISSUER=https://idp.example.com
OIDC_CLIENT_ID=...
OIDC_CLIENT_SECRET=...
OIDC_REDIRECT_URI=https://tierity.example.com/auth/oidc/callback
```

## Environment variables

These live in `backend/.env`.

### Required

| Variable | Description |
| - | - |
| `DATABASE_URL` | PostgreSQL connection string, for example `postgres://postgres:password@postgres:5432/pwnbook` |
| `REDIS_URL` | Redis connection string, for example `redis://redis:6379` |
| `SESSION_SECRET` | A random secret of 32+ characters for signing sessions |
| `FRONTEND_URL` | The public URL of your instance, for example `https://tierity.example.com` |
| `AUTH_PROVIDER` | `local`, `workos` or `oidc` |

### Strongly recommended

| Variable | Description |
| - | - |
| `VCS_ENCRYPTION_KEY` | 32-byte hex key used to encrypt stored credentials: integration secrets, personal tokens and cloud keys. If it isn't set, a key is derived from `SESSION_SECRET`. |

> [!WARNING]
>
> Changing `VCS_ENCRYPTION_KEY`, or `SESSION_SECRET` when no encryption key is set, makes every stored credential unreadable; people would have to re-enter them. Set `VCS_ENCRYPTION_KEY` once, back it up with your database, and don't rotate it without a re-encryption plan.

### Optional

| Variable | Description |
| - | - |
| `RESEND_API_KEY`, `EMAIL_FROM` | Send invitations and notifications by email through Resend |
| `GITHUB_APP_CLIENT_ID`, `GITHUB_APP_SLUG`, `GITHUB_APP_PRIVATE_KEY`, `GITHUB_APP_WEBHOOK_SECRET` | Use a GitHub App for the GitHub integration instead of tokens |
| `SLACK_CLIENT_ID`, `SLACK_CLIENT_SECRET`, `SLACK_REDIRECT_URI` | Your own Slack app for the Slack integration |
| `OPENAI_API_KEY`, `ANTHROPIC_API_KEY` | A server-wide default AI key. Organizations can also add their own under Config → AI Providers. |
| `STORAGE_PATH`, `STORAGE_BASE_URL` | Where uploaded files are stored and served from |
| `IDP_SYNC_INTERVAL_MINUTES` | How often identity providers sync (default 360) |
| `DRATA_SYNC_INTERVAL_MINUTES` | How often Drata syncs (default 360) |
| `ELECTRON_FRONTEND_URL` | The URL the desktop app uses to reach this instance |

> [!WARNING]
>
> Never commit `.env` files to version control.

## HTTPS

Caddy gets and renews a Let's Encrypt certificate for the hostname in the `DOMAIN` variable of the top-level `.env`. Hostnames ending in `.local` or `.internal` get a certificate from Caddy's own local CA instead. For an IP address, uncomment `tls internal` in the `Caddyfile`.

## Upgrading

Run the installer again and choose to upgrade, or pull new images yourself:

```bash theme={null}
cd ~/pwnbook
docker compose pull
docker compose up -d
```

Migrations run automatically. Back up the database first.

## Backups

```bash theme={null}
docker compose exec postgres pg_dump -U postgres pwnbook > tierity-backup.sql
```

The backend also has export and import scripts for moving an instance between hosts:

```bash theme={null}
docker compose exec backend npm run db:export
docker compose exec backend npm run db:import
```

Back up `backend/.env` (and especially `VCS_ENCRYPTION_KEY`) with the database: a backup without its encryption key can't decrypt stored credentials.

## Health check

```bash theme={null}
docker compose exec backend node -e "fetch('http://localhost:3001/health').then(r => r.text()).then(console.log)"
# {"status":"ok"}
```

From outside, `GET https://tierity.example.com/api/config` returns `200` when the frontend and backend are both up.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.