Nextcloud shows .docx and .ods files in the Files app, but clicking one only offers a download until a document server is attached. Nextcloud Office is that missing piece, and it comes in two flavours that are installed and configured differently. This tutorial deploys both variants in Docker and connects them to an existing Nextcloud instance.
What is Nextcloud Office?
Nextcloud Office is the browser-based editor for text documents, spreadsheets and presentations inside Nextcloud, and it always consists of two parts: the Nextcloud connector app plus a separate document server, either Collabora Online or OnlyOffice Docs.
The connector app itself renders nothing. It hands out a WOPI token, tells the browser where the document server lives, and exposes a callback API that the document server uses to read and write the file back into Nextcloud storage. That means three parties exchange traffic, and two of them must be reachable from the user's browser over HTTPS.
graph LR U["Browser"] -->|"HTTPS: Nextcloud UI"| NC["Nextcloud"] U -->|"HTTPS: editor assets and websocket"| DS["Document server"] NC -->|"discovery, WOPI token"| DS DS -->|"WOPI callback: GetFile / PutFile"| NC
This is the reason a document server behind a private-only address fails: the browser needs to load the editor directly from office.example.com, not through Nextcloud.
Collabora or OnlyOffice: which one should you pick?
Pick Collabora Online when your users work mainly with ODF files and you want the LibreOffice rendering engine, and pick OnlyOffice Docs when round-trip fidelity with Microsoft Office formats such as .docx and .xlsx matters more than anything else.
| Criterion | Collabora Online (CODE) | OnlyOffice Docs Community |
|---|---|---|
| Engine | LibreOffice core | Own OOXML engine |
| Native format | ODF | OOXML |
| Free edition limit | 20 documents / 10 connections | 20 concurrent connections |
| Container image | collabora/code |
onlyoffice/documentserver |
| Nextcloud app | richdocuments |
onlyoffice |
| Idle RAM | roughly 1 GB | roughly 2 GB |
Both free editions are meant for small teams. Above roughly 20 simultaneous editors you need the commercially licensed build of either product.
Prerequisites
- A reachable Nextcloud instance, version 28 or newer, served over HTTPS
- A Linux host with Docker Engine 24.0 or newer and the Compose plugin (
docker compose version) - At least 4 GB RAM free for the document server. A scalable Cloud VPS with dedicated vCPU is a reasonable baseline for the container.
- A second DNS record, for example
office.example.com, pointing at the Docker host - A valid TLS certificate for that name and a reverse proxy such as nginx
- Shell access with
sudoand the ability to runoccinside the Nextcloud container
Use a distinct hostname for the document server. Running it on a subpath of the Nextcloud domain works, but it complicates the proxy rules and breaks several upstream troubleshooting recipes.
Matching infrastructure at centron
No hardware needed to follow along: ccloud³ VMs with full root access, billed by the hour and ready in seconds. Rent a cloud server →
Deploy Collabora Online with Docker
Create /opt/collabora/compose.yaml. The aliasgroup1 value is a regular expression that lists the Nextcloud instances allowed to use this server, so dots are escaped:
services:
collabora:
image: collabora/code:latest
container_name: collabora
restart: unless-stopped
ports:
- "127.0.0.1:9980:9980"
environment:
- aliasgroup1=https://cloud\\.example\\.com:443
- server_name=office.example.com
- username=admin
- password=CHANGE_ME
- DONT_GEN_SSL_CERT=true
- extra_params=--o:ssl.enable=false --o:ssl.termination=true
cap_add:
- MKNODPin a concrete tag from Docker Hub instead of latest for reproducible deployments. Start the container:
$ cd /opt/collabora
$ docker compose up -d
$ docker compose logs -f collabora | grep -i "coolwsd"The extra_params line matters. It turns off TLS inside the container and tells coolwsd that TLS is terminated upstream. Without --o:ssl.termination=true the editor loads and then hangs on an empty page.
Terminate TLS with nginx
Collabora needs several distinct location blocks, including one that upgrades to a websocket. Place this in /etc/nginx/sites-available/office.example.com.conf:
server {
listen 443 ssl;
http2 on;
server_name office.example.com;
ssl_certificate /etc/letsencrypt/live/office.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/office.example.com/privkey.pem;
# editor assets, discovery and capabilities
location ^~ /browser {
proxy_pass http://127.0.0.1:9980;
proxy_set_header Host $http_host;
}
location ^~ /hosting/discovery {
proxy_pass http://127.0.0.1:9980;
proxy_set_header Host $http_host;
}
location ^~ /hosting/capabilities {
proxy_pass http://127.0.0.1:9980;
proxy_set_header Host $http_host;
}
# websocket for the live editing session
location ~ ^/cool/(.*)/ws$ {
proxy_pass http://127.0.0.1:9980;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_read_timeout 36000s;
}
# download, presentation and image upload endpoints
location ~ ^/(c|l)ool {
proxy_pass http://127.0.0.1:9980;
proxy_set_header Host $http_host;
}
}Reload nginx after checking the syntax:
$ sudo ln -s /etc/nginx/sites-available/office.example.com.conf /etc/nginx/sites-enabled/
$ sudo nginx -t
$ sudo systemctl reload nginxCollabora renamed its paths in version 21.11: /loleaflet became /browser and /lool became /cool. The ^/(c|l)ool pattern above covers both, which keeps older client caches working during an upgrade.
Connect Nextcloud to Collabora
Install the connector app and point it at the proxy hostname. Run occ as the web server user:
$ sudo -u www-data php /var/www/nextcloud/occ app:install richdocuments
$ sudo -u www-data php /var/www/nextcloud/occ config:app:set richdocuments wopi_url --value="https://office.example.com"
$ sudo -u www-data php /var/www/nextcloud/occ config:app:set richdocuments public_wopi_url --value="https://office.example.com"
$ sudo -u www-data php /var/www/nextcloud/occ richdocuments:activate-configIf Nextcloud itself runs in Docker, replace the prefix with docker exec -u www-data nextcloud php occ.
The last command fetches /hosting/discovery and stores the result. It prints Activated config on success and an HTTP error otherwise.
Deploy OnlyOffice Docs with Docker
OnlyOffice Docs authenticates every request with a JSON Web Token, so generate the secret first and reuse the exact same string on both sides:
$ openssl rand -hex 32
9f2c1d...Create /opt/onlyoffice/compose.yaml:
services:
onlyoffice:
image: onlyoffice/documentserver:8.2
container_name: onlyoffice
restart: unless-stopped
ports:
- "127.0.0.1:8082:80"
environment:
- JWT_ENABLED=true
- JWT_SECRET=9f2c1d...
- JWT_HEADER=Authorization
volumes:
- ./data:/var/www/onlyoffice/Data
- ./log:/var/log/onlyoffice
- ./lib:/var/lib/onlyoffice
- ./db:/var/lib/postgresqlThe four volumes are not optional. Without them the internal PostgreSQL database and the generated signing keys are lost on every container recreation, and existing documents fail to reopen.
$ cd /opt/onlyoffice
$ docker compose up -d
$ docker compose logs onlyoffice | tail -20The nginx front end is simpler than the Collabora one, because OnlyOffice serves everything under a single root:
server {
listen 443 ssl;
http2 on;
server_name docs.example.com;
ssl_certificate /etc/letsencrypt/live/docs.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/docs.example.com/privkey.pem;
client_max_body_size 200M;
location / {
proxy_pass http://127.0.0.1:8082;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 3600s;
}
}Raise client_max_body_size to match the largest file your users edit. The default of 1 MB rejects most real spreadsheets with a 413 response.
Connect Nextcloud to OnlyOffice
$ sudo -u www-data php /var/www/nextcloud/occ app:install onlyoffice
$ sudo -u www-data php /var/www/nextcloud/occ config:app:set onlyoffice DocumentServerUrl --value="https://docs.example.com/"
$ sudo -u www-data php /var/www/nextcloud/occ config:app:set onlyoffice jwt_secret --value="9f2c1d..."
$ sudo -u www-data php /var/www/nextcloud/occ config:app:set onlyoffice jwt_header --value="Authorization"The trailing slash in DocumentServerUrl is required. If both services share a Docker network, add the container-to-container shortcut so the callback does not leave the host:
$ sudo -u www-data php /var/www/nextcloud/occ config:app:set onlyoffice DocumentServerInternalUrl --value="http://onlyoffice/"
$ sudo -u www-data php /var/www/nextcloud/occ config:app:set onlyoffice StorageUrl --value="http://nextcloud/"Verify the installation
Check the document server directly before touching the Nextcloud UI. Collabora answers the discovery endpoint with an XML document listing every supported MIME type:
$ curl -s https://office.example.com/hosting/discovery | head -4
<?xml version="1.0" encoding="UTF-8"?>
<wopi-discovery>
<net-zone name="external-http">
<app name="application/vnd.oasis.opendocument.text" favIconUrl="...">OnlyOffice exposes a health endpoint that returns the literal string true:
$ curl -s https://docs.example.com/healthcheck
trueThen confirm the stored configuration on the Nextcloud side:
$ sudo -u www-data php /var/www/nextcloud/occ config:app:get richdocuments wopi_url
https://office.example.com
$ sudo -u www-data php /var/www/nextcloud/occ config:list onlyofficeFinally, create a new document from the Files app + menu. The editor toolbar should appear within a few seconds, and a second browser session opening the same file must show a live cursor for the first user.
Why does the editor fail to open a document?
An editor that loads but shows an error almost always fails on one of three things: the WOPI allowlist rejecting the document server's source address, an internal URL the container cannot resolve, or a JWT secret that differs between Nextcloud and OnlyOffice.
- Collabora reports "Failed to connect to the remote server" — the container cannot reach the Nextcloud URL. Test it from inside:
docker exec collabora curl -I https://cloud.example.com. If DNS resolves to a public IP that the host does not route back to itself, add an entry withextra_hostsin the Compose file. - Nextcloud logs
WOPI request denied— the request arrived from an address outside the allowlist. Add the proxy or container subnet:occ config:app:set richdocuments wopi_allowlist --value="10.0.0.0/8,172.16.0.0/12". - OnlyOffice shows "The document security token is not correctly formed" — the secret differs. Compare
docker exec onlyoffice env | grep JWT_SECRETwithocc config:app:get onlyoffice jwt_secret. After changing the value incompose.yaml, recreate the container withdocker compose up -d --force-recreate. - Documents open read-only — the free edition connection limit is reached, or the Nextcloud user lacks write permission on the share.
Next steps
Pin the image tag, then schedule a monthly docker compose pull && docker compose up -d window; both projects ship security fixes in the document rendering path. Back up /opt/onlyoffice/db together with the Nextcloud data directory, because the document server keeps unsaved editing sessions there. Watch container memory over the first weeks: a Collabora instance serving 15 concurrent editors regularly exceeds 3 GB, and a document server killed by the OOM killer drops every open session without warning.
Read next
- Back Up and Restore Nextcloud: Data, Database, Config
- Install Nextcloud All-in-One with Docker
- Install Nextcloud on Ubuntu 24.04 with nginx
- Mount Nextcloud via WebDAV on Linux, Windows and macOS
- Nextcloud vs ownCloud vs Seafile: Which One Fits?
- Run Nextcloud with Docker Compose
- Updating Nextcloud: Web Updater, occ and a Rollback Plan
- What Is Nextcloud? Architecture, Components and Use Cases
- Which Server for Nextcloud? Sizing RAM, CPU and Storage
Testen Sie Ihr Setup auf ccloud³
Registrieren Sie sich in der ccloud³ und erhalten Sie 200 € Startguthaben für Ihr Projekt – z. B. für eine PostgreSQL-VM mit automatischen Backups.