Caddy reverse proxy + Nextcloud + Collabora + Bitwarden_rs with local HTTPS

1. TL;DL

This Wiki contains the info to setup a frontend Caddy reverse proxy service with a Let’s Encrypt authorized TLS certificate and a backend host running a Caddy reverse proxy / webserver which serves Nextcloud with Collabora integrated and Bitwarden_rs. The frontend Caddy will also issue TLS certificates for the backend LAN connections and renew them periodically. With this setup the connection will be encrypted from A to Z. For quick references, just scroll down to the second post which contains final and complete configuration files.

2. Introduction

In the Wiki Use Caddy for local HTTPS (TLS) between front-end reverse proxy and LAN hosts I described how to add TLS between the downstream reverse proxy and the upstream hosts (services). This Wiki is a continuation, which results in a setup with Nextcloud and Collabora integrated and Bitwarden_rs running behind a Caddy reverse proxy with a Let’s Encrypt certificate. The connections upstream, are also encrypted with the help of the ACME server built into Caddy. This is specifically interesting for Bitwarden_rs because without, your passwords will cross your LAN unencrypted. There is no need for any other software as Caddy has everything build in to connect the pieces (services) together.

This Wiki assumes you have managed to setup a Caddy reverse proxy as explained in the Wiki Using Caddy as a reverse proxy in a home network by @matt. First reading the Wiki Use Caddy for local HTTPS (TLS) between front-end reverse proxy and LAN hosts is helpful but probably not necessary.

3. Definitions and Requirements

The definitions and requirements from the Wiki’s mentioned above apply to this Wiki too. Please note that the setup described in this setup requires a local DNS or split DNS (as described in the above Wiki).

This Wiki also assumes you have docker and docker-compose working and you know how to use this. I consider it out of scope for this Wiki to go over every docker(-compose) detail but I tried to include enough info for the less experienced readers.

4. Topology

The below figure shows a frontend (downstream) host and a backend (upstream) host. Each host can be virtual or physical. The frontend host is setup with Caddy as reverse proxy to the outside world and provides trusted certificates from Let’s Encrypt. The backend host act as a Caddy reverse proxy and webserver. Nextcloud, Collabora and Bitwarden_rs are installed as Docker containers on this host. Bitwarden_rs is a fork from Bitwarden which is less heavy but compatible with all the official clients.

On the top of each host you see the IP and port number and FQDN that this host is listening to.
In the backend host, you see docker containers with inside the service and the port its running on. Under each docker container you see the port that is being exposed to the backend host.

Note that Caddy has not been installed as a Docker container for a reason. It complicates the local certification renewal.

5. DNS

To set up the DNS you can follow the same guidance as in Using Caddy as a reverse proxy in a home network. The result should be that you have a domain name setup for each service pointing to the public IP address leased to your network ie;

nextcloud.mydomain.com
bitwarden.mycomain.com

6. Local (Split) DNS

Each host or service should be given a FQDN to resolve the IP of the corresponding host in the local network. This is required to make the local certificate mechanism to work. For this wiki I created:

caddy.roadrunner192.168.0.2 to reach the frontend Caddy service
nextcloud.roadrunner192.168.0.4 to reach Nextcloud service
bitwarden.roadrunner192.168.0 .4 to reach Bitwarden service

Collabora will be lifting on nextcloud.roadrunner and therefore it does not require its own FQDN like collabora.roadrunner.

It is also a good idea to setup split DNS for the public domains. That way you can access the services from you LAN without going outside the LAN. Ie

nextcloud.mydomain.com192.168.0.2 to redirect to the Caddy frontend
bitwarden.mydomain.com192.168.0.2 to redirect to the Caddy frontend

7. Port forwarding

To set up the port forwarding you can follow the same guidance as in Using Caddy as a reverse proxy in a home network.

8. Frontend (downstream)

This is where the connections from the internet come into your LAN. Caddy will issue a certificate to make the connection secure with Let’s Encrypt as Certificate Authority. Depending which service the user is trying to connect to ie Nextcloud, Caddy will forward the incoming connection to the backend where the actual service is running. To make this work, the Caddyfile needs to be configured.

