# Running a Couchbase Edge Server

A copy-and-run example — a Dockerfile, a docker run command, and the config and users files — for the server Bring Your LM syncs against.

Status: Shipped

This is the concrete server-side companion to [Sync](/docs/features/sync). It gives you
a working **Couchbase Edge Server** you can run in Docker and point the app at.
For what actually replicates, how secrets are kept out of the sync stream, and
the in-app connection form, read the Sync page — this page is just the server.

Remember the version rule from that page: Bring Your LM is **Couchbase Lite
3.x**, and Couchbase Edge Server is a 3.x-protocol product. Pin the image to a
1.x release, as below — there is no Edge Server for the newer Couchbase Lite 4.x
line yet.

## Build the image

Couchbase publishes Edge Server as a Debian package; this Dockerfile installs it
onto a slim base and runs it against a mounted config file.

```dockerfile
FROM debian:bookworm-slim

ARG CBES_VERSION=1.0.1
ARG CBES_DEB_URL=https://packages.couchbase.com/releases/couchbase-edge-server/${CBES_VERSION}/couchbase-edge-server_${CBES_VERSION}_amd64.deb

RUN apt-get update \
    && apt-get install -y --no-install-recommends curl ca-certificates \
    && curl -fsSL -o /tmp/cbes.deb "${CBES_DEB_URL}" \
    && apt-get install -y --no-install-recommends /tmp/cbes.deb \
    && rm -f /tmp/cbes.deb \
    && apt-get purge -y curl \
    && apt-get autoremove -y \
    && rm -rf /var/lib/apt/lists/*

USER couchbase
WORKDIR /opt/couchbase-edge-server/etc
EXPOSE 59840

CMD ["/opt/couchbase-edge-server/bin/couchbase-edge-server", "config.json"]
```

Build it:

```bash
docker build -t couchbase-edge-server:1.0.1 .
```

## The config file

Save this next to the Dockerfile as `config.json`. It defines one database,
`byllm`, syncing bidirectionally, and lists every collection the app
replicates. The list must cover them all — a collection the app pushes but the
server doesn't serve will 404. Don't add the server's own `_default._default`;
the app deliberately doesn't sync it.

```json
{
  "interface": "0.0.0.0:59840",
  "users": "/opt/couchbase-edge-server/etc/users.json",
  "enable_anonymous_users": false,
  "logging": { "console": true },
  "databases": {
    "byllm": {
      "path": "/opt/couchbase-edge-server/var/databases/byllm.cblite2",
      "create": true,
      "enable_client_writes": true,
      "enable_client_sync": "bidirectional",
      "collections": [
        "_default.memories",
        "_default.tools",
        "_default.api_providers",
        "_default.bots",
        "_default.conversations",
        "_default.conversation_messages",
        "_default.image_blobs",
        "_default.image_blob_chunks",
        "_default.settings",
        "_default.workspaces",
        "_default.jobs",
        "_default.devices",
        "_default.key_offers",
        "_default.key_requests",
        "_default.secret_entries",
        "_default.constant_entries",
        "_default.embedded_model_bundles",
        "_default.elicitations",
        "_default.compaction_events",
        "_default.spend_events",
        "_default.tool_captures",
        "_default.conversation_drafts"
      ]
    }
  }
}
```

## The users file

Save this as `users.json`. Each user needs a **bcrypt** password hash and the
`replicate` role. The username and password here are what you type into the
app's sync settings.

```json
{
  "alice": {
    "password": "$2a$12$REPLACE_WITH_A_BCRYPT_HASH",
    "roles": ["replicate"]
  }
}
```

Generate the hash with Apache's `htpasswd` (from `apache2-utils`) and drop the
`user:` prefix it prints, leaving just the `$2a$...` / `$2y$...` string:

```bash
htpasswd -nbBC 12 alice 'your-strong-password'
```

If you'd rather run an open server on a trusted network, set
`"enable_anonymous_users": true` in `config.json`, drop the `"users"` line and
the `users.json` mount, and turn **Anonymous access** on in the app instead.
Prefer real users for anything reachable beyond your own machine.

## Run it

Mount the two config files read-only and keep the database on a named volume so
it survives restarts:

```bash
docker run -d \
  --name couchbase-edge-server \
  --restart unless-stopped \
  -p 59840:59840 \
  -v "$PWD/config.json:/opt/couchbase-edge-server/etc/config.json:ro" \
  -v "$PWD/users.json:/opt/couchbase-edge-server/etc/users.json:ro" \
  -v cbes-data:/opt/couchbase-edge-server/var/databases \
  couchbase-edge-server:1.0.1
```

Or, with a `docker-compose.yml`:

```yaml
services:
  couchbase-edge-server:
    build: .
    image: couchbase-edge-server:1.0.1
    container_name: couchbase-edge-server
    ports:
      - "0.0.0.0:59840:59840"
    volumes:
      - cbes-data:/opt/couchbase-edge-server/var/databases
      - ./config.json:/opt/couchbase-edge-server/etc/config.json:ro
      - ./users.json:/opt/couchbase-edge-server/etc/users.json:ro
    restart: unless-stopped

volumes:
  cbes-data:
```

## Point the app at it

In the app, open **Settings**, then **Sync**, enable it, and set the endpoint to
your host, port `59840`, and the database name `byllm`:

```text
ws://<host>:59840/byllm
```

Fill in the username and password from `users.json`. On a plain LAN `ws://` is
fine; over the internet, terminate TLS at a reverse proxy and use `wss://` —
the endpoint carries all your synced data.

```text
wss://cbe.example.com/byllm
```

## Behind a reverse proxy

For remote access, put the container behind a proxy that terminates HTTPS on a
hostname and forwards to `59840`. With Traefik, labels on the container do it:

```yaml
labels:
  traefik.enable: "true"
  traefik.http.routers.cbe.rule: "Host(`cbe.example.com`)"
  traefik.http.routers.cbe.entrypoints: "websecure"
  traefik.http.services.cbe.loadbalancer.server.port: "59840"
```

The app then connects with `wss://cbe.example.com/byllm`.

## Keep the collection list current

When a future version of the app adds a new collection, this server's
`collections` list has to grow to match, or that new data silently won't sync.
The list above is the complete set the current app replicates.

More in [Features](/docs/features): [Providers — bring your own LLM](/docs/features/providers) · [On-device models — run fully offline](/docs/features/embedded-models) · [Agents — the thing you build](/docs/features/agents) · [Tools — giving an agent more than the model knows](/docs/features/tools) · [Workspaces — keep your work in scopes](/docs/features/workspaces) · [Conversations — how a turn runs](/docs/features/conversations) · [Attachments — images and files in a message](/docs/features/attachments) · [Context management — what the model still sees](/docs/features/context-management) · [Background turns — replies that keep running](/docs/features/background-turns) · [Local-first & private by design](/docs/features/local-first) · [Sync — your data across your devices](/docs/features/sync) · [Sharing — move agents, tools and providers as a file](/docs/features/sharing) · [Marketplace — find and publish shared agents, tools and providers](/docs/features/marketplace) · [Spell checking — catch typos while you write](/docs/features/spell-check)

---

[Bring Your LM](/) · [Docs](/docs/features) · [Marketplace](/marketplace)

[Articles](/articles) · [Releases](/releases) · [Bundle Format](/marketplace/bundle-format) · [Marketplace Terms](/terms) · [App Privacy](/privacy) · [Website Privacy](/website-privacy) · [Open Source](/open-source) · [llms.txt](/llms.txt)
