Skip to main content
Version: v5.3.0

Object Storage

Document files, generated audio, audiobooks and preview images live in object storage. The database holds only their records.

Embedded or external​

BackendWhen it is used
Embedded SeaweedFS (default)OpenReader starts weed mini itself and stores data under docstore. Its S3 endpoint listens on port 8333 inside the container; browsers never need to reach it.
External S3-compatibleSet USE_EMBEDDED_WEED_MINI=false with S3_BUCKET, S3_REGION, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY and S3_INTERNAL_ENDPOINT (for AWS, https://s3.<region>.amazonaws.com), plus a browser transport. Works with AWS S3, Cloudflare R2, MinIO, an external SeaweedFS and similar.

Every variable is listed in Environment Variables.

Persist and back up docstore​

In Docker, mount a volume at /app/docstore:

-v openreader_docstore:/app/docstore

It holds the embedded storage, the SQLite database and temporary files. Embedded SeaweedFS encrypts every object with a key kept in the same directory (.mini_sse_kek), so back up the whole volume. The object files cannot be read without that key.

The full Compose stacks keep storage in the seaweedfs-data volume instead. Back it up together with examples/docker/.env, which may hold its key as WEED_S3_SSE_KEK (see Docker Compose).

How browsers reach files​

S3_BROWSER_TRANSPORT decides how browsers upload and download files:

ValueBehavior
proxyBrowsers go through OpenReader's own routes. The default for embedded storage.
presignedBrowsers use signed URLs to S3_PUBLIC_ENDPOINT directly. The app and worker still use S3_INTERNAL_ENDPOINT.
autoproxy for embedded storage; otherwise presigned, which requires a public HTTPS S3_PUBLIC_ENDPOINT.

A failed direct transfer is not retried through the proxy.

For presigned, give the bucket its own HTTPS hostname, such as s3.reader.example, rather than a path like /s3. Your reverse proxy must keep the signed path, query string, Host and signed headers unchanged. Configure CORS for the OpenReader address with GET, HEAD, PUT and OPTIONS, allowing the Content-Type and x-amz-server-side-encryption headers.

What is stored​

All keys are under S3_PREFIX.

PrefixContentsKept until
documents_v1/Uploaded documents, named by SHA-256 so identical files are stored once. Each upload is read back and its hash checked before it is added to the library.No document references it (Clean up unowned documents).
document_uploads_temp_v1/Uploads in progress.Finished, or expired (Clean up expired uploads).
document_previews_v1/Library thumbnails for PDF and EPUB.The document is deleted. They can be regenerated.
tts_playback_segments_audio_v1/Generated speech, one file per segment.The user clears audio or deletes the document.
tts_playback_segments_v1/, tts_playback_plan_v1/Word timings and the playback plan for each document and voice.Same as the audio.
tts_playback_exports_v1/Finished audiobooks and temporary account export ZIPs.Audiobooks: until audio is cleared. Export ZIPs: seven days.

Deleting an account removes its documents, previews and audio first. If that fails, the account is kept so the deletion can be retried.

Browsers also keep copies of documents, previews and audio in Cache Storage (openreader-blobs-v1) to load faster. It is only a cache; clearing it loses nothing.

Inspect playback audio​

aws s3 ls "s3://$S3_BUCKET/$S3_PREFIX/tts_playback_segments_audio_v1/" --recursive | grep "/docs/<document-id>/"