---
title: Running a Couchbase Edge Server
weight: 11000
extra:
  summary: "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/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.embedded_model_bundles",
        "_default.elicitations"
      ]
    }
  }
}
```

## 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.
