Source docs/docker.md · 1de96aa

Install Libris with Docker

This guide is for anyone who wants to run Libris Translate (Libris for short) on their own machine or server. You do not need to know Python or Node.js: Docker does the work. By the end you will have Libris running, signed in, connected to a language model and translating a first book. Later sections cover network access, HTTPS, updates, removal and common problems.

What you need

  • A Linux machine (x86-64 / AMD64) with at least 2 GB of free memory, and disk space for your books, their translations, exports and backups.
  • Docker Engine 26 or newer with the Compose v2 plugin. Follow Docker’s installation guide for your distribution.
  • A language model Libris can reach over the network: a hosted service with an API key (OpenAI, Anthropic, or any OpenAI-compatible provider) or your own inference server. Libris itself needs no GPU.

Check Docker before you continue:

docker version
docker compose version

The library and its history are stored on your server. Configured model providers receive passages and their translation context; optional external memory, mail, webhooks and delivery integrations receive the data needed for the features you enable. Licence checks send installation identity and usage, not book text. Review these destinations before importing confidential material.

Install

A licence — bought, or a trial asked for on the website — comes by email with two things: the key you will type in Settings › Licence, and read-only credentials for the licensed image registry. No archive and no Git checkout are needed. Run:

curl --fail --location --silent --show-error https://libris-translate.com/install.sh | sudo bash

The bootstrap first tries the registry credentials already stored by Docker. If no valid login exists, it asks for the read-only username and token through the terminal (never through the downloaded script’s standard input). It then pulls registry.libris-translate.com/libris/libris:latest, resolves that tag to an immutable image digest, and:

  1. takes the Compose file from that exact image, so the stack definition cannot drift from the application it runs;
  2. creates /opt/libris/.env with random secrets and the initial administrator password;
  3. downloads PostgreSQL, migrates the database, and starts the web application, the worker and the Codex bridge;
  4. waits until the API is healthy, then prints the local address and the command that displays the password.

It takes a few minutes the first time. A retry or update keeps the existing configuration, secrets and Docker volumes; it never deletes data. latest is the latest stable release published by Libris. To install the current public release explicitly instead of following later stable releases:

curl --fail --location --silent --show-error https://libris-translate.com/install.sh | sudo env LIBRIS_TAG=0.28.0 bash

The installer itself travels in every image, from 0.15 onwards, beside the Compose file and the configuration template (/app/deploy/install.sh, /app/deploy/docker-compose.yml, /app/deploy/env.example). Whatever copy is started, it resolves the requested tag to a digest and hands over to the installer of that exact image, so the installer, the Compose file and the template installed are always those of the version that runs. With no access to the site, the same installation starts from the registry alone:

sudo docker pull registry.libris-translate.com/libris/libris:<version>
sudo docker run --rm --entrypoint cat registry.libris-translate.com/libris/libris:<version> /app/deploy/install.sh > install-libris.sh
sudo env LIBRIS_TAG=<version> bash install-libris.sh

The new .env is written with mode 0600 in a staging directory next to /opt/libris, then renamed into place in one step: an interrupted first run leaves nothing behind, and a run interrupted after that (download, migration, start) keeps the configuration and resumes when the same command is run again. LIBRIS_REGISTRY_USERNAME and LIBRIS_REGISTRY_TOKEN log in without a prompt (the token goes to docker login through its standard input only).

All Compose commands below assume cd /opt/libris. The archive’s scripts/install-docker.sh remains a source-checkout helper for contributors; it is not required for a customer installation.

For a restore on a new machine, place the saved .env first, run the installer with --no-start (or LIBRIS_NO_START=1), start only database, restore the database and books, then start the other services; see backup and restore.

What is running

ServiceRole
apiWeb interface and HTTP API, published on port 8088 of the host (loopback only by default)
workerRuns analysis, translation and review jobs in the background; resumes them after a restart
databasePostgreSQL 17: accounts, books, translations and job state
migrateUpdates the database schema, then stops. Seeing it as “exited (0)” is normal
codexThe optional Codex bridge, started by the installer (COMPOSE_PROFILES=codex); only a Codex provider uses it

