Skip to content

Nextcloud and Collabora behind HAProxy

srottschaefer edited this page Jan 8, 2019 · 1 revision

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.

Prerequisites

  • 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

Change Nextcloud's ports

# snap set nextcloud ports.http=81 ports.https=444

Configure HAProxy

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

Collabora/Code container

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.

Certbot configuration

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 and configure the Collabora plugin

Notes

  • 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”.
    
Clone this wiki locally