Categories
DevOps

How to fix OnlyOffice download failed error when enforcing Nextcloud https with Docker

Recently I had a task to install Nextcloud with OnlyOffice integration on a client’s server. In order to save some time, I’ve decided to use the official repository that allows for OnlyOffice and Nextcloud installation via Docker compose. It’s container structure looks like this:

  • app-server which is basically a Nextcloud instance
  • onlyoffice-document-server self-explanatory
  • nginx-server which acts as a reverse proxy for Nextcloud and OnlyOffice

Everything was fine up until the point in when I decided to edit the nginx config file (/docker-onlyoffice-nextcloud/nginx.conf) in order to enforce SSL usage by redirecting HTTP to HTTPS. After restarting the nginx server container, OnlyOffice would no longer load the documents inside Nextcloud’s UI (“Download failed.” was all the info it gave me).

Error when foring https in nginx conf for nextcloud and onlyoffice docker image

It appears that when HTTPS is enforced, Nextcloud attempts to communicate with OnlyOffice Document Server via HTTPS, which fails due to the fact that there is no SSL certificate installed on the document server. Since leaving HTTPS usage up to the end users of the instance that I was deploying was not an option, I’ve found a workaround for that problem.

Let’s take a look at the structure of nginx.conf file after installation:

# ---
# section: user, worker_processes, events, ect.
# ---

http {

    # ----
    #section: upstream, include, map, ect.
    # ----

    server {
        listen 80;
        listen 443 ssl http2;

        server_name nextcloud.domain.tld;

        # ----
        # section: ssl certs, ciphers
        # ----

        # typical force-https redirect
        if ($scheme != "https") {
            return 301 https://$host$request_uri;
        }

        # ----
        # section: add header, ect

        # [ ... ]

    }
}

How to fix this problem

The idea is to apply 301 redirection rule only if the request is coming from the outside. In order to do that, we can use NGINX’s Geo module like so:

# ---
# section: user, worker_processes, events, ect.
# ---

http {

    # ----
    #section: upstream, include, map, ect.
    # ----

    #just before server add this (using geo module):

    geo $docker_ip {
        default 0;
        172.18.0.2/32 1; # app-server (nextcloud) container's IP
        172.18.0.4/32 1; # onlyoffice-document-server container's IP
    }

    server {
        listen 80;
        listen 443 ssl http2;

        server_name nextcloud.domain.tld;

        # ----
        # section: ssl certs, ciphers
        # ----

        # add the following checks:

        set $enforce_https 0;
        if ($scheme != "https") {
            # if a user is not using https, enforce https
            set $enforce_https 1;
        }

        if ($docker_ip) {
            # unless that user is our Docker container
            set $enforce_https 0;
        }

        if ($enforce_https) {
            # redirect to https
            return 301 https://$host$request_uri;
        }

        # ----
        # section: add header, ect

        # [ ... ]

    }
}

Just in case you are wondering how I got the containers’ IP addresses – you can retrieve these via:

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container-name

You may also wonder why I used 3 if statements in total. That’s due to the fact that NGINX’s syntax does not allow logic operators like and, or, xor, ect. inside the if statement’s condition. NGINX’s config files are generally meant to be just rule-based.

After saving the nginx.conf file, just restart the nginx-server container and everything should be good to go:

sudo docker restart nginx-server

Bonus tip

Let’s say that you are deploying an app you want to prevent the users from accessing it before everything is ready. You can do that very quickly using nginx.conf:

server {
    listen 80;
    listen 443 ssl http2;

    server_name nextcloud.domain.tld;

    # protip: use this for development/maintenance

    # allow your own ip to connect
    allow your.ip.addr.v4;

    # allow Docker container's IPs
    allow 172.18.0.0/24;

    # say no to anything else
    deny all;

    # ----
    # section: ssl certs, ciphers
    # ----

    # [ ... ]

}

Leave a Reply

Your email address will not be published. Required fields are marked *