Skip to content

feat(docker): standalone entrypoint env-var parity with upstream#116

Merged
rikled merged 4 commits into
mainfrom
fix/jwt-header-standalone
May 28, 2026
Merged

feat(docker): standalone entrypoint env-var parity with upstream#116
rikled merged 4 commits into
mainfrom
fix/jwt-header-standalone

Conversation

@juliusknorr

@juliusknorr juliusknorr commented May 28, 2026

Copy link
Copy Markdown
Member

Summary

  • Brings build/scripts/standalone/entrypoint.sh to feature parity with the upstream run-document-server.sh, turning the standalone container into a drop-in replacement for the upstream one.
  • Wires every relevant env var into /etc/euro-office/documentserver/local.json (and into nginx for SSL) before handing off to supervisord.
  • Adds netcat-openbsd, xxd, and openssl to the standalone image; flips ds-metrics supervisor program to opt-in via METRICS_ENABLED.

Env vars now supported

Group Vars
JWT JWT_ENABLED, JWT_SECRET, JWT_HEADER, JWT_IN_BODY, and *_INBOX / *_OUTBOX variants for each
Database (postgres) DB_TYPE (postgres only), DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PWD (alias: DB_PASSWORD, logs deprecation)
Redis REDIS_SERVER_HOST, REDIS_SERVER_PORT, REDIS_SERVER_USER, REDIS_SERVER_PASS, REDIS_SERVER_DB
AMQP AMQP_URI, AMQP_HOST, AMQP_PORT, AMQP_USER, AMQP_PWD, AMQP_VHOST
WOPI WOPI_ENABLED (auto-generates RSA keypair under /var/www/euro-office/Data)
SSL/nginx SSL_CERTIFICATE_PATH, SSL_KEY_PATH, SSL_DHPARAM_PATH, SSL_VERIFY_CLIENT, ONLYOFFICE_HTTPS_HSTS_ENABLED, ONLYOFFICE_HTTPS_HSTS_MAXAGE, NGINX_WORKER_PROCESSES, NGINX_WORKER_CONNECTIONS, NGINX_ACCESS_LOG
Metrics METRICS_ENABLED, METRICS_HOST, METRICS_PORT, METRICS_PREFIX
Misc DS_LOG_LEVEL, PLUGINS_ENABLED, GENERATE_FONTS, USE_UNAUTHORIZED_STORAGE, ALLOW_PRIVATE_IP_ADDRESS, ALLOW_META_IP_ADDRESS, SECURE_LINK_SECRET

Defaults match upstream where reasonable (JWT_ENABLED=true, WOPI_ENABLED=false, PLUGINS_ENABLED=true, METRICS_ENABLED=false, GENERATE_FONTS=true, JWT_IN_BODY=false, JWT_HEADER=Authorization). METRICS_PREFIX defaults to ds. to line up with our cluster image instead of upstream's .ds (per review feedback).

Behavior notes

  • Persisted secrets: JWT_SECRET, SECURE_LINK_SECRET, and the WOPI keypair are auto-generated on first boot and stored under /var/www/euro-office/Data/.private/ (directory 0700, files 0600 — including the WOPI RSA private key). Mount that directory as a volume to keep them stable across restarts; the JWT message printed at boot reminds operators of this.
  • Conditional bundled services: postgresql, redis-server, and rabbitmq-server only start when the corresponding *_HOST points at localhost. For remote hosts the entrypoint waits for the port to open before starting supervisord.
  • DB type restriction: the standalone image only ships postgresql-client, so non-postgres DB_TYPE values are rejected with a clear error. Users needing MariaDB/MySQL/MSSQL/Oracle should use the cluster image.
  • AMQP_VHOST normalization: a value like myvhost is normalized to /myvhost before assembling the amqp:// URI, so users don't have to know the leading-slash detail.
  • Deliberately not implemented: Let's Encrypt automation (LETS_ENCRYPT_*) and the upstream ONLYOFFICE_DATA_CONTAINER split-deployment mode. The cluster image covers split deployments; users with public TLS termination typically run a reverse proxy in front.
  • Behavior change: boolean env vars (ALLOW_PRIVATE_IP_ADDRESS, USE_UNAUTHORIZED_STORAGE, etc.) are now compared against "true" rather than emptiness, matching upstream semantics. Anyone passing 1 or yes before will need to switch to true.

