Configuration
qnop is configured in two places, and knowing which is which saves a lot of time:
- Environment variables — infrastructure. Where the database is, where the bucket is, which secrets to use. Changing them needs a restart.
- Administration → Settings — everything an operator tunes while the system runs: SMTP, upload limits, self-registration, retention. These are not environment variables.
Every environment variable is prefixed QNOP_.
The three secrets
Section titled “The three secrets”These have no usable default. Each ships as CHANGE_ME, which is rejected at
startup — the server refuses to boot rather than run insecurely.
| Variable | Purpose | Requirement |
|---|---|---|
QNOP_AUTH_JWT_SECRET | signs access tokens | ≥ 32 characters |
QNOP_AUTH_ENCRYPTION_KEY | encrypts secrets held at rest (e.g. OIDC client secrets) | ≥ 32 characters |
QNOP_AUTH_ENCRYPTION_SALT | key-derivation salt | hex-encoded, ≥ 16 characters |
QNOP_AUTH_JWT_SECRET="$(openssl rand -base64 48)"QNOP_AUTH_ENCRYPTION_KEY="$(openssl rand -base64 48)"QNOP_AUTH_ENCRYPTION_SALT="$(openssl rand -hex 32)"Note the salt uses -hex, not -base64.
Database
Section titled “Database”| Variable | Default | Purpose |
|---|---|---|
QNOP_DB_HOST | localhost | Postgres host |
QNOP_DB_PORT | 5432 | Postgres port |
QNOP_DB_NAME | qnop | database name |
QNOP_DB_USERNAME | qnop | user |
QNOP_DB_PASSWORD | qnop | password |
The defaults are development values — set all of them in production. The
standard SPRING_DATASOURCE_* variables override the URL assembled from these
if you need full control.
Object storage
Section titled “Object storage”| Variable | Default | Purpose |
|---|---|---|
QNOP_S3_ENDPOINT | (empty) | endpoint URL — leave empty for real AWS S3 |
QNOP_S3_BUCKET | qnop-documents | bucket name |
QNOP_S3_ACCESS_KEY | qnop | access key |
QNOP_S3_SECRET_KEY | qnop_secret | secret key |
QNOP_S3_REGION | us-east-1 | region, or the placeholder your vendor requires |
QNOP_S3_PATH_STYLE_ACCESS | true | true for MinIO; set false for AWS S3 |
QNOP_S3_AUTO_CREATE_BUCKET | false | create the bucket on first start |
QNOP_S3_REAPER_GRACE_PERIOD | PT1H | grace before a staged, unreferenced object is swept |
QNOP_S3_REAPER_CRON | 0 30 3 * * * | when that sweep runs |
The defaults are tuned for the bundled MinIO. Pointing at AWS S3 means clearing
the endpoint and flipping QNOP_S3_PATH_STYLE_ACCESS to false.
HTTP and proxying
Section titled “HTTP and proxying”| Variable | Default | Purpose |
|---|---|---|
QNOP_HTTP_FORWARD_HEADERS_STRATEGY | none | set framework behind a trusted reverse proxy |
QNOP_CORS_ALLOWED_ORIGINS | http://localhost:5173 | comma-separated exact origins; not needed for the embedded UI |
QNOP_HTTP_SHUTDOWN_GRACE | 30s | graceful-shutdown drain |
QNOP_HTTP_CONNECTION_TIMEOUT | 20s | connection timeout |
QNOP_HTTP_KEEP_ALIVE_TIMEOUT | 20s | keep-alive reap |
QNOP_HTTP_REQUEST_TIMEOUT | 30s | async dispatch cap |
Outbound timeouts — used for OIDC discovery, JWKS fetches and SMTP — are
QNOP_HTTP_CLIENT_OUTBOUND_CONNECT_TIMEOUT (5s),
QNOP_HTTP_CLIENT_OUTBOUND_READ_TIMEOUT (15s), and the
QNOP_HTTP_CLIENT_SMTP_* trio (10s connect, 30s read, 30s write).
Uploads
Section titled “Uploads”| Variable | Default | Purpose |
|---|---|---|
QNOP_UPLOAD_MULTIPART_LIMIT_MB | 55 | servlet-level multipart ceiling |
Authentication
Section titled “Authentication”| Variable | Default | Purpose |
|---|---|---|
QNOP_AUTH_OIDC_FRONTEND_BASE_URL | (empty) | where to return after OIDC login; empty = same origin |
QNOP_AUTH_OIDC_ALLOW_PRIVATE_DISCOVERY_URIS | false | SSRF guard — see below |
QNOP_AUTH_RATE_LIMIT_TRUSTED_PROXY_CIDRS | (empty) | which hops may set the client IP |
OIDC providers themselves are not configured by environment variable — they are managed at runtime under Administration → OIDC providers. See Authentication.
Bootstrap
Section titled “Bootstrap”| Variable | Default | Purpose |
|---|---|---|
QNOP_ADMIN_PASSWORD | (unset) | fixed initial admin password |
Unset, qnop generates a one-time password on first start and forces a change at first login. Set, it uses yours and skips the forced change.
What is not an environment variable
Section titled “What is not an environment variable”These live in Administration → Settings and change without a restart. The list matters because operators regularly go looking for them in the environment:
- General — application name, base URL, default language and timezone.
- Uploads —
document_max_file_size_mb(default 25),attachment_max_file_size_mb(default 10). - SMTP — enabled, host, port, credentials, encryption, from-address and from-name. Mail is configured here, not in the environment.
- Authentication — self-registration and its default role, password reset and its token lifetime.
- Notifications — whether review e-mails are sent.
- Review — free reattach, finalize-with-open-annotations, and the archive and purge retention windows.
Advanced knobs
Section titled “Advanced knobs”A number of further variables exist and bind by naming convention, but are not
part of the documented contract and can change without notice: token lifetimes
(QNOP_AUTH_ACCESS_TOKEN_TTL, QNOP_AUTH_REFRESH_TOKEN_TTL), the re-anchoring
similarity thresholds (QNOP_REANCHORING_*), the per-endpoint rate-limit
budgets (QNOP_AUTH_RATE_LIMIT_*), and the maintenance cron expressions
(QNOP_S3_ORPHAN_REAPER_CRON, QNOP_REVIEW_ARCHIVE_CRON,
QNOP_REVIEW_PURGE_CRON). Reach for them only with a specific reason.