ONLYOFFICE Docs v7.3 released: enhanced forms, SmartArt, new security settings, Watch Window, and more
ONLYOFFICE Docs v7.3 released

Nextcloud+onlyoffice 403 Forbidden nginx


First of all, I’m going to admit that i’m not professional server admin, this is more like my hobby and I’m still learning.

So, after recent (about week ago) docker automated update of my docservice container (i’m using watchtower), integration stopped working. Nextcloud connector shows this message:

(Client error: `GET https://xxx.xxxx.xxxx.xx/cache/files/data/conv_check_1441340148_docx/output.docx/check_1441340148.docx?md5=hKZsGY_JOCoTwmL-GckOlA&expires=1664352867&filename=check_1441340148.docx` resulted in a `403 Forbidden` response:

403 Forbidden

403 Forbidden

When i use DS example, it shows message:

The document security token is not correctly formed. Please contact your Document Server administrator.

My apache2 vhost:

<VirtualHost *:443>
     ServerName xxxxxxx
     DocumentRoot "/srv/www/htdocs/onlyoffice"
     ProxyPass /.well-known/ !
     ProxyPreserveHost On
     ProxyPass "/" "http://localhost:88/"
     ProxyPassReverse "/" "http://localhost:88/"

     RewriteEngine on
# Some rewrite rules in this file were disabled on your HTTPS site,
# because they have the potential to create redirection loops.

#      RewriteCond %{SERVER_NAME} =xxxxx
#      RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

     <IfModule mod_headers.c>
     RewriteEngine On
     SetEnvIf Host "^(.*)$" THE_HOST=$1
     RequestHeader set X-Forwarded-Proto "https"
     ProxyAddHeaders Off

     SetEnvIf Host "^(.*)$" THE_HOST=$1
     RequestHeader setifempty X-Forwarded-Proto https
     RequestHeader setifempty X-Forwarded-Host %{THE_HOST}e

     ProxyPassMatch (.*)(\/websocket)$ "ws://localhost:88/$1$2"
     ProxyPass / "http://localhost:88/"
     ProxyPassReverse / "http://localhost:88/"


Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/xxxxl/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/xxxx/privkey.pem

Nextcloud config.php

 'onlyoffice' =>
  array (
    'verify_peer_off' => true,
    'jwt_secret' => 'secret',
    'jwt_header' => 'AuthorizationJWT'

Onlyoffice local.json

  "services": {
    "CoAuthoring": {
      "sql": {
        "type": "postgres",
        "dbHost": "localhost",
        "dbPort": "5432",
        "dbName": "onlyoffice",
        "dbUser": "onlyoffice",
        "dbPass": "onlyoffice"
      "token": {
        "enable": {
          "request": {
            "inbox": true,
            "outbox": true
          "browser": true
        "inbox": {
          "header": "AuthorizationJWT"
        "outbox": {
          "header": "AuthorizationJWT"
      "secret": {
        "inbox": {
          "string": "secret"
        "outbox": {
          "string": "secret"
        "session": {
          "string": "secret"
  "rabbitmq": {
    "url": "amqp://guest:guest@localhost"

With configuration above, everything worked fine until last docker image update. I tried looking for solution in other topics, yet i found none.

Connector: 7.5.4, DS: 7.2

Any idea what should i do?

Hello @Viis
Please double-check your local.json file. In the DSv.7.2 we have implemented random key for JWT. So JWT secret could change.
If config file is OK, please reproduce the issue (go to connector page > click Save button) and provide us with whole Document server logs folder.
One more thing, would you mind checking mutual availability between servers? Go to DS host and run wget https://nextcloud_domain_name. And vice versa, from Nextcloud host run wget https://DS_domain name.

Thanks for response.

  1. HERE is documentserver log folder, pulled directly from container. I’ll send password to open archive in private message.

  2. I have double checked JWT secret with

docker exec e4f7e173b25f /var/www/onlyoffice/documentserver/npm/json -f /etc/onlyoffice/documentserver/local.json 'services.CoAuthoring.secret.session.string'

and it matches with nextcloud config.php and connector password field (though it’s different than what i wrote in first post, because didn’t want to share it publicly).

  1. There is no problem using wget to reach ds ->nextcloud and nextcloud ->ds, both results in saving index.html, if it’s what should’ve happen.

I got the same error with a fresh installation documentserver-ee on ubuntu (no docker).

Found this in local.jason whichwas new since version 7.2.0

“storage”: {
“fs”: {
“secretString”: “SomeString different from other jwt secrets”

Commenting this out resolved the error notification from onlyoffice nextcloud app.

Maybe stuff member can verify if this should be set to the same secreat as ,inbox", ,outbox" and ,session"

Regards Lukas

I would do the same with my local.json, but i have a script replacing whole content of this file, so it is the same after watchtower updates container as it was before, and since i don’t have anything like this in my local.json, default values stored in default.json should be put to use.

Correct me If i’m wrong, but having it commented out or absent in local.json is basically same thing, right? As commented out → ommited → default values, and same goes for: not present → default values.

Well, i would appreciate onlyoffice 7.2 local.json file anyway, maybe i’ll find something in there that is missing in my current config. Anyone wiling to share? (since i’m retarded and had it autoreplaced by script…)

Hello @lmensinck

This section defines the secret string which is used to sign the URL. We have information about it here: Configuring ONLYOFFICE Docs Developer Edition - ONLYOFFICE
When editing session is over, Document server builds a file and the link to the file in its cache. It uses MD5 hash to secure it.
So this section needs to improve security of your Document server.

@Viis I have sent you a message via PM about your described situation.

I would do the same with my local.json, but i have a script replacing whole content of this file

local.json file generates during the installation. I’ll send you example from my test machine in a few minutes, but I think it’s better just to re-install Document server.

I had a old server so i creat a new server the new server had the same setup as on Ubuntu, Ngix etc i copied the ds.conf from old to new server. i was getting error that nextcloud can not access 403 So what i noticed the old server had set $secure_link_secret verysecretstring; in the ds.conf and the new server had set $secure_link_secret kkjnjkok1kk1k1nkj1; so when i copied the old ds.conf set $secure_link_secret kkjnjkok1kk1k1nkj1; got removed so i had to update the following from set $secure_link_secret verysecretstring; $secure_link_secret kkjnjkok1kk1k1nkj1; and 403 went away . Why is this ? Before the server accepted $secure_link_secret verysecretstring;

The secretstring has been motified for this post server is different just wnated to give an example

{"reqId":"xf8a8MSm0Facw1UitFeI","level":3,"time":"2022-10-11T16:08:06+00:00","remoteAddr":"","user":"axheli","app":"onlyoffice","method":"PUT","url":"/apps/onlyoffice/ajax/settings/address","message":"Request converted file on check error","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/ Safari/537.36","version":"","exception":{"Exception":"GuzzleHttp\\Exception\\ClientException","Message":"Client error: `GET` resulted in a `403 Forbidden` response:\n<html>\r\n<head><title>403 Forbidden</title></head>\r\n<body>\r\n<center><h1>403 Forbidden</h1></center>\r\n<hr><center>nginx</c (truncated...)\n","Code":403,"Trace":[{"file":"/var/www/nextcloud/3rdparty/guzzlehttp/guzzle/src/Middleware.php","line":69,"function":"create","class":"GuzzleHttp\\Exception\\RequestException","type":"::"},{"file":"/var/www/nextcloud/3rdparty/guzzlehttp/promises/src/Promise.php","line":204,"function":"GuzzleHttp\\{closure}","class":"GuzzleHttp\\Middleware","type":"::","args":["*** sensitive parameters replaced ***"]},{"file":"/var/www/nextcloud/3rdparty/guzzlehttp/promises/src/Promise.php","line":153,"function":"callHandler","class":"GuzzleHttp\\Promise\\Promise","type":"::"},{"file":"/var/www/nextcloud/3rdparty/guzzlehttp/promises/src/TaskQueue.php","line":48,"function":"GuzzleHttp\\Promise\\{closure}","class":"GuzzleHttp\\Promise\\Promise","type":"::","args":["*** sensitive parameters replaced ***"]},{"file":"/var/www/nextcloud/3rdparty/guzzlehttp/promises/src/Promise.php","line":248,"function":"run","class":"GuzzleHttp\\Promise\\TaskQueue","type":"->"},{"file":"/var/www/nextcloud/3rdparty/guzzlehttp/promises/src/Promise.php","line":224,"function":"invokeWaitFn","class":"GuzzleHttp\\Promise\\Promise","type":"->"},{"file":"/var/www/nextcloud/3rdparty/guzzlehttp/promises/src/Promise.php","line":269,"function":"waitIfPending","class":"GuzzleHttp\\Promise\\Promise","type":"->"},{"file":"/var/www/nextcloud/3rdparty/guzzlehttp/promises/src/Promise.php","line":226,"function":"invokeWaitList","class":"GuzzleHttp\\Promise\\Promise","type":"->"},{"file":"/var/www/nextcloud/3rdparty/guzzlehttp/promises/src/Promise.php","line":62,"function":"waitIfPending","class":"GuzzleHttp\\Promise\\Promise","type":"->"},{"file":"/var/www/nextcloud/3rdparty/guzzlehttp/guzzle/src/Client.php","line":187,"function":"wait","class":"GuzzleHttp\\Promise\\Promise","type":"->"},{"file":"/var/www/nextcloud/lib/private/Http/Client/Client.php","line":218,"function":"request","class":"GuzzleHttp\\Client","type":"->"},{"file":"/var/www/nextcloud/apps/onlyoffice/lib/documentservice.php","line":374,"function":"get","class":"OC\\Http\\Client\\Client","type":"->"},{"file":"/var/www/nextcloud/apps/onlyoffice/lib/documentservice.php","line":458,"function":"Request","class":"OCA\\Onlyoffice\\DocumentService","type":"->"},{"file":"/var/www/nextcloud/apps/onlyoffice/controller/settingscontroller.php","line":174,"function":"checkDocServiceUrl","class":"OCA\\Onlyoffice\\DocumentService","type":"->"},{"file":"/var/www/nextcloud/lib/private/AppFramework/Http/Dispatcher.php","line":225,"function":"SaveAddress","class":"OCA\\Onlyoffice\\Controller\\SettingsController","type":"->"},{"file":"/var/www/nextcloud/lib/private/AppFramework/Http/Dispatcher.php","line":133,"function":"executeController","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->"},{"file":"/var/www/nextcloud/lib/private/AppFramework/App.php","line":172,"function":"dispatch","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->"},{"file":"/var/www/nextcloud/lib/private/Route/Router.php","line":298,"function":"main","class":"OC\\AppFramework\\App","type":"::"},{"file":"/var/www/nextcloud/lib/base.php","line":1047,"function":"match","class":"OC\\Route\\Router","type":"->"},{"file":"/var/www/nextcloud/index.php","line":36,"function":"handleRequest","class":"OC","type":"::"}],"File":"/var/www/nextcloud/3rdparty/guzzlehttp/guzzle/src/Exception/RequestException.php","Line":113,"message":"Request converted file on check error","CustomMessage":"Request converted file on check error"},"id":"634599cf2ecfb"}
1 Like

Changing secure_link_secret to from some random code back to “verysecretstring” worked like a charm. But what should I change and where in nextcloud instance if i want to keep this random code? And what command should i use to retrieve this string from onlyoffice?

PS: Sorry for my late response, i had really busy week.

Hello @axheli
I assume that your servers had different versions of Document server. This way we do not recommend to use old config files. From time to time we change config files during new version release to achieve new features.

As far as I see, you had the same issue:

I would do the same with my local.json, but i have a script replacing whole content of this file

You have replaced new data with old one. I believe this is the reason of the issue.