Skip to content

docs(office): document all env vars and add size limits guide - #15414

Open
chrip wants to merge 2 commits into
masterfrom
feature/nextcloud-office-docs
Open

docs(office): document all env vars and add size limits guide#15414
chrip wants to merge 2 commits into
masterfrom
feature/nextcloud-office-docs

Conversation

@chrip

@chrip chrip commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Document every environment variable supported by the Document Server Docker image in the installation page. Previously only a subset was listed.

Add a 'Size limits' section with a 200 MB PPTX example showing how the four size-gate variables interact at different stages (nginx upload, temp file buffer, converter download, uncompressed XML size).

Related to Euro-Office/DocumentServer#237 and Euro-Office/server#35

Assisted-by: OpenCode:qwen3.6-27b

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

📖 Documentation Preview

🔍 Open preview →

📄 1 changed documentation page

Last updated: Thu, 13 Aug 2026 15:24:16 GMT

@chrip
chrip force-pushed the feature/nextcloud-office-docs branch from 84fbe4b to 75c25c3 Compare August 6, 2026 08:51
Document every environment variable supported by the Document Server
Docker image in the installation page. Previously only a subset was listed.

Add a 'Size limits' section with a 200 MB PPTX example showing how the
four size-gate variables interact at different stages (nginx upload, temp
file buffer, converter download, uncompressed XML size).

Assisted-by: OpenCode:qwen3.6-27b
Signed-off-by: Christoph Schaefer <christoph.schaefer@nextcloud.com>
@chrip
chrip force-pushed the feature/nextcloud-office-docs branch from 75c25c3 to 1eba328 Compare August 6, 2026 09:39
@chrip
chrip requested review from moodyjmz and rikled August 6, 2026 10:03

@moodyjmz moodyjmz 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.

TL;DR: Most of the new env-var table checks out against the entrypoint script and the two upstream PRs it's based on, but the new "Size limits" walkthrough gets the request flow wrong for its own headline scenario (opening a stored document), and USE_UNAUTHORIZED_STORAGE is mis-described in a way that understates its security impact. Requesting changes on those two before merge; the completeness gaps below can be a fast follow.

Full review, with exact lines

1. "Size limits" section's core narrative is backwards

installation_docker.rst#L192-L228

