Nextcloud and Collabora behind HAProxy
This guide explains how to get Nextcloud working with Collabora using HAProxy as a reverse proxy. This specific setup assumes that both run on the same host as HAProxy. If that is not the case please take care securing your connections.
NOTE: This is not a perfect solution since the reverse proxy configuration additionally exposes port 81 and 444. I do not consider this to be a clean setup but, at the moment, the snap does not allow listening only on localhost.
- A domain for Nextcloud (e.g. nextcloud.domain.com) and Collabora (e.g. office.domain.com)
- Nextcloud snap installed
- Set trusted domain and enabled HTTPS for Nextcloud
- Docker (CE) installed (e.g. for Ubuntu)
- certbot (standalone) installed (e.g. for Ubuntu 18.04)
- HAProxy (>v1.5) installed
systemctl stop haproxy
# snap set nextcloud ports.http=81 ports.https=444
This configuration establishes a mixed SSL/TLS setup where Nextcloud's traffic is passed through in tcp mode
and Collabora's SSL/TLS is terminated by HAproxy.
Edit /etc/haproxy/haproxy.cfg:
global
. . .
# Default is 1024 which is not recommended
tune.ssl.default-dh-param 2048
frontend http-in
# Bind all IPv4 and IPv6
bind :::80 v4v6 # bind *:80 for IPv4 only
mode http
acl host_nextcloud hdr(host) -i nextcloud.domain.com
acl path_letsencrypt path_beg /.well-known/acme-challenge/
use_backend letsencrypt if !host_nextcloud path_letsencrypt
use_backend nextcloud-http if host_nextcloud
frontend https-in
bind :::443 v4v6 # See above
# This needs tcp mode since it is SSL/TLS traffic
mode tcp
# Test if valid SSL request
tcp-request inspect-delay 5s
tcp-request content accept if { req.ssl_hello_type 1 }
acl host_nextcloud req.ssl_sni -i nextcloud.domain.com
# If traffic is not destined for Nextcloud, it's SSL is terminated at HAProxy
use_backend nextcloud-https if host_nextcloud
default_backend https-term
frontend https-term
bind :::9443 v4v6 ssl crt /etc/haproxy/certs
#HTTP mode is required since SSL is terminated here
mode http
# In case of challenges over HTTPS
acl path_letsencrypt path_beg /.well-known/acme-challenge/
use_backend letsencrypt if path_letsencrypt
default_backend collabora
# This sends the request over to the https-term frontend
backend https-term
mode tcp
server terminator 127.0.0.1:9443
# This sends an acme challenge to a selected port where certbot is listening, hopefully
backend letsencrypt
mode http
server letsencrypt 127.0.0.1:10500
backend nextcloud-http
mode http
# Check health status of server with a HEAD request
option httpchk HEAD / HTTP/1.1\r\nHost:localhost
server nextcloud 127.0.0.1:81 check
backend nextcloud-https
mode tcp
# Send an ssl-hello request to check the server's health
option ssl-hello-chk
server nextcloud 127.0.0.1:444 check
backend collabora
mode http
option httpchk HEAD / HTTP/1.1\r\nHost:localhost
# This initiates an SSL connection to the Collabora server.
# I couldn't find a way to disable HTTPS in the Collabora container.
# This is ok as long as they both run on the same host.
# Otherwise, the Collabora container's cert has to be imported to HAProxy.
server collabora 127.0.0.1:9980 check ssl verify none
Do not reload HAProxy, yet. You need
From Collabora Online Office -- Nextcloud:
# docker pull collabora/code
# docker run -t -d -p 127.0.0.1:9980:9980 -e 'domain=nextcloud\\.domain\\.com' --name collabora --restart always --cap-add MKNOD collabora/code
NOTE: It is important to use your Nextcloud domain as domain
. Collabora will match against it when your Nextcloud instance tries to connect.
HAProxy needs the certificate chain and the domain's certificate to be in one file so we have to
# certbot certonly --standalone -d office.domain.com
# mkdir -p /etc/haproxy/certs
# cd /etc/letsencrypt/live/office.domain.com
# cat fullchain.pem privkey.pem > "/etc/haproxy/certs/office.domain.com.pem"
# systemctl start haproxy # 'systemctl enable --now haproxy' instead if it is disabled
Create a new file /usr/local/bin/renew.sh:
#!/bin/bash
# RENEWED_LINEAGE is set by certbot and points to the renewed certificate's directory
DOMAIN=`basename "$RENEWED_LINEAGE"`
CERTS_PATH="/etc/haproxy/certs"
# Only create new certificates for already existing certificates
# We wouldn't want to import certs for domains we don't need
if [ -e "$CERTS_PATH/$DOMAIN.pem" ];then
# move to the correct let's encrypt directory
cd /etc/letsencrypt/live/"$DOMAIN"
# cat files to make combined .pem for haproxy
cat fullchain.pem privkey.pem > "$CERTS_PATH/$DOMAIN.pem"
fi
Test if everything works, set up the deploy- and post-hook and change the port certbot listens on (The service will still send the challenge to port 80 which is why HAProxy listens on port 80 for acme challenges).
# chmod 755 /usr/local/bin/renew.sh
# certbot renew --force-renewal --preferred-challenges http --deploy-hook /usr/local/bin/renew.sh --post-hook "systemctl reload haproxy" --http-01-port 10500
- Install the Collabora plugin in your Nextcloud instance (Collabora Online App)
- Go into Nextcloud's settings and select "Collabora Online", enter https://office.domain.com, Hit "Save"
- The Collabora container sometimes hung up on me on boot so I had to manually restart it again
- You will probably get these warnings in your NC's self test which you can safely ignore:
Your web server is not properly set up to resolve “/.well-known/caldav”. Your web server is not properly set up to resolve “/.well-known/carddav”.
Nextcloud snap Wiki, use all information and scripts at own risk