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 instanceonlyoffice-document-server
self-explanatorynginx-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).
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 # ---- # [ ... ] }