Skip to content

Getting Started

This guide covers running your own Colibri AppView. It does not cover deploying the colibri.social website.

  • The AppView, which serves the XRPC API, the two WebSockets and the voice SFU in one process.
  • A PDS running the spaces alpha, which hosts every community account your instance creates. Either one you already run, or the one in docker-compose.pds.yml.

Storage defaults to libSQL against a file, so there is no database service to run. Postgres is available as an overlay if you would rather use it.

  • A PDS you control running the spaces alpha (ghcr.io/bluesky-social/atproto:pds-spaces-alpha), plus its admin password. This is required: communities are AT Protocol accounts and the AppView creates them there. A stock PDS will not do, because it does not implement com.atproto.simplespace.
  • A domain with TLS, for example appview.example.com. The AppView identifies itself with a did:web derived from a hostname, serves its DID document at /.well-known/did.json, and both clients and community PDSs reach it over HTTPS. A bare IP will not work.
  • Wildcard DNS for community handles. Communities get handles under COMMUNITY_HANDLE_DOMAIN, answered by the PDS, so *.${COMMUNITY_HANDLE_DOMAIN} must resolve to it under a covering certificate.
  • Docker and Docker Compose, or Node 24 and pnpm to run it directly.
  • A Linux server. It is the only tested platform.
  1. Clone the repository and create your config:

    Terminal window
    git clone https://github.com/colibri-social/api.git
    cd appview
    cp .env.example .env
  2. Fill in .env. Six values have no default and the AppView refuses to boot without them: APPVIEW_DID, PUBLIC_URL, SIGNING_KEY, CREDENTIAL_ENCRYPTION_KEY, PDS_URL and COMMUNITY_HANDLE_DOMAIN. The file carries the openssl lines that generate the two secrets.

  3. Build and start it. There is no published image, so compose builds one from the Dockerfile in the repository. Expect the first build to take a few minutes.

    Terminal window
    docker compose up -d --build

    That runs the AppView alone on libSQL, against the appview-data volume, pointed at whatever PDS_URL names. Rebuild with the same command after pulling new commits, since nothing updates the image for you.

  4. Put it behind a TLS-terminating reverse proxy on your domain.

  5. Confirm your DID document resolves and lists #colibri_appview and #atproto_space_syncer:

    Terminal window
    curl https://appview.example.com/.well-known/did.json
  6. Confirm it identifies itself:

    Terminal window
    curl https://appview.example.com/xrpc/social.colibri.beta.server.describeServer

docker-compose.yml is the base. Three files compose on top of it:

Overlay What it adds
docker-compose.postgres.yml Postgres, and rewrites DATABASE_URL to use it
docker-compose.pds.yml A local spaces-alpha PDS and a private PLC directory, for developing without a PDS of your own
docker-compose.integration.yml The same pair, ephemeral, for the integration suite
Terminal window
docker compose -f docker-compose.yml -f docker-compose.pds.yml up

The spaces-alpha PDS is published for amd64 only, so it runs under emulation on an arm64 host. The PLC directory is built from docker/plc rather than pulled, because every published PLC image dates from 2023 and predates the operation format this PDS emits.

The full list is in .env.example. These are the ones you are likely to touch:

Variable Required Purpose
APPVIEW_DID Yes The did:web this instance answers as, for example did:web:appview.example.com
PUBLIC_URL Yes Where this AppView is reachable from the public internet
SIGNING_KEY Yes secp256k1 private key, 64 hex characters, published in the DID document
CREDENTIAL_ENCRYPTION_KEY Yes 32 bytes base64, encrypts community passwords at rest
PDS_URL Yes The spaces-alpha PDS where communities are created
COMMUNITY_HANDLE_DOMAIN Yes Domain community handles live under. *. of it must resolve to the PDS
PDS_ADMIN_PASSWORD No Without it the AppView serves reads but cannot create a community or repair one whose password stopped working
DATABASE_URL No Defaults to file:./data/colibri.db. A postgres:// URL switches driver
CORS_ORIGINS No Browser origins allowed to call /xrpc, comma-separated, or * for any. Unset, production allows none, so a client on another origin needs it
SYNC_WORKERS, SYNC_SWEEP_SECONDS No Sync worker pool size and sweep interval
SERVICE_AUTH_MAX_LIFETIME_SECONDS No Rejects service auth tokens whose expiry is further away than this
JETSTREAM_URL No Jetstream v2 host. Only identity and account events are consumed
VAPID_*, FCM_SERVICE_ACCOUNT_JSON No Web Push and Android push. Unset disables background notifications
KLIPY_API_KEY No Enables the GIF picker
SFU_ANNOUNCED_IP No Public IP announced in the SFU’s ICE candidates. Required behind NAT

Voice runs on a mediasoup SFU inside the AppView process. WebRTC media flows directly to the host rather than through your reverse proxy, and it needs two things arranged for it:

  • Announced IP and media ports. Set SFU_ANNOUNCED_IP to your public IP and open SFU_RTC_MIN_PORT through SFU_RTC_MAX_PORT (40000 to 40100 by default) for both UDP and TCP, because the SFU falls back to ICE over TCP when UDP is blocked. Without this, users connect and hear nothing.
  • TURN for restrictive networks. Clients behind symmetric NAT cannot reach the media ports directly. Point them at a TURN server with SFU_ICE_SERVERS, a JSON array of RTCIceServer objects. Unset means direct connection only.

Open user settings, then Preferences, and set the AppView URL to your instance. The client probes describeServer, accepts the host only if it reports software: "colibri-appview", and re-authenticates so your session is scoped to the new AppView.

Authentication scopes are pinned to an AppView’s did:web and cannot use a wildcard, so a client only authorises AppViews it was configured to trust. You generally cannot point an arbitrary hosted client at a brand-new self-hosted AppView and sign in. The shared UI is published as @colibri-social/client.