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. If not look at my approach here. I assume you have Docker and Docker Compose already installed. THis tutorial will mainly focus on the connection between NGINX and NextCloudPi and the integration with Docker Compose. Let’s start.

I choosed to run NextCloudPi rather than NextCloud because everything is preconfigured. Perhaps you can achieve 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 most importantly 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 if we use NGINX that handles TLS as reverse proxy. This way I can run multiple web 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 # to get nginx_more_headers 
RUN apt-get update && apt-get install -y nginx-extras 
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.tld;
      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:
      # for error.log (choose any volume path you want)
      - .my_docker_compose_volume/nginx:/var/log/nginx
      # nginx.conf expects ssl files here
      - /etc/letsencrypt/live/:/etc/letsencrypt/live
      - /etc/letsencrypt/archive:/etc/letsencrypt/archive
      # DH params (needs to be generated first, see e.g.: `sudo openssl dhparam -out /etc/ssl/dhparam.pem 4096`
      - /etc/ssl/:/etc/ssl
    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

UPDATE I added a little guide how to glue together Lets Encrypt certificates and NGINX inside a Docker container.

Philipp Schuster

Ich bin Philipp, studiere Informatik an der TU Dresden und neben meinem Studio arbeite ich beruflich als Werkstudent und Privat an zahlreichen Projekten. Dabei nutze ich unter anderem Rust, Java, Angular, Typescript, C/C++, uvm.

Das könnte dich auch interessieren …

