Pydio Cells with Collabora/Code using NGINX Proxy Manager

Hi Pydio Team and forum subs.

Using the latest version of Pydio Cells at post time (4.4.0) as an alternative to NextCould.

Has anyone sucessfully deployed Pydio Cells with Collabora/Code using NGINX Proxy Manager.

We’ve spent the better part of 2 weeks on and off trying to integrate these 3 packages with no success.

We’re using Docker/Portainer (latest vers) wunning on a Debian Bookworm host to create our compose files. Have successfully been using NGINX PM for Cells and many other container apps and web services.

Pydio is working excellent behind NPM with a Let’sEncrypt SSL cert.
We managed to get Code installed with a ‘ok’ response in the browser too and now can go to admin panel at https://collabora.domain.com:9980/browser/dist/admin/admin.html
And successfully log in with UN/PW set in compose file…
Collabora eems to be working…

We enabled the plugin for Collabora Online, using
21 and upper (also tried 6 and lower)
Libre Office SSL checked (also tried unchecked with TLS disabled)
Skip Certificate unchecked (tried unchecked)
Office Host localhost (also tried IP, contain names, and FQDN)
Port 9980

For some reason the closest we got to Code opening up a doc in Pydio is a blank white screen that only allows us to back away by clicking the arrow in the top left of the screen that appears.

If anyone was successful or share some insight, or better yet point us to some working compose files for docker that would be greatly appreciated.

We’re ready to give up!

Here is the compose stacks for Collabora/Code;

services:
   collabora:
    image: collabora/code
    container_name: collabora
    restart: always
    cap_add:
     - MKNOD
    ports:
      - 9980:9980
    environment:
      # IMPORTANT: Note the backslashs before the dots here (and only here)!
      - domain=collabora\.domain\.com
      - username=password_here
      - password=password_here
      - VIRTUAL_HOST=collabora.domain.com
      - LETSENCRYPT_HOST=collabora.accretionmedia.com
      - extra_params=--o:ssl.enable=true --o:ssl.termination=true
	volumes:
      - /home/user/docker/collabora/config/:/config

Here is the Pydio stack;

version: '3.8'
services:

  cells:
    image: pydio/cells:latest
    restart: unless-stopped
    ports: ["8081:8080"]
    volumes:
      - /home/user/docker/pydio-cells/cellsdir:/var/cells
      - /home/user/docker/pydio-cells/data:/var/cells/data

  mysql:
    image: mysql:8
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: PASSWORD
      MYSQL_DATABASE: cells
      MYSQL_USER: pydio
      MYSQL_PASSWORD: PASSWORD
    command: [mysqld, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci]
    volumes:
      - /home/user/docker/pydio-cells/mysqldir:/var/lib/mysql

volumes:
    data: {}
    cellsdir: {}
    mysqldir: {}

There are many posts like this marked closed or solved with no solutions… believe me we’ve been checking! This post provides the most insight; Pydio Cells 3.03 and Collabora Online 21.06 Integration - #15 by MSK

As a followup from this video tutorial (German) Collabora Online (Nextcloud Office) Code Server Docker Container Installation inkl. Reverse Proxy
I added a NGINX PM rule to see if this worked. What it did was redirect to my WAN IP which I needed to open a port on the router to resolve properly. But I still get the blank white page when opening a doc in PC.

I’m now thinking I have 2 issues 1) incorrect proxy settings 2) incorrect app settings.

####### Nginx Proxy Manager config #######
1. Create your new Proxy Host, specify https protocol and the server host/ip and port 9980. Also enable Websockets Support.
2. On the SSL tab select a new certificate, enable HTTP/2.
3. On the Advanced tab, enter:
# static files
location ^~ /loleaflet {
  proxy_pass $forward_scheme://$server:$port;
  proxy_set_header Host $http_host;
}
# WOPI discovery URL
location ^~ /hosting/discovery {
  proxy_pass $forward_scheme://$server:$port;
  proxy_set_header Host $http_host;
}
# main websocket
location ~ ^/lool/(.*)/ws$ {
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
  proxy_http_version 1.1;
  proxy_pass $forward_scheme://$server:$port;
  proxy_set_header Host $http_host;
  proxy_read_timeout 36000s;
}
# download, presentation and image upload
location ~ ^/lool {
  proxy_pass $forward_scheme://$server:$port;
  proxy_set_header Host $http_host;
}
# Admin Console websocket
location ^~ /lool/adminws {
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
  proxy_http_version 1.1;
  proxy_pass $forward_scheme://$server:$port;
  proxy_set_header Host $http_host;
  proxy_read_timeout 36000s;
}

Hi @nmincone ,

The following configuration is working with both onlyoffice & collabora

Nginx reverse proxy

map $http_x_forwarded_proto $the_scheme {
     default $http_x_forwarded_proto;
     "" $scheme;
}

map $http_x_forwarded_host $the_host {
    default $http_x_forwarded_host;
    "" $this_host;
}

map $http_upgrade $proxy_connection {
  default upgrade;
  "" close;
}
map $http_host $this_host {
    "" $host;
    default $http_host;
}



server {
        client_max_body_size 200M;
        proxy_send_timeout   600;
        proxy_read_timeout   600;

		proxy_buffer_size 128k;
		proxy_buffers 4 256k;
		proxy_busy_buffers_size 256k;

        server_name domain.dot.io;


# main Cells
        location /  {
        proxy_buffering off;
		proxy_ssl_verify off;
        proxy_pass https://BACKEND_IP_ADDRESS:8080$request_uri;

		# cells-sync - grpc service
		grpc_pass grpcs://BACKEND_IP_ADDRESS:8080;
		
        proxy_pass_request_headers on;

		proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
#		proxy_set_header X-Forwarded-For $remote_addr;
		proxy_set_header X-Forwarded-Proto $scheme;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#		proxy_pass_header Date;
#		proxy_pass_header Server;
        }

# Cells socket
        location /ws {
                proxy_buffering off;
				proxy_ssl_verify off;
                proxy_pass https://BACKEND_IP_ADDRESS:8080$request_uri;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "Upgrade";
                proxy_read_timeout 86400;
        }


# OnlyOffice
	location /onlyoffice/ {
        proxy_buffering off;
        proxy_pass https://BACKEND_IP_ADDRESS:8080$request_uri;

		server_tokens off;
		proxy_ssl_verify off;
#       proxy_read_timeout 86400;
		proxy_connect_timeout 75s;

		proxy_set_header Upgrade $http_upgrade;
		proxy_set_header Connection $proxy_connection;
		proxy_set_header X-Forwarded-Host $the_host;
		proxy_set_header X-Forwarded-Proto $the_scheme;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
# OnlyOffice End ===============

# Collabora
	# main websocket
	location ~ ^/cool/(.*)/ws$ {
		   proxy_pass https://BACKEND_IP_ADDRESS:8080$request_uri;
		   proxy_set_header Upgrade $http_upgrade;
		   proxy_set_header Connection "Upgrade";
		   proxy_set_header Host $host;
		   proxy_set_header X-Forwarded-Proto $scheme;
		   proxy_read_timeout 36000s;
	 }

# Collabora End ==============
    error_log /var/log/nginx/domain.dot.io-proxy-error.log;
    access_log /var/log/nginx/domain.dot.io-proxy-access.log;


    listen 443 ssl http2; # managed by Certbot
    ssl_certificate /etc/.../fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/.../privkey.pem; # managed by Certbot
#    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    ssl_session_cache shared:le_nginx_SSL:1m;
    ssl_session_timeout 1d;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;

    # A+ ssllabs
    #ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES>
    ssl_ecdh_curve secp521r1:secp384r1;
    ssl_ciphers EECDH+AESGCM:EECDH+AES256;


# Good security setting
    add_header X-Frame-Options SAMEORIGIN;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
    add_header X-Content-Type-Options "nosniff";
    add_header Referrer-Policy "same-origin";
    add_header Permissions-Policy "accelerometer=(), geolocation=(), fullscreen=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), display-capture=()";

#  add_header Content-Security-Policy-Report-Only "default-src 'self'; connect-src 'self' wss:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' ; report-uri /csp-violation-report-endpoint/";
#  add_header Content-Security-Policy "default-src 'self' https://domain.dot.io; connect-src 'self' wss:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; font-src 'self' data:"; 

}

Docker compose

version: "3.7"

networks:
  cells-onenode:
    external: false
volumes:
  onenode-cells-config: {}
  onenode-cells-data: {}
  onenode-mysql: {}
services:
  cells:
    image: pydio/cells-enterprise:latest
    restart: unless-stopped
    ports: ["8080:8080"]
    volumes:
      - onenode-cells-config:/var/cells
      - onenode-cells-data:/var/cells/data
    environment:
      - CELLS_BIND_ADDRESS=0.0.0.0    
      - CELLS_EXTERNAL=https://domain.dot.io
    depends_on:
      mysql:
        condition: service_started
    networks:
      - cells-onenode


  mysql:
    image: mysql:8
    restart: unless-stopped
    ports:
      - 3316:3306
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: cells
      MYSQL_USER: cells
      MYSQL_PASSWORD: cells
    networks:
      - cells-onenode
    command:
      [
        mysqld,
        --character-set-server=utf8mb4,
        --collation-server=utf8mb4_unicode_ci,
        --max_connections=10000,
        --max-allowed-packet=254108864
      ]
    volumes:
      - onenode-mysql:/var/lib/mysql


  onlyoffice:
    image: onlyoffice/documentserver:8.0.1
    hostname: onlyoffice
    volumes:
      - ./certs:/var/www/onlyoffice/Data/certs
    networks:
      - cells-onenode
    expose:
      - 443
      - 80
    # ports:
    #   - 443:443
    #   - 9988:80
    environment:
      - JWT_ENABLED=false

  collabora:
    image: collabora/code
    hostname: collabora
    networks:
      - cells-onenode
    expose:
      - 9980
    cap_add:
      - MKNOD
    ports:
      - 9982:9980
    environment:
      - aliasgroup1="https://domain\\.dot\\.io:443"

Thank you for this!

In the NPM code (I place in the Pydio WAN URL in NPM, ie cells2.mydomain.com)?

> map $http_x_forwarded_proto $the_scheme {
>      default $http_x_forwarded_proto;
>      "" $scheme;
> }
> 
> map $http_x_forwarded_host $the_host {
>     default $http_x_forwarded_host;
>     "" $this_host;
> }
> 
> map $http_upgrade $proxy_connection {
>   default upgrade;
>   "" close;
> }
> map $http_host $this_host {
>     "" $host;
>     default $http_host;
> }
> 
> 
> 
> server {
>         client_max_body_size 200M;
>         proxy_send_timeout   600;
>         proxy_read_timeout   600;
> 
> 		proxy_buffer_size 128k;
> 		proxy_buffers 4 256k;
> 		proxy_busy_buffers_size 256k;
> 
>         server_name cells2.mydomain.com;
> 
> 
> 
> 
> # main Cells
>         location /  {
>         proxy_buffering off;
> 		proxy_ssl_verify off;
>         proxy_pass https://192.168.1.149:8080$request_uri;
> 
> 		# cells-sync - grpc service
> 		grpc_pass grpcs://192.168.1.149:8080;
> 		
>         proxy_pass_request_headers on;
> 
> 		proxy_set_header Host $host;
>         proxy_set_header X-Real-IP $remote_addr;
> #		proxy_set_header X-Forwarded-For $remote_addr;
> 		proxy_set_header X-Forwarded-Proto $scheme;
> 		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
> #		proxy_pass_header Date;
> #		proxy_pass_header Server;
>         }
> 
> # Cells socket
>         location /ws {
>                 proxy_buffering off;
> 				proxy_ssl_verify off;
>                 proxy_pass https://192.168.1.149:8080$request_uri;
>                 proxy_set_header Upgrade $http_upgrade;
>                 proxy_set_header Connection "Upgrade";
>                 proxy_read_timeout 86400;
>         }
> 
> 
> # OnlyOffice
> 	location /onlyoffice/ {
>         proxy_buffering off;
>         proxy_pass https://192.168.1.149:8080$request_uri;
> 
> 		server_tokens off;
> 		proxy_ssl_verify off;
> #       proxy_read_timeout 86400;
> 		proxy_connect_timeout 75s;
> 
> 		proxy_set_header Upgrade $http_upgrade;
> 		proxy_set_header Connection $proxy_connection;
> 		proxy_set_header X-Forwarded-Host $the_host;
> 		proxy_set_header X-Forwarded-Proto $the_scheme;
> 		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
>         }
> # OnlyOffice End ===============
> 
> # Collabora
> 	# main websocket
> 	location ~ ^/cool/(.*)/ws$ {
> 		   proxy_pass https://192.168.1.149:8080$request_uri;
> 		   proxy_set_header Upgrade $http_upgrade;
> 		   proxy_set_header Connection "Upgrade";
> 		   proxy_set_header Host $host;
> 		   proxy_set_header X-Forwarded-Proto $scheme;
> 		   proxy_read_timeout 36000s;
> 	 }
> 
> # Collabora End ==============
>     error_log /var/log/nginx/cells2.mydomain.com-proxy-error.log;
>     access_log /var/log/nginx/cells2.mydomain.com-proxy-access.log;
> 
> 
>     listen 443 ssl http2; # managed by Certbot
>     ssl_certificate /etc/.../fullchain.pem; # managed by Certbot
>     ssl_certificate_key /etc/.../privkey.pem; # managed by Certbot
> #    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
>     ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
> 
>     ssl_session_cache shared:le_nginx_SSL:1m;
>     ssl_session_timeout 1d;
> 
>     ssl_protocols TLSv1.2 TLSv1.3;
>     ssl_prefer_server_ciphers on;
> 
>     # A+ ssllabs
>     #ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES>
>     ssl_ecdh_curve secp521r1:secp384r1;
>     ssl_ciphers EECDH+AESGCM:EECDH+AES256;
> 
> 
> # Good security setting
>     add_header X-Frame-Options SAMEORIGIN;
>     add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
>     add_header X-Content-Type-Options "nosniff";
>     add_header Referrer-Policy "same-origin";
>     add_header Permissions-Policy "accelerometer=(), geolocation=(), fullscreen=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), display-capture=()";
> 
> #  add_header Content-Security-Policy-Report-Only "default-src 'self'; connect-src 'self' wss:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' ; report-uri /csp-violation-report-endpoint/";
> #  add_header Content-Security-Policy "default-src 'self' https://cells2.accretionmedia.com; connect-src 'self' wss:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; font-src 'self' data:"; 
> 
> }
>

Is the BACKEND_IP_ADDRESS the docker host IP or the IP provided for the Pydio container when the stack is built?

In NPM can I use my wild card SSL cert with this? When I add this Advanced setting code, NPM shows the site as “Offline”.

The bindings now seem correct.

I notice there are contain pulls in the stack for both openoffice and collabora/code.
Are both needed or just one?

In the stack I originally provided as my first attempt I only used collabora/code and was able to reach both the ‘OK’ confirmation and the admin page for collabora, in your stack example I can not…

  • if nginx in the same docker compose: hostname of cells container
  • if nginx is outside of docker compose: the host ip address.

Please replace “domain.dot.io” by yours

Progress!!! So there is a typo in your config for the collabora stack, the collabora/code exposed 9980 but then you have the mapping set to 9982:9980, I changed it to 9980 and was able to access the admin page of collabora and received ‘OK’ reply in the browser.
Now I get this when opening a document.
socket error
I believe it’s a NGINX PM config setting…

It’s not a typo error, I use this port for internal test. However cells & collabora are in the same network, this configuration is not necessary.

IN Cells > All plugins > Collabora, the hostname should be the container name of collabora/code - collabora and default port: 9980

Thank you, and thank you for your patience.

It must be the advanced proxy configuration since it is resolving to the hosts built in Apache web server rather than the container.

I receive 404 errors and the cells2.mydomain.com appears offline in NGINX.
When I remove the advanced settings code it resolves correctly but I get the socket error shown above.

I’m struggling with the proxy settings, if anyone can assist that would be very helpful. I really don’t want to move to Nextcloud!

hi @nmincone

The configuration of reverse proxy is not trivial.

This schema may help you in troubleshooting the configuration

Does Pydio Cells need to be restarted after each change to the proxy or system settings?
All the tests listed in your diagram pass, but when opening a document I get this.
I haven’t added anything to the Advanced section of NPM because anything I add puts the proxy on ‘offline’

So… I spent a few hours looking into the NPM reverse proxy settings… The only way I could get NPM to keep the site “online” using the advanced settings provided was to eliminate everything except these lines.

# main Cells
         location /  {
         proxy_buffering off;
 		proxy_ssl_verify on;
         proxy_pass https://192.168.1.149:8080$request_uri;
 
 		# cells-sync - grpc service
 		grpc_pass grpcs://192.168.1.149:8080;
 		
         proxy_pass_request_headers on;
 
 		proxy_set_header Host $host;
         proxy_set_header X-Real-IP $remote_addr;
 #		proxy_set_header X-Forwarded-For $remote_addr;
 		proxy_set_header X-Forwarded-Proto $scheme;
 		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 #		proxy_pass_header Date;
 #		proxy_pass_header Server;
         }
 
# Collabora
	# main websocket
	location ~ ^/cool/(.*)/ws$ {
		   proxy_pass https://cells2.mydomain.com:9980$request_uri;
		   proxy_set_header Upgrade $http_upgrade;
		   proxy_set_header Connection "Upgrade";
		   proxy_set_header Host $host;
		   proxy_set_header X-Forwarded-Proto $scheme;
		   proxy_read_timeout 36000s;
	 }

# Collabora End ==============

No errors are being reported in the container logs for Collabora…
Collabora Code Report
At this stage I think I might be done. I have to provide the report Friday. it might be NC AIO going forward. :pensive:

@nmincone

Please take a look at the websocket connection. You should have more information dev tools of google chrome

Try to open a doc when you are at (2) ?

How do you get the SSL cert keys for collabora installed in the docker container?

Running Cells behind a Nginx reverse proxy

What is this error?

Level : error
Logger : pydio.rest.frontend
Msg : Policies blocked GET request at /a/frontend/binaries/USER/nmincone?c1134aa0-517.jpeg&dim=33. Response: DefaultDeny:true
Ts : 1716390942
SpanUuid : span-0