Koreader sync server is built on top of the Gin JSON-API framework which runs on OpenResty and is entirely written in Lua.
Users of koreader devices can register their devices to the synchronization server and use the sync service to keep all reading progress synchronized between devices.
This project is licenced under Affero GPL v3, see the COPYING file.
The API is described in the third-party kosync-conformance, together with a verifier that checks an implementation against it in one command. The description is observational rather than normative: it documents what this server does, and it notes where implementations in the wild disagree. The spec text is CC0, so anything in it may be copied here or anywhere else without attribution.
Using docker, you can spin up your own server in two commands:
# for quick test
docker run -d -p 7200:7200 --name=kosync koreader/kosync:latest
# for production, we mount redis data volume to persist state
mkdir -p ./logs/{redis,app} ./data/redis
docker run -d -p 7200:7200 \
-v `pwd`/logs/app:/app/koreader-sync-server/logs \
-v `pwd`/logs/redis:/var/log/redis \
-v `pwd`/data/redis:/var/lib/redis \
--name=kosync koreader/kosync:latestThe above command will spin up a sync server in a docker container.
To build your own docker image from scratch:
docker build --rm=true --tag=koreader/kosync .Alternatively, if you'd rather use docker compose:
docker compose up -d --buildTo setup the server manually, please refer to the commands used in the Dockerfile.
You can use the following command to verify that the sync server is ready to serve traffic:
curl -k -v -H "Accept: application/vnd.koreader.v1+json" https://localhost:7200/healthcheck
# should return {"state":"OK"}As you can see, the server responds over HTTPS using a self-signed certificate. If you'd like to run the server behind a reverse proxy and let the proxy handle TLS termination, run the server on port 17200 instead of 7200. As an example, your Traefik V3 configuration could look like this:
kosync:
# ...
labels:
- traefik.enable=true
- 'traefik.http.routers.kosync.rule=Host(`kosync.example.com`)'
- 'traefik.http.services.kosync.loadbalancer.server.port=17200'DELETE /users/me uses the x-auth-user and x-auth-key headers to delete an
account and all its reading progress. Success returns HTTP 200 with
{"deleted":true}. Invalid credentials return HTTP 401 (code 2001).
An absent account returns HTTP 404 (code 2006, Account not found.), after
removing any orphaned user data. This specific response confirms deletion after a
lost response; a generic 404 or 401 does not.
No deletion records are retained. Usernames can be registered again immediately with empty progress. Use a different password when re-registering: a stale deletion request cannot be distinguished from a new one if both credentials are reused.
PUT /users/password uses the current x-auth-user and x-auth-key headers and a
JSON body of {"password":"<replacement key>"}. As with registration, supply a
nonempty client-derived key (KOReader uses the password's MD5 hash).
Success returns HTTP 200 with {"updated":true} and preserves reading progress.
Update the saved password on all connected readers. This requires the current key;
it does not provide forgotten-password recovery.
Incorrect credentials and stale retries return HTTP 401. If a response is lost,
confirm the replacement key with GET /users/auth. Invalid replacement values
return HTTP 403 (code 2003).
Koreader sync server does not store file name or file content in the database. For each user it uses a unique string of 32 digits (MD5 hash) to identify the same document from multiple koreader devices and keeps a record of the furthest reading progress for that document. Sample progress data entries stored in the sync server are like these:
"user:chrox:document:0b229176d4e8db7f6d2b5a4952368d7a:percentage" --> "0.31879884821061"
"user:chrox:document:0b229176d4e8db7f6d2b5a4952368d7a:progress" --> "/body/DocFragment[20]/body/p[22]/img.0"
"user:chrox:document:0b229176d4e8db7f6d2b5a4952368d7a:device" --> "PocketBook"
And the account authentication information is stored like this:
"user:chrox:key" --> "1c56000eef209217ec0b50354558ab1a"
the password is MD5 hashed at client when authorizing with the sync server.
In addition, all data transferred between koreader devices and the sync server are secured by HTTPS (Hypertext Transfer Protocol Secure) connections.