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

# Self-hosting on Node

> Run the Burnside Steps relay on your own server, Node 20 or later, with no Cloudflare account.

Run the open relay on your own box with no Cloudflare account. It is a single
Node process: project config lives in one JSON file, screenshots live on disk,
and rate limiting is in-memory. Put a TLS reverse proxy in front of it.

## Quickstart (Docker)

1. Create a data directory and an `.env` file next to `docker-compose.yml`:

   ```
   PUBLIC_BASE_URL=https://feedback.example.com
   ADMIN_SETUP_TOKEN=<a long random string>
   LICENSE_PUBLIC_KEY=<optional: your Pro license public key>
   SHOT_SIGNING_KEY=<optional: a random string to sign screenshot URLs>
   ```

2. Start it:

   ```
   docker compose up -d
   ```

3. Put a TLS reverse proxy (Caddy, nginx, or Cloudflare Tunnel) in front and
   point `PUBLIC_BASE_URL` at the https origin it serves. HTTPS is required for
   the admin panel, because the admin session cookie is Secure.

4. Claim the admin panel at `https://feedback.example.com/admin`, using the
   `ADMIN_SETUP_TOKEN` and a password of at least 8 characters. Add a project,
   set its allowed origins, and connect Linear, GitHub, or GitLab.

5. Install the widget on your site with the relay origin:

   ```
   <script src="https://feedback.example.com/widget.js"
           data-relay="https://feedback.example.com"
           data-project="your-project-id"></script>
   ```

## Quickstart (no Docker)

```
npm i -g @burnsidesteps/relay
DATA_DIR=./data PUBLIC_BASE_URL=https://feedback.example.com \
  ADMIN_SETUP_TOKEN=<random> burnside-relay
```

Run it under a process supervisor (systemd, pm2) and front it with a TLS proxy
as above.

## Configuration

All configuration is via environment variables.

| Variable              | Required    | Default                  | Purpose                                                                                                            |
| --------------------- | ----------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------ |
| `PORT`                | no          | `8787`                   | HTTP listen port.                                                                                                  |
| `DATA_DIR`            | no          | `./data`                 | Holds `config.json` and `shots/`.                                                                                  |
| `PUBLIC_BASE_URL`     | recommended | `http://localhost:$PORT` | The public origin. Used for screenshot URLs and CORS. Set this to your https origin.                               |
| `LINEAR_TOKEN`        | no          | empty                    | Bootstraps a default Linear token. You can also set it in the admin panel.                                         |
| `LICENSE_PUBLIC_KEY`  | no          | empty                    | Unset means licensing is off and only the free tier is available.                                                  |
| `SHOT_SIGNING_KEY`    | no          | empty                    | When set, screenshot URLs are signed and verified at serve time.                                                   |
| `ADMIN_SETUP_TOKEN`   | recommended | empty                    | Required to claim the admin panel. Setup returns 403 until this is set.                                            |
| `PROJECT_MAP`         | no          | empty                    | Optional JSON bootstrap of projects. Projects are normally managed in the admin panel.                             |
| `SHOT_RETENTION_DAYS` | no          | `0`                      | Days to keep screenshots. `0` keeps them indefinitely. A positive number starts a sweeper that deletes older ones. |

## Data and backups

`DATA_DIR/config.json` holds your project config, integration tokens, the admin
password hash, and any Pro license. It is written with `0600` permissions. Back
up the whole `DATA_DIR` to preserve config and stored screenshots. Keep the
directory private.

## Screenshots

Only GitHub destinations store screenshots here. Linear and GitLab upload through their own APIs,
so nothing of theirs lands on disk and retention does not apply to them.

Screenshots are stored on disk under `DATA_DIR/shots/` and served from
`/api/shot/...`. There is nothing external to configure. If you set
`SHOT_SIGNING_KEY`, the URLs are signed so only links the relay generated can be
fetched.

Screenshots are kept indefinitely unless you say otherwise. Set `SHOT_RETENTION_DAYS` to a
positive number of days and the relay deletes anything older, sweeping once at startup and every
six hours after that, logging a line whenever it removes something. This is yours to decide and
your licence does not affect it: the disk is yours.
