Has anyone installed OnlyOffice Server using Docker on macOS?

Before we fall into a deep rabbit hole of logs and troubleshooting I’d love to hear if anyone has gotten OnlyOffice Server to run using Docker on macOS?

Using docker compose I can get up to the point of the web browser attempting to load the sample doc before it everything falls apart. There is absolutely no documentation on the Internet for the plethora of problems we’ve encountered. Just wondering if this software was NOT INTENDED for use on this platform or if I should dig in and start really debugging. Thanks!

Hello @haus

Using Docker Desktop I was able to run Document Server. However, I did not use Compose, but docker run from the Terminal app once the image has been pulled.

Can you specify which problem did you face after enabling integrated test example and how do you access the Document Server? Did you try to access it from localhost?

Thanks @constantine.

Here is a quick overview of the setup:

  • docker-compose that makes the following directories accessible to macOS:
    ** data
    ** lib
    ** logs
  • OnlyOffice DocumentServer 9.0.4
  • Redis
  • Nginx proxy
    ** SSL
    ** websockets
    ** access via named URL
    ** password protection

The forum will only let me upload one image so I’m including a view of the stacked errors after attempting to open the desktop editor for the sample dock.

So onlyoffice is running and accessible, but something is preventing the sample docs from being saved/used.

The error that is covered reads:

The document could not be saved. Please check connection settings or contact your administrator. When you click the “OK” button, you will be prompted to download the document.

The number and nesting of log files makes it challenging to find where problems are but there was this in logs/documentserver/converter/out.log:

[2025-10-21T13:45:58.930] [ERROR] [localhost] [192.168.65.1__172.18.0.5new.docx1759365579948] [uid-1] nodeJS - error downloadFile:url=https://mysampleurl.com/example/download?fileName=new.docx&useraddress=192.168.65.1__172.18.0.5;attempt=1;code:ERR_BAD_REQUEST;connect:undefined AxiosError: Request failed with status code 401
    at settle (/snapshot/server/Common/node_modules/axios/dist/node/axios.cjs)
    at RedirectableRequest.handleResponse (/snapshot/server/Common/node_modules/axios/dist/node/axios.cjs)
    at RedirectableRequest.emit (node:events:536:35)
    at RedirectableRequest._processResponse (/snapshot/server/Common/node_modules/follow-redirects/index.js:409:10)
    at ClientRequest.<anonymous> (/snapshot/server/Common/node_modules/follow-redirects/index.js:102:12)
    at Object.onceWrapper (node:events:639:26)
    at ClientRequest.emit (node:events:524:28)
    at HTTPParser.parserOnIncomingClient (node:_http_client:702:27)
    at HTTPParser.parserOnHeadersComplete (node:_http_common:118:17)
    at TLSSocket.socketOnData (node:_http_client:544:22)
    at Axios.request (/snapshot/server/Common/node_modules/axios/dist/node/axios.cjs)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Object.downloadUrlPromise (/snapshot/server/Common/sources/utils.js)

This is a stack from logs/documenserver/docservice.out.log:

