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 .
⚠️ Before build: make sure that the file nginx.conf
(the content is listed below) must be at the correct path. In this case in "./nginx.conf"
, i.e. the directory where the Dockerfile
is located. ⚠️
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.
10 Comments
Sascha · 2020-01-28 at 22:50
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!
Philipp Schuster · 2020-01-29 at 07:41
Sehr cool 🙂 Gerne
Sascha · 2020-02-04 at 03:42
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.
Philipp Schuster · 2020-02-08 at 20:58
Hilft dir das hier weiter? 🙂
https://phip1611.de/2020/02/programmierung-und-skripte/running-nginx-with-lets-encrypt-certificates-outside-of-the-container/
David · 2020-07-11 at 15:49
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 · 2020-07-12 at 00:01
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
Jonathan Aud · 2021-06-15 at 18:26
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
Philipp Schuster · 2021-06-26 at 16:18
Hi Jonathan,
I’m confused by “Das Deutsche wird mit Google Translate übersetzt.” – do you want me to answer in english or german? 😀 I’ll just use English.
The error message is relatively clear, “nginx.conf” is not found. Inside the directory where you execute “docker build”, you need `Dockerfile` as well as `nginx.conf`. The content of this `nginx.conf` is listed above in my blogpost. There is no much magic behind this.
PS: I edited the blogpost a bit to make this more clear to future readers.
Silas · 2023-09-14 at 19:29
Hi,
ich habe den Proxy mit dem Home Assistant Addon Nginx Proxy Manager aufgesetzt. Im NCP habe ich https-only deaktiviert und leite im Nginx Proxy Manager auf den Port 80 weiter. Das funktioniert für mehrere Minuten tadellos, dann kommt auf einmal “502 Bad Gateway” von einem nginx server. Allerdings benutzt NCP soweit ich weiß gar kein nginx, die Meldung kommt wohl vom Home Assistant Addon.
Der Log sieht ungefähr so aus:
[14/Sep/2023:19:24:06 +0200] – 502 502 – GET https cloud.xxx.de “/push/ws” [Client xxx.xxx.xxx.xxx] [Length 150] [Gzip -] [Sent-to 192.168.178.10] “-” “-”
2023/09/14 19:24:06 [warn] 4677#4677: *3777 using uninitialized “server” variable while logging request, client: xxx.xxx.xxx.xxx, server: cloud.xxx.de, request: “����T��R”
[14/Sep/2023:19:24:06 +0200] – – 400 – – https cloud.xxx.de “-” [Client xxx.xxx.xxx.xxx] [Length 150] [Gzip -] [Sent-to ] “-” “-”
Warum geht die Verbindung erst einige Minuten und reißt dann plötzlich ab?
Philipp Schuster · 2023-09-20 at 16:16
Hey! Kann ich dir so leider auch nicht sagen. Da müsste man mal mehr in die Container zur Laufzeit reindebuggen. Bin aber selbst seit Jahren leider gar nicht mehr im Docker-Umfeld aktiv. Ich hoffe, du kannst das Problem bald noch lösen! Viel Erfolg