OnlyOffice
OnlyOffice Document Server is a shared editing backend — it provides browser-based Office document editing for any application that integrates with it, such as Seafile Pro or Nextcloud. It runs as a single container and serves an editor that embeds as an iframe inside the consuming application.
Last run on a host 8 Nov 2026
Pinned at 10.0.0 (released 12 Oct 2026) · the newest upstream release
In the upstream images: 0 CRITICAL · 2 HIGH with a published fix — per image
One OnlyOffice instance can serve multiple consuming applications simultaneously. Each application must hold the same JWT secret and have its origin listed in the allowed-origins setting.
To try it: Docker, and a JWT secret, which the editor requires either way. See Try it locally.
To deploy it behind the proxy: Traefik running, a hostname, a JWT secret, and the origin(s) of each application that will embed the editor.
Try it locally
Section titled “Try it locally”On your own machine, with no proxy, domain or certificate. From apps/onlyoffice/:
cp .env.local.example .env.local
# The secrets ship empty; generate the ones this stack needsecho "JWT_SECRET=$(openssl rand -base64 30 | tr -d '\n')" >> .env.local
docker compose -f docker-compose.local.yml --env-file .env.local up -dThen open http://localhost:8080. Stop it again with the same command and down.
Installation
Section titled “Installation”From apps/onlyoffice/:
-
Terminal window cp .env.example .env -
Set the hostname and timezone in
.env:APP_TRAEFIK_HOST=office.example.comTZ=Europe/Vienna -
Set
ONLYOFFICE_ALLOWED_ORIGINSto the hostname(s) of each application that will embed the editor — space-separated, withhttps://prefix:ONLYOFFICE_ALLOWED_ORIGINS=https://files.example.com -
Generate the JWT secret:
Terminal window mkdir -p .secretsopenssl rand -base64 30 | tr -d '\n' > .secrets/jwt_secret.txt -
Start:
Terminal window docker compose up -d -
First boot takes roughly 90 seconds — PostgreSQL initialises and the document server warms up:
Terminal window docker compose logs onlyoffice-app --follow# Wait for: ONLYOFFICE Document Server ... is up and running
After OnlyOffice is running, share the JWT secret with each consuming application. The exact step depends on the app — for example, Seafile Pro reads it from .env rather than a secrets file. See the consuming application’s guide for the specific step.
Verify
Section titled “Verify”curl -fsSI https://your-domain/healthcheck # expect 200 OKcurl -fsSI https://your-domain/web-apps/apps/api/documents/api.js # expect 200 OKFull functional verification requires a consuming application — open a .docx file in Seafile Pro (or another connected app) and confirm the editor loads in the browser without X-Frame-Options or CSP errors in the browser console.
Allowed origins
Section titled “Allowed origins”ONLYOFFICE_ALLOWED_ORIGINS controls which application origins browsers are permitted to embed the editor from. It maps to a CSP frame-ancestors directive — any origin not listed is rejected by the browser even if the JWT is valid.
Changes to ONLYOFFICE_ALLOWED_ORIGINS require container recreation, not just a restart. The value is embedded in a Traefik label at container creation time:
# After changing ONLYOFFICE_ALLOWED_ORIGINS in .env:docker compose up -d --force-recreateA plain docker compose restart leaves the old CSP in place and the browser will continue to block embedding from any origin not in the original value.
Network path
Section titled “Network path”OnlyOffice fetches each document from the consuming application and saves it back through a callback. The consuming applications ship closed routes, and a closed route refuses every container (DEC-076), so on the same host these calls go past the route:
- Nextcloud — its opt-in
office.ymljoins Nextcloud’s nginx to this stack’s edge network; the connector hands out nginx as the storage address and needs this server’s secret as its settingjwt_secret(apps/nextcloud/README.md, “Office servers behind a closed route”). - Seafile CE and Pro — their opt-in
onlyoffice-callback.ymlopens the two paths OnlyOffice uses.
An OnlyOffice server on another host reaches a closed consuming application only by its address in TRUSTED_RANGES. DOCX, XLSX and PPTX open, save and reopen through Nextcloud and through Seafile CE and Pro this way; the private-address filter lets the JWT-signed storage URL through without ALLOW_PRIVATE_IP_ADDRESS.
Going further
Section titled “Going further”Multiple consuming applications
Section titled “Multiple consuming applications”Add each application’s origin to ONLYOFFICE_ALLOWED_ORIGINS, space-separated:
ONLYOFFICE_ALLOWED_ORIGINS=https://files.example.com https://cloud.example.comEach application also needs a copy of the same JWT secret. Mismatched secrets produce Token is invalid errors in the browser console.
After adding a new origin, recreate the container to apply the updated CSP:
docker compose up -d --force-recreateTailscale-only or private access
Section titled “Tailscale-only or private access”Set APP_TRAEFIK_ACCESS=access-vpn in .env to admit only VPN clients to the OnlyOffice server. The browser loads the editor from this route, so every user then needs the VPN. Nextcloud also calls the document server at its public name from its own container, and a closed route refuses every container (DEC-076): with access-vpn that call fails and the Nextcloud integration stops working.
JWT secret rotation
Section titled “JWT secret rotation”Rotating the JWT secret requires updating both sides simultaneously — there is no downtime-free path:
- Update
.secrets/jwt_secret.txton the OnlyOffice server. - Update the secret in every consuming application (check each app’s guide for where it is stored).
- Restart OnlyOffice and each consuming application.
Active editing sessions will break when the secret changes.
Backup
Section titled “Backup”| Database | None in this stack. |
| State | .secrets/jwt_secret.txt — shared with the embedding application |
| Rebuildable | volumes/data (document cache) · volumes/logs |
| Quiescing | Not applicable. |
Documents live in the application that embeds this document server and are backed up there; what is cached here is a working copy. The JWT secret is the one thing whose loss is felt: both sides hold the same value, so regenerating it means updating every embedding application too.
Updates
Section titled “Updates”-
Read the release notes.
-
If people are editing, let their sessions close first — up to five minutes:
Terminal window docker exec onlyoffice-app documentserver-prepare4shutdown -
Raise
APP_TAGin.env, then:Terminal window docker compose pull && docker compose up -ddocker compose logs onlyoffice-app --followThe first start takes one to five minutes; wait for
Document Server … is up and running. -
Check health, then open a
.docxfrom each embedding application, save it and reopen it:Terminal window curl -fsSI https://<APP_TRAEFIK_HOST>/healthcheck # 200curl -fsSI https://<APP_TRAEFIK_HOST>/web-apps/apps/api/documents/api.js # 200
Troubleshooting
Section titled “Troubleshooting”Editor fails to load or shows a blank area: open the browser console and look for a CSP or X-Frame-Options error. The most likely cause is the consuming application’s origin missing from ONLYOFFICE_ALLOWED_ORIGINS. Confirm the value matches exactly, including the https:// prefix, then recreate the OnlyOffice container.
Document does not load or changes do not save: OnlyOffice cannot reach the consuming application server-to-server. Check:
- DNS resolution for the consuming application’s hostname from the OnlyOffice host.
- Whether the consuming application’s Traefik access middleware is blocking the request.
- That the JWT secret in the consuming application matches the OnlyOffice secret exactly.
Allowed-origins change has no effect: ONLYOFFICE_ALLOWED_ORIGINS is baked into a Traefik label at container creation time, so docker compose restart does not update it. Run docker compose up -d --force-recreate on the OnlyOffice server.
A request is rejected although the consuming application uses access-vpn: the source IP Traefik sees may not match the expected Tailscale address — see Traefik troubleshooting for the Docker bridge source-IP caveat.
Private or Tailscale path: document does not load: verify that DNS for the consuming application’s hostname resolves to an address reachable from the OnlyOffice host. If it resolves to a public IP blocked by a firewall, the server-to-server fetch fails, and the browser console shows no clear error.
Repository files
Section titled “Repository files”apps/onlyoffice/README.md— setup, JWT secret handling, iframe and CSP architectureapps/onlyoffice/UPSTREAM.md— upgrade checklist, version notes, operational notesapps/onlyoffice/.env.example— all configurable variables with inline comments
Official sources
Section titled “Official sources”© 2026 SecDockBlueCode Apache-2.0Site content CC BY-NC 4.0