Setting up NGINX as reverse proxy for multiple containerized services - nginx

I developed a web app with vue and django however, I'm having problems deploying it.
I added another container to serve as reverse proxy so only port 80 would be exposed and when I finish struggling with this also port 443. I could not find exact anwser how to do it so I hope someone here will be kind enoug to give me some clues.
Here is the conf for the nginx.
The error I'm getting is on ui container.
2022/07/14 09:09:00 [emerg] 1#1: bind() to 0.0.0.0:8080 failed (98: Address already in use)
I looked it up of course, but it was always some different scenario.
BR and thanks in advance
server {
listen 0.0.0.0:80;
listen [::]:80;
location / {
proxy_pass http://0.0.0.0:3000;
}
location /predict {
proxy_pass http://0.0.0.0:5000/predict;
}
location /aggregate {
proxy_pass http://0.0.0.0:5000/aggregate;
}
location /media/pictures {
proxy_pass http://0.0.0.0:5000/media/pictures;
}
access_log /opt/bitnami/nginx/logs/anomaly_access.log;
error_log /opt/bitnami/nginx/logs/anomaly_error.log;
}
My docker-compose looks as follows.
version: '3.2'
services:
se-kpi-sim:
image: test-app:0.0.1
network_mode: "host"
restart: unless-stopped
environment:
MODEL_NAME: "model_final.pickle.dat"
se-kpi-sim-ui:
image: test-ui:0.0.3
network_mode: "host"
restart: unless-stopped
reverse-proxy:
image: test-proxy:0.0.7
network_mode: "host"
restart: unless-stopped
database:
image: postgres
environment:
POSTGRES_PASSWORD: password
POSTGRES_USER: kpi_sim_user
POSTGRES_DB: kpi_sim
POSTGRES_HOST_AUTH_METHOD: trust
ports:
- 5432:5432
volumes:
- database:/var/lib/postgresql/data
restart: unless-stopped
volumes:
database:

You can run containers on docker internal network and docker-compose by default creates an network for inter communication of containers. One can modify the port to expose the application to host. while you are trying to run most of the app on host network, there might be two application trying to use the same port (like port 8080 [in this case]), one port can only be used by one application in an OS . Please look at the below snippet for more information to solve this issue.
[port mapping <port on HOST>:<container port where app is exposed inside container>]
version: '3.2'
services:
se-kpi-sim:
image: test-app:0.0.1
ports:
- 5000:8080
restart: unless-stopped
environment:
MODEL_NAME: "model_final.pickle.dat"
se-kpi-sim-ui:
image: test-ui:0.0.3
ports:
- 3000:8080
restart: unless-stopped
reverse-proxy:
image: test-proxy:0.0.7
ports:
- 80:80
# this volume mount if you are using bitnami/nginx image
volumes:
- /path/to/my_server_block.conf:/opt/bitnami/nginx/conf/server_blocks/my_server_block.conf:ro
restart: unless-stopped
database:
image: postgres
environment:
POSTGRES_PASSWORD: password
POSTGRES_USER: kpi_sim_user
POSTGRES_DB: kpi_sim
POSTGRES_HOST_AUTH_METHOD: trust
ports:
- 5432:5432
volumes:
- database:/var/lib/postgresql/data
restart: unless-stopped
volumes:
database:
One have to specify either the IP address or DNS name of the application , in order to forward the traffic to specific application. docker-compose create Domain name for all the services defined in docker-compose.yaml file.
server {
listen 0.0.0.0:80;
listen [::]:80;
location / {
proxy_pass http://se-kpi-sim-ui:8080;
}
location /predict {
proxy_pass http://se-kpi-sim:8080/predict;
}
location /aggregate {
proxy_pass http://se-kpi-sim:8080/aggregate;
}
location /media/pictures {
proxy_pass http://se-kpi-sim:8080/media/pictures;
}
access_log /opt/bitnami/nginx/logs/anomaly_access.log;
error_log /opt/bitnami/nginx/logs/anomaly_error.log;
}
One can mount the nginx.conf like:[in bitnami/nginx image]
...
volumes:
- /path/to/my_server_block.conf:/opt/bitnami/nginx/conf/server_blocks/my_server_block.conf:ro
...
Note: all the above is an example for reference to solve the problem. entrypoint for containers might change according to one's requirements.

Related

How to assign domain to a docker container

