Productivity & Home
OnlyOffice logo

How to install ONLYOFFICE with Docker

ONLYOFFICE cover: How to install ONLYOFFICE with Docker
Difficulty: IntermediateTime: 30 minutesTested with: ONLYOFFICE Docs 9 (Document Server, official image)

ONLYOFFICE Docs (the Document Server) is a free, open-source online office suite: Word documents, spreadsheets, presentations and PDFs, edited in the browser with real-time co-editing and excellent Microsoft Office compatibility. On its own it is an editing engine; you plug it into something that stores files, such as Nextcloud, and suddenly every .docx in your cloud opens in a full editor.

In this guide we will run the Community Edition of the Document Server in Docker using the official image, secure it with a JWT secret, and connect it to Nextcloud with the official ONLYOFFICE connector app.

💡
Note: This guide works with ONLYOFFICE Docs 9 (the latest GitHub release is v9.4.0 at the time of writing) from onlyoffice/documentserver. The Community Edition is free and supports up to 20 simultaneous connections.

✅ Before you start

  • A Linux host with Docker and Docker Compose v2 installed (docker compose version should work). Use docker compose with a space: the old Python docker-compose v1 can crash on modern Docker.
  • At least 2 CPU cores and 4 GB of RAM (plus swap). The Document Server bundles its own PostgreSQL, RabbitMQ and Redis, so it is not small.
  • A Nextcloud server (see my Nextcloud guide), reachable over HTTPS.
  • A hostname for ONLYOFFICE, such as office.example.com, on your reverse proxy. Browsers load the editors from it directly, so it has to be reachable by your users and by Nextcloud.

STEP 1: User and group IDs (and your secrets)

The Document Server image does not use PUID/PGID; it runs its own services inside the container and manages their folders.

What you do need is a JWT secret. It stops anyone else from using your Document Server, and Nextcloud must know the same secret. Make it long and random:

openssl rand -hex 32

Keep them somewhere safe, such as your password manager. In the examples below they appear as placeholders like CHANGE_ME_STRONG_PASSWORD and change-me.

⚠️
Warning: If you do not set JWT_SECRET, the image generates a random one on every fresh container, and your Nextcloud connection breaks each time the container is recreated. Always set your own.

STEP 2: Create the folders

I keep every app's files under one parent folder so a backup is a single job. Create the folders for ONLYOFFICE:

mkdir -p /path/to/appdata/onlyoffice/{logs,data,lib,db,rabbitmq,redis}

If Nextcloud runs on the same host, put both on this proxy network and they can reach each other by container name.

When you are done, the layout should look like this:

/path/to/appdata/onlyoffice/
    docker-compose.yml
    logs/                         # /var/log/onlyoffice
    data/                         # /var/www/onlyoffice/Data (certificates)
    lib/                          # /var/lib/onlyoffice (cache, document files)
    db/                           # bundled PostgreSQL
    rabbitmq/                     # bundled RabbitMQ
    redis/                        # bundled Redis

Folder layout

Finally, I give every web app that sits behind my reverse proxy one shared Docker network called proxy. ONLYOFFICE joins it so Traefik or Nginx Proxy Manager can reach it by container name, while its database and helpers stay on the stack's own private network. Create it once (if it already exists, Docker just tells you so):

docker network create proxy

STEP 3: The compose file

Create /path/to/appdata/onlyoffice/docker-compose.yml and paste in the following. It is based on the official compose file and README, with the JWT settings filled in, persistent folders for every bundled service and the shared proxy network added. Use the copy button in the top right corner of the block.

