Running NextCloudPi with Docker Compose behind NGINX Reverse Proxy with TLS

I have successfully managed to run NextCloudPi on my Raspberry Pi 4 (4GB) with Docker Compose behind a NGINX as reverse proxy. It was quite some work to figure out how to configure everything. I want to share what I have learned in case you want to do something similar. Hopefully I can help you. This tutorial will assume that you know how to setup NGINX as reverse proxy with TLS on your Pi. It will mainly focus on the connection between NGINX and NextCloudPi and the integration with Docker Compose. It assumes you have Docker and Docker Compose already installed. How to let a domain point to your device wont be covered here as well. Let’s start 🙂

I choosed to run NextCloudPi rather than NextCloud because everything is preconfigured. Perhaps you can archive something similar by running several Docker containers for NextCloud and a database as well. NextCloudPi has the big advantage that it’s one single image and there are pre compiled images for ARM available on Docker Hub – that’s what we need for the Pi.

The challenge was that NextCLoudPi expects to be the primary web server on a machine, thus owning ports 80 and 443 as well as doing the TLS-handshake. This wont work for me because my primary web server is a NGINX reverse proxy that handles TLS. This way I can run multiple services on my Pi whereas NextCloudPi is just one of them. I want NGINX to forward requests specified by the subdomain to the corresponding service.

TL;DR

A request to https://nextcloud.domain.tld will be internally forwarded to https://nextcloudpi using NGINX and Docker Compose. All services on the Pi (NGINX, NextCloudPi, …) will be part of one big docker-compose.yml.

NGINX reverse proxy

My NGINX comes from a Dockerfile that copies my nginx.conf into the NGINX image. It’s a pretty simple Dockerfile. The interesting part is the nginx.conf. Also I have a docker-compose.yml to start everything up. The docker-compose.yml and the nginx.conf are highly connected to each other, i.e. nginx.conf expects Docker Compose to do DNS internally for "https://nextcloudpi" and so on.

Dockerfile

FROM nginx:1.17.5
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx
VOLUME /var/log/nginx

Build with: $ docker build -t yourname/raspberry-pi-master-nginx .

nginx.conf

The important lines are proxy_pass https://nextcloudpi; for the regular web UI and proxy_pass https://nextcloudpi:4443; for the web configuration UI.

http {
  # if you have many server{}-declarations, 32 is not enough ---> 64
  server_names_hash_bucket_size 64;

  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;

  # Common TLS Config
  # ..
  # not covered in this tutorial
  
  # redirects all http requests to https requests
  server {
    listen 80 default_server;
    listen [::]:80 default_server;
    return 301 https://$host$request_uri;
  }

  server {
    # replace with your domain
    server_name nextcloud.domain.tld;

    listen 443 ssl http2;
    listen [::]:433 ssl http2;

    # maximum 3GB Upload File; change to fit your needs
    client_max_body_size 3G;

    location / {
      # remove upgrade h2 header (breaks some http clients, like curl or safari)
      # from NextCloudPi's Apache; we do HTTP/2 between Client and NGINX
      more_clear_headers 'upgrade';
      # we set this already in our reverse proxy
      more_clear_headers 'Strict-Transport-Security';

      # nextcloudpi only works with https but it's ssl has no valid 
      # certificate  configured
      proxy_ssl_verify off;
      // docker-compose does DNS for "nextcloudpi" 
      proxy_pass https://nextcloudpi;
      # set proper x-forwarded-headers
      proxy_set_header 'X-Forwarded-Host' nextcloud.domain.told;
      proxy_set_header 'X-Forwarded-Proto' https;
      # -For and -IP:
      # see https://stackoverflow.com/questions/19366090/what-is-the-difference-between-x-forwarded-for-and-x-forwarded-ip
      proxy_set_header 'X-Forwarded-For' $remote_addr;
      proxy_set_header 'X-Forwarded-IP' $remote_addr;
    }
  }

  server {
    # replace with your domain
    server_name nextcloud.domain.tld;

    # 4443 ist der port von nextcloudpi für das konfig web ui
    listen 4443 ssl http2;
    listen [::]:4433 ssl http2;


    location / {
      more_clear_headers 'upgrade';
      more_clear_headers 'Strict-Transport-Security';

      # nextcloudpi only works with https but it's ssl has no valid 
      # certificate configured
      proxy_ssl_verify off;
      proxy_pass https://nextcloudpi:4443;
      # forward basic auth 
      proxy_pass_header Authorization;
      # not necessary; but perhaps the next instance will use this somehow
      # and don't do double TLS
      proxy_set_header 'X-Forwarded-Proto' https;
      proxy_set_header 'X-Forwarded-For' $remote_addr;
      proxy_set_header 'X-Forwarded-IP' $remote_addr;
    }
  }
}

Docker Compose

Now the real magic happens. Ports 80 and 443 on the host system are bound to NGINX but NextCloudPi also wants Port 80 and Port 443. Docker Compose helps us and creates a Docker Compose network. Inside this network Docker Compose will provide DNS by container names. NGINX can therefore forward requests to „https://nextcloudpi“ (which equals https://nextcloudpi:443). Thats it basically.

networks:
  nextcloudpi:

services:
  # main nginx : reverse proxy for ssl
  nginx:
    restart: always
    container_name: raspberry-pi-master-nginx
    image: yourname/raspberry-pi-master-nginx:latest
    ports:
      - 80:80
      - 443:443
      - 4443:4443 # configuration port for nextcloudpi
    volumes:
      # -  volumes for let's encrypt certificates; (stripped here)
    depends_on:
      - nextcloudpi
    networks:
      - nextcloudpi

  ##################

  # nextcloud pi
  nextcloudpi:
    restart: always
    container_name: nextcloudpi
    image: ownyourbits/nextcloudpi-armhf
    expose:
      - 80
      - 443
      - 4443 # nextcloudpi web config ui port
    volumes:
    - .docker_compose_volume/next_cloud_pi:/data
    - /etc/localtime:/etc/localtime:ro
    networks:
      - nextcloudpi

First run

Open in your browser https://nextcloud.mydomain.tld/activate and you should see NextCloud. After you set everything up you should also be able to call https://nextcloud.mydomain.tld:4443 for the NextCloudPi configuration web UI.

After first run

Unfortunately I didn’t found a way to configure the trusted host of NextCloud via Docker Compose. Shut down your container and open „nextcloud/config/config.php“ in the Docker volume of NextCloudPi.

  • set ‚overwriteprotocol‘ to https
  • set ‚overwritehost‘ to your domain (e.g. nextcloud.domain.tld)
  • add your domain to the trusted hosts array

That’s it. Everything should work! This last step are necessary because otherwise NextCloud thinks it runs on „https://nextcloudpi“ under several circumstances. I hope it works for you as well. If you have questions feel free to ask!

PS

I stripped lot’s of information how my NGINX gets access to the let’s encrypt certificates. I thought it be better to strip this information here. If you have questions feel free to ask! The basically workflow is the following:

  • shut down NGINX
  • use certbot --standalone ... to get the certificate for all domains
  • using Docker Compose volumes to link /etc/letsencrypt/... into the NGINX container
  • start NGINX

Philipp Schuster

Ich bin Philipp, studiere Informatik an der TU Dresden und arbeite als Werkstudent im Bereich Software-Entwicklung bei T-Systems MMS. Ich bin 22 Jahre alt und beschäftige mich in meiner Freizeit gerne mit meinem Blog, Programierung, Technik, aber auch mit Joggen und vielen anderen Dingen. Get To Know Me oder schreibt mich an!

Das könnte Dich auch interessieren …

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.