Single certificate for nextcloud and collabora

Hi everyone,

I just got my nextcloud running with collabora based on nginx. At this point: Thanks to all people posting in this forum which helped me a lot to got it running!

Now I have a question concerning the security/meaningfulness of my setup because I’m using the same certificate for nextcloud and collabora.

nginx config:

upstream php-handler {
    server unix:/run/php-fpm/php-fpm.sock;
}

server {
   listen 80;
   server_name myNextCloudDomain;

   # enforce https
   return 301 https://$server_name$request_uri;

    # Redirect non-https traffic to https
    # if ($scheme != "https") {
    #     return 301 https://$host$request_uri;
    # } # managed by Certbot

}

server {
    listen 443 ssl http2;
    server_name myNextCloudDomain;

    ssl_certificate /etc/letsencrypt/live/myNextCloudDomain-0001/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/myNextCloudDomain-0001/privkey.pem; # managed by Certbot

    # 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;";
    add_header X-Content-Type-Options nosniff;
    #add_header X-Frame-Options "SAMEORIGIN";
    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;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # Path to the root of your installation
    ##
    root pathToMyNextcloudData;

    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;
    }

    location ~ /.well-known/acme-challenge {
      allow all;
    }

    # set max upload size
    client_max_body_size 512M;
    fastcgi_buffers 64 4K;

    # Disable gzip to avoid the removal of the ETag header
    gzip off;

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

    error_page 403 /core/templates/403.php;
    error_page 404 /core/templates/404.php;

    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/.+|core/templates/40[34])\.php(?:$|/) {
       include fastcgi_params;
       fastcgi_split_path_info ^(.+\.php)(/.*)$;
       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)$ {
        try_files $uri /index.php$uri$is_args$args;
        add_header Cache-Control "public, max-age=7200";
        # 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;";
        add_header X-Content-Type-Options nosniff;
        add_header X-Frame-Options "SAMEORIGIN";
        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 ~* \.(?:svg|gif|png|html|ttf|woff|ico|jpg|jpeg)$ {
        try_files $uri /index.php$uri$is_args$args;
        # Optional: Don't log access to other assets
        access_log off;
   }

}

server {
    listen       9981 ssl;
    server_name  myNextCloudDomain;

    ssl_certificate /etc/letsencrypt/live/myNextCloudDomain-0001/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/myNextCloudDomain-0001/privkey.pem;
    
    # static files
    location ^~ /loleaflet {
        proxy_pass https://localhost:9980;
        proxy_set_header Host $http_host;
    }

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

   # main websocket
   location ~ ^/lool/(.*)/ws$ {
       proxy_pass https://localhost: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 https://localhost:9980;
       proxy_set_header Host $http_host;
   }
   
   # Admin Console websocket
   location ^~ /lool/adminws {
       proxy_pass https://localhost:9980;
       proxy_set_header Upgrade $http_upgrade;
       proxy_set_header Connection "Upgrade";
       proxy_set_header Host $http_host;
       proxy_read_timeout 36000s;
   }
}

In the admin section of nextcloud I’ve put the following into the field Collabora Online Server: https://myNextCloudDomain:9981

Sumup:
With this setup my nextcloud sends collabora related request to port 9981 and nginx redirects them to port 9980 where the docker image is listening. With this I can use the same domain and cert for nextcloud and collabora.

It works but is it a good practice? And is it critical to open port 9981 at my router (necessary to get it running)?

Thanks in advance!

No ideas on this topic?

Note: I´m not an nginx expert, so i didn´t analyse your setup in depth, but i feel i got the important parts.

It should be fine i guess. The port must be open, cause the Webbrowser which is calling NC and Collabora must reach the CollaboraServer on its own.

I use different subdomains to achieve this kind of setup. like:
nc.domain.com and collabora.domain.com, so i always ever have only port 443 open. Reverse proxy is used to split the trafic from a single ip. I then use a *.domain.com cert. Not sure if this possible with Letsencrypt. And since you use Letsencrypt, i see no reason to deliver Colabora with a cert on its own on Port 433.

Your setup seems to me just half a notch more unsafe than mine, cause of the additional open port.

Sometime the one or the other thread escapes the team here, you did the right thing to push it a few days later :slight_smile:

Hi @Burner

I’m no security expert neither, but I believe your setup is not bad necessarily. I’d say it’s fine to run it that way, but still I wouldn’t do it myself :slight_smile:
The approach of @Ascendancer is the same I followed:
nginx listening on port 443 and sending the request to the right recipient depending on the domain name.
The advantage I see here is not only that there is just one port open instead of two, I can also run security tests against both domains with https://www.ssllabs.com/ssltest/
– specials ports like 9981 are not supported by that test.

So I for myself make sure, that such tests show me very good grades as result, close every other port then needed and do some hardening of the server itself.

Here the two tests I found useful and helpful:

And regarding the SSL certificates: just like creating and automatically renewing your current certificate with letsencrypt you can create many more certificates and let them renew as well. There is no limit.

Wildcard certs like *.yourdomain.tld from letsencrypt will come very soon. There are tests for these wildcard certs since January 4th and in February letsencrypt is going provide these certs for everyone. I’m very much waiting for them as well :slight_smile:

Hope this helps.

1 Like

Thanks for the replies. As you can imagine I’m not 100% satisfied with my setup either that’s why I’m asking.
I wanted to go with the subdomaining in the first place, but not letsencrypt was the problem FreeDNS was. I don’t see a possibility there for subdomains at least not with wildcards and adding two domains is not supported by my router. But maybe I can find a way around that problem.

Hi,

Maybe there is a miss-understanding there. Don’t know FreeDNS or your router, but usually you do:

  • create a domain, let’s say >> burner.net <<
  • go to the router config and setup port-forwarding
  • forward port 80 to port 80 on the local IP of your server
  • forward port 443 to port 443 on the local IP of your server
  • setup the web server to listen on 80 and 443 for the two different FQDNs (full qualified domain names) you would like to use. For example nextcloud.burner.net and collabora.burner.net
  • check if you can reach both services (nextcloud via nextcloud.burner.net, collabora via collabora.burner.net)
  • use the letsencrypt cert bot to receive certificates for both subdomains
  • setup a cron job to renew the certificates for both services

Of course you have setup most of it already, I just wanted to make clear the usual way to set it up. Please adjust accordingly to your setup.
Hope it helps.