[2025-10-21T13:39:25.067] [WARN] [localhost] [docId] [userId] nodeJS - Express server starting...
[2025-10-21T13:39:25.069] [WARN] [localhost] [docId] [userId] nodeJS - Set services.CoAuthoring.token.enable.browser, services.CoAuthoring.token.enable.request.inbox, services.CoAuthoring.token.enable.request.outbox in the Document Server config to prevent an unauthorized access to your documents and the substitution of important parameters in Document Server requests.
[2025-10-21T13:39:25.079] [WARN] [localhost] [docId] [userId] nodeJS - notifyLicenseExpiration(): expiration date is not defined
[2025-10-21T13:39:25.080] [WARN] [localhost] [docId] [userId] nodeJS - notifyLicenseExpiration(): expiration date is not defined
[2025-10-21T13:39:25.227] [WARN] [localhost] [docId] [userId] nodeJS - Express server listening on port 8000 in production-linux mode. Version: 9.0.4. Build: 50
[2025-10-21T13:39:56.926] [WARN] [localhost] [docId] [userId] nodeJS - Express server starting...
[2025-10-21T13:39:56.928] [WARN] [localhost] [docId] [userId] nodeJS - Set services.CoAuthoring.token.enable.browser, services.CoAuthoring.token.enable.request.inbox, services.CoAuthoring.token.enable.request.outbox in the Document Server config to prevent an unauthorized access to your documents and the substitution of important parameters in Document Server requests.
[2025-10-21T13:39:56.937] [WARN] [localhost] [docId] [userId] nodeJS - notifyLicenseExpiration(): expiration date is not defined
[2025-10-21T13:39:56.938] [WARN] [localhost] [docId] [userId] nodeJS - notifyLicenseExpiration(): expiration date is not defined
[2025-10-21T13:39:57.072] [WARN] [localhost] [docId] [userId] nodeJS - Express server listening on port 8000 in production-linux mode. Version: 9.0.4. Build: 50
[2025-10-21T13:45:58.858] [ERROR] [localhost] [192.168.65.1__172.18.0.5new.docx1759365579948] [uid-1] nodeJS - postData error: url = https://mysampleurl.com/example/track?filename=new.docx&useraddress=192.168.65.1__172.18.0.5;data = {"key":"192.168.65.1__172.18.0.5new.docx1759365579948","status":1,"users":["uid-1"],"actions":[{"type":1,"userid":"uid-1"}]} AxiosError: Request failed with status code 401
    at settle (/snapshot/server/Common/node_modules/axios/dist/node/axios.cjs)
    at IncomingMessage.handleStreamEnd (/snapshot/server/Common/node_modules/axios/dist/node/axios.cjs)
    at IncomingMessage.emit (node:events:536:35)
    at endReadableNT (node:internal/streams/readable:1698:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
    at Axios.request (/snapshot/server/Common/node_modules/axios/dist/node/axios.cjs)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Object.postRequestPromise (/snapshot/server/Common/sources/utils.js)
    at async sendServerRequest (/snapshot/server/DocService/sources/DocsCoServer.js)
    at async sendStatusDocument (/snapshot/server/DocService/sources/DocsCoServer.js)
[2025-10-21T13:46:10.216] [ERROR] [localhost] [192.168.65.1__172.18.0.5new.docx1759365579948] [uid-13] nodeJS - postData error: url = https://mysampleurl.com/example/track?filename=new.docx&useraddress=192.168.65.1__172.18.0.5;data = {"key":"192.168.65.1__172.18.0.5new.docx1759365579948","status":4,"actions":[{"type":0,"userid":"uid-1"}]} AxiosError: Request failed with status code 401
    at settle (/snapshot/server/Common/node_modules/axios/dist/node/axios.cjs)
    at IncomingMessage.handleStreamEnd (/snapshot/server/Common/node_modules/axios/dist/node/axios.cjs)
    at IncomingMessage.emit (node:events:536:35)
    at endReadableNT (node:internal/streams/readable:1698:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
    at Axios.request (/snapshot/server/Common/node_modules/axios/dist/node/axios.cjs)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Object.postRequestPromise (/snapshot/server/Common/sources/utils.js)
    at async sendServerRequest (/snapshot/server/DocService/sources/DocsCoServer.js)
    at async sendStatusDocument (/snapshot/server/DocService/sources/DocsCoServer.js)

Lastly, this is what the pertinent docker-compose.yml section looks like:

# ------------------
# OnlyOffice Server
# ------------------

  onlyoffice:
    # numbered version to avoid surprises on restart
    image: onlyoffice/documentserver:9.0.4
    container_name: onlyoffice
    restart: unless-stopped
    environment:
      # Database configuration
      - DB_TYPE=mysql
      - DB_HOST=mysql
      - DB_NAME=oo
      - DB_USER=oodbuser
      - DB_PWD=oopassword

      # Redis configuration
      - REDIS_SERVER_HOST=redis
      - REDIS_SERVER_PORT=6379

      # https handled through nginx proxy
      - ONLYOFFICE_HTTPS_HSTS_ENABLED=false

      # we're not messing with tokens
      - JWT_ENABLED=false

      # Enable the NodeJS example doc service
      - DS_EXAMPLE=true

    expose:
      - "80" # expose only reveals ports to nginx proxy. no direct access

    volumes:
      - ./onlyoffice/data:/var/www/onlyoffssh ice/Data
      - ./onlyoffice/logs:/var/log/onlyoffice
      - ./onlyoffice/lib:/var/lib/onlyoffice

    networks:
      - proxy

Thank you for the information.

Do you open the files via integrated test example in that case?

Can you elaborate on this? Do you have an external proxy, i.e. a proxy outside the container with Document Server/in front of it, that provides password protection of the requests?
In general, you can take a look at sample configs for various proxies that we recommend using with Document Server here:

Status code 401 (unauthorized) can be caused by the password protection (depending on what it is and how it is set up) or by a incorrect proxy configuration. For the last point, you may use sample configs and test it out in that way.

Alternatively, you can try disabling external proxy to see if Document Server works without it. Keep in mind, that to properly test it, you have to either build a sample HTML with direct to the file or access integrated test example via static IP of the device (not localhost/Docker network IP).

Thanks @Constantine.

Do you opening the files via integrated test example in that case?

Yes, I open via the highlighted link in this uploaded screenshot. If it is helpful, “viewing” a doc results in the same download error as attempting to edit it.

Can you elaborate on this? Do you have an external proxy, i.e. a proxy outside the container with Document Server/in front of it, that provides password protection of the requests?

Yes, I have an nginx container in front of OpenOffice with “Authentication” enabled (htpasswd) and it works as expected: you are prompted to log in to view anything within Onlyoffice, and then not prompted again on subsequent clicks.

Can you share a sample config for that NGINX to test it out?

In the meantime, please try setting these parameters:

  1. rejectUnauthorized to false;
  2. allowPrivateIPAddress to true.

These parameters are located in default.json config inside the container in /etc/onlyoffice/documentserver. Once changes are made, restart the services with supervisorctl restart all to apply them, then try creating a new file again.

Thanks @Constantine

While I can provide the text for the proxy settings, I’m not sure how useful it is long-term given that the intended interface for changes is the GUI. These are the GUI settings (tabs not shown are empty/null values):

As it relates to default.json: that file is not exposed using docker-compose and is therefore on volatile docker-managed volumes that get overwritten on rebuild.

I can expose that file by creating a volume for it, but it will be empty on build. Before we go and hunt down what that default file should contain so that we can change those two values, is this “best practice” for using the docker version of this app?

Ah, Proxy Manager, I see. Can you show the password settings? htpasswd is a known way to set up such protection, but I’d like to know whether it is also configured via Proxy Manager or not in your case.

Yes, this is correct. There is workaround for such cases, please see it here:

Thanks @Constantine

I’m going to break this reply into two: one for Nginx and one for OnlyOffice.

Authentication is set up entirely through the Nginx Proxy Manager GUI using the “Access List” option:

I did hunt down the actual config file that it spits out. It’s not pretty because it was created by pushing buttons rather than typing.

# ------------------------------------------------------------
# custom.mydomain.com
# ------------------------------------------------------------



map $scheme $hsts_header {
    https   "max-age=63072000; preload";
}

server {
  set $forward_scheme http;
  set $server         "onlyoffice";
  set $port           80;

  listen 80;
listen [::]:80;

listen 443 ssl http2;
listen [::]:443 ssl http2;


  server_name custom.mydomain.com;


  # Let's Encrypt SSL
  include conf.d/include/letsencrypt-acme-challenge.conf;
  include conf.d/include/ssl-ciphers.conf;
  ssl_certificate /etc/letsencrypt/live/npm-1/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/npm-1/privkey.pem;






  # Block Exploits
  include conf.d/include/block-exploits.conf;







    # Force SSL
    include conf.d/include/force-ssl.conf;




proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_http_version 1.1;


  access_log /data/logs/proxy-host-1_access.log proxy;
  error_log /data/logs/proxy-host-1_error.log warn;







  location / {


    
    # Authorization
    auth_basic            "Authorization required";
    auth_basic_user_file  /data/access/1;

    
    proxy_set_header Authorization "";
    

    

    # Access Rules: 1 total
    
    allow 0.0.0.0/0;
    
    deny all;

    # Access checks must...
    
    satisfy all;
    








    
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;
    proxy_http_version 1.1;
    

    # Proxy!
    include conf.d/include/proxy.conf;
  }


  # Custom
  include /data/nginx/custom/server_proxy[.]conf;
}

I’ve adapted the above in the following way:

  1. In docker-compose.yml a new volume mount was added:
  volumes:
      # target our custom file directly instead of mounting the entire directory
      # mounting the entire directory will break onlyoffice init
      - ./onlyoffice/documentserver/local-custom.json:/etc/onlyoffice/documentserver/local-custom.json
  1. On my local filesystem in onlyoffice/documentserver/local-custom.json:
{
  "services": {
    "CoAuthoring": {
      "requestDefaults": {
        "rejectUnauthorized": false
      },
      "request-filtering-agent": {
        "allowPrivateIPAddress": true,
        "allowMetaIPAddress": false
      }
    }
  }
}
  1. again in docker-compose.yml:
      # We use JWT_SECRET INSTEAD of admin groups in Nginx Proxy
      # Because Onlyoffice needs to talk to itself and auth breaks it
      - JWT_ENABLED=true
      - JWT_SECRET={manually-created-super-secret-secret}
  1. Disabled admin access in Nginx Proxy Manager

It doesn’t feel 100% right, but it does work!

Does it mean that the plain authorization via NGINX has been removed?

All the steps are correct, this config allows you specifying custom parameters. Just want to clarify – is Document Server working now?

Thanks @Constantine

Yes, Authorization has been removed completely from this Nginx proxy host. Now onlyoffice is open to the world, which is why I say this doesn’t feel right.

The Document is working now.

As I’m coming to understand better how this works, and that this is an incomplete tool, it seems like the next steps to getting this password protected once again is to:

  1. Install Nextcloud and have users connect to that via password-protected Nginx proxy
  2. Have Nextcloud connect to OnlyOffice by named container rather than by domain name/external IP address
  3. Remove Nginx proxy connection to OnlyOffice altogether

Is that correct?

Its not feasible to use password protection, because the client can pass it, but the backend service of Document Server cannot. Considering that the integrated test example, which is used for testing purposes only, is disabled, there is no way to use Document Server from outside if JWT is enabled.

Such password protection will cause status code 401, when called from outside. For instance, in the integration with Nextcloud, the connector performs connectivity check to Document Server upon saving the settings, thus if Document Server is protected with a plain password, then it will fail with 401.

Specifically for such cases, JWT is used to sign the requests to and from Document Server. You can find more about it here:

Thanks @Constantine.

This is good information but something is still missing. If you don’t mind, I’d like to keep digging.

When thinking about OnlyOffice primarily as a GUI with something else in front of it (Nextcloud, OnlyOffice Workgroup?), can the services in front provide their own authentication (ether via Nginx proxy or via their own built-in user management)?

If yes, then can these frontends communicate with OnlyOffice Server locally, such as connecting from docker container to docker container rather than via the broader network?

The goals would be:

  1. Have a system in which users with accounts can create and edit their own documents, and collaborate on shared docs with other authenticated users
  2. Not have any file management or document editing accessible to the world at large
  3. Not have OnlyOffice accessible directly. OnlyOffice is only accessible to the frontend app (NextCloud, OnlyOffice Workgroup) for security

Let’s take a look at Nextcloud integration for example. It has its own login interface that stores information as a cookie, thus users need to log in to Nextcloud to use the editors, they do not need to log in to Document Server separately.

At the same time, opening a document for editing uses JWT to secure the connection to open the document. That way, a crawler from outside Nextcloud cannot access the file, nor the editor. JWT authorizes requests from both services, which provides additional layer of security.

If there is need to put Document Server behind its own password protection, then there should a separate service that passes this authorization for incoming requests, because Document Server is a service and not a “user” for the storage it is integrated with. Thus using JWT and HTTPS provides stable security without a password protection of Document Server itself.


Both of these are available in Nextcloud integration as an example. Think about Document Server as a tool for editing the documents, you cannot access the tool without logging into the app, to which it belongs.

With JWT enabled, only the service with valid JWT credentials can access Document Server. Other than that, you can enhance the networking queries with a proxy. Examples for proxies are available here. With some tweaking you can even have Document Server not available to the public at all by routing the traffic to the local network, it’s up to you to develop the logic of handling networking queries.

I hope it makes sense.

Thanks @Constantine. I think the only remaining question is how Nextcloud would connect to Document Server in the context of Docker.

If you can configure it to simply connect on to the container name on the docker proxy network that would plug a lot of security holes by seriously limiting outside access as the only access would then be via Nextcloud.

Going to play with Nextcloud over the US Thanksgiving holiday and report back.

You can, by running both Document Server and Nextcloud in a single compose. Technically, to check connectivity, connector app for Nextcloud sends a simple conversion request to Document Server to see it if is available. If Document Server returns a result, then it is accessible, if not, well, it’s not and you see the status code or whatever error causing the issue.