Your data lives in two Docker volumes, libris_database and libris_books (a third, libris_codex-state, holds the sign-ins of the optional Codex bridge). They survive container updates and restarts. The Compose project is named libris (LIBRIS_PROJECT in .env); keep that name, because another name would start with empty volumes.

An installation made by an earlier release ran as epub-translator, with epub-translator_* volumes. The next update with the installer renames it once: Libris stops for the time it takes to copy the volumes into their libris_* twins, each copy is checked, then Libris starts under its new name and .env records LIBRIS_PROJECT=libris. The epub-translator_* volumes are left untouched; the installer prints the docker volume rm command that removes them once you are satisfied. Without the free space for a copy, it keeps the old name (LIBRIS_PROJECT=epub-translator) and says how to retry.

The containers run with a read-only file system and no extra privileges. The only writable places are the volumes and a small temporary area.

The API, the worker and the migrations also keep a journal in the libris_logs volume: one file per service, read as a single chronology with docker compose exec api python -m app.journal (last events, follow, export --since 2h). Secrets are masked in it. See operations.

Sign in

Open http://localhost:8088 on the machine where Libris runs. The username is admin; the password was generated for you. Display both with:

grep '^BOOTSTRAP_' .env

Treat this output as a password: do not paste it into issues, chats or screenshots. Change the password after your first sign-in from your account page.

The interface is in French or English; switch with the language button in the top bar.

Activate the licence

Open Settings › Licence, type the key from your licence email and click Activate. The installation then renews its certificate on its own, every hour; a certificate is worth 72 hours, so an outage of the licence server does not stop your work. Until a licence is active, Libris imports and shows books but starts no analysis and no translation. The screen shows the plan, the words of the current quota cycle and the date the quota renews, and whether the automation API and book sharing are included. What each plan allows, and the rules of the quota, are in the configuration reference.

Moving to another server: click Release this machine on the old one first, then activate the same key on the new one.

