Skip to content

rencomputer/rensync-server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rensync-server

A small, self-hostable sync server for end-to-end-encrypted data.

rensync-server stores opaque encrypted blobs and tells clients what changed. Encryption keys and plaintext stay on client devices: the server does not encrypt, decrypt, or interpret your data.

It is designed as the sync backend for Ren applications, but the HTTP API is deliberately small and can be implemented by other clients.

How it works

Each account has collections containing encrypted items. Every mutation gets a monotonically increasing sequence number. Clients keep their last seen sequence and request newer changes, making incremental sync a simple cursor operation.

  • Writes use optimistic concurrency. A stale write receives the current encrypted row so the client can resolve the conflict.
  • Deletes become tombstones, allowing offline clients to observe them later.
  • Batch writes execute in one SQLite transaction.
  • Accounts are provisioned by the server operator; there is no public signup endpoint.

The server stores:

  • usernames and SHA-256 hashes of bearer tokens;
  • opaque collection metadata and item blobs;
  • collection and item identifiers, sizes, and sequence numbers.

The server can observe account names, IP addresses, item counts, blob sizes, request timing, and which rows change. It cannot see encryption keys or the plaintext inside blobs. Clients are responsible for using authenticated encryption correctly.

Run with Docker

Build and start the server:

docker build -t rensync-server .
docker volume create rensync-data
docker run -d \
  --name rensync \
  --restart unless-stopped \
  -p 127.0.0.1:8080:8080 \
  -v rensync-data:/data \
  rensync-server

Create an account:

docker exec rensync /rensync user add alice

The command prints a bearer token once. Save it securely; only its hash is stored by the server.

Check the server:

curl http://127.0.0.1:8080/v1/health

The container serves plain HTTP. Put it behind a TLS reverse proxy before exposing it to the internet. For example, with Caddy:

sync.example.com {
  reverse_proxy 127.0.0.1:8080
}

Configuration

Variable Default Description
RENSYNC_DATA_DIR /data Directory containing the SQLite database
RENSYNC_LISTEN :8080 HTTP listen address
RUST_LOG server defaults Logging filter

The SQLite database is stored at $RENSYNC_DATA_DIR/rensync.sqlite3. Back up the data volume regularly.

Operator commands

rensync user add <name>
rensync user list
rensync user rm <name>
rensync serve

Use --data-dir or RENSYNC_DATA_DIR with every command when running outside the container.

HTTP API

Authenticated endpoints require:

Authorization: Bearer <token>
Method Path Purpose
GET /v1/health Liveness check; no authentication required
GET /v1/collections List collections
POST /v1/collections Create, update, or delete a collection
GET /v1/changes?since=<seq> Read changes after a cursor
POST /v1/batch Apply item mutations atomically

Binary metadata and blobs are represented as standard base64 in JSON. IDs are client-generated opaque strings of at most 64 bytes.

Current limits:

  • 256 KiB per blob;
  • 1,000 mutations per batch;
  • 8 MiB of decoded blob data per batch;
  • 1,000 rows per changes page.

Development

Requires a recent stable Rust toolchain:

cargo test
cargo run -- --data-dir /tmp/rensync user add alice
cargo run -- --data-dir /tmp/rensync serve --listen 127.0.0.1:8080

The runtime image is built from scratch; SQLite is statically linked into the server binary.

About

A dumb encrypted server for syncing end-to-end encrypted data between devices

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors