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

# Self-host SelfTune

> Run the dashboard, backups, multi-device sync, and private sharing in one container

SelfTune Self-Host runs the canonical OSS dashboard and the same Remote Library
v1 protocol used by SelfTune Cloud. It is one non-root container with one
`/data` volume. SQLite stores users, organizations, roles, snapshot heads,
private shares, and audit records; immutable content-addressed objects live
beside it. Raw transcripts never sync.

## Before you start

You need Docker Compose, persistent storage, an HTTPS reverse proxy for public
access, and an administrator who owns authentication, backups, and upgrades.

## Start the service

```bash theme={null}
git clone https://github.com/selftune-dev/selftune.git
cd selftune/apps/selfhost
cp .env.example .env
openssl rand -hex 32
# Store the generated value as SELFTUNE_AUTH_TOKEN in .env
chmod 600 .env
docker compose up -d
```

Open `http://localhost:8787` and enter the admin token. The container runs as
UID 10001, uses a read-only root filesystem, drops Linux capabilities, and
stores writable state only in `selftune-data`.

The web Library and Skill Sets screens read the authenticated admin
organization's Remote Library snapshot. They never inspect a filesystem-local
skill installation inside the container. This hosted dashboard is intentionally
read-only for Skill Sets: modify a Set on a trusted device, sync it, then reload
the self-hosted dashboard.

<Warning>
  Put TLS in front before exposing the service publicly. Set
  `SELFTUNE_PUBLIC_URL` to the exact HTTPS origin; SelfTune does not trust the
  incoming `Host` header to create an allowed origin.
</Warning>

## Connect a SelfTune installation

```bash theme={null}
selftune library configure \
  --url https://selftune.example.com \
  --api-key "$SELFTUNE_ACCOUNT_TOKEN"
selftune library preview
selftune library sync
selftune library status
```

Preview the artifact manifest before the first sync. Keep account tokens out of
shell history, skill packages, source control, and diagnostic output.

The sync protocol uploads immutable skill revisions, selected drafts, Skill
Sets with their pinned dependencies, decision history, and redacted evidence
summaries. It does not upload raw prompts or transcripts.

## Private accounts and shares

The admin account is configured with `SELFTUNE_SELFHOST_ADMIN_EMAIL` and
`SELFTUNE_AUTH_TOKEN`. Add closed accounts with
`SELFTUNE_SELFHOST_USERS_JSON`:

```json theme={null}
[
  {
    "email": "teammate@example.com",
    "name": "Teammate",
    "org_name": "Teammate",
    "role": "member",
    "token": "a-unique-random-token-with-at-least-32-characters"
  }
]
```

Restart after changing accounts. Removed accounts are deactivated without
deleting their snapshots or share history. Tokens are SHA-256 hashed in SQLite,
but the `.env` file still contains the source credentials and must remain
private.

Only immutable skill revisions and Skill Sets can be shared. A Skill Set share
includes every pinned skill revision, requires explicit recipient acceptance,
and copies the objects into the recipient organization during import. Senders
can revoke a share and may set an expiration.

## Back up and restore

Stop writes and archive the complete named volume:

```bash theme={null}
docker compose stop selftune
docker run --rm \
  -v selftune-data:/data:ro \
  -v "$PWD":/backup \
  alpine tar -czf /backup/selftune-backup.tgz -C /data .
docker compose start selftune
```

Restore into an empty `selftune-data` volume while the service is stopped.
Never archive only `selftune-selfhost.db`: snapshots reference files under
`objects/`, so both stores are required for a consistent recovery.

## Health and updates

`GET /healthz` is an unauthenticated process-liveness endpoint. `GET /readyz`
verifies SQLite initialization and every configured organization's referenced
immutable objects. Readiness returns `503` when storage is unavailable or
integrity is degraded, and the container health check uses this endpoint.
Neither probe returns tenant data. Every Remote Library operation under
`/api/v1/remote-library/*` requires a bearer token and applies its persisted
role and organization scope.

Corrupt or missing immutable objects degrade readiness and block affected
snapshot operations rather than returning silently damaged content.

Release builds publish `linux/amd64` and `linux/arm64` images to
`ghcr.io/selftune-dev/selftune-selfhost`. Pin `SELFTUNE_VERSION` in Compose for
controlled upgrades; SQLite migrations run before the server accepts traffic.

<Warning>
  Self-hosting changes who operates security and availability; it does not
  remove those responsibilities. Do not expose the service without TLS,
  authentication, persistent storage, backups, and an upgrade owner.
</Warning>

Confirm the user intends to operate a network service. Inspect Docker, storage,
TLS, hostname, and backup ownership before mutation. Generate unique tokens but
never print them into shared output. Start locally, verify health and readiness,
then stop for approval before exposing the service or syncing artifacts.