8 Antworten

  1. Sascha sagt:

    Sehr interessant. Danach suche ich seit Monaten, weil ich gerne neben NCP noch eine Hompage hosten wollen würde und am besten sogar PiHole, wobei das wegen lighttpd wohl nicht gehen wird. Aber sehr interessant. Bin ebenfalls 22 und IT-Werkstudent, deshalb umso cooler 🙂
    Ich hoffe ich bekomme das auch so hin wie du. Aber auf jeden Fall schonmal danke!

  2. David sagt:

    Hi, ich bekomme beim nginx immer folgende Meldung: „unknown directive „more_clear_headers“ in /etc/nginx/nginx.conf:32″

    Hast du eine Idee, was das Problem sein könnte?

    Danke dir im Voraus

    • Philipp Schuster sagt:

      Hi David 🙂
      Beim Bauen des nginx Containers die Zeile `RUN apt-get update && apt-get install -y nginx-extras` beachten.

      Dann wird das auch gefunden

  3. Jonathan Aud sagt:

    Hello Philip,
    The German is translated with Google translate.

    I am following the steps in the article, but am getting hung up on the docker build command.
    This is a fresh install of ubuntu 20.04 on ext4

    here is the Dockerbuild file
    FROM nginx:1.17.5
    # to get nginx_more_headers
    RUN apt-get update && apt-get install -y nginx-extras
    RUN rm /etc/nginx/conf.d/default.conf
    COPY /var/log/nginx.conf /etc/nginx
    VOLUME /var/log/nginx

    while running the build, I get the error
    debconf: delaying package configuration, since apt-utils is not installed

    I have installed apt-utils manually

    However, I get the error
    Step 4/5 : COPY /var/log/nginx.conf /etc/nginx
    COPY failed: file not found in build context or excluded by .dockerignore: stat var/log/nginx.conf: file does not exist

    I have tried with –no-cache, same result.

    I am trying to run nextcloudpi along with several other apps, with ssl.

    Your site is the only one I have found that has a way to do this.
    Would you be able to help with this error?
    Thanks

    Translation types
    Text translation
    Source text
    Sehr interessant. Danach suche ich seit Monaten, weil ich gerne neben NCP noch eine Hompage hosten wollen würde und am besten sogar PiHole, wobei das wegen lighttpd wohl nicht gehen wird. Aber sehr interessant. Bin ebenfalls 22 und IT-Werkstudent, deshalb umso cooler 🙂
    Ich hoffe ich bekomme das auch so hin wie du. Aber auf jeden Fall schonmal danke!
    Antworten

    Philipp Schuster
    29. Januar 2020 um 07:41 Uhr

    Sehr cool 🙂 Gerne
    Antworten
    Sascha
    4. Februar 2020 um 03:42 Uhr

    Der Schritt wie man die Zertifikate für NCP einrichtet wäre vermutlich in anderem anderen Beitrag noch hilfreich. Stecke da bspw. gar nicht drin und weiß, auch mit den Commands die du andeutetest, nicht weiter.
    Antworten
    Philipp Schuster
    8. Februar 2020 um 20:58 Uhr

    Hilft dir das hier weiter? 🙂
    https://phip1611.de/2020/02/programmierung-und-skripte/running-nginx-with-lets-encrypt-certificates-outside-of-the-container/
    Antworten

    David
    11. Juli 2020 um 15:49 Uhr

    Hi, ich bekomme beim nginx immer folgende Meldung: „unknown directive „more_clear_headers“ in /etc/nginx/nginx.conf:32″

    Hast du eine Idee, was das Problem sein könnte?

    Danke dir im Voraus
    Antworten

    Philipp Schuster
    12. Juli 2020 um 00:01 Uhr

    Hi David 🙂
    Beim Bauen des nginx Containers die Zeile `RUN apt-get update && apt-get install -y nginx-extras` beachten.

    Dann wird das auch gefunden
    Antworten
    1015 / 5000
    Translation results
    Hallo Philipp,
    Das Deutsche wird mit Google Translate übersetzt.

    Ich befolge die Schritte in dem Artikel, hänge aber beim Docker-Build-Befehl auf.
    Dies ist eine Neuinstallation von Ubuntu 20.04 auf ext4

    hier ist die Dockerbuild-Datei
    VON nginx: 1.17.5
    # um nginx_more_headers zu erhalten
    apt-get update ausführen && apt-get install -y nginx-extras
    RUN rm /etc/nginx/conf.d/default.conf
    /var/log/nginx.conf /etc/nginx . KOPIEREN
    LAUTSTÄRKE /var/log/nginx

    Beim Ausführen des Builds erhalte ich den Fehler
    debconf: Verzögerung der Paketkonfiguration, da apt-utils nicht installiert ist

    Ich habe apt-utils manuell installiert

    Allerdings bekomme ich den Fehler
    Schritt 4/5: /var/log/nginx.conf /etc/nginx . KOPIEREN
    KOPIEREN fehlgeschlagen: Datei im Build-Kontext nicht gefunden oder von .dockerignore ausgeschlossen: stat var/log/nginx.conf: Datei existiert nicht

    Ich habe es mit –no-cache versucht, gleiches Ergebnis.

    Ich versuche, nextcloudpi zusammen mit mehreren anderen Apps mit SSL auszuführen.

    Ihre Website ist die einzige, die ich gefunden habe, die eine Möglichkeit bietet, dies zu tun.
    Könnten Sie bei diesem Fehler helfen?
    Vielen Dank
    More about this source text
    Source text required for additional translation information
    Send feedback
    Side panels

  4. Jonathan Aud sagt:

    Hallo Philipp,
    Das Deutsche wird mit Google Translate übersetzt.

    Ich befolge die Schritte in dem Artikel, hänge aber beim Docker-Build-Befehl auf.
    Dies ist eine Neuinstallation von Ubuntu 20.04 auf ext4

    hier ist die Dockerbuild-Datei
    VON nginx: 1.17.5
    # um nginx_more_headers zu erhalten
    apt-get update ausführen && apt-get install -y nginx-extras
    RUN rm /etc/nginx/conf.d/default.conf
    /var/log/nginx.conf /etc/nginx . KOPIEREN
    LAUTSTÄRKE /var/log/nginx

    Beim Ausführen des Builds erhalte ich den Fehler
    debconf: Verzögerung der Paketkonfiguration, da apt-utils nicht installiert ist

    Ich habe apt-utils manuell installiert

    Allerdings bekomme ich den Fehler
    Schritt 4/5: /var/log/nginx.conf /etc/nginx . KOPIEREN
    KOPIEREN fehlgeschlagen: Datei im Build-Kontext nicht gefunden oder von .dockerignore ausgeschlossen: stat var/log/nginx.conf: Datei existiert nicht

    Ich habe es mit –no-cache versucht, gleiches Ergebnis.

    Ich versuche, nextcloudpi zusammen mit mehreren anderen Apps mit SSL auszuführen.

    Ihre Website ist die einzige, die ich gefunden habe, die eine Möglichkeit bietet, dies zu tun.
    Könnten Sie bei diesem Fehler helfen?
    Vielen Dank

Schreibe einen Kommentar

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