Hey there!
thanks for all the open source software you are providing here!
i have some questions about the docker compose examples you offer here.
on the ninx mariadb letsencrypt fpm example compose file, as long i understood it correct, there is nginx (offical) and jwilder/nginx installed with jwilder bound to the ports 80 and 443.
the offical nginx container is started with the nginx.config for the nextcloud server listening and they share the nextcloud html folder.
both nginx containers are on the same network (proxy-tier) but the folders are not the same and there are no bindings of the same directorys (certs, html etc)
so how is it working exactly?
my thoughts:
nexcloud is started with default port 9000 in default network, nginx offical is started with default settings on networks default and proxy-trier with a config file for nextcloud.
jwilder nginx is started with bounded ports and gonna create a server entry for the nginx offical which should expose ports 80/443 internaly taking the servername from virtual_host of the web build.
is this correct so far?
why is it done like this and would there be a way to use only jwilder nginx?
i am working on a docker setup where i can reach several services (pihole, nextcloud, portainer, openhab etc.) with my nginx reverse proxy.
to do so i would adjust the variables (folders etc.) in the provided compose file and just bind my other containers to the jwilder network (in this case proxy-trier) and it should work?
I hope this and the following postings are helpful for other users as well - took me some time to get into the docker stuff
The example you're talking about requires an additional (plain) nginx server, because the php-fpm container, can't serve basic files like images. It's just for php requests and uses port 9000 (this is NOT http!!!). That's why the fpm and nginx container share the nextcloud volume. It also acts as proxy for the php requests and listens on it's http port.
Up to here you have a basic, unencrypted installation (port 80 is exposed by default).
The nginx-proxy is acting as an additional layer on top of the nextcloud-fpm-setup. It listens to the docker daemon and automatically rewrites it's rules to proxy any request to other docker containers, that you have configured accordingly. That's what the environment variables VIRTUAL_HOSTand VIRTUAL_PORT are for. With this setup you get the ability to serve different website on the same port on your host (80 for http and 443 for https) with different domain names and / or subdomains.
Internally the communication between proxy and nextcloud container is unencrypted http (port 80).
With the letsencrypt companion container you also get automatic generation and renewal of letsencrypt certificates, and the proxy will be configured to redirect to https.
If you want to run multiple services on your host, you can just add them to the docker-compose file, or create different compose files, for each service.
For example my setup looks like this:
/docker/
-> proxy/docke-compose.yml
-> nextcloud/docker-compose.yml
-> portainer/docker-compose.yml
-> wordpress/docker-compose.yml
-> wordpress2/docker-compose.yml
-> ldap/docker-compose.yml
...
The proxy part just contains the nginx proxy and the letsencrypt companion, as well as a user defined network.
version: '2'
volumes:
conf.d:
vhost.d:
html:
certs:
services:
proxy:
image: jwilder/nginx-proxy:alpine
ports:
- 80:80
- 443:443
volumes:
- conf.d:/etc/nginx/conf.d
- vhost.d:/etc/nginx/vhost.d
- html:/usr/share/nginx/html
- certs:/etc/nginx/certs:ro
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./uploadsize.conf:/etc/nginx/conf.d/uploadsize.conf:ro
networks:
- proxy-tier
restart: always
labels:
- com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy
letsencrypt:
image: jrcs/letsencrypt-nginx-proxy-companion
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- certs:/etc/nginx/certs:rw
- conf.d:/etc/nginx/conf.d:ro
- html:/usr/share/nginx/html:rw
- vhost.d:/etc/nginx/vhost.d
restart: always
networks:
proxy-tier:
For nextcloud you would just have the database, php-fpm and nginx containers (I use the apache image, but with the php-fpm image it would look similar) and I define the proxy-tier network as external (the name of the network ist FOLDERNAME_NETWORK_NAME):
version: '2'
volumes:
nextcloud:
db:
services:
app:
image: nextcloud
links:
- db
volumes:
- nextcloud:/var/www/html
restart: always
environment:
- VIRTUAL_HOST=cloud.example.com
- LETSENCRYPT_HOST=cloud.example.com
- [email protected]
networks:
- default
- proxy
db:
image: mariadb
volumes:
- db:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=
- MYSQL_DATABASE=
- MYSQL_USER=
- MYSQL_PASSWORD=
restart: always
networks:
proxy:
external:
name: proxy_proxy-tier
And you would do the same for all other services, for example portainer:
version: '2'
networks:
proxy:
external:
name: proxy_proxy-tier
services:
portainer:
image: portainer/portainer
command: -H unix:///var/run/docker.sock
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
environment:
- VIRTUAL_HOST=docker.example.com
- VIRTUAL_PORT=9000
- LETSENCRYPT_HOST=docker.example.com
- [email protected]
networks:
- proxy
volumes:
portainer_data:
So I can reach my nextcloud with cloud.example.com and portainer with docker.example.com on the default https port 443.
I hope I could answer a few questions :grin:
thanks a lot for your fast answer!
as nginx can handle the php-requests it should be possible to make a setup with only one instance of nginx.
probably the way the automated jwilder nginx container is creating the server/proxy entries is the reason to have another nginx container in which the location/fastcgi is handled.
so what i mean is, if i wouldnt use the automated nginx container, writing my own server/proxy entries there would be no reason for using 2 nginx containers.
to the topic of the other services running on the jwilder nginx:
i was able to get every container runing as long as i used the standard ports.
i was not able to use a different "outside" port - then i get Error 503.
So for example Pihole ports 8050:80, virtual port 80, virtual_host my.server
For your first question: This should be possible. I just can't help you with that :grin:
I don't know pihole but you have to distinguish between ports (port bindings) and exposed ports. Exposed ports are defined in the dockerfile. Port bindings can only be defined in the docker run command or docker-compose file.
If you use a proxy, you should not add a port binding, because the ports are just used internally in the virtual docker network. You don't want to bind the container ports directly to your host.
For your example I guess you have to add pihole to the proxy network, use VIRTUAL_PORT=8085 and don't use the ports block.
Do you mind posting your compose-file for wordpress as well @SnowMB ? I have a similar compose setup with multiple apps, but I simply can't get the Wordpress-service to run. Using the official image. Error 502 when trying to access it through the configured subdomain. Anyways, informative discussion on this thread
Sure, here you go:
version: '2'
networks:
proxy-tier:
external:
name: proxy_proxy-tier
volumes:
db:
files:
services:
db:
image: mariadb
restart: always
environment:
- MYSQL_USER=wordpress
- MYSQL_ROOT_PASSWORD=password
- MYSQL_PASSWORD=password
- MYSQL_DATABASE=wordpress
volumes:
- db:/var/lib/mysql
web:
image: wordpress
restart: always
environment:
- WORDPRESS_DB_HOST=db
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_PASSWORD=password
- VIRTUAL_HOST=wordpress.example.com
- LETSENCRYPT_HOST=wordpress.example.com
- [email protected]
depends_on:
- db
volumes:
- files:/var/www/html
networks:
- default
- proxy-tier
Thanks @SnowMB! I had not included the networks entry for the wordpress container. Now it's up! But to be honest I don't understand the difference between networks: and VIRTUAL_NETWORK under environment:. Nor the difference between ports: and VIRTUAL_PORTS. Anyways, thanks for your help!
networks: and ports: are settings for docker to correctly configure and connect your containers. The environment variables (VIRTUAL_PORT and VIRTUAL_NETWORK) are completely irrelevant for docker. They are however important for the proxy container. The nginx proxy gets access to the docker socket running on your host. It now monitors all changes (containers getting started and stopped). When a new container is started it checks its Environment variables to automatically generate the routing configuration for that container.
I had a follow up question to this thread. As I understand, the nextcloud-fpm container will handle the php execution. We spin up another container (vanilla nginx) to handle calls to static content - it is referred to as web. However, this web container as the variable VIRTUAL_HOST attached to it. I would think that variable should go on the nextcloud-fpm container? But that doesn't work.
So if i wanted to add additional services that required a webserver, would i need to spin up an additional nginx server because the 'web' container will only serve up nextcloud content because of the VIRTUAL_HOST parameter on it? Thanks in advance for any help!
The nginx instance does not only serves static files, but is also the http - frontend for the php-fpm process. A user connects via http(s) through the reverse proxy to the nginx webserver. The webserver then talks to it's php-fpm backend. So the reverse proxy only has to know and reach the nginx container.
The nginx container only serves nextcloud because of the conf.d file. Theoretically you can also give it additional services there and could use multiple domains for VIRTUAL_HOST and LETSENCRYPT_HOST but this goes against the docker philosophy.
In a containerized world you really want to spin up a web server for each service to minimize coupling between the services. When your nextcloud goes down it shouldn't affect what else runs on the server.
Most helpful comment
The example you're talking about requires an additional (plain) nginx server, because the php-fpm container, can't serve basic files like images. It's just for php requests and uses port 9000 (this is NOT http!!!). That's why the fpm and nginx container share the
nextcloudvolume. It also acts as proxy for the php requests and listens on it's http port.Up to here you have a basic, unencrypted installation (port 80 is exposed by default).
The nginx-proxy is acting as an additional layer on top of the nextcloud-fpm-setup. It listens to the docker daemon and automatically rewrites it's rules to proxy any request to other docker containers, that you have configured accordingly. That's what the environment variables
VIRTUAL_HOSTandVIRTUAL_PORTare for. With this setup you get the ability to serve different website on the same port on your host (80 for http and 443 for https) with different domain names and / or subdomains.Internally the communication between proxy and nextcloud container is unencrypted http (port 80).
With the letsencrypt companion container you also get automatic generation and renewal of letsencrypt certificates, and the proxy will be configured to redirect to https.
If you want to run multiple services on your host, you can just add them to the docker-compose file, or create different compose files, for each service.
For example my setup looks like this:
The proxy part just contains the nginx proxy and the letsencrypt companion, as well as a user defined network.
For nextcloud you would just have the database, php-fpm and nginx containers (I use the apache image, but with the php-fpm image it would look similar) and I define the proxy-tier network as external (the name of the network ist
FOLDERNAME_NETWORK_NAME):And you would do the same for all other services, for example portainer:
So I can reach my nextcloud with
cloud.example.comand portainer withdocker.example.comon the default https port 443.I hope I could answer a few questions :grin: