Download

Sync

Running a sync server

The sync server holds your accounts' libraries so their devices can sync. It runs in Docker on any machine that stays on, such as a home server, a NAS or a small VPS.

What you need #

  • Docker on an x86_64 or arm64 machine that stays on.
  • Room for every account's covers and fonts, which take most of the space, and their libraries and history, which take little.
  • For devices outside your home network, an https:// address. Katari accepts plain http:// only for addresses on your local network.

Start the server #

With Docker:

Shell
docker run -d --name katari-sync --restart unless-stopped \
  -p 8080:8080 -v katari-sync:/data \
  ghcr.io/pa2x2/katari-sync-server:latest

Or with Docker Compose, in a compose.yaml, started with docker compose up -d:

compose.yaml
services:
  katari-sync:
    image: ghcr.io/pa2x2/katari-sync-server:latest
    restart: unless-stopped
    ports:
      - "8080:8080"
    volumes:
      - katari-sync:/data

volumes:
  katari-sync:

The server listens on port 8080 and keeps everything in the katari-sync volume at /data. Open http://<machine>:8080 in a browser to set it up.

Set up the admin account #

A new server has no accounts, and its web page opens on Set up this server. It asks for a Setup code, which the server prints to its log when it starts:

Shell
docker logs katari-sync

Look for No accounts yet. The setup code for creating the admin account is …, enter the code with a username and password, and select Create admin account. The admin account syncs like any other, and it manages everyone else's.

Until the admin account exists, a device that signs in is told to open the web page first. The same happens after the server is reset, as Move, restore or reset the server describes.

Add people #

On the web page's Accounts, an admin can:

  • Invite someone: the page shows the server address, an invite code and a QR code. The person opens Settings › Sync › Sign in with server address › I have an invite code and chooses their own username and password, or scans the QR code with Scan a code from a linked device. An invite works once, for 1 day.
  • Add account with a username and password you choose and pass on. They can change the password later.
  • Open an account to Reset password, Make admin, Disable it, which stops its devices syncing and keeps its data, or Delete account, which removes its synced data and files from the server. Its devices keep theirs either way.
The server's web page

Everyone can sign in to the web page to see their devices and storage, change their password, remove a device, or delete their synced data under My account. How people use sync on their devices is in Sync.

HTTPS behind a reverse proxy #

The server speaks plain HTTP. For an https:// address, put a reverse proxy with a certificate in front of it, such as Caddy, nginx or Traefik, and set KATARI_SYNC_TRUSTED_PROXIES to the number of proxies in front of it, usually 1. Caddy needs one line:

Caddyfile
sync.example.com {
  reverse_proxy localhost:8080
}

With another proxy, make sure it:

  • passes the Host header on unchanged, since invites show the address the browser used;
  • appends to X-Forwarded-For and sets X-Forwarded-Proto;
  • allows WebSocket upgrades, which bring changes to devices as they happen;
  • accepts request bodies up to 64 MB, the largest cover or font a device uploads.

nginx does none of these by default. In the server block that holds your certificate:

nginx.conf
location / {
    proxy_pass http://localhost:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    client_max_body_size 64m;
}

If a proxy blocks WebSocket upgrades, sync still works, but changes from other devices no longer show within seconds. They come when the app is opened or brought to the front, when the device sends its own changes, and otherwise every few minutes.

Settings #

The server reads these environment variables when it starts, such as -e KATARI_SYNC_TRUSTED_PROXIES=1 with Docker.

Variable Default What it sets
KATARI_SYNC_PORT 8080 The port it listens on.
KATARI_SYNC_HOST 0.0.0.0 The address it listens on.
KATARI_SYNC_DATA_DIR /data Where it keeps its database and files.
KATARI_SYNC_TRUSTED_PROXIES 0 How many reverse proxies are in front of it, from 0 to 10.
KATARI_SYNC_MAX_FILE_BYTES 64 MiB The largest cover or font a device can upload, in bytes.
KATARI_SYNC_MAX_REQUEST_BYTES 32 MiB The largest request it reads, in bytes, at least 1 MiB.
KATARI_SYNC_PULL_PAGE_SIZE 500 How many changes a device downloads at a time, from 1 to 10,000.

A value it can't use stops the server with a message naming the variable.

Back up the data #

Everything the server holds is in its /data volume. Stop the server while you copy it, so the database is copied whole:

Shell
docker stop katari-sync
docker run --rm -v katari-sync:/data -v "$PWD":/backup alpine \
  tar -czf /backup/katari-sync.tar.gz -C /data .
docker start katari-sync

Devices keep their own full copies, so a lost server costs no one their library; a backup saves the accounts and spares every device from filling the server in again.

Update the server #

When a new version of Katari needs a newer server, the app says the server needs a server update. Back up the data first: a new version can change the database so that older versions can't open it, and its release notes say so.

With Docker, pull the new image and start the container again with the same command as before:

Shell
docker pull ghcr.io/pa2x2/katari-sync-server:latest
docker rm -f katari-sync
docker run -d --name katari-sync --restart unless-stopped \
  -p 8080:8080 -v katari-sync:/data \
  ghcr.io/pa2x2/katari-sync-server:latest

With Docker Compose:

Shell
docker compose pull && docker compose up -d

The server's releases list what each version changes, and the web page's footer shows admins which version is running.

Locked out #

An admin who can't sign in to the web page gets a new password from inside the container:

Shell
docker exec katari-sync katari-sync-server reset-password <username>

It prints the new password, enables the account if it was disabled, and ends its web sign-ins. Its devices keep syncing.

Move, restore or reset the server #

  • A new address, such as a new IP address or domain: on each device, enter it under Settings › Sync › Server address. Devices stay signed in when the same server answers there.
  • Restored from a backup: devices that synced after the backup notice the server went back, show Catching the server up, and send it what it's missing.
  • Reset, starting from an empty /data: set up the admin account again. Devices show Your sync server was reset and keep their libraries; once their accounts exist again, Set it up again signs them in and they fill the server in.