This PR also picks up the existing JWT_HEADER inbox/outbox fix (commit 5ba0cad), so it closes both #94 and #95.

Test plan

All items verified against a derivative image (nightly base + new entrypoint + new packages). The container-level checks were exercised end-to-end with live docker runs.

  • JWT_SECRET=mysecret JWT_HEADER=AuthorizationJwtsecret.{browser,session,inbox,outbox}.string == "mysecret" and token.{inbox,outbox}.header == "AuthorizationJwt" (closes JWT_HEADER env variable is only partially working #94)
  • DB_PASSWORD=oldpwd emits WARNING: DB_PASSWORD is deprecated, use DB_PWD instead on stderr and populates services.CoAuthoring.sql.dbPass
  • DB_HOST=db.internal DB_PWD=… DB_USER=… DB_NAME=… wires the external host into services.CoAuthoring.sql
  • REDIS_SERVER_HOST=redis.internal REDIS_SERVER_PASS=… REDIS_SERVER_DB=2 populates services.CoAuthoring.redis.{host,options.password,options.database}
  • AMQP_URI=amqp://u:p@rabbit.internal:5672/vhost lands in rabbitmq.url; AMQP_VHOST=myvhost normalizes to /myvhost
  • DB_TYPE=mysql is rejected at startup with a clear error
  • WOPI_ENABLED=true generates the RSA keypair under /var/www/euro-office/Data and re-uses it across restarts (modulus stable); private key is 0600
  • Auto-generated JWT_SECRET persists across restarts when the data dir is mounted
  • Baseline docker run prints the generated JWT secret on stdout and serves /welcome/ (welcome page contains "Euro-Office Docs Community Edition")
  • With DB_HOST=<external pg>, pgrep postgres returns nothing inside the container and docservice's queries hit the external host (proven by schema-not-bootstrapped errors against the external DB)
  • With REDIS_SERVER_HOST=<external redis>, pgrep redis-server returns nothing inside the container; redis.host set to external host in local.json
  • SSL_CERTIFICATE_PATH + SSL_KEY_PATH produce a working HTTPS listener (HTTP/2 200) with HSTS header (strict-transport-security: max-age=31536000)
  • Full docker buildx bake standalone from scratch — not re-verified in this round; the prior bake hung partway in the WASM/closure-compiler stages (likely OOM in the buildkit VM, not in our diff). Recommend re-running in CI or with more memory before merge.

🤖 Generated with Claude Code

@juliusknorr juliusknorr requested a review from rikled May 28, 2026 10:51
@juliusknorr juliusknorr changed the title fix: apply JWT_HEADER to inbox/outbox token config in standalone feat(docker): standalone entrypoint env-var parity with upstream May 28, 2026
@juliusknorr juliusknorr requested a review from Copilot May 28, 2026 13:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR expands the standalone Docker entrypoint to better match upstream DocumentServer container behavior by wiring more environment variables into runtime configuration, adding service/SSL setup logic, and making metrics opt-in.

Changes:

  • Reworks build/scripts/standalone/entrypoint.sh to configure JWT, DB, Redis, AMQP, WOPI, nginx/SSL, metrics, logging, fonts, plugins, and bundled service startup.
  • Changes standalone metrics supervisor autostart behavior to opt-in via METRICS_ENABLED.
  • Adds runtime tools needed by the new entrypoint logic to the standalone Docker image.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
build/scripts/standalone/entrypoint.sh Implements the expanded standalone startup/configuration flow and env-var support.
build/configs/standalone/supervisor/ds-metrics.conf Disables metrics autostart so the entrypoint can enable it conditionally.
build/.docker/standalone.bake.Dockerfile Installs additional utilities required by the new entrypoint behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread build/scripts/standalone/entrypoint.sh Outdated
Comment thread build/scripts/standalone/entrypoint.sh Outdated
Comment thread build/scripts/standalone/entrypoint.sh
@juliusknorr

Copy link
Copy Markdown
Member Author

Addressed Copilot's three review comments in ed75701:

  • METRICS_PREFIX default changed from .ds (upstream's odd convention) to ds. (matches our cluster entrypoint, also the more typical statsd prefix shape).
  • AMQP_VHOST normalized to add a leading slash if missing, so AMQP_VHOST=myvhost produces a valid URI.
  • WOPI private key gets chmod 600 after generation so the RSA key isn't world-readable on the Data volume.

The standalone entrypoint only applied JWT_SECRET to local.json but
ignored JWT_HEADER, so custom values like AuthorizationJwt were not
written to services.CoAuthoring.token.inbox.header /
services.CoAuthoring.token.outbox.header. Mirror the orchestrated
entrypoint's behavior and also honor JWT_HEADER_INBOX / JWT_HEADER_OUTBOX.

Fixes #94

Signed-off-by: Julius Knorr <jus@bitgrid.net>
Extends build/scripts/standalone/entrypoint.sh from a small JWT-only
wrapper to a configuration layer that mirrors the upstream
run-document-server.sh. Adds support for DB_*, REDIS_SERVER_*, AMQP_*,
WOPI_*, METRICS_*, SSL_*, NGINX_*, DS_LOG_LEVEL, PLUGINS_ENABLED,
GENERATE_FONTS, JWT_ENABLED, JWT_IN_BODY and inbox/outbox JWT
variants.

Behavior:
- Auto-generates JWT_SECRET, SECURE_LINK_SECRET, and the WOPI RSA
  keypair on first boot; persists them under /var/www/euro-office/Data
  so a mounted volume survives restarts.
- Skips starting bundled postgres/redis/rabbitmq when the
  corresponding *_HOST points at a non-localhost address and waits
  for the remote port to open before launching supervisord.
- Honors DB_PASSWORD as a deprecated alias of DB_PWD with a logged
  warning.
- Configures the deb-shipped ds-ssl.conf.tmpl when SSL_CERTIFICATE_PATH
  and SSL_KEY_PATH are provided (HSTS / dhparam / verify_client knobs
  match upstream); Let's Encrypt and ONLYOFFICE_DATA_CONTAINER mode are
  intentionally not implemented (cluster image covers the split case).
- Rejects non-postgres DB_TYPE values up front since the standalone
  image only ships postgresql-client.

Dockerfile adds netcat-openbsd (remote-host wait), xxd (WOPI modulus
extraction) and an explicit openssl. ds-metrics supervisor program
flipped to autostart=false so METRICS_ENABLED becomes the real toggle.

Closes #94
Closes #95

Signed-off-by: Julius Knorr <jus@bitgrid.net>
- METRICS_PREFIX default is "ds." (matches cluster image) instead of
  the upstream-inherited ".ds", which produced metric names with a
  leading dot and didn't line up with existing dashboards.
- Normalize AMQP_VHOST to ensure a leading slash before appending to
  the URI, so values like "myvhost" yield "amqp://...:5672/myvhost"
  instead of an invalid "amqp://...:5672myvhost".
- chmod 600 the WOPI private key after generation so the RSA key isn't
  world-readable on the Data volume.

Signed-off-by: Julius Knorr <jus@bitgrid.net>
@rikled rikled force-pushed the fix/jwt-header-standalone branch from ed75701 to aad8bc3 Compare May 28, 2026 15:22
Signed-off-by: Hendrik Leidinger <hendrik.leidinger@nextcloud.com>
@rikled

rikled commented May 28, 2026

Copy link
Copy Markdown
Member

tested locally, works fine. fixed some missed static paths.

@rikled rikled merged commit e67a31c into main May 28, 2026
1 of 3 checks passed
@github-project-automation github-project-automation Bot moved this from 📄 To do to ☑️ Done in 📄 Euro-Office team May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: ☑️ Done

Development

Successfully merging this pull request may close these issues.

JWT_HEADER env variable is only partially working

3 participants