Configuration
All configuration is done via environment variables in a .env file at the project root.
Core Settings
| Variable | Description | Default |
|---|---|---|
DATABASE_URL | SQLite database file path | sqlite:///./data/librislog.db |
CORS_ORIGINS | Allowed CORS origins (JSON array or comma-separated) | ["http://localhost", "http://localhost:5173", "http://localhost:4173"] |
LOG_LEVEL | Logging level (DEBUG, INFO, WARNING, ERROR) | INFO |
API_KEY_ENCRYPTION_KEY | Secret key for API key encryption (must be real, not placeholder) | Requires 32+ characters |
FORWARDED_ALLOW_IPS | Trusted proxy IPs | * |
Authentication
| Variable | Description | Default |
|---|---|---|
AUTH_COOKIE_NAME | Session cookie name | librislog_session |
AUTH_COOKIE_SECURE | Use secure cookies (HTTPS only) | false |
AUTH_COOKIE_SAMESITE | SameSite cookie attribute | lax |
AUTH_COOKIE_DOMAIN | Cookie domain | — |
OIDC (Optional)
| Variable | Description |
|---|---|
OIDC_ENABLED | Enable OIDC authentication (true/false) |
OIDC_CLIENT_ID | OIDC client ID |
OIDC_CLIENT_SECRET | OIDC client secret |
OIDC_WELL_KNOWN_URL | OIDC well-known configuration URL |
Password Reset / Email (Optional)
Password reset is optional. If mail is not configured, the "Forgot password?" link on the login page still appears, but no reset email is sent. A warning is logged at startup when mail is not configured.
| Variable | Description | Default |
|---|---|---|
MAIL_SERVER | SMTP server hostname (e.g. smtp.gmail.com). Leave empty to disable password reset emails. | — |
MAIL_PORT | SMTP server port | 587 |
MAIL_USERNAME | SMTP username (leave empty for unauthenticated relay) | — |
MAIL_PASSWORD | SMTP password | — |
MAIL_FROM | Sender email address | — |
MAIL_FROM_NAME | Sender display name | LibrisLog |
MAIL_STARTTLS | Use STARTTLS (True/False) | True |
MAIL_SSL_TLS | Use implicit SSL/TLS (True/False) | False |
PUBLIC_APP_URL | Public URL of the frontend (used to build the reset link in emails) | http://localhost:5173 |
PASSWORD_RESET_TOKEN_MAX_AGE | Reset token validity in seconds | 3600 (1 hour) |
Local Development
For local development, use Mailpit (included in docker-compose.dev.yml):
MAIL_SERVER=localhost
MAIL_PORT=1025
MAIL_STARTTLS=False
MAIL_SSL_TLS=False
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_FROM=noreply@localhostThe Mailpit web UI is available at http://localhost:8025 to inspect sent emails.
Book Import Sources
Every search source can be switched on or off individually. At least one source must be able to answer: if every source is disabled, or the only enabled ones are Hardcover and Google Books without their credentials, the backend refuses to start and logs an error naming the variables to set.
| Variable | Description | Built-in default | Recommended |
|---|---|---|---|
OPEN_LIBRARY_IMPORT_SEARCH_ENABLED | Query Open Library | true | true |
BNF_IMPORT_SEARCH_ENABLED | Query BnF (French national library), title and ISBN | true | true |
INVENTAIRE_IMPORT_SEARCH_ENABLED | Query Inventaire.io, ISBN only | true | true |
LIBRARY_OF_CONGRESS_IMPORT_SEARCH_ENABLED | Query the Library of Congress, title and ISBN | true | depends, see below |
DNB_IMPORT_SEARCH_ENABLED | Query the Deutsche Nationalbibliothek (German National Library), title and ISBN | true | true |
HARDCOVER_IMPORT_SEARCH_ENABLED | Query Hardcover.app (also needs HARDCOVER_APP_API_TOKEN) | true | false unless a token is set |
GOOGLE_BOOKS_IMPORT_SEARCH_ENABLED | Allow the Google Books fallback (also needs GOOGLE_BOOKS_API_KEY) | true | false unless a key is set |
GOOGLE_BOOKS_API_KEY | Google Books API key (see API Keys) | empty | — |
HARDCOVER_APP_API_TOKEN | Hardcover.app API token (see API Keys) | empty | — |
The built-in default is true for every source, so upgrading never silently drops a source that worked before these switches existed. .env.example sets the two keyed sources to false, which is what you want unless you have configured a key or token.
BnF, Inventaire, the Library of Congress, and the German National Library need no API key and are enabled by default.
Hardcover and Google Books cannot answer without credentials. Either way they are handled the same way: if the switch is on and the key or token is empty, the source is reported as skipped in the search progress list and no request is sent, so it never slows a search down. To use either, set its credential and keep the switch on:
GOOGLE_BOOKS_API_KEY=your-key
GOOGLE_BOOKS_IMPORT_SEARCH_ENABLED=trueInventaire answers ISBN lookups only; it has no title search, so on a title search it is reported as skipped. Google Books runs last, only when every other enabled source returned nothing. Setting GOOGLE_BOOKS_IMPORT_SEARCH_ENABLED=false also turns off the on-demand Search Google Books too button.
Warning: The Library of Congress SRU endpoint (
http://lx2.loc.gov:210/LCDB) is only reachable over plain HTTP. Queries are therefore unencrypted and can be observed or altered on the network path. It is the official, documented LC SRU server and returns public bibliographic data only, but setLIBRARY_OF_CONGRESS_IMPORT_SEARCH_ENABLED=falseif unencrypted egress to port 210 is not acceptable in your environment. The other sources are all HTTPS.
Cover Scraping
| Variable | Description | Default |
|---|---|---|
COVERS_DIR | Directory for cached cover images | ./data/covers |
THALIA_COVER_SEARCH_ENABLED | Enable Thalia cover search | false |
Disclaimer: Enabling Thalia cover search uses automated scraping of thalia.de. This likely violates their Terms of Service. The app ships with this feature disabled by default. Enable it only for research purposes and at your own risk. Do not use in production.
Dashboard
| Variable | Description | Default |
|---|---|---|
DASHBOARD_QUOTE_ENABLED | Enable dashboard quote | true |
DASHBOARD_QUOTE_URL | Quote API endpoint | https://motivational-spark-api.vercel.app/api/quotes/random |
DASHBOARD_QUOTE_CACHE_TTL | Quote cache time-to-live (seconds) | 86400 |
Telemetry
LibrisLog sends minimal, anonymous installation telemetry (see Telemetry) to understand how many installations exist and on which platforms they run. It is an installation census. No user, book, reading, or host data is ever collected.
The telemetry server is open source (github.com/codebude/librislog-telemetry) and the aggregated results are public at metrics.librislog.app.
| Variable | Description | Default |
|---|---|---|
TELEMETRY_DISABLED | Disable all telemetry (true/false) | false |
TELEMETRY_ENDPOINT | Telemetry API endpoint | https://metrics.librislog.app/api/telemetry |
TELEMETRY_TIMEOUT_SECONDS | HTTP timeout for telemetry requests | 10 |
To opt out entirely:
TELEMETRY_DISABLED=trueFrontend
Run Time
| Variable | Description |
|---|---|
BACKEND_ADDR | Configures the upstream address for the Nginx webserver. For the default docker-compose.yml this is set to http://backend:8000. NOTE: Remove trailing / as they might interfere with NGINXs routing behavior. |
Build Time
| Variable | Description | Default |
|---|---|---|
PUBLIC_DEFAULT_LOCALE | Default UI language (en, de, zh, es, or fr) | en |
Import Limits
| Variable | Description | Default |
|---|---|---|
MAX_IMPORT_FILE_SIZE_MB | Maximum import file size (MB) | 100 |
MAX_IMPORT_ROW_COUNT | Maximum import row count | 10000 |
Validation Rules
API_KEY_ENCRYPTION_KEYmust be a real secret key (minimum 32 characters). Do not use the placeholder value from.env.example. If left as placeholder or set to a weak value, API key creation will fail.- When
OIDC_ENABLED=true, all three OIDC variables must be set. GOOGLE_BOOKS_API_KEYandHARDCOVER_APP_API_TOKENare optional. See API Keys for how to obtain them. The app runs fine without them using Open Library, BnF, Inventaire, the Deutsche Nationalbibliothek, and the Library of Congress..env.examplesetsHARDCOVER_IMPORT_SEARCH_ENABLEDandGOOGLE_BOOKS_IMPORT_SEARCH_ENABLEDtofalse; set either totrueonce its credential is configured.- At least one book import source must be able to answer. Disabling every source, or enabling only Hardcover and Google Books without their credentials, stops the backend from starting.
Example .env
DATABASE_URL=sqlite:///./data/librislog.db
CORS_ORIGINS=["http://localhost", "http://localhost:5173", "http://localhost:4173"]
LOG_LEVEL=INFO
API_KEY_ENCRYPTION_KEY= # CHANGE ME: generate with `openssl rand -base64 32`
FORWARDED_ALLOW_IPS=*
AUTH_COOKIE_NAME=librislog_session
AUTH_COOKIE_SECURE=false
AUTH_COOKIE_SAMESITE=lax
GOOGLE_BOOKS_API_KEY=your-google-books-api-key
HARDCOVER_APP_API_TOKEN=your-hardcover-token
COVERS_DIR=./data/covers
THALIA_COVER_SEARCH_ENABLED=false
DASHBOARD_QUOTE_ENABLED=true
DASHBOARD_QUOTE_URL=https://motivational-spark-api.vercel.app/api/quotes/random
DASHBOARD_QUOTE_CACHE_TTL=86400
PUBLIC_DEFAULT_LOCALE=en
MAX_IMPORT_FILE_SIZE_MB=100
MAX_IMPORT_ROW_COUNT=10000
# Password reset (optional — leave empty to disable)
MAIL_SERVER=
MAIL_PORT=587
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_FROM=
MAIL_FROM_NAME=LibrisLog
MAIL_STARTTLS=True
MAIL_SSL_TLS=False
PUBLIC_APP_URL=http://localhost:5173
PASSWORD_RESET_TOKEN_MAX_AGE=3600