mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
fix(docker): support mounted files for every app secret
PODCAST_ENCRYPTION_KEY is required in production but was absent from the entrypoint file_env list, leaving it as the only secret with no _FILE path. Test every supported name rather than spot-checking a single one. Move secrets-file and OIDC hardening detail to bookorbit.app/installation.
This commit is contained in:
@@ -38,6 +38,7 @@ SETUP_BOOTSTRAP_TOKEN=change-this-to-a-long-random-secret
|
|||||||
# The file must be mounted into every service that uses it, and must not be empty.
|
# The file must be mounted into every service that uses it, and must not be empty.
|
||||||
# POSTGRES_PASSWORD_FILE=/run/secrets/bookorbit_postgres_password
|
# POSTGRES_PASSWORD_FILE=/run/secrets/bookorbit_postgres_password
|
||||||
# JWT_SECRET_FILE=/run/secrets/bookorbit_jwt_secret
|
# JWT_SECRET_FILE=/run/secrets/bookorbit_jwt_secret
|
||||||
|
# PODCAST_ENCRYPTION_KEY_FILE=/run/secrets/bookorbit_podcast_encryption_key
|
||||||
# SETUP_BOOTSTRAP_TOKEN_FILE=/run/secrets/bookorbit_setup_bootstrap_token
|
# SETUP_BOOTSTRAP_TOKEN_FILE=/run/secrets/bookorbit_setup_bootstrap_token
|
||||||
|
|
||||||
# External/public URL used by emails and Kobo endpoints
|
# External/public URL used by emails and Kobo endpoints
|
||||||
|
|||||||
@@ -112,35 +112,10 @@ BOOKS_HOST_PATH=./books # folder on your server where your book fil
|
|||||||
|
|
||||||
POSTGRES_PASSWORD= # database password - openssl rand -hex 24
|
POSTGRES_PASSWORD= # database password - openssl rand -hex 24
|
||||||
JWT_SECRET= # signs login tokens - openssl rand -hex 32
|
JWT_SECRET= # signs login tokens - openssl rand -hex 32
|
||||||
PODCAST_ENCRYPTION_KEY= # encrypts podcast URLs - openssl rand -hex 32
|
|
||||||
SETUP_BOOTSTRAP_TOKEN= # one-time setup wizard token - openssl rand -hex 16
|
SETUP_BOOTSTRAP_TOKEN= # one-time setup wizard token - openssl rand -hex 16
|
||||||
```
|
```
|
||||||
|
|
||||||
Sensitive values can instead be supplied through mounted files by setting the corresponding `_FILE` variable, such as `JWT_SECRET_FILE=/run/secrets/bookorbit_jwt_secret`. Leave the direct variable blank, mount the file into every service that uses it, and restart. Keep the blank assignment rather than deleting the line: the bundled `docker-compose.yml` marks `POSTGRES_PASSWORD`, `JWT_SECRET`, and `SETUP_BOOTSTRAP_TOKEN` as required, so removing them entirely fails before the container starts. BookOrbit rejects configurations where both forms are non-empty, and rejects a file that is missing, unreadable, or empty. This convention is supported for database credentials, application encryption keys, `GITHUB_RELEASES_TOKEN`, `JWT_SECRET`, and `SETUP_BOOTSTRAP_TOKEN`.
|
On a NAS, or any host where your book folder is owned by a user other than UID 1000, also set `PUID` and `PGID` to match that owner. Getting these wrong is the most common cause of permission errors on first scan.
|
||||||
|
|
||||||
For example, a Compose override can mount one database password file into both containers:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
services:
|
|
||||||
app:
|
|
||||||
secrets: [bookorbit_postgres_password]
|
|
||||||
postgres:
|
|
||||||
environment:
|
|
||||||
POSTGRES_PASSWORD_FILE: ${POSTGRES_PASSWORD_FILE?required}
|
|
||||||
secrets: [bookorbit_postgres_password]
|
|
||||||
|
|
||||||
secrets:
|
|
||||||
bookorbit_postgres_password:
|
|
||||||
file: ./secrets/postgres_password
|
|
||||||
```
|
|
||||||
|
|
||||||
Set `POSTGRES_PASSWORD=` and `POSTGRES_PASSWORD_FILE=/run/secrets/bookorbit_postgres_password` in `.env`. The override passes the file path to PostgreSQL while the app receives it from the existing `.env` import. Other container platforms may mount secret files directly without a Compose override.
|
|
||||||
|
|
||||||
On a NAS, or any host where your book folder is owned by a user other than UID 1000, also set `PUID` and `PGID` to match that owner. Run `id -u` and `id -g` as the owning user to find them. Getting these wrong is the most common cause of permission errors on first scan.
|
|
||||||
|
|
||||||
When upgrading an installation that previously used podcasts without `PODCAST_ENCRYPTION_KEY`, set it to the current `JWT_SECRET` first. A new key would make existing encrypted podcast URLs unreadable. Fresh installations should use an independent generated key.
|
|
||||||
|
|
||||||
Optionally set `LIBRARY_BROWSE_ROOT=/books` to start the library folder picker at `/books` instead of `/`.
|
|
||||||
|
|
||||||
Then start:
|
Then start:
|
||||||
|
|
||||||
@@ -150,11 +125,7 @@ docker compose up -d
|
|||||||
|
|
||||||
Open `http://your-server-ip:3000` and complete setup using your `SETUP_BOOTSTRAP_TOKEN`.
|
Open `http://your-server-ip:3000` and complete setup using your `SETUP_BOOTSTRAP_TOKEN`.
|
||||||
|
|
||||||
After configuring OIDC and linking at least one active administrator, you can set `DISABLE_LOCAL_AUTH=true` and restart BookOrbit to remove and reject password sign-in. BookOrbit refuses to start if that would leave no usable OIDC administrator. Set it back to `false` and restart to recover access during an identity-provider outage.
|
For the full installation guide including reverse proxy setup, file permissions on NAS, secrets from mounted files, external databases, OIDC hardening, and environment variable reference, see **[bookorbit.app/installation](https://bookorbit.app/installation)**.
|
||||||
|
|
||||||
An OIDC provider signed by a private certificate authority requires its PEM CA bundle to be mounted read-only in the BookOrbit container. Set `NODE_EXTRA_CA_CERTS` to that in-container path and restart BookOrbit. This adds the private authority to Node's normal certificate verification; it does not disable TLS security. Private-network issuers also require `OIDC_ALLOW_LOCAL_ISSUERS=true`.
|
|
||||||
|
|
||||||
For the full installation guide including reverse proxy setup, file permissions on NAS, external databases, and environment variable reference, see **[bookorbit.app/installation](https://bookorbit.app/installation)**.
|
|
||||||
|
|
||||||
## KOReader Plugin
|
## KOReader Plugin
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ load_file_env() {
|
|||||||
GITHUB_RELEASES_TOKEN \
|
GITHUB_RELEASES_TOKEN \
|
||||||
JWT_SECRET \
|
JWT_SECRET \
|
||||||
MIGRATION_ENCRYPTION_KEY \
|
MIGRATION_ENCRYPTION_KEY \
|
||||||
|
PODCAST_ENCRYPTION_KEY \
|
||||||
POSTGRES_PASSWORD \
|
POSTGRES_PASSWORD \
|
||||||
SETUP_BOOTSTRAP_TOKEN
|
SETUP_BOOTSTRAP_TOKEN
|
||||||
do
|
do
|
||||||
|
|||||||
@@ -38,16 +38,26 @@ describe('Docker file-backed environment values', () => {
|
|||||||
expect(result.stdout).toBe(' file-secret-value |unset');
|
expect(result.stdout).toBe(' file-secret-value |unset');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('loads application encryption keys', () => {
|
it.each([
|
||||||
const secretPath = join(secretDir, 'book-request-key');
|
'BOOK_REQUEST_ENCRYPTION_KEY',
|
||||||
writeFileSync(secretPath, 'book-request-encryption-key');
|
'DATABASE_URL',
|
||||||
|
'EMAIL_ENCRYPTION_KEY',
|
||||||
|
'GITHUB_RELEASES_TOKEN',
|
||||||
|
'JWT_SECRET',
|
||||||
|
'MIGRATION_ENCRYPTION_KEY',
|
||||||
|
'PODCAST_ENCRYPTION_KEY',
|
||||||
|
'POSTGRES_PASSWORD',
|
||||||
|
'SETUP_BOOTSTRAP_TOKEN',
|
||||||
|
])('loads %s from a mounted file', (name) => {
|
||||||
|
const secretPath = join(secretDir, 'secret-value');
|
||||||
|
writeFileSync(secretPath, `${name}-from-file`);
|
||||||
|
|
||||||
const result = runHelper('load_file_env; printf "%s" "$BOOK_REQUEST_ENCRYPTION_KEY"', {
|
const result = runHelper(`load_file_env; printf "%s" "$${name}"`, {
|
||||||
BOOK_REQUEST_ENCRYPTION_KEY_FILE: secretPath,
|
[`${name}_FILE`]: secretPath,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.status).toBe(0);
|
expect(result.status).toBe(0);
|
||||||
expect(result.stdout).toBe('book-request-encryption-key');
|
expect(result.stdout).toBe(`${name}-from-file`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rejects non-empty direct and file values together', () => {
|
it('rejects non-empty direct and file values together', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user