Connect a language model

  1. Open Settings › LLM providers and click New provider.
  2. Choose the Connection / protocol: OpenAI-compatible · Chat Completions for most services and local servers, Anthropic · Claude (API key), OpenAI · Chat Completions (API key), Codex / OpenAI · API key (Responses), or Codex · ChatGPT account (needs the optional bridge, see Codex).
  3. Enter the Base URL (for example https://api.example.com/v1), the API key and the Model.
  4. Set the Context window and Maximum output tokens to your model’s real limits, and Concurrent books to how many books this provider may work on at once.
  5. Click Save, then Test / detect models.

The address must be reachable from the containers. Inside a container, localhost is the container itself, not your machine. For a model server on the same Linux host, use the host’s network address, or add extra_hosts: ["host.docker.internal:host-gateway"] to both api and worker in a Compose override file and use http://host.docker.internal:<port>.

A successful model list does not prove that translation works: try a short book first.

API keys are stored encrypted with SECRET_KEY and never sent back to the browser.

Translate a first book

  1. In the library, click Add content and choose EPUB books (or TXT chapters for a web novel, or Markdown, HTML or DOCX chapters). Pick where the book goes: an existing series, a new series or a standalone volume.
  2. Open the book and click Configure the book: choose the provider, the languages and the quality level. Leave the memory on internal unless you run OpenViking.
  3. Click Start the autopilot. Libris analyses the book, translates it, reviews it and settles open points on its own; the autopilot page explains every stage.
  4. When it is done, click Download the EPUB (Download the chapters for a text volume).

The full user guide, in French, is user-guide.fr.md.

Open Libris to your network

By default Libris only listens on the machine itself (127.0.0.1). Settings mentioned here are described in the configuration reference.

On a private network (plain HTTP)

Edit .env, replacing your-server with the machine’s name or IP address. COOKIE_SECURE=false is needed here because the browser refuses Secure cookies over plain HTTP on any address other than localhost:

BIND_ADDRESS=0.0.0.0
PORT=8088
ALLOWED_ORIGINS=http://your-server:8088
COOKIE_SECURE=false

Apply the change:

docker compose up -d --no-build --wait

Anyone who can reach that port can see the sign-in page: restrict it with the host firewall. ALLOWED_ORIGINS only checks which web page sent a request; it is not a firewall.

On the Internet (HTTPS)

Keep Libris on 127.0.0.1 and put an HTTPS reverse proxy in front of it. In .env:

BIND_ADDRESS=127.0.0.1
ALLOWED_ORIGINS=https://books.example.com
COOKIE_SECURE=true
FORWARDED_ALLOW_IPS=172.18.0.1

FORWARDED_ALLOW_IPS is the address from which the proxy’s requests reach the container, so that Libris reads each visitor’s real address (used for logs and to slow down password guessing). For a proxy on the same host it is usually the gateway of the Compose network; the access lines of docker compose logs api show which address the requests come from.

The proxy must:

  • pass the browser’s Origin and Host headers unchanged, and set X-Forwarded-For and X-Forwarded-Proto;
  • accept request bodies up to MAX_UPLOAD_MB (256 MB by default);
  • keep long-lived connections open and unbuffered for live progress (/api/projects/<id>/events, server-sent events).

A minimal nginx example (certificates configured as usual for your server):

server {
    listen 443 ssl;
    server_name books.example.com;

    client_max_body_size 260m;

    location / {
        proxy_pass http://127.0.0.1:8088;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_buffering off;
        proxy_read_timeout 1h;
    }
}

A proxy running in a container cannot use its own localhost to reach Libris: give it a shared Docker network or the host’s address.

Update

Read the changelog, pause running books and make a backup, then run the same bootstrap command again:

curl --fail --location --silent --show-error https://libris-translate.com/install.sh | sudo bash

It moves the installation to the current stable latest, preserving every secret, account, book and Docker volume. To choose an exact release instead:

curl --fail --location --silent --show-error https://libris-translate.com/install.sh | sudo env LIBRIS_TAG=0.28.0 bash

Before changing the image, the bootstrap compares /opt/libris/docker-compose.yml with the template from the installed image. An untouched file is replaced automatically. A customised file is never overwritten: the new template is saved as /opt/libris/docker-compose.yml.libris-new, and the update stops before changing LIBRIS_IMAGE; merge local proxy or mount changes deliberately, then retry. Database migrations run automatically before the web application starts. Confirm the health check and resume the paused books afterwards:

curl --fail http://127.0.0.1:8088/health

Updating with docker compose pull alone moves the images forward but keeps the old Compose file. Libris notices what the new version expects and the file does not give it (a mount such as the journal’s /logs): /health answers "configuration": "outdated" or "degraded", administrators see a banner with the details in Settings › Installation health, and librisctl doctor lists the same checks. Run the installer again, or merge docker-compose.yml.libris-new, then recreate the containers.

Libris never updates itself. When the licence server announces a newer release (it takes it from the website, which publishes each release once its images are out), administrators see a banner « Libris X.Y.Z is available » with the changelog, the installer command (or the one pinned with LIBRIS_TAG=X.Y.Z) and the same reminder: back up, pause the books. Each administrator can hide it for that release. Nothing is shown to other members, nor when the licence server is older or unreachable.

An image rollback cannot undo a schema migration. To go back after one, restore the backup made before the update; see backup and restore. For finer control over restarts, see operations.

Everyday commands

docker compose ps                              # state of each service
docker compose logs --since=10m api worker     # recent logs
docker compose restart api                     # restart the web application
docker compose stop                            # stop Libris, keep everything
docker compose start                           # start it again
curl --fail http://127.0.0.1:8088/health       # {"status":"ok","version":"..."}

Uninstall

Stop Libris and remove its containers, keeping your data:

docker compose down

To delete everything for good (database, books, translations), only after a backup you have verified:

cd /opt/libris
docker compose --profile codex down --volumes --remove-orphans
docker image rm "$(sed -n 's/^LIBRIS_IMAGE=//p' .env | head -n 1)"

Check with docker volume ls that no libris_* (nor epub-translator_*) volume is left, then delete the Libris directory, which contains .env.

Build from source

Contributors can build the image instead of downloading it:

LIBRIS_IMAGE=libris:local docker compose build --pull api
LIBRIS_IMAGE=libris:local docker compose up -d --no-build --wait

See development for tests and the development setup.

Supported environments

EnvironmentStatus
Linux x86-64 (AMD64) with Docker Engine and Compose v2Supported and tested
Ubuntu, DebianSupported with Docker’s official packages
PostgreSQL 17 (bundled)Supported and tested; the only database for Docker installations
Chromium-based desktop browsers, and mobile layoutsTested
Firefox, Safari, physical mobile devicesExpected to work, not tested
Fedora, RHEL, Rocky, AlmaLinuxNot tested; SELinux may need local configuration
Windows and macOS with Docker Desktop, WSL 2Not tested; keep data in Docker volumes, not in Windows folders
Linux ARM64Not tested; images are published for AMD64 only
KubernetesNot supported: no manifests are provided

Books. Reflowable EPUB 2 and 3 books are supported, and a translation into a right-to-left language (Arabic, Hebrew, Persian, Urdu) is exported right to left. Fixed-layout and DRM-protected books are not supported: both are refused at import. A fixed-layout book is one whose package declares rendition:layout = pre-paginated (for the whole book, or on every text page of its spine), whose Apple Books options (META-INF/com.apple.ibooks.display-options.xml) set fixed-layout to true, or which carries Kindle’s fixed-layout meta: its pages have fixed dimensions, so a longer or shorter translation would overflow or be cut off. When only some text pages are fixed, the book is imported with a warning that names how many. Encrypted archive entries are refused. Text volumes can also be imported as TXT, Markdown, HTML or DOCX chapters, or as JSON through the automation API. EPUBCheck validates the structure of an exported EPUB, not the quality of its translation.

Project archives. Libris restores project archives (Export › Complete project (.zip)) written by any earlier version. Archives written by this version cannot be read by versions older than 0.6.

Troubleshooting

SymptomWhat to check
The page does not loaddocker compose ps: api must be healthy. Check BIND_ADDRESS, PORT and the firewall.
Sign-in answers “origin not allowed” (403)ALLOWED_ORIGINS must match the address in the browser exactly: scheme, host and port, no trailing slash.
Sign-in seems to do nothing, you stay on the login pageYou open Libris over plain HTTP on a network address (not localhost) with COOKIE_SECURE=true: set it to false, or use HTTPS. http://localhost:8088 works with true.
The API does not start: “SECRET_KEY must be at least 32 characters long” or “BOOTSTRAP_PASSWORD must be set”.env is missing values: generate one with python3 scripts/setup.py (it refuses to overwrite an existing .env).
migrate shows “exited”Normal when the exit code is 0. Otherwise read docker compose logs migrate.
The provider test failsTest the URL from a container, not from your browser; localhost means the container itself.
A book stays queuedThe worker must be running (docker compose ps worker) and the provider must have free Concurrent books capacity. The Queue page says what each waiting job waits for (see operations).
A book is “waiting”Read its stop reason and next attempt: provider recovery, a closed work window, a daily cap or a dependency can defer it. See operations.
Upload refused as too largeRaise MAX_UPLOAD_MB (and your proxy’s limit).
Read-only file system in the logsA customised Compose file writes outside the volumes: add a volume or tmpfs for that path instead of removing read_only.

On a host driven by the production deployment script, the same checks — and the Compose incantation these commands need — are one command: librisctl doctor.

When you write to support@libris-translate.com for help, from the address your licence was sent to, include the Libris version, docker version, docker compose ps and a few minutes of logs. Remove passwords, API keys, cookies and book text first.