services:
  onlyoffice:
    image: onlyoffice/documentserver:latest
    container_name: onlyoffice
    restart: always
    stop_grace_period: 60s
    environment:
      JWT_ENABLED: "true"
      JWT_SECRET: change-me                  # the secret from STEP 1
      JWT_HEADER: Authorization
      ALLOW_PRIVATE_IP_ADDRESS: "true"       # needed if Nextcloud is on a private IP/LAN
    ports:
      - "8082:80"
    volumes:
      - /path/to/appdata/onlyoffice/logs:/var/log/onlyoffice
      - /path/to/appdata/onlyoffice/data:/var/www/onlyoffice/Data
      - /path/to/appdata/onlyoffice/lib:/var/lib/onlyoffice
      - /path/to/appdata/onlyoffice/db:/var/lib/postgresql
      - /path/to/appdata/onlyoffice/rabbitmq:/var/lib/rabbitmq
      - /path/to/appdata/onlyoffice/redis:/var/lib/redis
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/info/info.json"]
      interval: 30s
      retries: 5
      start_period: 60s
      timeout: 10s
    networks:
      - proxy

networks:
  proxy:
    external: true

docker-compose.yml

STEP 4: The settings explained

Setting What it does
JWT_ENABLED Requires a signed token on every request. On by default; keep it on.
JWT_SECRET The shared secret. Nextcloud's ONLYOFFICE app must use exactly the same value.
JWT_HEADER The HTTP header the token travels in. Default Authorization. If you change it (the README's Nextcloud example uses AuthorizationJwt), change it in Nextcloud too.
ALLOW_PRIVATE_IP_ADDRESS Lets the Document Server download and save files from servers on private IP addresses. Default false; you need true when Nextcloud is on your LAN or a Docker network.
8082:80 The Document Server listens on 80 inside the container. Your reverse proxy handles HTTPS.
Volumes Logs, certificates, cache and the bundled PostgreSQL, RabbitMQ and Redis data, so nothing is lost when the container is recreated.
stop_grace_period: 60s Gives the bundled services a full minute to shut down cleanly, as in the official file.
healthcheck Polls the internal /info/info.json endpoint so docker ps shows when the server is really ready.
👍
Tip: Self-signed certificates on your Nextcloud?
Add USE_UNAUTHORIZED_STORAGE: "true" so the Document Server accepts them. Better still, use a real certificate from your reverse proxy.

STEP 5: Start ONLYOFFICE

From the folder containing your compose file:

cd /path/to/appdata/onlyoffice
docker compose up -d
docker compose logs -f

Wait until the logs settle down (press Ctrl+C to stop following them; the container keeps running), then check it is up:

docker ps --filter name=onlyoffice

The first start takes a couple of minutes while the bundled services initialise. When docker ps shows (healthy), open http://192.168.1.20:8082: you should see the Document Server is running welcome page.

STEP 6: First-run setup (connect Nextcloud)

The Document Server has no users or admin page of its own; all the setup happens in Nextcloud. Before you start, put ONLYOFFICE behind your proxy (STEP 7) so it has an HTTPS address: browsers refuse to load an http:// editor inside an https:// Nextcloud.

  1. In Nextcloud, go to Apps, search for ONLYOFFICE and click Download and enable.
  2. Open Administration settings → ONLYOFFICE.
  3. Set ONLYOFFICE Docs address to https://office.example.com/. This address must work from your users' browsers and from the Nextcloud server.
  4. Set Secret key to the same value as JWT_SECRET.
  5. If both containers share the proxy network, open Advanced server settings and set ONLYOFFICE Docs address for internal requests from the server to http://onlyoffice/ and Server address for internal requests from ONLYOFFICE Docs to http://nextcloud/. That keeps the server-to-server traffic inside Docker.
  6. Click Save. Nextcloud checks the connection; if it is happy, choose which file types should open in ONLYOFFICE by default.
  7. Open a .docx file in Nextcloud. It should open in the ONLYOFFICE editor.

You can do the same from the command line with occ, then ask the connector to check everything:

cd /path/to/appdata/nextcloud
docker compose exec -u 33 app php occ config:app:set onlyoffice DocumentServerUrl --value="https://office.example.com/"
docker compose exec -u 33 app php occ config:app:set onlyoffice DocumentServerInternalUrl --value="http://onlyoffice/"
docker compose exec -u 33 app php occ config:app:set onlyoffice StorageUrl --value="http://nextcloud/"
docker compose exec -u 33 app php occ config:app:set onlyoffice jwt_secret --value="change-me"
docker compose exec -u 33 app php occ onlyoffice:documentserver --check
💡
Note: If Nextcloud refuses to talk to an internal address such as http://onlyoffice/, it is blocking requests to local servers. Either leave the internal addresses empty (everything then goes via the public hostname), or allow local addresses as described in the connector's README.

STEP 7: Put ONLYOFFICE behind a reverse proxy

Use a dedicated hostname such as office.example.com. The editors use WebSockets, and the Document Server needs the X-Forwarded-Proto and X-Forwarded-Host headers to build correct https:// links (Traefik and Nginx Proxy Manager send these by default).

Option A: Traefik (Docker labels)

If Traefik runs on the same Docker host and is attached to the proxy network, add these labels to the onlyoffice service. They assume your HTTPS entry point is called websecure and your certificate resolver is called cloudflare; change them to match your Traefik config.

    labels:
      - traefik.enable=true
      - traefik.http.routers.onlyoffice.rule=Host(`office.example.com`)
      - traefik.http.routers.onlyoffice.entrypoints=websecure
      - traefik.http.routers.onlyoffice.tls.certresolver=cloudflare
      - traefik.http.services.onlyoffice.loadbalancer.server.port=80

docker-compose.yml (extra lines)

Option B: Traefik (file provider)

If Traefik runs on a different machine, add a router and service to your dynamic config file instead:

http:
  routers:
    onlyoffice:
      rule: Host(`office.example.com`)
      entryPoints:
        - websecure
      tls:
        certResolver: cloudflare
      service: onlyoffice
  services:
    onlyoffice:
      loadBalancer:
        servers:
          - url: http://192.168.1.20:8082

dynamic.yml

Option C: Nginx Proxy Manager

Add a Proxy Host for office.example.com with scheme http, forward hostname onlyoffice (if NPM is on the proxy network) or 192.168.1.20, and forward port 80 (or 8082 if you use the host IP). Request a certificate on the SSL tab and tick Force SSL. Turn Websockets Support on. If large documents fail to open or save, add client_max_body_size 100m; under the Advanced tab.

Once Nextcloud reaches ONLYOFFICE through the proxy (or the shared network), you can remove the ports: section or limit it to "127.0.0.1:8082:80".

Updating ONLYOFFICE

The latest tag follows the newest release. To update:

cd /path/to/appdata/onlyoffice
docker compose pull
docker compose up -d
docker image prune -f
⚠️
Warning: Before updating, close any documents that are open for editing: the Document Server keeps unsaved changes in its own cache. The ONLYOFFICE docs suggest running docker exec onlyoffice documentserver-prepare4shutdown.sh first, which saves everything that is still being edited. Pin an exact version (for example onlyoffice/documentserver:9.4.0, if that tag exists on Docker Hub) if you want to control upgrades.

Troubleshooting

Nextcloud says "Error when trying to connect" or the token is invalid. The secret in Nextcloud does not match JWT_SECRET, or the headers differ. Run occ onlyoffice:documentserver --check to see what it is complaining about.

The editor opens but says "Download failed". The Document Server cannot reach Nextcloud. Set ALLOW_PRIVATE_IP_ADDRESS: "true", check the "Server address for internal requests" setting, and test from the container: docker exec onlyoffice curl -I http://nextcloud/.

Mixed-content errors in the browser. The Docs address is http:// while Nextcloud is https://, or your proxy is not sending X-Forwarded-Proto.

Nextcloud was fine yesterday, broken after a container recreate. You did not set JWT_SECRET, so a new random one was generated. Set it in the compose file and in Nextcloud.

The container is slow to become healthy or gets killed. It is out of memory. ONLYOFFICE needs about 4 GB of RAM including swap.

That's it! Your Nextcloud now has a full office suite built in, and your documents never leave your server. 📝