Opening a document already stored in Nextcloud is a server-side download, not a browser upload:

  • canvasService.downloadFile (canvasservice.js#L1744) is what actually fetches the document. It reads FILECONVERTER_MAX_DOWNLOAD_BYTES at L1771 and passes it into utils.downloadUrlPromise at L1849 — that's stage 3/4 territory, not stage 1/2.
  • The route is registered as app.get('/downloadfile/:docid', canvasService.downloadFile) with no body parser at all — see the route table in server.js#L206-L244. rawFileParser (the bodyParser.raw({ limit: limits_tempfile_upload }) that MAX_FILE_SIZE controls, L206-L211) is only attached to /command, /converter, /upload/:docid, /savefile/:docid, /downloadfile/:docid POST — image inserts, save-back, WOPI callbacks. Nothing in the "open a stored document" path.
  • NGINX_CLIENT_MAX_BODY_SIZE gates inbound POST bodies to nginx — same problem, no inbound POST body exists when the Document Server is the one fetching the file.

So of the four stages walked through in the doc, only 3 and 4 (FILECONVERTER_MAX_DOWNLOAD_BYTES, FILECONVERTER_INPUT_LIMIT_UNCOMPRESSED) apply to the "user opens a 200 MB PPTX" scenario as written. Following the guide's stage 1/2 advice for that scenario won't do anything.

2. USE_UNAUTHORIZED_STORAGE description is wrong, and understates the risk

installation_docker.rst#L161-L163 documents it as "Allow fetching documents from HTTP (non-TLS) storage."

It actually flows into requestDefaults.rejectUnauthorized, cloned into the HTTPS agent options for the exact same downloadUrlPromise call used to fetch documents — see utils.js#L345-L355, specifically httpsAgentOptions = {...https.globalAgent.options, ...options} at L354. rejectUnauthorized: false is the standard Node.js TLS option for skipping certificate-chain validation — it has no bearing on plain HTTP (no certificate is ever presented on an HTTP connection either way). Flip this thinking you're permitting a legacy plaintext endpoint, and you've disabled cert validation on every HTTPS storage connection too — an unlabelled MITM exposure.

3. The PR's stated goal — "document every environment variable" — isn't quite true

entrypoint.sh still reads several operator-facing vars the table skips (all in entrypoint.sh):
SSL_CERTIFICATE_PATH/SSL_KEY_PATH/SSL_DHPARAM_PATH (L349-L367), SECURE_LINK_SECRET (L118-L127), METRICS_HOST/PORT/PREFIX (L45-L47), REDIS_SERVER_USER/DB, AMQP_URI/VHOST, NGINX_WORKER_CONNECTIONS, ADMINPANEL_ENABLED/EXAMPLE_ENABLED, DS_LOG_LEVEL.

Worth prioritizing the SSL ones: this PR does document SSL_VERIFY_CLIENT and both ONLYOFFICE_HTTPS_HSTS_* vars, but all three only take effect inside the if [ -n "$SSL_CERTIFICATE_PATH" ] && [ -n "$SSL_KEY_PATH" ] gate at L349-L367. Document those three without the two vars that gate them, and a reader can set all three and see zero effect.

4. Minor — undocumented edge-case behavior (low priority)

  • FILECONVERTER_INPUT_LIMIT_UNCOMPRESSED replaces the entire inputLimits array rather than patching one entry (entrypoint.sh#L261-L270). Harmless today (only four format groups exist in default.json), but a footgun if a fifth type group is ever added upstream.
  • FILECONVERTER_MAX_DOWNLOAD_BYTES is silently ignored (stderr warning only) if it isn't a plain integer (entrypoint.sh#L255-L260) — worth a one-line callout.

Addresses the review on #15414.

The "Size limits" walkthrough described opening a stored document as a
browser upload and walked through all four variables in one sequence. The
Document Server downloads such a file itself, so the two request-body
limits never apply. Split into the two paths that actually exist:

- documents the server downloads (FILECONVERTER_MAX_DOWNLOAD_BYTES,
  FILECONVERTER_INPUT_LIMIT_UNCOMPRESSED)
- files posted to the server (NGINX_CLIENT_MAX_BODY_SIZE, MAX_FILE_SIZE)
  for image inserts, save-back, and conversion or command requests

USE_UNAUTHORIZED_STORAGE was documented as allowing HTTP storage. It sets
rejectUnauthorized: false on every outbound HTTPS connection, disabling
certificate, host name, and expiry validation, and has no effect on plain
HTTP. Now carries a warning naming the MITM exposure.

Adds the operator-facing variables the table skipped: SSL_CERTIFICATE_PATH,
SSL_KEY_PATH, SSL_DHPARAM_PATH, SECURE_LINK_SECRET, METRICS_HOST/PORT/PREFIX,
REDIS_SERVER_USER/DB, AMQP_VHOST/URI, NGINX_WORKER_CONNECTIONS,
ADMINPANEL_ENABLED, EXAMPLE_ENABLED, DS_LOG_LEVEL. SSL_VERIFY_CLIENT and
both HSTS variables are noted as inert unless SSL_CERTIFICATE_PATH and
SSL_KEY_PATH are set and both files exist, since documenting them without
their gate led readers to expect an effect.

Also notes that FILECONVERTER_MAX_DOWNLOAD_BYTES is silently ignored when
given a unit suffix, that FILECONVERTER_INPUT_LIMIT_UNCOMPRESSED replaces
the whole limit list, and documents /var/www/euro-office/Data, whose loss
regenerates the JWT secret and breaks the connector.

Tables are grouped by concern, since one flat table had become unreadable.

Signed-off-by: Christoph Schäfer <christoph.schaefer@nextcloud.com>
Assisted-by: Claude Opus 5 (1M context)
Signed-off-by: Christoph Schäfer <christoph.schaefer@nextcloud.com>
chrip added a commit to Euro-Office/documentation that referenced this pull request Aug 13, 2026
Ports the corrections from the review of the same content in
nextcloud/documentation#15414, where these two defects were caught.

The "Size limits" box described opening a stored document as a browser
upload and walked through all four variables in one sequence. The Document
Server downloads such a file itself, so the two request-body limits never
apply. Split into the two paths that actually exist:

- documents the server downloads (FILECONVERTER_MAX_DOWNLOAD_BYTES,
  FILECONVERTER_INPUT_LIMIT_UNCOMPRESSED)
- files posted to the server (NGINX_CLIENT_MAX_BODY_SIZE, MAX_FILE_SIZE)
  for image inserts, save-back, and conversion or command requests

USE_UNAUTHORIZED_STORAGE was documented as allowing HTTP storage. It sets
rejectUnauthorized: false on every outbound HTTPS connection, disabling
certificate, host name, and expiry validation, and has no effect on plain
HTTP. Now carries a warning naming the MITM exposure.

Adds the operator-facing variables the table skipped: SSL_CERTIFICATE_PATH,
SSL_KEY_PATH, SSL_DHPARAM_PATH, SECURE_LINK_SECRET, REDIS_SERVER_USER/DB,
AMQP_VHOST/URI, NGINX_WORKER_CONNECTIONS, ADMINPANEL_ENABLED,
EXAMPLE_ENABLED, DS_LOG_LEVEL. SSL_VERIFY_CLIENT and both HSTS variables
are noted as inert unless SSL_CERTIFICATE_PATH and SSL_KEY_PATH are set and
both files exist.

Also documents the /var/www/euro-office/Data volume on the Docker
installation page, whose loss regenerates the JWT secret and breaks the
connector, and groups the environment tables by concern since one flat
table had become unreadable.

Signed-off-by: Christoph Schaefer <christoph.schaefer@nextcloud.com>
Assisted-by: Claude Opus 5 (1M context)
Signed-off-by: Christoph Schaefer <christoph.schaefer@nextcloud.com>
@chrip

chrip commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @moodyjmz — this was a genuinely useful review, and you were right on both
blocking points. Pushed as 743a812b16. Item by item:

1. Size limits narrative — fixed

You were right that opening a stored document is a server-side download, so
NGINX_CLIENT_MAX_BODY_SIZE and MAX_FILE_SIZE never enter that path. Rather than
reorder the four stages I split the section into the two paths that actually exist,
because a single sequence implies a single pipeline that isn't there:

  • Documents the server downloadsFILECONVERTER_MAX_DOWNLOAD_BYTES,
    FILECONVERTER_INPUT_LIMIT_UNCOMPRESSED
  • Files posted to the serverNGINX_CLIENT_MAX_BODY_SIZE, MAX_FILE_SIZE, scoped
    to the routes your rawFileParser list covers: image inserts, save-back, and
    conversion or command requests

The 200 MB PPTX example stays but now resolves correctly: the 500 MB download default is
already sufficient, so only FILECONVERTER_INPUT_LIMIT_UNCOMPRESSED has to be raised. The
summary table now maps each variable to which path it governs instead of to a stage
number.

2. USE_UNAUTHORIZED_STORAGE — fixed

Rewritten to say it disables TLS certificate validation, with a warning that it sets
rejectUnauthorized: false on every outbound HTTPS connection, that chain, host name and
expiry all stop being checked, and that it has no effect on plain HTTP since no
certificate is presented there. Recommends adding the CA to the container trust store
instead.

3. Missing variables — added

All of them: SSL_CERTIFICATE_PATH, SSL_KEY_PATH, SSL_DHPARAM_PATH,
SECURE_LINK_SECRET, METRICS_HOST/PORT/PREFIX, REDIS_SERVER_USER/DB,
AMQP_VHOST/URI, NGINX_WORKER_CONNECTIONS, ADMINPANEL_ENABLED, EXAMPLE_ENABLED,
DS_LOG_LEVEL.

On the SSL gate you flagged — one refinement. The condition is stricter than
-n-on-both; it also requires the files to exist:

if [ -n "${SSL_CERTIFICATE_PATH:-}" ] && [ -n "${SSL_KEY_PATH:-}" ] \
   && [ -f "$SSL_CERTIFICATE_PATH" ] && [ -f "$SSL_KEY_PATH" ] \
   && [ -f "$NGINX_DS_SSL_TMPL" ]; then

So a typo'd path fails the same way an unset one does, silently and with plain HTTP
served. The note says set and both files exist, since that's the more likely way an
admin trips over it.

4. Edge cases — both documented

Not deferred, they were cheap:

  • FILECONVERTER_MAX_DOWNLOAD_BYTES with a unit suffix is silently ignored — warning to
    stderr, built-in default kept, container starts normally.
  • FILECONVERTER_INPUT_LIMIT_UNCOMPRESSED replaces the whole inputLimits array rather
    than patching one entry, so a future fifth format group would lose its own default.

Two things beyond the review

Tables grouped by concern. At ~40 variables one flat table had stopped being
readable, so it is now split into Authentication, Database, Redis, RabbitMQ, WOPI,
Outbound requests, HTTPS and TLS termination, Nginx, Metrics, and Logging and optional
services. Larger diff than the review asked for, but it seemed better to do it while the
section was already being rewritten than to touch every row twice.

/var/www/euro-office/Data documented. Not from your review, but adjacent and worth
having: the volume list omitted it, and it holds runtime.json, the generated
jwt_secret and secure_link_secret, and the WOPI key pair. Lose it and the JWT secret
regenerates on next start, silently breaking the connector until the new value is copied
into Nextcloud. Same omission existed downstream and is fixed there too.

Verification

sphinx-lint, codespell, and sphinx-build -W --keep-going on admin_manual all
clean. Every default in the new tables was checked against entrypoint.sh rather than
carried over — which is how the NGINX_WORKER_CONNECTIONS default landed on 768
(Ubuntu's packaged nginx.conf in the ubuntu:24.04 base) rather than the 1024 in the
repo's own orchestrated config, and DS_LOG_LEVEL on WARN from
Common/config/log4js/production.json.

Worth noting this same content also lives in the Euro-Office project docs, which is where
it was written first. Both defects were present there too and are now corrected in
Euro-Office/documentation#13, so
the two aren't going to disagree.

Ready for another look when you have time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants