Collabora and Nextcloud in docker-compose - not working

Good day to all.
I am having a trouble connecting nextcloud and collabora - would appreciate a hint on configuration.
I have a nextcloud and collabora installation in docker-compose (using the latest versions of both from docker hub - just installed last week - nextcoud - 18.0.3 and collabora/code - ) - here’s the compose file:

version: '3'

services:
  db:
    image: mariadb
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
    restart: always
    volumes:
      - /data/ncloud/mysql:/var/lib/mysql
    env_file:
      - db.env
  app:
    image: nextcloud:stable-fpm
    restart: always
    volumes:
      - /data/ncloud/data:/var/www/html
    environment:
      - MYSQL_HOST=db
    env_file:
      - db.env
    depends_on:
      - db

  web:
    image: nginx:latest
    restart: always
    ports:
      - 443:443
      - 9980:9980 
    volumes:
      - /data/ncloud/data:/var/www/html:ro
      - ./webshare:/webshare
      - ./web/nginx.conf:/etc/nginx/nginx.conf
      - ./certs:/certs
    depends_on:
      - app

  collabora:
    image: collabora/code
    restart: always
    cap_add: 
      - MKNOD
#    ports: 
#      - 9980:9980
    environment:
      - extra_params=--o:ssl.enable=false
      - domain=chorus-domain.com
      - username=admin 
      - password=<admin password>

I am using SSL termination for collabora at nginx reverse proxy and used the config here to setup nginx - https://www.collaboraoffice.com/code/nginx-reverse-proxy/ - snippet #2 - 2. SSL terminates at the proxy:

Here’s my full nginx config for both nextcloud and collabora:

user  www-data;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    upstream php-handler {
        server app:9000;
    }

    server {
        listen 443 ssl;

        ssl_certificate /certs/cert1.pem;
        ssl_certificate_key /certs/privkey1.pem;
        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:50m;
        ssl_session_tickets off;

  # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
  # Generate with:
  #   `openssl dhparam -out dhparam.pem 2048`

        ssl_dhparam /certs/dhparam.pem;

  # modern configuration. tweak to your needs.
        ssl_protocols TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;

  # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
        add_header Strict-Transport-Security max-age=15768000;

  # OCSP Stapling ---
  # fetch OCSP records from URL in ssl_certificate and cache them
        ssl_stapling off;
  #      ssl_stapling_verify on;

  ## verify chain of trust of OCSP response using Root CA and Intermediate certs
        ssl_trusted_certificate /certs/fullchain1.pem;

        # Add headers to serve security related headers
        # Before enabling Strict-Transport-Security headers please read into this
        # topic first.
        # add_header Strict-Transport-Security "max-age=15768000;
        # includeSubDomains; preload;";
        #
        # WARNING: Only add the preload option once you read about
        # the consequences in https://hstspreload.org/. This option
        # will add the domain to a hardcoded list that is shipped
        # in all major browsers and getting removed from this list
        # could take several months.
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Robots-Tag none;
        add_header X-Download-Options noopen;
        add_header X-Permitted-Cross-Domain-Policies none;

        root /var/www/html;

        location = /robots.txt {
            allow all;
            log_not_found off;
            access_log off;
        }

        # The following 2 rules are only needed for the user_webfinger app.
        # Uncomment it if you're planning to use this app.
        #rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
        #rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json
        # last;

        location = /.well-known/carddav {
            return 301 $scheme://$host/remote.php/dav;
        }
        location = /.well-known/caldav {
            return 301 $scheme://$host/remote.php/dav;
        }

        # set max upload size
        client_max_body_size 1G;
        fastcgi_buffers 64 4K;

        # Enable gzip but do not remove ETag headers
        gzip on;
        gzip_vary on;
        gzip_comp_level 4;
        gzip_min_length 256;
        gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
        gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;

        # Uncomment if your server is build with the ngx_pagespeed module
        # This module is currently not supported.
        #pagespeed off;

        location / {
            rewrite ^ /index.php$uri;
        }

        location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
            deny all;
        }
        location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
            deny all;
        }

        location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
            fastcgi_split_path_info ^(.+\.php)(/.*)$;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_path_info;
            # fastcgi_param HTTPS on;
            #Avoid sending the security headers twice
            fastcgi_param modHeadersAvailable true;
            fastcgi_param front_controller_active true;
            fastcgi_pass php-handler;
            fastcgi_intercept_errors on;
            fastcgi_request_buffering off;
        }

        location ~ ^/(?:updater|ocs-provider)(?:$|/) {
            try_files $uri/ =404;
            index index.php;
        }

        # Adding the cache control header for js and css files
        # Make sure it is BELOW the PHP block
        location ~ \.(?:css|js|woff|svg|gif)$ {
            try_files $uri /index.php$uri$is_args$args;
            add_header Cache-Control "public, max-age=15778463";
            # Add headers to serve security related headers (It is intended to
            # have those duplicated to the ones above)
            # Before enabling Strict-Transport-Security headers please read into
            # this topic first.
            # add_header Strict-Transport-Security "max-age=15768000;
            #  includeSubDomains; preload;";
            #
            # WARNING: Only add the preload option once you read about
            # the consequences in https://hstspreload.org/. This option
            # will add the domain to a hardcoded list that is shipped
            # in all major browsers and getting removed from this list
            # could take several months.
            add_header X-Content-Type-Options nosniff;
            add_header X-XSS-Protection "1; mode=block";
            add_header X-Robots-Tag none;
            add_header X-Download-Options noopen;
            add_header X-Permitted-Cross-Domain-Policies none;
            # Optional: Don't log access to assets
            access_log off;
        }

        location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ {
            try_files $uri /index.php$uri$is_args$args;
            # Optional: Don't log access to other assets
            access_log off;
        }
    }
# collabora server    
    server {
        listen       9980 ssl;
        server_name  chorus-domain.com;

        ssl_certificate /certs/cert1.pem;
        ssl_certificate_key /certs/privkey1.pem;

    
    # static files
    location /  {
        proxy_pass http://collabora:9980;
        proxy_set_header Host $http_host;
    }

    # static files
    location ^~ /loleaflet {
        proxy_pass http://collabora:9980;
        proxy_set_header Host $http_host;
    }

    # WOPI discovery URL
    location ^~ /hosting/discovery {
        proxy_pass http://collabora:9980;
        proxy_set_header Host $http_host;
    }

    # Capabilities
    location ^~ /hosting/capabilities {
        proxy_pass http://collabora:9980;
        proxy_set_header Host $http_host;
    }

    # main websocket
    location ~ ^/lool/(.*)/ws$ {
        proxy_pass http://collabora:9980;
        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
    location ~ ^/lool {
        proxy_pass http://collabora:9980;
        proxy_set_header Host $http_host;
    }

    # Admin Console websocket
    location ^~ /lool/adminws {
        proxy_pass http://collabora:9980;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $http_host;
        proxy_read_timeout 36000s;
    }

    }
    
}

When I access the collabora at https://chorus-domain.com:9980 it gives me OK in the browser but when I access from nextcloud - I got a timeout.
I can only access the admin console of Collabora with https://chorus-domain.com:9980/loleaflet/dist/admin/admin.html

Any help would be appreciated.

Regards, Sergei.

I’m not sure if this matters but in your configuration.yml file for collabora you have:

domain=chorus-domain.com

it should be

domain=chorus-domain\.com

Also any logs from docker collabora? (docker logs collabora).

I also think you want this option:
ssl.enable=false and ssl.termination=true

Thanks.
I have tried changing the domain to domain=chorus-domain.com - no effect.
Also added ssl.enable=false and ssl.termination=true - this results in an error when accessing https://chorus-domain.com:9980 - it no longer gives OK but nginx error.
Docker logs -f collabora_1 shows no errors - seems like it nextcloud can not reach it.

Can you repost your docker-configuration.yml file?

You mead docker-compose.yml?

Sure:

version: '3'
services:
  db:
    image: mariadb
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
    restart: always
    volumes:
      - /data/ncloud/mysql:/var/lib/mysql
    env_file:
      - db.env
  app:
    image: nextcloud:stable-fpm
    restart: always
    volumes:
      - /data/ncloud/data:/var/www/html
    environment:
      - MYSQL_HOST=db
    env_file:
      - db.env
    depends_on:
      - db
  web:
    image: nginx:latest
    restart: always
    ports:
      - 443:443
      - 9980:9980 
    volumes:
      - /data/ncloud/data:/var/www/html:ro
      - ./webshare:/webshare
      - ./web/nginx.conf:/etc/nginx/nginx.conf
      - ./certs:/certs
    depends_on:
      - app

  collabora:
    image: collabora/code
    restart: always
    cap_add: 
      - MKNOD
#    ports: 
#      - 9980:9980
    environment:
      - extra_params=--o:ssl.enable=false
      - domain=chorus-domain\.com
      - username=admin 
      - password=<password>

I’m confused – why do you not have an expose a ports or expose statement for the collabora server?

you don’t need to do the ports in collabora since it goes outside via reverse proxy and inside docker networks all ports are visible to all containers.
So the problem is not there since I can access the root of collabora and I get an OK response and I can access the admin gui with https://chorus-domain.com:9980/loleaflet/dist/admin/admin.html

Ok @chorus12 – my setup is a little bit different than you but I understand what you are telling me – also based on my experience with working with other docker containers in general.

Can you post a nextcloud log file section – or portion of the log file that is generated when you try to open a document? Could you also check the collabora docker logs to see if anything is generated?

This is the log of nginx when opening an odt file:
The conference does not allow me to post nginx log since it contains more then 4 links - so I post the log here - http://code.re/nw6

And here is the log of collabora from the startup and after a startup it is not changing much:

kit-00032-00030 2020-04-24 12:21:47.197271 [ kit_spare_001 ] INF  Process is ready.| kit/Kit.cpp:2612
office version details: { "ProductName": "Collabora Office", "ProductVersion": "6.2", "ProductExtension": ".10.9", "BuildId": "741127f2cc995bb8dc8b4ee57145fa5387af227e" }
kit-00032-00030 2020-04-24 12:21:47.197486 [ kit_spare_001 ] DBG  #23 Thread affinity set to 0x7f711deac780.| net/Socket.hpp:322
kit-00032-00030 2020-04-24 12:21:47.197498 [ kit_spare_001 ] DBG  StreamSocket ctor #23| net/Socket.hpp:881
kit-00032-00030 2020-04-24 12:21:47.197504 [ kit_spare_001 ] TRC  #23 Connected to WS Handler 0x55be46168710| ./net/WebSocketHandler.hpp:101
kit-00032-00030 2020-04-24 12:21:47.197512 [ kit_spare_001 ] DBG  Connected to local UDS loolwsd-l1WJbBg3 #23| net/Socket.cpp:329
kit-00032-00030 2020-04-24 12:21:47.197519 [ kit_spare_001 ] TRC  Requesting upgrade of websocket at path /loolws/newchild?jailid=zmd5WYkpCiFpHuzh&version=%7B%20%22ProductName%22:%20%22Collabora%20Office%22%2C%20%22ProductVersion%22:%20%226.2%22%2C%20%22ProductExtension%22:%20%22.10.9%22%2C%20%22BuildId%22:%20%22741127f2cc995bb8dc8b4ee57145fa5387af227e%22%20%7D #23| net/Socket.cpp:286
kit-00032-00030 2020-04-24 12:21:47.197541 [ kit_spare_001 ] TRC  #23: Wrote outgoing data 503 bytes of 503 bytes buffered.| net/Socket.hpp:1171
kit-00032-00030 2020-04-24 12:21:47.197550 [ kit_spare_001 ] TRC  #23 Connected to WS Handler 0x55be46168710| ./net/WebSocketHandler.hpp:101
wsd-00006-00029 2020-04-24 12:21:47.197519 [ prisoner_poll ] TRC  Poll completed with 1 live polls max (5000ms)| ./net/Socket.hpp:606kit-00032-00030 2020-04-24 12:21:47.197561 [ kit_spare_001 ] DBG  Inserting socket #23 into kit| ./net/Socket.hpp:734

kit-00032-00030 2020-04-24 12:21:47.197569 [ kit_spare_001 ] DBG  #23 Thread affinity set to 0 (was 0x7f711deac780).| ./net/Socket.hpp:282
kit-00032-00030 2020-04-24 12:21:47.197582 [ kit_spare_001 ] INF  New kit client websocket inserted.| kit/Kit.cpp:2671
kit-00032-00030 2020-04-24 12:21:47.197590 [ kit_spare_001 ] INF  Kit initialization complete: setting log-level to [warning] as configured.| kit/Kit.cpp:2676
wsd-00006-00029 2020-04-24 12:21:47.197590 [ prisoner_poll ] DBG  Accepted prisoner socket #19, creating socket object.| net/Socket.cpp:564
wsd-00006-00029 2020-04-24 12:21:47.197612 [ prisoner_poll ] DBG  #19 Thread affinity set to 0x7f102e94e700.| ./net/Socket.hpp:322
wsd-00006-00029 2020-04-24 12:21:47.197636 [ prisoner_poll ] DBG  StreamSocket ctor #19| ./net/Socket.hpp:881
wsd-00006-00029 2020-04-24 12:21:47.197651 [ prisoner_poll ] TRC  #19 Prisoner connected.| wsd/LOOLWSD.cpp:1898
wsd-00006-00029 2020-04-24 12:21:47.197676 [ prisoner_poll ] DBG  Accepted socket is UDS - address uds-to-pid-6 and uid/gid 101/101| net/Socket.cpp:593
wsd-00006-00029 2020-04-24 12:21:47.197693 [ prisoner_poll ] DBG  Accepted client #19| net/ServerSocket.hpp:89
wsd-00006-00029 2020-04-24 12:21:47.197708 [ prisoner_poll ] DBG  Inserting socket #19 into prisoner_poll| ./net/Socket.hpp:734
wsd-00006-00029 2020-04-24 12:21:47.197723 [ prisoner_poll ] DBG  #19 Thread affinity set to 0 (was 0x7f102e94e700).| ./net/Socket.hpp:282
wsd-00006-00029 2020-04-24 12:21:47.197747 [ prisoner_poll ] TRC  Poll start, timeoutMs: 5000| ./net/Socket.hpp:597
wsd-00006-00029 2020-04-24 12:21:47.197767 [ prisoner_poll ] TRC  Poll completed with 1 live polls max (5000ms)| ./net/Socket.hpp:606
wsd-00006-00029 2020-04-24 12:21:47.197786 [ prisoner_poll ] DBG  #19 Thread affinity set to 0x7f102e94e700 (was 0).| ./net/Socket.hpp:282
wsd-00006-00029 2020-04-24 12:21:47.197804 [ prisoner_poll ] TRC  PrisonerPoll - wakes up with 0 new children and 0 brokers and 1 kits forking| wsd/LOOLWSD.cpp:1646
wsd-00006-00029 2020-04-24 12:21:47.197827 [ prisoner_poll ] TRC  rebalance children to 1| wsd/LOOLWSD.cpp:425
wsd-00006-00029 2020-04-24 12:21:47.197844 [ prisoner_poll ] TRC  Poll start, timeoutMs: 5000| ./net/Socket.hpp:597
wsd-00006-00029 2020-04-24 12:21:47.197861 [ prisoner_poll ] TRC  Poll completed with 1 live polls max (5000ms)| ./net/Socket.hpp:606
wsd-00006-00029 2020-04-24 12:21:47.197895 [ prisoner_poll ] TRC  #19: Incoming data buffer 503 bytes, closeSocket? false| ./net/Socket.hpp:1101
wsd-00006-00029 2020-04-24 12:21:47.197918 [ prisoner_poll ] TRC  #19 handling incoming 503 bytes.| net/Socket.cpp:641
wsd-00006-00029 2020-04-24 12:21:47.197986 [ prisoner_poll ] INF  #19: Prisoner HTTP Request: GET /loolws/newchild?jailid=zmd5WYkpCiFpHuzh&version=%7B%20%22ProductName%22:%20%22Collabora%20Office%22%2C%20%22ProductVersion%22:%20%226.2%22%2C%20%22ProductExtension%22:%20%22.10.9%22%2C%20%22BuildId%22:%20%22741127f2cc995bb8dc8b4ee57145fa5387af227e%22%20%7D HTTP/1.1 / Connection: Upgrade / User-Foo: Adminbits / Sec-WebSocket-Key: fxTaWTEMVhq1PkWsMoLxGw== / Upgrade: websocket / Accept-Language: en / Cache-Control: no-cache / Pragma: no-cache / Sec-WebSocket-Version: 13 / User-Agent: LOOLWSD WOPI Agent 4.2.2| net/Socket.cpp:680
wsd-00006-00029 2020-04-24 12:21:47.198023 [ prisoner_poll ] TRC  Child connection with URI [/loolws/newchild?jailid=zmd5WYkpCiFpHuzh&version=%7B%20%22ProductName%22:%20%22Collabora%20Office%22%2C%20%22ProductVersion%22:%20%226.2%22%2C%20%22ProductExtension%22:%20%22.10.9%22%2C%20%22BuildId%22:%20%22741127f2cc995bb8dc8b4ee57145fa5387af227e%22%20%7D].| wsd/LOOLWSD.cpp:1943
wsd-00006-00029 2020-04-24 12:21:47.198069 [ prisoner_poll ] INF  New child [32], jailId: zmd5WYkpCiFpHuzh.| wsd/LOOLWSD.cpp:1992
wsd-00006-00029 2020-04-24 12:21:47.198085 [ prisoner_poll ] TRC  Calling make_shared<ChildProcess>, for NewChildren?| wsd/LOOLWSD.cpp:2000
wsd-00006-00029 2020-04-24 12:21:47.198101 [ prisoner_poll ] TRC  #19: Upgrading to WebSocket.| ./net/WebSocketHandler.hpp:701
wsd-00006-00029 2020-04-24 12:21:47.198121 [ prisoner_poll ] INF  #19: WebSocket version: 13, key: [fxTaWTEMVhq1PkWsMoLxGw==], protocol: [chat].| ./net/WebSocketHandler.hpp:711
wsd-00006-00029 2020-04-24 12:21:47.198158 [ prisoner_poll ] TRC  #19: Sending WS Upgrade response: HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: GAcwqP21iVOY2yKefQ64c0yVN5M=

| ./net/WebSocketHandler.hpp:726
wsd-00006-00029 2020-04-24 12:21:47.198187 [ prisoner_poll ] TRC  #19: Wrote outgoing data 129 bytes of 129 bytes buffered.| ./net/Socket.hpp:1171
wsd-00006-00029 2020-04-24 12:21:47.198209 [ prisoner_poll ] INF  ChildProcess ctor [32].| wsd/LOOLWSD.hpp:61
wsd-00006-00029 2020-04-24 12:21:47.198235 [ prisoner_poll ] DBG  Removing socket #19 (of 3) from prisoner_poll| ./net/Socket.hpp:687
wsd-00006-00029 2020-04-24 12:21:47.198256 [ prisoner_poll ] DBG  #19 Thread affinity set to 0 (was 0x7f102e94e700).| ./net/Socket.hpp:282
wsd-00006-00029 2020-04-24 12:21:47.198281 [ prisoner_poll ] TRC  Calling addNewChild in disposition's move thing to add to NewChildren| wsd/LOOLWSD.cpp:2010
wsd-00006-00029 2020-04-24 12:21:47.198305 [ prisoner_poll ] TRC  Adding one child to NewChildren| wsd/LOOLWSD.cpp:477
wsd-00006-00029 2020-04-24 12:21:47.198325 [ prisoner_poll ] INF  Have 1 spare child after adding [32].| wsd/LOOLWSD.cpp:481
wsd-00006-00029 2020-04-24 12:21:47.198346 [ prisoner_poll ] TRC  Notifying NewChildrenCV| wsd/LOOLWSD.cpp:484
wsd-00006-00029 2020-04-24 12:21:47.198396 [ prisoner_poll ] TRC  Poll start, timeoutMs: 5000| ./net/Socket.hpp:597
wsd-00006-00006 2020-04-24 12:21:47.198436 [ loolwsd ] TRC  Have 1 new children.| wsd/LOOLWSD.cpp:3529
wsd-00006-00006 2020-04-24 12:21:47.198535 [ loolwsd ] INF  WSD initialization complete: setting log-level to [warning] as configured.| wsd/LOOLWSD.cpp:3536
wsd-00006-00034 2020-04-24 17:18:41.602389 [ websrv_poll ] WRN  client - server version mismatch, disabling browser cache. Expected: a96fdaa| wsd/FileServer.cpp:280
wsd-00006-00034 2020-04-24 17:18:41.784040 [ websrv_poll ] WRN  client - server version mismatch, disabling browser cache. Expected: a96fdaa| wsd/FileServer.cpp:280
wsd-00006-00034 2020-04-24 17:18:55.269234 [ websrv_poll ] WRN  client - server version mismatch, disabling browser cache. Expected: a96fdaa| wsd/FileServer.cpp:280
wsd-00006-00034 2020-04-24 17:18:55.351915 [ websrv_poll ] WRN  client - server version mismatch, disabling browser cache. Expected: a96fdaa| wsd/FileServer.cpp:280
wsd-00006-00034 2020-04-24 17:18:59.129057 [ websrv_poll ] WRN  client - server version mismatch, disabling browser cache. Expected: a96fdaa| wsd/FileServer.cpp:280

I am not bound to my setup - I am willing to implement any working setup as well but have not found any configuration that really works. If you could give a clue how to change the setup to make it working - that would be fine as well.
The trickies part is reverse proxy setup - locations.
For instance the root of collabora was not working until I added the following into config of nginx:
location / {
proxy_pass http://collabora:9980;
proxy_set_header Host $http_host;
}
But that was not in any of how-tos.

@chorus - Yea I’m struggling with adding headers as well since that part is definitely tricky. I’ve found values of $host, $proxy_host, $http_host or simply just putting the name of the host you are proxying to. I’m not sure the effect of any of them, however they will change what shows up in the browser URL.

So I’m asking a question about your setup. You have the following containers:

  • mariadb (known as db)
  • nextcloud (known as app)
  • nginx (known as web)
  • collabora (known as collabora)

Nginx is binding ports 443 of the host and also host port 9980. (I’m assuming the 9980 port bind is for testing since in actuality you could probably go through your reverse proxy to reach collabora).

Within nginx you have two server domains however server_name is defined only in one block (what’s server_name for the nextcloud server block).

So I’m no reverse proxy pro - but why do you have the nginx collabora server block listening on port 9980? Shouldn’t both the nginx server blocks be listening on ports 443? I see the way you set things up you are connecting at chorus-domain.com:9980 whereas I would think if you had a listen on port 443, I think you could use https://chorus-domain.com.

Anyway the chorus-domain.com server block is going to proxy_pass via to the collabora:9980 port using reverse proxy.

Right now your reverse proxy seems to be working for the OK test page or location / and the admin interface but not the document server interface.

The logs files you posted are not exactly helpful – I think you posted the nginx access log rather than error log?? and the nextcloud log isn’t really all that helpful either.

What URL are you using within the Nextcloud->Settings->Collabora Code page?

Hello @kevdog
The problem is in nginx reverse proxy as I suppose.
Here’s why I think it is the case. I have made all working removing the nginx from collabora and just running CODE with ssl.
Here is my new docker-compose.yml

version: '3'

services:
  db:
    image: mariadb
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
    restart: always
    volumes:
      - /data/ncloud/mysql:/var/lib/mysql
    environment:
# use .env file do specify values for these vars
      - MYSQL_DATABASE=${MYSQL_DATABASE}
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - MYSQL_USER=${MYSQL_USER}
#    ports:
#      - 3306:3306

  app:
    image: nextcloud:stable-fpm
    restart: always
    volumes:
      - /data/ncloud/data:/var/www/html
    environment:
      - MYSQL_HOST=db
    environment:
# use .env file do specify values for these vars
      - MYSQL_DATABASE=${MYSQL_DATABASE}
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - MYSQL_USER=${MYSQL_USER}
    depends_on:
      - db

  web:
    image: nginx:latest
    restart: always
    ports:
      - 443:443
    volumes:
      - /data/ncloud/data:/var/www/html:ro
      - ./webshare:/webshare
      - ./web/nginx.conf:/etc/nginx/nginx.conf
      - ./certs:/certs
    depends_on:
      - app

  collabora:
    image: collabora/code
    restart: always
    cap_add: 
      - MKNOD
    ports: 
      - 9980:9980
    environment:
      - domain=chorus-domain.com
# please put the below two variables into .env file
# like CLBR_ADMIN=admin
# CLBR_PASSWORD=your password
      - username=${CLBR_ADMIN} 
      - password=${CLBR_PASSWORD}
      - DONT_GEN_SSL_CERT=true
    volumes:
      - ./certs/fullchain1.pem:/etc/loolwsd/ca-chain.cert.pem
      - ./certs/privkey1.pem:/etc/loolwsd/key.pem
      - ./certs/fullchain1.pem:/etc/loolwsd/cert.pem

In case anyone would want to reproduce the config please pay attention for the .env file that must be present in the root folder from where you run docker-compose.
All sensitive env variables are there - just read the comments inside the docker-compose.yml

Many thanks for supporting me in this affair.
Partial credits also go to this site
If anyone will find out the proper nginx reverse proxy config - will be glad to adapt that.

@chorus12

What’s not exactly working now and/or what exactly do you want to acheive?

Do you want collabora to go through the reverse proxy?

Yes - I would like to use nginx reverse proxy in the installation - now I use plain CODE.

@chorus12

I’ll try to help you however I don’t have your exact setup. I’m running CODE in docker, but my nginx reverse proxy runs on the docker host, and my nextcloud installation runs on yet a totally different VM.

What does your nginx.conf file look like right now?

I think I need just the location parts for CODE and server.
Mine nginx.conf is below - it is only for ncloud:

user  www-data;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    upstream php-handler {
        server app:9000;
    }

    server {
        listen 443 ssl;

        ssl_certificate /certs/cert1.pem;
        ssl_certificate_key /certs/privkey1.pem;
        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:50m;
        ssl_session_tickets off;

  # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
  # Generate with:
  #   `openssl dhparam -out dhparam.pem 2048`

        ssl_dhparam /certs/dhparam.pem;

  # modern configuration. tweak to your needs.
        ssl_protocols TLSv1.1 TLSv1.2;
        ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK';
        ssl_prefer_server_ciphers on;

  # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
        add_header Strict-Transport-Security max-age=15768000;

  # OCSP Stapling ---
  # fetch OCSP records from URL in ssl_certificate and cache them
        ssl_stapling off;
  #      ssl_stapling_verify on;

  ## verify chain of trust of OCSP response using Root CA and Intermediate certs
        ssl_trusted_certificate /certs/fullchain1.pem;

        # Add headers to serve security related headers
        # Before enabling Strict-Transport-Security headers please read into this
        # topic first.
        # add_header Strict-Transport-Security "max-age=15768000;
        # includeSubDomains; preload;";
        #
        # WARNING: Only add the preload option once you read about
        # the consequences in https://hstspreload.org/. This option
        # will add the domain to a hardcoded list that is shipped
        # in all major browsers and getting removed from this list
        # could take several months.
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Robots-Tag none;
        add_header X-Download-Options noopen;
        add_header X-Permitted-Cross-Domain-Policies none;

        root /var/www/html;

        location = /robots.txt {
            allow all;
            log_not_found off;
            access_log off;
        }

        # The following 2 rules are only needed for the user_webfinger app.
        # Uncomment it if you're planning to use this app.
        #rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
        #rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json
        # last;

        location = /.well-known/carddav {
            return 301 $scheme://$host/remote.php/dav;
        }
        location = /.well-known/caldav {
            return 301 $scheme://$host/remote.php/dav;
        }

        # set max upload size
        client_max_body_size 1G;
        fastcgi_buffers 64 4K;

        # Enable gzip but do not remove ETag headers
        gzip on;
        gzip_vary on;
        gzip_comp_level 4;
        gzip_min_length 256;
        gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
        gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;

        # Uncomment if your server is build with the ngx_pagespeed module
        # This module is currently not supported.
        #pagespeed off;

        location / {
            rewrite ^ /index.php$uri;
        }

        location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
            deny all;
        }
        location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
            deny all;
        }

        location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
            fastcgi_split_path_info ^(.+\.php)(/.*)$;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_path_info;
            # fastcgi_param HTTPS on;
            #Avoid sending the security headers twice
            fastcgi_param modHeadersAvailable true;
            fastcgi_param front_controller_active true;
            fastcgi_pass php-handler;
            fastcgi_intercept_errors on;
            fastcgi_request_buffering off;
        }

        location ~ ^/(?:updater|ocs-provider)(?:$|/) {
            try_files $uri/ =404;
            index index.php;
        }

        # Adding the cache control header for js and css files
        # Make sure it is BELOW the PHP block
        location ~ \.(?:css|js|woff|svg|gif)$ {
            try_files $uri /index.php$uri$is_args$args;
            add_header Cache-Control "public, max-age=15778463";
            # Add headers to serve security related headers (It is intended to
            # have those duplicated to the ones above)
            # Before enabling Strict-Transport-Security headers please read into
            # this topic first.
            # add_header Strict-Transport-Security "max-age=15768000;
            #  includeSubDomains; preload;";
            #
            # WARNING: Only add the preload option once you read about
            # the consequences in https://hstspreload.org/. This option
            # will add the domain to a hardcoded list that is shipped
            # in all major browsers and getting removed from this list
            # could take several months.
            add_header X-Content-Type-Options nosniff;
            add_header X-XSS-Protection "1; mode=block";
            add_header X-Robots-Tag none;
            add_header X-Download-Options noopen;
            add_header X-Permitted-Cross-Domain-Policies none;
            # Optional: Don't log access to assets
            access_log off;
        }

        location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ {
            try_files $uri /index.php$uri$is_args$args;
            # Optional: Don't log access to other assets
            access_log off;
        }
    }
        
}

Ok cool. I always hesitate to give advice without a test system similar to the person answering the question… but… let’s just try some things.

So far your nginx stuff is pretty boring vanilla nextcloud.

So I’m going to make a few design assumption, since its possible to run a few different way.

Right now you probably access code through the nextcloud CODE settings at https://chorus-domain.com:9980. I’m assuming you want to access CODE at https://chorus-domain.com and then proxy_pass via http so the backend CODE container.

Within nginx, you’ll need likely another virtual domain or server block that looks something like the following:

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

    server_name chorus-domain.com;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/chorus-domain.com.access.log main buffer=32k;
    error_log /var/log/nginx/chorus-domain.com.error.log;

    #These two include files contain the path to the certs and various cert parameters as borrowed from mozilla (intermediate configuration)
    include snippets/chorus-domain.com.cert.conf;
    include snippets/ssl-params.conf;

keepalive_timeout 65;

# Allow large attachments
client_max_body_size 128M;

index index.html index.htm index.php /index.php;

    #Optional block for testing to receive OK from server
location / {
	proxy_pass http://collabora:9980/;
}

# static files
location ^~ /loleaflet {
    proxy_pass http://collabora:9980;
    proxy_set_header Host $http_host;
}

# WOPI discovery URL
location ^~ /hosting/discovery {
    proxy_pass http://collabora:9980;
    proxy_set_header Host $http_host;
}

# Capabilities
location ^~ /hosting/capabilities {
    proxy_pass http://collabor:9980;
    proxy_set_header Host $http_host;
}

# main websocket
location ~ ^/lool/(.*)/ws$ {
    proxy_pass http://collabora:9980;
    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
location ~ ^/lool {
    proxy_pass http://collabora:9980;
    proxy_set_header Host $http_host;
}

# Admin Console websocket
location ^~ /lool/adminws {
    proxy_pass http://collabora:9980;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $http_host;
    proxy_read_timeout 36000s;
}

}

with your docker compose file for collabora, can you structure it similar to this:

networks:
net:
driver: bridge

collabora:
restart: always
image: collabora/code:latest
container_name: collabora
networks:
- net
ports:
- 9980:9980
cap_add:
- MKNOD
environment:
- TZ=America/Chicago (or whatever
- username=admin
- password=
- domain=app|collabora
- server_name=collabora
- extra_params=–o:ssl.enable=false --o:ssl.termination=true

We can change ports/expose statement later.

Here is a working example where an Apache reverse proxy is running on the host.

https://help.nextcloud.com/t/howto-ubuntu-docker-nextcloud-talk-collabora/76430

I don’t use nginx, so I’m not sure I can offer much there, however one thing that stuck out to me was you mentioned you couldn’t connect to CODE from NC. What I do in my setup is have them both connect to each other through the reverse proxy on the host, where they are both presented valid certs by the proxy. And I used the docker-compose extra_hosts directive to make sure they both resolve the names to the LAN IP of the host.