I use Docker-compose to develop the WordPress website together with Mysql and PHPMyAdmin.
Also, use Portainer to monitor them, showing the health icon, and I can access it by typing the IP address 192.168.188.80:3001, and I can curl the page from port 3001.
I try to assign the domain name for the different containers, there will have a couple of WordPress websites and I plan to host them on ports 3001, 3002, 3003...
I enable the conf file in Nginx and the conf file like
server {
listen 80;
server_name forktruck.bcsystems.nz;
location / {
proxy_pass http://0.0.0.0:3001;
}
}
The yml file is here
version: '3.8'
volumes:
wp-forktruck-data:
networks:
wp-forktruck-network:
services:
db:
image: mysql:latest
volumes:
- ./wp-forktruck-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: wordpress-forktruck
MYSQL_USER: wp-forktruck
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
ports:
- 3201:3306
healthcheck:
test: curl --fail http://localhost || exit 1
interval: 300s
start_period: 5s
timeout: 10s
restart: always
networks:
- wp-forktruck-network
phpmyadmin:
depends_on:
- db
image: phpmyadmin/phpmyadmin
environment:
PMA_HOST: db
MYSQL_USER: wp-forktruck
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
ports:
- 3101:80
healthcheck:
test: curl --fail http://localhost || exit 1
interval: 300s
start_period: 5s
timeout: 10s
networks:
- wp-forktruck-network
wordpress:
depends_on:
- db
image: wordpress
ports:
- 3001:80
healthcheck:
test: curl --fail http://localhost || exit 1
interval: 300s
start_period: 5s
timeout: 10s
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wp-forktruck
WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
WORDPRESS_DB_NAME: wordpress-forktruck
volumes:
- ./forktruck:/var/www/
container_name: wp-forktruck
networks:
- wp-forktruck-network
but something wrong and the domain name got 520 error.
you need to add the redirect option in nginx
server {
listen 80;
server_name forktruck.bcsystems.nz;
location / {
proxy_pass http://0.0.0.0:3001;
proxy_read_timeout 90;
proxy_redirect http://0.0.0.0:3001 http://forktruck.bcsystems.nz/;
}
}
And should work, good luck
You are using Cloudflare? What is your Cloudflare DNS configs. Are you sure that the domain is pointing to public address of 192.168.188.80 (as 192.168.188.80 is private IP address and it's accessible only on your internal network but not the internet).
If you don't know your public IP address, run curl ipinfo.io on the 192.168.188.80 server to get your public IP address. And then update your Cloudflare DNS config of domain forktruck.bcsystems.nz to that address.
Note: it's easy and worked only if you are using static IP address. If not, please consider https://ngrok.com/ instead of Cloudflare.

nginx basic auth not working in docker-compose

i'm setting up basic authentication(credential) for loki and promtail using nginx in docker-compose. i have created htpasswd to set the password for loki and promtail andcreated seperate config file for loki and promtail and passing it through volumes.
however its not triggering authentication for loki and promtail
docker-compose.yaml
version: "2"
services:
my-nginx-service:
image: nginx
ports:
- "8098:80"
container_name: nginx
volumes:
- ./config/sites-enabled/loki:/etc/nginx/sites-enabled/loki
- ./config/conf.d/loki.conf:/etc/nginx/conf.d/loki.conf
- ./config/conf.d/loki.conf:/etc/nginx/conf.d/promtail.conf
- ./config/sites-available/default:/etc/nginx/sites-available/default
- ./config/htpasswd/.htloki:/etc/nginx/.htloki
- ./config/htpasswd/.htloki:/etc/nginx/.htpromtail
loki:
image: grafana/loki:2.0.0
container_name: loki
volumes:
- ./config/loki.yaml:/etc/config/loki.yaml
entrypoint:
- /usr/bin/loki
- -config.file=/etc/config/loki.yaml
ports:
- "3100:3100"
promtail:
image: grafana/promtail:2.0.1
container_name: promtail
user: root
volumes:
- ./log:/var/log/test
- /var/log/system.log:/var/log/root/system.log
- ./config/promtail-local-config.yaml:/etc/config/promtail-local-config.yaml
entrypoint:
- /usr/bin/promtail
- -config.file=/etc/config/promtail-local-config.yaml
ports:
- "9080:9080"
loki.conf
server {
listen 443;
location / {
auth_basic "Protected Area";
auth_basic_user_file /etc/nginx/.htloki;
proxy_pass http://loki:3100;
}
}
promtail.conf
server {
listen 442;
location / {
auth_basic "Protected Area";
auth_basic_user_file /etc/nginx/.htpromtail;
proxy_pass http://promtail:9080;
}
}
has anybody faced this issue?
Apparently, I forgot to rebuild the container images after including the .htpasswd files. Rebuilding fixed this
docker compose up --build

Nginx reverse proxy deeplinks Wordpress on Docker

I'm trying to run Wordpress on Digital Ocean through Docker. Things started out well, I had it up and running in no time configured like so:
version: '3.3'
services:
wordpress:
depends_on:
- db
image: wordpress:5.5.1-php7.2-apache
container_name: wp
restart: always
volumes:
- ./www/wp-content:/var/www/html/wp-content
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_PASSWORD: ${DB_PWD}
ports:
- 3010:80
networks:
- network
db:
image: mysql:5.7
container_name: db
restart: always
volumes:
- ./dbdata:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: ${DB_PWD}
networks:
- network
phpmyadmin:
depends_on:
- db
image: phpmyadmin/phpmyadmin
container_name: pma
restart: always
ports:
- 3011:80
environment:
PMA_HOST: db
MYSQL_ROOT_PASSWORD: ${DB_PWD}
UPLOAD_LIMIT: 20000000
networks:
- network
networks:
network:
volumes:
db_data:
On the Digital Ocean droplet I configured Nginx as a reverse proxy:
server {
listen 80;
listen [::]:80;
server_name my.test.url;
location / {
rewrite /(.*) /$1 break;
proxy_pass http://localhost:3010;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
}
}
I already had my.test.url pointing to the droplet's IP.
I updated the 'siteurl' and 'home' records in the wp_options table in the database to my.test.url
This all worked well, serving the homepage if I visit my.test.url. However when I visit a deep link, like my.test.url/example I get redirected to 127.0.0.1/example where obviously nothing is running.
I don't know how to proceed; I thought setting the rewrite rule in the nginx config would do the trick but alas..
I should mention I want to run multiple sites on the Digital Ocean droplet, each serving from their own port, so 'just' serving from port 80 is not an option.
Can anyone point me in the right direction?
As it turns out, the above configuration was correct; the problem was a DNS error combined with Wordpress permalink settings that dictated a trailing slash after the post name. This caused a DNS lookup on the server that failed, resulting in the redirect to 127.0.0.1...

Nginx, Wordpress, and SQL

I currently am trying to learn how to use docker and was wondering if there is a way to make a Docker stack that includes Wordpress, SQL, and Nginx.
Right now I want to have 3 containers running, 1 for each and use nginx as a reverse proxy for my wordpress app.
However, every time I attempt to get this stack up and running through a composer file, only Wordpress and SQL get linked, but not the Nginx.
version: '2'
services:
db:
image: mysql:5.7
volumes:
- "./.data/db:/var/lib/mysql"
restart: always
environment:
MYSQL_ROOT_PASSWORD: wordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:fpm
links:
- db
ports:
- "8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_PASSWORD: wordpress
nginx:
restart: always
image: nginx
ports:
- "80:80"
This is all I have in my docker-compose.yml
Your basic approach should work. I have a feeling there is a configuration issue somewhere, possibly with nginx that is preventing it from working as you intend.
You can try this similar docker-compose.yml file as a sample to see how it may differ from what you are doing:
docker-compose.yml
version: '2'
services:
php:
image: phpmyadmin/phpmyadmin
links:
- mysql:db
depends_on:
- mysql
mysql:
image: k0st/alpine-mariadb
volumes:
- ./data/mysql:/var/lib/mysql
environment:
- MYSQL_DATABASE=mydb
- MYSQL_USER=myuser
- MYSQL_PASSWORD=mypass
nginx:
image: nginx:stable-alpine
ports:
- "81:80"
volumes:
- ./nginx/log:/var/log/nginx
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/files:/var/www/nginx:ro
depends_on:
- php
nginx/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
sendfile off;
server {
listen 80;
location / {
proxy_pass http://php;
proxy_set_header Host $host;
proxy_redirect off;
}
}
}
The nginx config is simplified but that should work for testing -- basically all it's doing is proxying the php app. Maps to port 81 to avoid conflicts on the host. (Note this is just a rough demo, would need to be fleshed out for any use more than that.)
Regarding linking, you can see that if you run: docker-compose exec mysql ping -c2 nginx to ping from the mysql container to the nginx container, you will succeed even though there are no links specified between these containers. Docker Compose will maintain those links in the default network for you.
If you like, you can fetch a working version from this repo here and run docker-compose up, and (assuming you don't have anything running on port 81) see results on http://localhost:81/ (or whatever your corresponding hostname/IP is).
For more info on Docker Compose networking see:
https://docs.docker.com/compose/networking/
By default Compose sets up a single network for your app. Each
container for a service joins the default network and is both
reachable by other containers on that network, and discoverable by them at a hostname identical to the container name.
Links allow you to define extra aliases by which a service is
reachable from another service. They are not required to enable
services to communicate - by default, any service can reach any other
service at that service’s name.
You could go with the jwilder-nginx docker image. It is using docker-gen to detect containers, and will register them in nginx.conf.
This should work, if you add "VIRTUAL_HOST" the domain will be added to nginx.conf. Please note: You don't have to expose ports on WordPress with this Setup. jwilder-nginx will use default port to forward traffic.
version: '2'
services:
db:
image: mysql:5.7
volumes:
- "./.data/db:/var/lib/mysql"
restart: always
environment:
MYSQL_ROOT_PASSWORD: wordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:fpm
links:
- db
- nginx
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_PASSWORD: wordpress
VIRTUAL_HOST: myblog.mydomain.de
nginx:
restart: always
image: jwilder/nginx-proxy
ports:
- "80:80"

Docker-compose: nginx does not work with django and gunicorn

I've been trying to set up an environment in docker-compose where there are several containers:
Django
Nginx
Postgres
DbData
Storage
I've used the following configuration:
app:
restart: always
build: src
expose:
- "8000"
links:
- postgres:postgres
volumes_from:
- storage_files_1
env_file: .env
command: gunicorn barbell.wsgi:application \
-b 0.0.0.0:8000 -w 4
nginx:
restart: always
build: nginx
ports:
- "80:80"
- "443:443"
volumes_from:
- storage_files_1
links:
- app:app
postgres:
restart: always
image: postgres:latest
volumes_from:
- storage_data_1
ports:
- "5432:5432"
My nginx sites-enabled config file looked like this:
server {
listen 80;
server_name localhost;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
location /static {
alias /static/;
autoindex on;
}
location / {
proxy_pass http://app:8000;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Real-IP $remote_addr;
add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"';
}
}
And it doesn't work - nginx always returns 502, but serves static files perfectly. I also tried the same setup with uwsgi, no luck. However, when I combine the Django with nginx and serve everything from the same container, everything works (again, both on uwsgi and gunicorn).
Any idea what am I missing?
Update
Here are the nginx logs:
*1 connect() failed (111: Connection refused) while connecting to upstream,
client: 172.17.42.1, server: 0.0.0.0, request: "GET / HTTP/1.1", upstream:
"http://172.17.1.75:8000/", host: "localhost"
It turned out that Gunicorn was the culprit. Putting its configuration into a file resolved the issue.
gunicorn_config.py put in the same folder as manage.py:
bind = "0.0.0.0:8000"
loglevel = "INFO"
workers = "4"
reload = True
errorlog = "/var/log/gunicorn/error.log"
accesslog = "/var/log/gunicorn/access.log"
And some changes in docker-compose.yml:
app:
restart: always
build: src
expose:
- "8000"
links:
- postgres:postgres
volumes_from:
- storage_files_1
env_file: .env
command: gunicorn --config=gunicorn_config.py barbell.wsgi:application
Now it works as it should.
So I haven't seen any further feedback from you regarding error logs and what may or may not be hapenning for you; however I've stripped your example down to it's simplest as a demonstration of Docker+Django+NGINX working:
See: docker-django-test
NB: This is running on some infrastructure of mine that uses autodock If you want to replicate this you'll need this snippet of docker-compose.yml:
autodock:
image: prologic/autodock
ports:
- "1338:1338/udp"
- "1338:1338/tcp"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
autodockhipache:
image: prologic/autodock-hipache
links:
- autodock
- hipache:redis
hipache:
image: hipache
ports:
- 80:80
- 443:443
See: A Docker-based mini-PaaS

Resources