I’m pretty experienced at setting up Collabora code via Docker/Docker compose, but I can’t seem to take a working configuration where collabora and an nginx reverse proxy is running on the same machine and tweak the configuration so that an nginx reverse proxy is running a different machine. I’m trying to setup an ssl terminating reverse proxy with http communication to collabora
Here is my docker-compose.yml file I’m tweaking (there are a number of different commented sections which I turn on and off for testing): I’ve substituted for my actual domain name.
---
version: '3.3'
networks:
net:
driver: bridge
services:
collabora:
restart: always
image: collabora/code:latest
container_name: collabora
networks:
- net
ports:
# - 127.0.0.1:9980:9980
- 9980:9980
cap_add:
- MKNOD
environment:
- TZ=America/Chicago
- username=admin
- password=dockercol
- domain=nextcloud\.<domain>\.com
# - cert_domain=office.<domain>.com
- DONT_GEN_SSL_CERT="True"
- server_name=office.<domain>.com
- extra_params=--o:ssl.enable=false --o:ssl.termination=true
# - extra_params=--o:ssl.enable=false --o:ssl.termination=false
# - extra_params="--o:ssl.enable=true"
# - extra_params="--o:ssl.enable=false"
# volumes:
# - /etc/letsencrypt/office.<domain>.com/privkey.pem:/etc/loolwsd/key.pem
# - /etc/letsencrypt/office.<domain>.com/cert.pem:/etc/loolwsd/cert.pem
# - /etc/ssl/certs/ca-certificates.crt:/etc/loolwsd/ca-chain.cert.pem
# - /etc/letsencrypt/office.<domain>.com/chain.pem:/etc/loolwsd/ca-chain.cert.pem
In terms of the compose file, perhaps someone could help me as I’m using this page as a reference. https://www.collaboraoffice.com/code/docker/
The domain parameter specifies the WOPI host. I believe the WOPI host (what that heck does WOPI stand for anyway??) is the nextcloud installation. I suppose if you running multiple nextcloud installations you would add a second host with a | separator.
The cert_domain is needed is needed if you are enabling TLS/SSL inside the container and want the collabora container to generate a “self signed certificate” with a specific domain name. Because I’m terminating SSl at the reverse proxy, I don’t think I need this option.
The server_name parameter I believe is the host-name of the reverse proxy. I believe the server_name needs to be changed depending on the location of the reverse proxy.
In terms of the nginx reverse proxy configuration – this is the configuration if the reverse proxy is on the same machine (this is a working configuration). This was directly adapted from the official collabora proxy instructions: https://www.collaboraoffice.com/code/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;
"" $host;
}
map $http_upgrade $proxy_connection {
default upgrade;
"" close;
}
server {
listen [::]:443 ssl http2;
listen 443 ssl http2;
server_name office.<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/office.<domain>.com.access.log main buffer=32k;
error_log /var/log/nginx/office.<domain>.com.error.log;
include snippets/office.<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;
location / {
root /var/www/office.<domain>.com/html;
}
# static files
location ^~ /loleaflet {
proxy_pass http://localhost:9980;
proxy_set_header Host $http_host;
}
# WOPI discovery URL
location ^~ /hosting/discovery {
proxy_pass http://localhost:9980;
proxy_set_header Host $http_host;
}
# Capabilities
location ^~ /hosting/capabilities {
proxy_pass http://localhost:9980;
proxy_set_header Host $http_host;
}
# main websocket
location ~ ^/lool/(.*)/ws$ {
proxy_pass http://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 http://localhost:9980;
proxy_set_header Host $http_host;
}
# Admin Console websocket
location ^~ /lool/adminws {
proxy_pass http://localhost:9980;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $http_host;
proxy_read_timeout 36000s;
}
}
So that’s a working configuration.
For the non-working reverse proxy on a different machine I’m running the same docker-collabora instance however with my compose file I set the server_name parameter to the reverse proxy (I named my reverse proxy test.<domain>.com and have LE certs for the test domain)
Here is my nginx config (almost as exactly above but with slight modifications);
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;
"" $host;
}
map $http_upgrade $proxy_connection {
default upgrade;
"" close;
}
server {
listen [::]:443 ssl http2;
listen 443 ssl http2;
server_name test.<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/test.<domain>.com.access.log main buffer=32k;
error_log /var/log/nginx/test.<domain>.com.error.log;
include snippets/test.<domain>.com.cert.conf;
include snippets/ssl-params.conf;
keepalive_timeout 65;
# Allow large attachments
client_max_body_size 128M;
# static files
location ^~ /loleaflet {
proxy_pass http://office.<domain>.com:9980;
proxy_set_header Host $http_host;
}
# WOPI discovery URL
location ^~ /hosting/discovery {
proxy_pass http://office.<domain>.com:9980;
proxy_set_header Host $http_host;
}
# Capabilities
location ^~ /hosting/capabilities {
proxy_pass http://office.<domain>.com:9980;
proxy_set_header Host $http_host;
}
# main websocket
location ~ ^/lool/(.*)/ws$ {
proxy_pass http://office.<domain>.com: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://office.<domain>.com:9980;
proxy_set_header Host $http_host;
}
# Admin Console websocket
location ^~ /lool/adminws {
proxy_pass http://office.<domain>.com:9980;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $http_host;
proxy_read_timeout 36000s;
}
}
I’ve ensured the firewall allows all connections for port 9980:
# ufw status
Status: active
To Action From
-- ------ ----
Apache Full ALLOW Anywhere
OpenSSH ALLOW Anywhere
9980 ALLOW Anywhere
Anywhere on docker0 ALLOW Anywhere
Anywhere ALLOW 172.17.0.0/24
Anywhere ALLOW 172.18.0.0/24
Anywhere ALLOW 172.19.0.0/24
Anywhere ALLOW 172.20.0.0/24
Apache Full (v6) ALLOW Anywhere (v6)
OpenSSH (v6) ALLOW Anywhere (v6)
9980 (v6) ALLOW Anywhere (v6)
Anywhere (v6) on docker0 ALLOW Anywhere (v6)
Unfortunately this configuration is definitely not working. I’m wondering if anyone had any ideas??
When I say not working let me clarify – there is a problem with the websocket connection.
I can reach the collabora administrator console through the reverse proxy and I can also with a tweak reach the docker instance where I’m getting an OK in the browser.
Here is an example from the nextcloud log:
{"reqId":"JSWPDYuZrMlvFolfSuPX","level":3,"time":"April 22, 2020 22:33:00","remoteAddr":"10.0.1.184","user":"ncadmin","app":"richdocuments","method":"GET","url":"/index.phpdocuments/index?fileId=25&requesttoken=lVriqZxmIC6nzqUuPFrk46Mk5PKmBKk86rOzkWMqFgI%3D%3A%2Bi207OYyYXjjg4pkVjCx1MxIsJfRYspXp%2FyY41F5d1M%3D","message":{"Exception":"GuzzleHttp\\Exception\\ConnectException","Message":"cURL error 35: error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)","Code":0,"Trace":[{"file":"/usr/local/www/nextcloud/3rdparty/guzzlehttp/guzzle/src/Handler/CurlFactory.php","line":149,"function":"createRejection","class":"GuzzleHttp\\Handler\\CurlFactory","type":"::","args":[{"sink":{"__class__":"GuzzleHttp\\Psr7\\Stream"},"headers":[],"response":null,"request":{"__class__":"GuzzleHttp\\Psr7\\Request"},"options":{"verify":false,"timeout":5,"synchronous":true,"handler":{"__class__":"GuzzleHttp\\HandlerStack"},"allow_redirects":{"max":5,"protocols":["http","https"],"strict":false,"referer":false,"track_redirects":false},"http_errors":true,"decode_content":true,"cookies":false},"errno":35,"onHeadersException":null,"__class__":"GuzzleHttp\\Handler\\EasyHandle"},{"errno":35,"error":"error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version","url":"https://test.<domain>.com/hosting/discovery"
Clearly there seems to be an SSL error – however why???