https with nginx and docker compose not working - django

Please I need some assistance. Your contributions will be greatly appreciated
I am trying to add ssl to my nginx and docker compose configuration.
Currently, everything works fine with http, but it won't work with https.
Here is my docker-compose.yml file
version: '3.8'
services:
web_gunicorn:
image: ACCT_ID.dkr.ecr.us-east-2.amazonaws.com/web_gunicorn:latest
volumes:
- static:/static
- media:/media
# env_file:
# - .env
pull_policy: always
restart: always
ports:
- "8000:8000"
environment:
- PYTHONUNBUFFERED=1
- PYTHONDONTWRITEBYTECODE=1
nginx:
image: ACCT_ID.dkr.ecr.us-east-2.amazonaws.com/nginx:latest
pull_policy: always
restart: always
volumes:
- static:/static
- media:/media
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
ports:
- "80:80"
- "443:443"
depends_on:
- web_gunicorn
certbot:
image: certbot/certbot
restart: unless-stopped
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
depends_on:
- nginx
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
volumes:
static:
media:
Here is my nginx.conf configuration that works (http)
upstream web {
server web_gunicorn:8000;
}
server {
listen 80;
server_name domain.com;
location / {
resolver 127.0.0.11;
proxy_pass http://web;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /static/ {
alias /static/;
}
location /media/ {
alias /media/;
}
}
Here is my nginx.conf configuration that does not work (http and https)
upstream web {
server web_gunicorn:8000;
}
server {
location / {
resolver 127.0.0.11;
proxy_pass http://web;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /static/ {
alias /static/;
}
location /media/ {
alias /media/;
}
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
server {
if ($host = domain.com) {
return 301 https://$host$request_uri;
}
listen 80;
server_name domain.com;
return 404;
}
Below is nginx logs, when I do docker-compose logs nginx
nginx_1 | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
nginx_1 | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
nginx_1 | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
nginx_1 | 10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf
nginx_1 | 10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
nginx_1 | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
nginx_1 | /docker-entrypoint.sh: Configuration complete; ready for start up
One more thing. On my server, I can see all ssl files generate by certbot, and are stored in folder called cerbot.

Finally found the problem. So all my configuration was actually okay -- The issue was that port 443 was not opened on my server
I had only opened it in the outbound rule, I didn't realise I had to open it in the inbound rule too.
My application was running in an ec2 server, on aws.
I used this tool https://www.yougetsignal.com/tools/open-ports/ to check whether the port was open or closed.
The closed port also caused my requests to the server to timeout.

Related

Nginx: Connection refused after removing port bindings from docker-compose file

Basically, I am trying to get access to MariaDB on the website. I needed to run a docker container so that it looks as if its network requests originate from the instance on which it runs (AWS Ubuntu Instance). For that, I used network_mode: "host" within my docker-compose file for each container. Also, I had to comment out the port bindings since they are not compatible with host network mode. However, now I get:
Connection refused error. I believe I have to change something within the nginx config file which is project.conf, but I am not sure what.
This is the docker-compose file:
version: '3'
services:
app:
restart: always
build: ./app
#ports:
# - "8501:8501"
env_file:
- .env
command: streamlit run Main.py
network_mode: "host"
mariadb:
image: mariadb:10.9.3
#ports:
# - "3306:3306"
volumes:
- db_data:/var/lib/mysql
- db_conf:/etc/mysql/conf.d
environment:
MYSQL_ROOT_PASSWORD: "xxx"
MYSQL_DATABASE: "xxx"
MYSQL_USER: "xxx"
MYSQL_PASSWORD: "xxx"
MYSQL_ROOT_HOST: "xxx"
network_mode: "host"
nginx:
restart: always
build: ./nginx
#ports:
# - "80:80"
depends_on:
- app
- mariadb
volumes:
db_data:
db_conf:
And, this is the project.conf file:
server {
listen 80;
server_name helloworld-st-app;
location / {
proxy_pass http://app:8501/;
}
location ^~ /static {
proxy_pass http://app:8501/static/;
}
location ^~ /healthz {
proxy_pass http://app:8501/healthz;
}
location ^~ /vendor {
proxy_pass http://app:8501/vendor;
}
location /stream {
proxy_pass http://app:8501/stream;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
}
I tried removing 8501 from the url, still nothing. Any help on this would be much appreciated. Thanks in advance.

Nginx support multiple hostnames

I am working on my django + nginx + docker-compose project
I want to access my site via ip and mysite.com
Problem -- ip url is working, but mysite.com returns error:
403 Forbidden Nginx
My code - docker-compose.yml
services:
django:
build: ./project # path to Dockerfile
command: sh -c "
sleep 3 && gunicorn --bind 0.0.0.0:8000 core_app.wsgi"
...
expose:
- 8000
env_file:
- ./.env
depends_on:
- db
nginx:
image: nginx:1.19.8-alpine
depends_on:
- django
env_file:
- ./.env
ports:
- "80:80"
volumes:
- ./project/nginx-conf.d/:/etc/nginx/conf.d
...
nginx-conf.conf
upstream app {
server django:8000;
}
server {
listen 80;
server_name 127.0.0.1 mysite.com www.mysite.com;
location / {
proxy_pass http://django:8000;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /static/ {
alias /var/www/html/static/;
}
}
UPDATE
I was trying to replace proxy_pass http://django:8000; with proxy_pass http://app; but it didn't help
Value of proxy_pass is incorrect.
When you're referencing an upstream group, you've to pass the name of the group to proxy_pass.
In your case, the name of upstream group is "app". So the value of proxy_pass should look like this:
proxy_pass http://app;

wsgi.url_scheme http in docker using nginx

I am using Apache on CentOS. On this server I have a Django project with docker. There are two containers in docker (nginx and python).
In the Apache I have .conf that have proxy to nginx container that is exposed on port 803. SSL is set in the Apache conf as well.
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Scheme "https"
ProxyPass / http://127.0.0.1:803/
ProxyPassReverse / http://127.0.0.1:803/
On the docker I have app.conf for nginx that looks like this:
upstream project {
server project-python:5000;
}
server {
listen 80;
server_name _;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
client_max_body_size 64M;
location / {
gzip_static on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Scheme "https";
proxy_set_header X-Forwarded-Proto "https";
proxy_set_header X-Forwarded-Protocol "ssl";
proxy_set_header X-Forwarded-Ssl=on;
proxy_set_header Host $host;
proxy_pass http://project;
proxy_redirect off;
}
}
In the Dockerfile Python is exposed on port 5000 and in the docker-compose.prod.yml file for production the python is started with gunicorn with this command:
gunicorn project.wsgi:application --preload --bind 0.0.0.0:5000
So I have two issues.
In the Django when I dump request.META I got wsgi.url_scheme that is http.
The second one is that I don't even understand how nginx is communicating with gunicorn because when I set app.conf to be just like below it is working also. How the nginx know that Python is exposed on port 5000.
server {
listen 80;
server_name _;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
client_max_body_size 64M;
location / {
proxy_pass http://project;
proxy_redirect off;
}
}
docker-compose.yml
version: '3'
services:
project-python:
build:
context: .
dockerfile: docker/python/Dockerfile
container_name: project-python
volumes:
- .:/var/www:rw
- .aws:/home/www/.aws
project-nginx:
build:
context: docker/nginx
dockerfile: Dockerfile
container_name: project-nginx
ports:
- "127.0.0.1:803:80"
depends_on:
- project-python
docker-compose.prod.yml
version: '3'
services:
project-python:
restart: unless-stopped
env_file:
- ./.env.prod
command: gunicorn project.wsgi:application --preload --bind 0.0.0.0:5000
expose:
- 5000
project-nginx:
restart: unless-stopped
environment:
APP_ENV: "production"
APP_NAME: "project-nginx"
APP_DEBUG: "False"
SERVICE_NAME: "project-nginx"

How to properly configure certbot in docker?

Please help me with this problem, i have been trying to solve it for 2 days!
Please, just tell me what i am doing wrong. And what i should to change to make it work! And what i should to do to take it work.
ERROR: for certbot Cannot start service certbot: network 4d3b22b1f02355c68a900a7dfd80b8c5bb64508e7e12d11dadae11be11ed83dd not found
My docker-compose file
version: '3'
services:
nginx:
restart: always
build:
context: ./
dockerfile: ./nginx/Dockerfile
depends_on:
- server
ports:
- 80:80
volumes:
- ./server/media:/nginx/media
- ./conf.d:/nginx/conf.d
- ./dhparam:/nginx/dhparam
- ./certbot/conf:/nginx/ssl
- ./certbot/data:/usr/share/nginx/html/letsencrypt
server:
build:
context: ./
dockerfile: ./server/Dockerfile
command: gunicorn config.wsgi -c ./config/gunicorn.py
volumes:
- ./server/media:/server/media
ports:
- "8000:8000"
depends_on:
- db
environment:
DEBUG: 'False'
DATABASE_URL: 'postgres://postgres:#db:5432/postgres'
BROKER_URL: 'amqp://user:password#rabbitmq:5672/my_vhost'
db:
image: postgres:11.2
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
certbot:
image: certbot/certbot:latest
command: certonly --webroot --webroot-path=/usr/share/nginx/html/letsencrypt --email artasdeco.ru#gmail.com --agree-tos --no-eff-email -d englishgame.ru
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/logs:/var/log/letsencrypt
- ./certbot/data:/usr/share/nginx/html/letsencrypt
My Dockerfile
FROM python:3.7-slim AS server
RUN mkdir /server
WORKDIR /server
COPY ./server/requirements.txt /server/
RUN pip install -r requirements.txt
COPY ./server /server
RUN python ./manage.py collectstatic --noinput
#########################################
FROM nginx:1.13
RUN rm -v /etc/nginx/nginx.conf
COPY ./nginx/nginx.conf /etc/nginx/
RUN mkdir /nginx
COPY --from=server /server/staticfiles /nginx/static
nginx.conf file
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 443 ssl http2;
server_name englishgame.ru;
ssl on;
server_tokens off;
ssl_certificate /etc/nginx/ssl/live/englishgame.ru/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/englishgame.ru/fullchain.pem;
ssl_dhparam /etc/nginx/dhparam/dhparam-2048.pem;
ssl_buffer_size 8k;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
location / {
return 301 https://englishgame.ru$request_uri;
}
}
server {
listen 80;
server_name englishgame.ru;
location ~ /.well-known/acme-challenge {
allow all;
root /usr/share/nginx/html/letsencrypt;
}
location /static {
alias /nginx/static/;
expires max;
}
location /media {
alias /nginx/media/;
expires 10d;
}
location /robots.txt {
alias /nginx/static/robots.txt;
}
location /sitemap.xml {
alias /nginx/static/sitemap.xml;
}
location / {
proxy_pass http://server:8000;
proxy_redirect off;
proxy_read_timeout 60;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
Thank you for your help!
Alright, so based on the error ERROR: for certbot Cannot start service certbot: network 4d3b22b1f02355c68a900a7dfd80b8c5bb64508e7e12d11dadae11be11ed83dd not found, the issue is not related to any of the other services defined in your compose file, so those and your Dockerfile and nginx configuration should be irrelevant to the problem.
Then to solve the problem of "why certbot service cannot be created". Usually this kind of error happens when a network that was configured for a service has been removed manually. In this case, however, no service is even referring to a network. Thus only the hash sum is printed, not any network name.
Googling the error brings up a similar problem from let's encrypt: https://github.com/BirgerK/docker-apache-letsencrypt/issues/8, which points to
an actual docker compose issue https://github.com/docker/compose/issues/5745.
The solution there is to run the docker compose with "--force-recreate" option to resolve the problem.
So, the problem should be fixed by running docker compose up -d --force-recreate.

Serving static files via Nginx proxying HTTPS to gunicorn django in docker-compose

I'm deploying my Django/Nginx/Gunicorn webapp to EC2 instance using docker-compose. EC2 instance has static IP where mywebapp.com / www.mywebapp.com points to, and I've completed the certbot verification (site works on port 80 over HTTP) but now trying to get working over SSL.
Right now, HTTP (including loading static files) is working for me, and HTTPS dynamic content (from Django) is working, but static files are not. I think my nginx configuration is wonky.
I tried copying the location /static/ block to the SSL server context in the nginx conf file, but that caused SSL to stop working altogether, not just static files over SSL.
Here's the final docker-compose.yml:
services:
certbot:
entrypoint: /bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h &
wait $${!}; done;'
image: certbot/certbot
volumes:
- /home/ec2-user/certbot/conf:/etc/letsencrypt:rw
- /home/ec2-user/certbot/www:/var/www/certbot:rw
nginx:
command: /bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done
& nginx -g "daemon off;"'
depends_on:
- web
image: xxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/xxxxxxxx:latest
ports:
- 80:80/tcp
- 443:443/tcp
volumes:
- /home/ec2-user/certbot/conf:/etc/letsencrypt:rw
- static_volume:/usr/src/app/public:rw
- /home/ec2-user/certbot/www:/var/www/certbot:rw
web:
entrypoint: gunicorn mywebapp.wsgi:application --bind 0.0.0.0:7000"
image: xxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/xxxxxxxx:latest
volumes:
- static_volume:/usr/src/app/public:rw
version: '3.0'
volumes:
static_volume: {}
nginx.prod.conf:
upstream mywebapp {
# web is the name of the service in the docker-compose.yml
# 7000 is the port that gunicorn listens on
server web:7000;
}
server {
listen 80;
server_name mywebapp;
location / {
proxy_pass http://mywebapp;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /static/ {
alias /usr/src/app/public/;
}
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
}
server {
# https://github.com/wmnnd/nginx-certbot/blob/master/data/nginx/app.conf
listen 443 ssl;
server_name mywebapp;
server_tokens off;
location / {
proxy_pass http://mywebapp;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# generated with help of certbot
ssl_certificate /etc/letsencrypt/live/mywebapp.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mywebapp.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
and finally the nginx service Dockerfile:
FROM nginx:1.15.12-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY ./nginx.prod.conf /etc/nginx/conf.d
I simply build, push to ECR on local machine then docker-compose pull and run with docker-compose up -d on the EC2 instance.
The error I see in docker-compose logs is:
nginx_1 | 2019/05/09 02:30:34 [error] 8#8: *1 connect() failed (111: Connection refused) while connecting to upstream, client: xx.xx.xx.xx, server: mywebapp, request: "GET / HTTP/1.1", upstream: "http://192.168.111.3:7000/", host: "ec2-xxx-xxx-xxx-xxx.compute-1.amazonaws.com"
And I'm not sure what's going wrong. I'm trying to get both dynamic content (gunicorn) and static content (from: /usr/src/app/public) served correctly under HTTPS using the certs I've generated and verified.
Anyone know what I might be doing wrong?
Check your configuration file with nginx -T - are you seeing the correct configuration? Is your build process pulling in the correct conf?
It's helpful to just debug this on the remote machine - docker-compose exec nginx sh to get inside and tweak the conf from there and nginx -s reload. This will speed up your iteration cycles debugging an SSL issue.