8.1. Caddyfile

First, to enable the ACME server in the frontend, include the acme_server directive in the Global section of the Caddyfile. Optional (recommended) you can also add debug which will help with debugging if things don’t work.

# Global Option Block
debug
# ACME Server
caddy.roadrunner {
        acme_server
        tls internal
}

Next is to configure to forward incoming connection for Nextcloud upstream:

## Nextcloud
nextcloud.mydomain.com {
        reverse_proxy https://nextcloud.roadrunner {
                header_up Host {http.reverse_proxy.upstream.hostport}
                header_up X-Forwarded-Host {host}
        }
}

The line header_up Host {http.reverse_proxy.upstream.hostport} is a host header with placeholder that will override the host header with the host name in the proxy upstream.

The line header_up X-Forwarded-Host {host} is to return the host name nextcloud.mydomain.com from the reverse proxy.

If you want more background info about this, read my previous Wiki or search my posts where @francislavoie helped me with this.

To forward incoming connections for Bitwarden upstream, include:

## Bitwarden
Bitwarden.mydomain.com {
        reverse_proxy https://bitwarden.roadrunner {
                header_up Host {http.reverse_proxy.upstream.hostporti}
                header_up X-Forwarded-Host {host}
        }
        respond /admin* "The admin panel is disabled, please configure the 'ADMIN_TOKEN' variable to enable it"
}

Bitwarden_rs comes with an optional admin web console. For security reasons I do not like to expose this to the world.

respond /admin* provides users that try to access the Bitwarden admin web console the same printed message as when the admin console is disabled. Hopefully this will make them give up. You can also present a 404 error. In the LAN the admin console can still be made available.

Additional settings for Collabora are not necessary because Collabora will be integrated with Nextcloud.

Start Caddy by running Caddy start and check the output for possible errors.

9. Backend (upstream)

This is the host where the services are running in docker containers. Caddy is installed directly (no docker to avoid certificate renewal issues) to forward the connections from the frontend to the docker containers and serve as a fileserver for Nextcloud.

9.1. Docker configuration

Although this Wiki is about Caddy, I’m including the docker-compose files that I composed too. I spend a lot of time to get a working setup and hope to provide users some guidance to a quick working setup. I’m quite sure the docker-compose files can be optimised and I am open for input for any comment or improvements.

There is one docker-compose file for Nextcloud and Collabora combined that also makes use of an .env file. The second docker-compose file is for Bitwarden_rs only.

9.2. Nextcloud and Collabora docker-compose

Below the docker-compose file to setup the docker containers for Nextcloud and Collabora.
Further down you also find an example of the required .env file. Adjust both files and save them in the same folder, ie ~/nextcloud/docker-compose.yml and ~/nextcloud/.env

version: '3.7'

networks:
 nextcloud:

services:
  nextcloud:
#    image: nextcloud:fpm
    build: ./nc_smb_image
    container_name: nextcloud
    restart: unless-stopped
    networks:
      - nextcloud
    ports:
      - "9000:9000"
    volumes:
      - ${NEXTCLOUD_ROOT}/html:/var/www/html
      - ${NEXTCLOUD_ROOT}/data:/srv/nextcloud/data
    depends_on:
      - mariadb
    environment:
      - 'NEXTCLOUD_TRUSTED_DOMAINS=${NEXTCLOUD_FQDN}'
#      - 'NEXTCLOUD_DATA_DIR=/srv/nextcloud/data'
      - 'MYSQL_DATABASE=nextcloud'
      - 'MYSQL_USER=nextcloud'
      - 'MYSQL_PASSWORD=${MYSQL_PASSWORD}'
      - 'MYSQL_HOST=nextcloud-mariadb'

  mariadb:
    image: mariadb
    container_name: nextcloud-mariadb
    restart: unless-stopped
    networks:
      - nextcloud
    volumes:
      - ${NEXTCLOUD_ROOT}/mariadb:/var/lib/mysql
    environment:
      - 'MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}'
      - 'MYSQL_PASSWORD=${MYSQL_PASSWORD}'
      - 'MYSQL_DATABASE=nextcloud'
      - 'MYSQL_USER=nextcloud'

  collabora:
    image: collabora/code
    container_name: nextcloud-collabora
    restart: unless-stopped
    networks:
      - nextcloud
    ports:
      - "9980:9980"
    volumes:
      - /etc/localtime:/etc/localtime
      - /etc/timezone:/etc/timezone
    environment:
      - username=admin
      - password=${COLLABORA_PASSWORD}
      - domain=${NEXTCLOUD_FQDN}
      - dictionaries=en nl du fr
      - extra_params=--o:ssl.enable=true --o:ssl.termination=false # Set SSL options
    cap_add:
      - MKNOD
    tty: true

