Skip to content
MoliSync
Self-hosted mTLS identity P2P streaming v0.4.0

Sync across devices.
On your own network.

One Go control plane, Windows and Android clients. The data path probes LAN/VPN candidates every 300 ms; if nothing answers by 1.2 s, the server relays the session with zero disk writes. Identity is the SHA-256 fingerprint of a client certificate verified at your proxy.

docker pull ghcr.io/molirain/molisync-server:latest

Docker 24+ · run Compose from the repo root · :9520 stays private

linux/amd64 · arm64 nonroot · read-only Releases ↗
Data path
LAN/VPN · Happy Eyeballs CONNECTED
0 ms Session Ticket · 32 B
0–300 ms Happy Eyeballs · 300 ms
300 ms ✓ CONNECTED
300 ms+ Direct Stream · WireGuard/LAN · 0 Server Load

direct path · 0 server load · end-to-end TLS

Capabilities / 06

What the protocol actually does.

No dashboard demo. Each capability below maps to the wire format, a client behavior or a deployment default.

01Auth

Certificate identity, not shared secrets.

The control plane derives DeviceID from the SHA-256 fingerprint of a client certificate verified at the reverse proxy. Inbound identity headers are stripped and rewritten.

SHA-256 · trusted CIDRs

02Routing

Happy Eyeballs with a hard deadline.

Both peers advertise LAN and VPN candidates; the receiver races them in 300 ms steps. If nothing answers by 1.2 s, the session moves to the relay.

300 ms · 1.2 s

03Relay

Zero disk writes.

The server pairs both peers, checks the single-use 32-byte ticket and forwards bytes with io.Copy. Pairing times out after 15 s.

0 B to disk · 15 s

04Framing

49-byte frames, resumable reads.

The data plane uses fixed 49-byte frames; Android adds BLAKE3 digests. Blob downloads support HTTP Range on both clients.

49 B · BLAKE3 · Range

05Records

Durable until the sender deletes.

Text up to 64 KiB lives in SQLite; images and files stream into a blob directory. Records do not expire automatically; only the sender can delete one.

64 KiB · owner-only delete

06Runtime

Distroless, nonroot, multi-arch.

The server image runs on linux/amd64 and linux/arm64 as nonroot with a read-only root filesystem, no shell and no package manager.

amd64 · arm64 · read-only

Text cap

64 KiB

per record, stored in SQLite

P2P threshold

15 MiB

default; 5–50 MiB adjustable

Relay deadline

1.2 s

300 ms candidate steps

Data frame

49 B

fixed size, both clients

Documentation

Deploy it behind your proxy.

The example Compose file never publishes port 9520. Terminate mTLS at the proxy, strip inbound X-Client-* headers, then set fresh verified values.