9.2.1. Nextcloud references and notes:

https://hub.docker.com/_/nextcloud/

Either use the Nextcloud fpm image or when the smbclient is desired, build the fpm image with smb included. In that case, add a folder nc_smb_image with a dockerfile that contains:

FROM nextcloud:fpm

RUN apt-get update && apt-get install -y procps smbclient && rm -rf /var/lib/apt/lists/*

Since I use samba network drives, I did not configure the Nextcloud data dir. If you do want to use local storage, uncomment NEXTCLOUD_DATA_DIR=/srv/nextcloud/data and don’t forget to change the path.

9.2.2. Collabora references and notes:

Add your desired dictionaries
SSL has been enables without termination. Although this should not be necessary, it was the only way to get it working. Disabling SSL will break the setup.

9.2.3. .env file

The above docker-compose file us making use of the below .env file. Tweak it and save it in the same folder as the docker-compose.yml

NEXTCLOUD_ROOT=/var/www
NEXTCLOUD_IPADDRESS=nextcloud ip address
NEXTCLOUD_FQDN=nextcloud.mydomain.com
COLLABORA_FQDN=nextcloud.mydomain.com
MYSQL_ROOT_PASSWORD=your very difficult password
MYSQL_PASSWORD=your also very difficult password
COLLABORA_PASSWORD=your yet another difficult password

In this Wiki NEXTCLOUD_FQDN and COLLABORA_FQDN are both set the same because I integrated Collabora with Nextcloud.

9.2.4. Run Nextcloud and Collabora docker containers

Now that both the docker-compose.yml and .env files are completed, run docker-compose up in the folder where you saved the files or docker-compose up -d to run in the background.

Once the downloading and compiling is done, run docker ps to confirm you have 3 docker containers running ie:

CONTAINER ID   IMAGE                       COMMAND                  CREATED       STATUS                 PORTS                                          NAMES
5091616dd9cd   collabora/code              "/bin/sh -c 'bash st…"   5 weeks ago   Up 5 weeks             0.0.0.0:9980->9980/tcp                         nextcloud-collabora
a2ff358b07f2   nextcloud_nextcloud         "/entrypoint.sh php-…"   5 weeks ago   Up 36 minutes          0.0.0.0:9000->9000/tcp                         nextcloud
e0e55215f4c6   mariadb                     "docker-entrypoint.s…"   5 weeks ago   Up 5 weeks             3306/tcp                                       nextcloud-mariadb

9.2.5. Configure Nexcloud config.php

Once you confirmed the docker containers are running, locate the file /var/www/html/config/config.php and update the trusted domains, trusted proxies and the overwrite.cli.url, ie:

  'trusted_domains' =>
  array (
    0 => 'nextcloud.mydomain',
  ),
  'trusted_proxies' =>
  array (
    0 => '<nextcloud IP address>',
…
…
'overwrite.cli.url' => 'https://nextcloud.mydomain.com:443',

Restart Nextcloud with docker restart nextcloud to apply the changes.

9.3. Bitwarden_rs

I highlight again that in this Wiki I have used Bitwarden_rs which is a lighter version of the official Bitwarden project. Copy and adjust the below docker-compose file and save it in e.g. ~/bitwarden_rs/docker-compose.yml

version: "3"
services:
  bitwardenrs:
    restart: unless-stopped
    image: "bitwardenrs/server:latest" # Dani Garcia image https://github.com/dani-garcia/bitwarden_rs
    container_name: bitwardenrs
    environment:
      - TZ=Europe/Amsterdam                # Timezone settings, important for Fail2ban to work
      - LOG_FILE=/data/bitwarden.log       # Logging connection attemps
      - EXTENDED_LOGGING='true'
      - LOG_LEVEL=warn
      - ROCKET_WORKERS=20
      - WEBSOCKET_ENABLED='true'
      - SIGNUPS_ALLOWED='false'            # Hardening a bit
      - DISABLE_ADMIN_TOKEN='false'
      - ADMIN_TOKEN=’your random string’
      - SHOW_PASSWORD_HINT='false'
      - DISABLE_ICON_DOWNLOAD='true'
    networks:
      - bitwarden_net
    ports:
      - 8080:80
      - 3012:3012
    volumes:
      - /opt/bitwarden_rs/bw-data:/data

networks:
  bitwarden_net:

9.3.1. Bitwarden_rs references and notes:

In this example config for security reasons the signups are disabled. New users can only signup after an invitation.
The admin console is enabled and can be reached within the LAN only via bitwarden.roadrunner/admin. Access through bitwarden.mydomain.com has been blocked in the frontend Caddyfile.

Please visit the github repository for additional info about the setup.

Run docker-compose up or docker-compose up -d to start the Bitwarden_rs container. Now you should have 4 docker containers running.

9.4. Caddyfile

Now that all the docker containers are up and running, continue to setup Caddy on the backend to request local certificates from the frontend Caddy. The easiest way is to do this in the global section so that it applies for the whole Caddyfile:

# Global Option Block
debug
# TLS Options
acme_ca https://caddy.roadrunner/acme/local/directory
acme_ca_root /etc/ssl/certs/root.crt

To request a certificate, a root certificate from the server is required. Once you have started the Caddy service on the frontend for the first time and there are no errors, a file named root.crt is generated in .local/share/caddy/pki/authorities/local

NOTE: The absolute path for the certificate depends on how you run Caddy. Typically when you use systemd the absolute path will be /var/lib/caddy/.local/share/caddy/pki/authorities/local but if you run caddy with caddy start the path .local/share/caddy/pki/authorities/local

You will have to copy this file to the backend and point to it in the Caddyfile. In the above example, the file root.crt has been copied to /etc/ssl/certs/root.crt

Once this is done, you can start adding the local domains that host the services:

# Nextcloud and Collabora
nextcloud.roadrunner {
   encode gzip

        @collabora {
                path /loleaflet/* # Loleaflet is the client part of LibreOffice Online
                path /hosting/discovery # WOPI discovery URL
                path /hosting/capabilities # Show capabilities as json
                path /lool/* # Main websocket, uploads/downloads, presentations
        }

        reverse_proxy @collabora https://127.0.0.1:9980 {
               header_up Host "nextcloud.mydomain.com"
                transport http {
                        tls_insecure_skip_verify
                }
        }

        root * /var/www/html
        file_server

        php_fastcgi 127.0.0.1:9000 {
                env front_controller_active true # Remove index.php form url
        }

        header {
                Strict-Transport-Security max-age=31536000; # enable HSTS
        }

        # .htaccess / data / config / ... shouldn't be accessible from outside
        @forbidden {
                path /.htaccess
                path /data/*
                path /config/*
                path /db_structure
                path /.xml
                path /README
                path /3rdparty/*
                path /lib/*
                path /templates/*
                path /occ
                path /console.php
        }

        respond @forbidden 404
}

9.4.1. Nextcloud and Collabora notes and references:

I also used @Basil post here which was very helpful getting Collabora to work.

The Collabora docker container has its own web server and therefore we can only forward the connection instead of using Caddy to act as a web server. While discussing the docker-compose file I mentioned that the SSL options for Collabora had to be enabled. Because an untrusted certificate is used, we need add tls_insecure_skip_verify to have Caddy accept the connection.

Similar to the frontend Caddyfile, the line header_up Host {http.reverse_proxy.upstream.hostport} will override the host header with the host name in the proxy upstream.

# Bitwarden
bitwarden.roadrunner {

        header {
                # Enable cross-site filter (XSS) and tell browser to block detected attacks
                X-XSS-Protection "1; mode=block"
                # Disallow the site to be rendered within a frame (clickjacking protection)
                X-Frame-Options "DENY"
                # Prevent search engines from indexing (optional)
                X-Robots-Tag "none"
                # Server name removing
                -Server
        }

        # The negotiation endpoint is also proxied to Rocket
        reverse_proxy /notifications/hub/negotiate http://127.0.0.1:8080 {
               header_up Host "bitwarden.mydomain.com"

}

        # Notifications redirected to the websockets server
        reverse_proxy /notifications/hub http://127.0.0.1:3012 {
               header_up Host " bitwarden.mydomain.com"
        }

        # Proxy the Root directory to Rocket
        reverse_proxy http://127.0.0.1:8080 {
               header_up Host " bitwarden.mydomain.com"
        }
}

9.4.2. Bitwarden notes and references:

The above setup is mostly copied from the Github wiki with the addition of the host header header_up Host.

10. Running and testing

At this point al(most) everything has been configured. It is time to test things.

  1. If not already, start Caddy on the frontend and backend with caddy run or caddy start (background).
  2. If not already, start all the docker containers by running docker-compose up -d in ~/nextcloud and ~/bitwarden_rs.

Verify that all 4 docker containers are running with the command docker ps if the answer is yes, lets try to connect to the services directly on the backend.

Lets test Nextcloud:
Browse to https://nextcloud.roadrunner and if all goes well you should see the following warning:

That is correct because you didn’t add the hostname nextcloud.roadrunner to the trusted list.

Now lets test Collabora:
First run curl -k https://localhost:9980 on the host where the Collabora docker container is running. It should return OK

Next browse to https://nextcloud.roadrunner/hosting/capabilities If you use Firefox, you should see something like the following:

Collabora_test1

Now browse to https://nextcloud.roadrunner/hosting/discovery and you will see a big list that starts like this:

<wopi-discovery>
<net-zone name="external-http">
<!-- Writer documents -->
<app favIconUrl="https://nextcloud.mydomain.com/loleaflet/44a46d7/images/x-office-document.svg" name="writer">
<action default="true" ext="sxw" name="view" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="odt" name="edit" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="fodt" name="edit" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<!-- Text template documents -->
<action default="true" ext="stw" name="view" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="ott" name="edit" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<!-- MS Word -->
<action default="true" ext="doc" name="edit" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="dot" name="edit" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<!-- OOXML wordprocessing -->
<action default="true" ext="docx" name="edit" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="docm" name="edit" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="dotx" name="view" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="dotm" name="view" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<!-- Others -->
<action default="true" ext="wpd" name="view" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="pdb" name="view" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="hwp" name="view" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="wps" name="view" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="wri" name="view" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="lrf" name="view" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="mw" name="view" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="rtf" name="edit" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="txt" name="edit" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="fb2" name="view" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="cwk" name="view" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="pages" name="view" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="abw" name="view" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
<action default="true" ext="602" name="view" urlsrc="https://nextcloud.mydomain.com/loleaflet/44a46d7/loleaflet.html?"/>
</app>

Very important to note is the urlsrc. This should be pointing to your public domain. If not, something is wrong with the Caddy setup.

Another test is to browse to https://nextcloud.roadrunner/loleaflet/dist/admin/admin.html and enter user:admin and the password that you provided in the .env file. If all goes well you will see the admin console:

Last to test is Bitwarden_rs.
Browse to https://bitwarden.roadrunner to find the login console.

If you managed to access all the services directly on the backend host, it is time to test if you can also access them throught the frontend. If you setup split DNS for your public domains, you can now browse to https://nextcloud.mydomain.com and you should get the setup page for Nextcloud. Here you can complete the Nextcloud installation.

When you go https://bitwarden.mydomain.com you get the login page for Bitwarden.

If you didn’t setup split DNS, the above may not work, depending on your network setup. In that case you have to try connecting from outside the LAN ie with a cellphone or with another internet connection. If you cannot connect from outside the LAN, probably something is wrong with your DNS.

Only one thing left to configure. When the Nextcloud installation has finalized, login as admin and go to Settings, Administration, Collabora Online Development E...

In the following screen you have to enter the URL of the Collabora Online-server. This is the same URL as your Nextcloud public domain. Ie nextcloud.mydomain.com.

After clicking save you should have the green check. Now when you open or create an office document in Nextcloud, Collabora will be started and you can start editing your document.

If Collabora is not starting, first make sure that the domain in the URL is not being changed in your session. If it does, something is wrong in your Caddyfiles.

That is it! Now you have a setup that provides an ecrypted connection to your own hosted Nextcloud + Collabora or Bitwarden_rs services from any device with internet.

12. Final word and disclaimer

Well, if you made it until here, I guess a few words more won’t hurt :blush:
It took me quite some time to gather all the info required to create this setup. I hope it will set you off quickly. I tried to link as much as possible to my info sources. I did however left too much time in between to write and finalize this Wiki and I may have left some (crucial) things out unintentionally. Sorry if that happened but please let me know and I will try to update this Wiki. I’m also sure the setup can be improved on some points and it would be great to receive inputs for this.

5 Likes

11. Configuration files (full)

Frontend Caddyfile

# Global Option Block
{
        # General Option
        debug
}

# ACME Server
acme.roadrunner {
        acme_server
        tls internal
}

### REVERSE PROXY

## Nextcloud
nextcloud.mydomain.com {
        reverse_proxy https://nextcloud.roadrunner {
                header_up Host {http.reverse_proxy.upstream.hostport}
                header_up X-Forwarded-Host {host}
        }
#        reverse_proxy /.well-known/carddav {$NEXTCLOUD_HOST:localhost}/remote.php/dav
#        reverse_proxy /.well-known/caldav {$NEXTCLOUD_HOST:localhost}/remote.php/dav
#        reverse_proxy * {$NEXTCLOUD_HOST:localhost}

}

## Bitwarden
bitwarden.mydomain.com {
        reverse_proxy https://bitwarden.roadrunner {
                header_up Host {http.reverse_proxy.upstream.hostporti}
                header_up X-Forwarded-Host {host}
        }
        respond /admin* "The admin panel is disabled, please configure the 'ADMIN_TOKEN' variable to enable it"
}

Backend Caddyfile

# Global Option Block
{
        # General Option
        debug

        # TLS Options
        acme_ca https://acme.roadrunner/acme/local/directory
        acme_ca_root /etc/ssl/certs/root.crt
}

# Nextcloud and Collabora
nextcloud.roadrunner {
        encode gzip
        @collabora {
                path /loleaflet/* # Loleaflet is the client part of LibreOffice Online
                path /hosting/discovery # WOPI discovery URL
                path /hosting/capabilities # Show capabilities as json
                path /lool/* # Main websocket, uploads/downloads, presentations
        }

        reverse_proxy @collabora https://127.0.0.1:9980 {
                header_up Host "nextcloud.mydomain.com"
                transport http {
                        tls_insecure_skip_verify
                }
        }

        root * /var/www/html
        file_server

        php_fastcgi 127.0.0.1:9000 {
                env front_controller_active true # Remove index.php form url
        }

        header {
                Strict-Transport-Security max-age=31536000; # enable HSTS
        }

        # .htaccess / data / config / ... shouldn't be accessible from outside
        @forbidden {
                path /.htaccess
                path /data/*
                path /config/*
                path /db_structure
                path /.xml
                path /README
                path /3rdparty/*
                path /lib/*
                path /templates/*
                path /occ
                path /console.php
        }

        respond @forbidden 404
}

# Bitwarden
bitwarden.roadrunner {
        encode gzip

        header {
                # Enable cross-site filter (XSS) and tell browser to block detected attacks
                X-XSS-Protection "1; mode=block"
                # Disallow the site to be rendered within a frame (clickjacking protection)
                X-Frame-Options "DENY"
                # Prevent search engines from indexing (optional)
                X-Robots-Tag "none"
                # Server name removing
                -Server
        }

        # The negotiation endpoint is also proxied to Rocket
        reverse_proxy /notifications/hub/negotiate http://127.0.0.1:8080 {
                header_up Host "bitwarden.mydomain.com"
        }

        # Notifications redirected to the websockets server
        reverse_proxy /notifications/hub http://127.0.0.1:3012 {
                header_up Host " bitwarden.mydomain.com"
        }

        # Proxy the Root directory to Rocket
        reverse_proxy http://127.0.0.1:8080 {
                header_up Host " bitwarden.mydomain.com"
        }
}

Backend docker-compose files

~/nextcloud/docker-compose.yml

version: '3.7'

networks:
 nextcloud:

services:
  nextcloud:
#    image: nextcloud:fpm
    build: ./nc_smb_image
    container_name: nextcloud
    restart: unless-stopped
    networks:
      - nextcloud
    ports:
      - "9000:9000"
    volumes:
      - ${NEXTCLOUD_ROOT}/html:/var/www/html
      - ${NEXTCLOUD_ROOT}/data:/srv/nextcloud/data
    depends_on:
      - mariadb
    environment:
      - NEXTCLOUD_TRUSTED_DOMAINS='${NEXTCLOUD_FQDN}'
#      - NEXTCLOUD_DATA_DIR=/srv/nextcloud/data
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
      - MYSQL_HOST=nextcloud-mariadb

  mariadb:
    image: mariadb
    container_name: nextcloud-mariadb
    restart: unless-stopped
    networks:
      - nextcloud
    volumes:
      - ${NEXTCLOUD_ROOT}/mariadb:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud

  collabora:
    image: collabora/code
    container_name: nextcloud-collabora
    restart: unless-stopped
    networks:
      - nextcloud
    ports:
      - "9980:9980"
    volumes:
      - /etc/localtime:/etc/localtime
      - /etc/timezone:/etc/timezone
    environment:
      - username=admin
      - password=${COLLABORA_PASSWORD}
      - domain=${NEXTCLOUD_FQDN}
      - dictionaries=en nl du fr
      - extra_params=--o:ssl.enable=true --o:ssl.termination=false # Set SSL options
    cap_add:
      - MKNOD
    tty: true

~/nextcloud/nc_smb_image/dockerfile

FROM nextcloud:fpm

RUN  apt-get update -y && apt-get install -y  smbclient

~/nextcloud/.env

NEXTCLOUD_ROOT=/var/www
NEXTCLOUD_IPADDRESS=nextcloud ip address
NEXTCLOUD_FQDN=nextcloud.mydomain.com
COLLABORA_FQDN=nextcloud.mydomain.com
MYSQL_ROOT_PASSWORD=your very difficult password
MYSQL_PASSWORD=your also very difficult password
COLLABORA_PASSWORD=your yet another difficult password

~/bitwarden_rs/docker-compose.yml

version: "3"
services:
  bitwardenrs:
    restart: unless-stopped
    image: "bitwardenrs/server:latest" # Dani Garcia image https://github.com/dani-garcia/bitwarden_rs
    container_name: bitwardenrs
    environment:
      - TZ=Europe/Amsterdam                # Timezone settings, important for Fail2ban to work
      - LOG_FILE=/data/bitwarden.log       # Logging connection attemps
      - EXTENDED_LOGGING='true'
      - LOG_LEVEL=warn
      - ROCKET_WORKERS=20
      - WEBSOCKET_ENABLED='true'
      - SIGNUPS_ALLOWED='false'            # Hardening a bit
      - DISABLE_ADMIN_TOKEN='false'
      - ADMIN_TOKEN=some very long and complicated super secret password string
      - SHOW_PASSWORD_HINT='false'
      - DISABLE_ICON_DOWNLOAD='true'
    networks:
      - bitwarden_net
    ports:
      - 8080:80
      - 3012:3012
    volumes:
      - /opt/bitwarden_rs/bw-data:/data

networks:
  bitwarden_net:
3 Likes

Thanks for this, I think it would be helpful in the Nextcloud section to add a configuration for a notify_push reverse proxy.

That’s indeed interesting. I wasn’t aware of this function. I’ll look into it and add it as soon as I can.