Intermittent 502s with nginx+gunicorn+django - django

Over the past few weeks we've been getting more and more 502 errors. Currently our stack is nginx + gunicron + django on an m1.large EC2 instance backed by a small RDS instance.
They seem to become more frequent as the request load increases. I will see the random 502 while using a browser, but our command line scripts that hit the api (Tasty Pie) will usually fail on their second or third request. However, if I add in a sleep function to the script right before it makes a request it will be okay for that request but 502 on the next. Note that we are using digest auth with the requests library and slumber wrapper -- hence the 401, 200 pattern.
To make debugging even trickier, the issue resolves itself when Gunicorn is run with the --debug option. The error still exists if I remove the --debug option but limit my Gunicorn workers to 1 explicitly.
My nginx.conf:
user www-data;
worker_processes 4;
pid /var/run/nginx.pid;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
gzip_proxied any;
gzip_types application/x-ghi-packedschemafeatures-v1
gzip_http_version 1.1;
gzip_comp_level 1;
gzip_min_length 500;
proxy_buffering on;
proxy_http_version 1.1;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Virtual Host File:
server {
listen 80;
server_name pipeline.ourdomain.com;
location / {
rewrite ^ https://$server_name$request_uri permanent;
}
}
server {
listen 443;
server_name pipeline.ourdomain.com;
ssl on;
ssl_protocols SSLv3 TLSv1;
ssl_ciphers ALL:-ADH:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP;
ssl_session_cache shared:SSL:10m;
ssl_certificate /etc/ssl/certs/ourdomain.com.combined.crt;
ssl_certificate_key /etc/ssl/private/ourdomain.com.key;
root /var/www/;
location /static/ {
alias /var/www/production/pipeline/public/;
}
location / {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Forwarded-Protocol https;
proxy_connect_timeout 240;
proxy_read_timeout 280;
proxy_pass http://localhost:8000/;
}
error_page 500 502 503 504 /static/50x.html;
}
Gunicorn Command
#!/bin/bash
set -e
LOGFILE=/var/log/gunicorn/ea_pipeline.log
LOGDIR=$(dirname $LOGFILE)
SETTINGS=production_settings
# user/group to run as
USER=ubuntu
GROUP=ubuntu
DJANGO_PATH=$(dirname $(readlink -f $0))/../
cd $DJANGO_PATH
echo $(pwd)
. ../env/bin/activate
test -d $LOGDIR || mkdir -p $LOGDIR
exec ../env/bin/gunicorn_django \
--user=$USER --group=$GROUP --log-level=debug \
--preload \
--workers=4 \
--timeout=90 \
--settings=$SETTINGS \
--limit-request-line=8190 \
--limit-request-field_size 0 \
--pythonpath=$DJANGO_PATH \
--log-file=$LOGFILE production_settings.py 2>>$LOGFILE
Sample of the Access Log:
67.134.170.194 - - [24/Aug/2012:00:28:17 +0000] "GET /api/v1/storage/ HTTP/1.1" 401 5 "-" "python-requests/0.13.8 CPython/2.7.3 Linux/3.2.0-29-generic"
67.134.170.194 - - [24/Aug/2012:00:28:18 +0000] "GET /api/v1/storage/ HTTP/1.1" 200 326 "-" "python-requests/0.13.8 CPython/2.7.3 Linux/3.2.0-29-generic"
67.134.170.194 - - [24/Aug/2012:00:28:18 +0000] "GET /api/v1/customer/?client_id=lamb_01 HTTP/1.1" 502 18 "-" "python-requests/0.13.8 CPython/2.7.3 Linux/3.2.0-29-generic"
67.134.170.194 - - [24/Aug/2012:00:29:41 +0000] "GET /api/v1/storage/ HTTP/1.1" 502 18 "-" "python-requests/0.13.8 CPython/2.7.3 Linux/3.2.0-29-generic"
Nginx Error log:
2012/08/24 00:28:18 [error] 16490#0: *3 connect() failed (111: Connection refused) while connecting to upstream, client: 67.134.170.194, server: pipeline.ourdomain.com, request: "GET /api/v1/customer/?client_id=lamb_01 HTTP/1.1", upstream: "http://127.0.0.1:8000/api/v1/customer/?client_id=lamb_01", host: "pipeline.ourdomain.com"
2012/08/24 00:29:41 [error] 16490#0: *7 connect() failed (111: Connection refused) while connecting to upstream, client: 67.134.170.194, server: pipeline.ourdomain.com, request: "GET /api/v1/storage/ HTTP/1.1", upstream: "http://127.0.0.1:8000/api/v1/storage/", host: "pipeline.ourdomain.com"
Sample of the Gunicorn log:
2012-08-24 17:03:13 [8716] [INFO] Starting gunicorn 0.14.3
2012-08-24 17:03:13 [8716] [DEBUG] Arbiter booted
2012-08-24 17:03:13 [8716] [INFO] Listening at: http://127.0.0.1:8000 (8716)
2012-08-24 17:03:13 [8716] [INFO] Using worker: sync
2012-08-24 17:03:13 [8735] [INFO] Booting worker with pid: 8735
2012-08-24 17:03:13 [8736] [INFO] Booting worker with pid: 8736
2012-08-24 17:03:13 [8737] [INFO] Booting worker with pid: 8737
2012-08-24 17:03:13 [8738] [INFO] Booting worker with pid: 8738
2012-08-24 17:03:21 [8738] [DEBUG] GET /api/v1/storage/
Assertion failed: ok (mailbox.cpp:84)
2012-08-24 17:03:21 [8738] [INFO] Parent changed, shutting down: <Worker 8738>
2012-08-24 17:03:21 [8738] [INFO] Worker exiting (pid: 8738)
Error in sys.exitfunc:
2012-08-24 17:03:21 [8737] [DEBUG] GET /api/v1/storage/
2012-08-24 17:03:22 [8838] [INFO] Starting gunicorn 0.14.3
2012-08-24 17:03:22 [8838] [ERROR] Connection in use: ('127.0.0.1', 8000)
2012-08-24 17:03:22 [8838] [ERROR] Retrying in 1 second.
2012-08-24 17:03:22 [8737] [INFO] Parent changed, shutting down: <Worker 8737>
2012-08-24 17:03:22 [8737] [INFO] Worker exiting (pid: 8737)
Error in sys.exitfunc:
2012-08-24 17:03:22 [8736] [DEBUG] GET /api/v1/customer/
2012-08-24 17:03:23 [8736] [INFO] Parent changed, shutting down: <Worker 8736>
2012-08-24 17:03:23 [8736] [INFO] Worker exiting (pid: 8736)
Error in sys.exitfunc:
2012-08-24 17:03:23 [8838] [ERROR] Connection in use: ('127.0.0.1', 8000)
2012-08-24 17:03:23 [8838] [ERROR] Retrying in 1 second.
2012-08-24 17:03:24 [8735] [DEBUG] GET /api/v1/upload_action/
2012-08-24 17:03:24 [8838] [ERROR] Connection in use: ('127.0.0.1', 8000)
2012-08-24 17:03:24 [8838] [ERROR] Retrying in 1 second.
2012-08-24 17:03:24 [8735] [INFO] Parent changed, shutting down: <Worker 8735>
2012-08-24 17:03:24 [8735] [INFO] Worker exiting (pid: 8735)
Error in sys.exitfunc:
2012-08-24 17:03:25 [8838] [DEBUG] Arbiter booted
2012-08-24 17:03:25 [8838] [INFO] Listening at: http://127.0.0.1:8000 (8838)
2012-08-24 17:03:25 [8838] [INFO] Using worker: sync
2012-08-24 17:03:25 [8907] [INFO] Booting worker with pid: 8907
2012-08-24 17:03:25 [8908] [INFO] Booting worker with pid: 8908
2012-08-24 17:03:25 [8909] [INFO] Booting worker with pid: 8909
2012-08-24 17:03:25 [8910] [INFO] Booting worker with pid: 8910

This is a very old post. But I had exactly the same problem with a NGinx+Gunicorn+Flask setup. I had as well a 502 error with the same log as yours on every 300th request or so. Changing the gunicorn worker type to an asynchronous solved the problem for me (I picked gthread). Hope this answer will help someone.
How to change the setting: http://docs.gunicorn.org/en/stable/settings.html#worker-class
How to choose your worker type:
http://docs.gunicorn.org/en/latest/design.html#choosing-a-worker-type
And here a good explanation why:
How many concurrent requests does a single Flask process receive?

Related

Nginx 502 bad gateway error when deploying django; (13: Permission denied) while connecting to upstream

I'm trying to set up a VPS Django server with nginx, however, I'm running into a 502 Bad Gateway error when I reload the nginx server with the following settings:
sudo nano /etc/nginx/sites-available/project
server {
listen 80;
server_name domainname.com;
location = /favicon.ico {
access_log off;
log_not_found off;
}
location /static/ {
root /home/ubuntu/Slide-Hackers-Web/src/static;
}
location /media/ {
root /home/ubuntu/Slide-Hackers-Web/src/static;
}
location / {
include proxy_params;
proxy_pass http://unix:/home/ubuntu/Slide-Hackers-Web/src/project.sock;
}
}
I execute the commands in this order
sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
sudo ln -sf /etc/nginx/sites-available/project /etc/nginx/sites-enabled
sudo systemctl restart nginx
sudo ufw allow 'Nginx Full'
If I exclude domainname.com from the server_name, then it responds with the classic "Welcome to nginx!" page, however, if I leave it, it responds with "502 Bad Gateway
nginx/1.18.0 (Ubuntu)".
I'm clueless as to what I'm supposed to do, any help?
sudo tail -f /var/log/nginx/error.log
2021/08/17 14:44:42 [crit] 45521#45521: *4 connect() to unix:/home/ubuntu/Slide-Hackers-Web/src/project.sock failed (13: Permission denied) while connecting to upstream, client: (CLIENTHOST), server: (SERVERHOST), request: "GET / HTTP/1.1", upstream: "http://unix:/home/ubuntu/Slide-Hackers-Web/src/project.sock:/", host: "(DOMAINNAME).com"
EDIT
gunicorn.service
[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/Slide-Hackers-Web/src
ExecStart=/home/ubuntu/Slide-Hackers-Web/env/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/ubuntu/Slide-Hackers-Web/src/project.sock project.wsgi:application
[Install]
WantedBy=multi-user.target
Status of both active services:
nginx:
ubuntu#vps-bdd44ecc:~$ sudo systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2021-08-17 14:13:08 UTC; 9s ago
Docs: man:nginx(8)
Process: 44170 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
Process: 44181 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
Main PID: 44186 (nginx)
Tasks: 2 (limit: 2272)
Memory: 4.2M
CGroup: /system.slice/nginx.service
├─44186 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
└─44187 nginx: worker process
gunicorn:
ubuntu#vps-bdd44ecc:~$ sudo systemctl status gunicorn
● gunicorn.service - gunicorn daemon
Loaded: loaded (/etc/systemd/system/gunicorn.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2021-08-17 14:13:08 UTC; 16s ago
Main PID: 44192 (gunicorn)
Tasks: 4 (limit: 2272)
Memory: 91.7M
CGroup: /system.slice/gunicorn.service
├─44192 /home/ubuntu/Slide-Hackers-Web/env/bin/python /home/ubuntu/Slide-Hackers-Web/env/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/ubuntu/Slide-Hackers-Web/src/project.sock project.wsgi:application
├─44221 /home/ubuntu/Slide-Hackers-Web/env/bin/python /home/ubuntu/Slide-Hackers-Web/env/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/ubuntu/Slide-Hackers-Web/src/project.sock project.wsgi:application
├─44225 /home/ubuntu/Slide-Hackers-Web/env/bin/python /home/ubuntu/Slide-Hackers-Web/env/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/ubuntu/Slide-Hackers-Web/src/project.sock project.wsgi:application
└─44231 /home/ubuntu/Slide-Hackers-Web/env/bin/python /home/ubuntu/Slide-Hackers-Web/env/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/ubuntu/Slide-Hackers-Web/src/project.sock project.wsgi:application
Aug 17 14:13:08 vps-bdd44ecc gunicorn[31290]: [2021-08-17 14:13:08 +0000] [31290] [INFO] Shutting down: Master
Aug 17 14:13:08 vps-bdd44ecc systemd[1]: gunicorn.service: Succeeded.
Aug 17 14:13:08 vps-bdd44ecc systemd[1]: Stopped gunicorn daemon.
Aug 17 14:13:08 vps-bdd44ecc systemd[1]: Started gunicorn daemon.
Aug 17 14:13:08 vps-bdd44ecc gunicorn[44192]: [2021-08-17 14:13:08 +0000] [44192] [INFO] Starting gunicorn 20.1.0
Aug 17 14:13:08 vps-bdd44ecc gunicorn[44192]: [2021-08-17 14:13:08 +0000] [44192] [INFO] Listening at: unix:/home/ubuntu/Slide-Hackers-Web/src/project.sock (44192)
Aug 17 14:13:08 vps-bdd44ecc gunicorn[44192]: [2021-08-17 14:13:08 +0000] [44192] [INFO] Using worker: sync
Aug 17 14:13:08 vps-bdd44ecc gunicorn[44221]: [2021-08-17 14:13:08 +0000] [44221] [INFO] Booting worker with pid: 44221
Aug 17 14:13:08 vps-bdd44ecc gunicorn[44225]: [2021-08-17 14:13:08 +0000] [44225] [INFO] Booting worker with pid: 44225
Aug 17 14:13:09 vps-bdd44ecc gunicorn[44231]: [2021-08-17 14:13:09 +0000] [44231] [INFO] Booting worker with pid: 44231
etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}

Gunicorn/Nginx configuration for Django 2.2 gives 502 Bad gateway

I am getting bad gateway 502 error when I access the site. This is how my configuration looks like
/etc/nginx/sites-enabled/django
upstream app_server {
server unix:/home/django/gunicorn.socket fail_timeout=0;
}
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
root /usr/share/nginx/html;
index index.html index.htm;
client_max_body_size 4G;
server_name _;
keepalive_timeout 5;
# Your Django project's media files - amend as required
location /media {
alias /home/django/my_project/current/my_project/media;
}
# your Django project's static files - amend as required
location /static {
alias /home/django/my_project/current/my_project/static;
}
# Proxy the static assests for the Django Admin panel
location /static/admin {
alias /usr/local/lib/python3.6/dist-packages/django/contrib/admin/static/admin/;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
proxy_buffering off;
proxy_pass http://app_server;
}
}
/etc/systemd/system/gunicorn.service
[Unit]
Description=Gunicorn daemon for Django
Before=nginx.service
After=network.target
[Service]
WorkingDirectory=/home/django/my_project/current
ExecStart=/usr/bin/gunicorn3 --name=my_project --pythonpath=/home/django/my_project/current --bind unix:/home/my_project/gunicorn.socket --config /etc/gunicorn.d/gunicorn.py my_project.wsgi:application --log-file /var/log/gunicorn.log --log-level debug --workers=2
Restart=always
SyslogIdentifier=gunicorn
User=django
Group=django
[Install]
WantedBy=multi-user.target
When I run service gunicorn status, I can see this:
● gunicorn.service - Gunicorn daemon for Django
Loaded: loaded (/etc/systemd/system/gunicorn.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Sun 2020-07-19 19:28:37 UTC; 7min ago
Process: 9373 ExecStart=/usr/bin/gunicorn3 --name=my_project --pythonpath=/home/django/my_project/current --bind unix:/home/django/gunicorn.socket --config /etc/gunicorn.d/gunicorn.py my_project.wsgi:application --log-file /var/log/gunicorn.l
Main PID: 9373 (code=exited, status=1/FAILURE)
Jul 19 19:28:37 admin-panel-s-2vcpu-4gb-fra1-01 systemd[1]: gunicorn.service: Service hold-off time over, scheduling restart.
Jul 19 19:28:37 admin-panel-s-2vcpu-4gb-fra1-01 systemd[1]: gunicorn.service: Scheduled restart job, restart counter is at 5.
Jul 19 19:28:37 admin-panel-s-2vcpu-4gb-fra1-01 systemd[1]: Stopped Gunicorn daemon for Django.
Jul 19 19:28:37 admin-panel-s-2vcpu-4gb-fra1-01 systemd[1]: gunicorn.service: Start request repeated too quickly.
Jul 19 19:28:37 admin-panel-s-2vcpu-4gb-fra1-01 systemd[1]: gunicorn.service: Failed with result 'exit-code'.
Jul 19 19:28:37 admin-panel-s-2vcpu-4gb-fra1-01 systemd[1]: Failed to start Gunicorn daemon for Django.
And I can see in the nginx error log:
2020/07/19 19:26:00 [crit] 9039#9039: *15 connect() to unix:/home/django/gunicorn.socket failed (2: No such file or directory) while connecting to upstream, client: 84.48.191.11, server: _, request: "GET / HTTP/1.1", upstream: "http://unix:/home/django/gunicorn.socket:/", host: "161.35.197.193"
Any advice? I looked into similar questions, but I was not able to resolve my problem.
It seems like I had an error 502 because it couldn't open database. I have found more information about it in Gunicorn log.

502 Bad Gateway nginx/1.14.0 (Ubuntu) Django

Well I've depoloyed my Django application on DigitalOcean, and used domain which I bought. Now instead of default application page it shows 502 Bad Gateway
nginx/1.14.0 (Ubuntu). And nginx errors log returns such error:
*4 connect() to unix:/home/username/project.sock failed (111: Connection refused) while connecting to upstream, client: 82.194.22.116, server: challenge.com, request: "GET / HTTP/1.1", upstream: "http://unix:/home/username/project.sock:/", host: "challenge.com"
my nginx configurations:
server {
listen 80;
server_name challenge.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/username;
}
location / {
include proxy_params;
proxy_pass http://unix:/home/username/ccproject.sock;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $server_name;
}
}
my settings in ``settings.py```:
ALLOWED_HOSTS = ['64.225.1.249', 'challenge.com']
And my socket file is in /home/username/
gunicorn status:
(env) progbash#challengers:~/ccproject$ sudo systemctl status gunicorn
● gunicorn.service - gunicorn daemon
Loaded: loaded (/etc/systemd/system/gunicorn.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Thu 2019-12-12 10:27:02 UTC; 1min 56s ago
Process: 29262 ExecStart=/home/username/ccproject/env/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/username/ccproject.sock
Main PID: 29262 (code=exited, status=1/FAILURE)
Dec 12 10:26:57 challenge systemd[1]: Started gunicorn daemon.
Dec 12 10:26:57 challenge gunicorn[29262]: [2019-12-12 10:26:57 +0000] [29262] [INFO] Starting gunicorn 20.0.4
Dec 12 10:26:57 challengers gunicorn[29262]: [2019-12-12 10:26:57 +0000] [29262] [ERROR] Retrying in 1 second.
Dec 12 10:26:58 challenge gunicorn[29262]: [2019-12-12 10:26:58 +0000] [29262] [ERROR] Retrying in 1 second.
Dec 12 10:26:59 challengers gunicorn[29262]: [2019-12-12 10:26:59 +0000] [29262] [ERROR] Retrying in 1 second.
Dec 12 10:27:00 challenge gunicorn[29262]: [2019-12-12 10:27:00 +0000] [29262] [ERROR] Retrying in 1 second.
Dec 12 10:27:01 challenge gunicorn[29262]: [2019-12-12 10:27:01 +0000] [29262] [ERROR] Retrying in 1 second.
Dec 12 10:27:02 challenge gunicorn[29262]: [2019-12-12 10:27:02 +0000] [29262] [ERROR] Can't connect to /home/username/ccproject.sock
Dec 12 10:27:02 challenge systemd[1]: gunicorn.service: Main process exited, code=exited, status=1/FAILURE
Dec 12 10:27:02 challenge systemd[1]: gunicorn.service: Failed with result 'exit-code'.
How did your unix socket came to life? Do you have /etc/systemd/system/gunicorn.socket script as per here: https://docs.gunicorn.org/en/stable/deploy.html

Nginx working outside Docker but not inside

I'm making a personal website using Django, Gunicorn, Nginx and Docker. When I execute:
gunicorn --chdir personal-website --bind :8000 personal_website.wsgi:application
The output is:
[arturocuya#localhost personalwebsite]$ gunicorn --chdir personal-website --bind :8000 personal_website.wsgi:application
[2018-09-09 11:49:02 -0500] [5161] [INFO] Starting gunicorn 19.6.0
[2018-09-09 11:49:02 -0500] [5161] [INFO] Listening at: http://0.0.0.0:8000 (5161)
[2018-09-09 11:49:02 -0500] [5161] [INFO] Using worker: sync
[2018-09-09 11:49:02 -0500] [5165] [INFO] Booting worker with pid: 5165
And it works (kinda, configuration for static files is yet to be done)
The problem is that when I run the Docker container with sudo docker-compose up, I get 502 Bad Gateway
I'm suspecting that the problem is how I use the ports but I don't really understand how it should be done.
This is my folder structure
.
├── config
│   └── nginx
│   └── conf.d
│   └── local.conf
├── docker-compose.yml
├── Dockerfile
└── personal-website
└── manage.py
Dockerfile
# Start from an official image
FROM python:3.6
# The following is an arbitrary location choice
RUN mkdir -p /opt/services/personalwebsite/src
WORKDIR /opt/services/personalwebsite/src
# Copy the project code
COPY . /opt/services/personalwebsite/src
# Install dependencies
RUN pip install django gunicorn Pillow
# Expose Port 8000
EXPOSE 8000
# Define the default command to run when starting the container
CMD ["gunicorn", "--chdir", "personal-website", "--bind", ":8000", "personal_website.wsgi:application"]
docker-compose.yml
version: '3'
services:
personalwebsite:
build: .
volumes:
- .:/opt/services/personalwebsite/src
networks:
- nginx_network
nginx:
image: nginx:1.13
ports:
- 8000:80
volumes:
- ./config/nginx/conf.d:/etc/nginx/conf.d
depends_on:
- personalwebsite
networks:
- nginx_network
networks:
nginx_network:
driver: bridge
config / nginx / conf.d / local.conf
# first we declare our upstream server, which is our Gunicorn application
upstream personalwebsite_server {
# docker will automatically resolve this to the correct address
# because we use the same name as the service: "personalwebsite"
server personalwebsite:8000;
}
# now we declare our main server
server {
listen 80;
server_name localhost;
location / {
# everything is passed to Gunicorn
proxy_pass http://personalwebsite;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
}
I also made sure to modify ALLOWED_HOSTS inside the Django project's settings.py
ALLOWED_HOSTS = ['127.0.0.1', '149.248.5.164', '0.0.0.0']
Edit 1:
As someone suggested in the comments, I accessed the Nginx container with sudo docker-compose exec nginx bash and then did curl personalwebsite:8000. I got a DISALLOWED HOST error so I added personalwebsite to the allowed hosts in settings.py then I tried to curl again and the output was the HTML of my page, which is fine.
That seemed to do the trick inside the container because the output was the HTML of my page. But then I did sudo docker-compose up and i got 502 Bad Gateway again. The exact output was:
[arturocuya#localhost personalwebsite]$ sudo docker-compose up
[sudo] password for arturocuya:
Starting personalwebsite_personalwebsite_1 ... done
Starting personalwebsite_nginx_1 ... done
Attaching to personalwebsite_personalwebsite_1, personalwebsite_nginx_1
personalwebsite_1 | [2018-09-10 02:07:12 +0000] [1] [INFO] Starting gunicorn 19.9.0
personalwebsite_1 | [2018-09-10 02:07:12 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1)
personalwebsite_1 | [2018-09-10 02:07:12 +0000] [1] [INFO] Using worker: sync
personalwebsite_1 | [2018-09-10 02:07:12 +0000] [10] [INFO] Booting worker with pid: 10
nginx_1 | 172.26.0.1 - - [10/Sep/2018:02:07:17 +0000] "GET / HTTP/1.1" 502 576 "-" "Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36" "-"
nginx_1 | 2018/09/10 02:07:17 [error] 8#8: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.26.0.1, server: localhost, request: "GET / HTTP/1.1", upstream: "http://172.26.0.2:80/", host: "0.0.0.0:8000"
nginx_1 | 2018/09/10 02:07:18 [error] 8#8: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.26.0.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", upstream: "http://172.26.0.2:80/favicon.ico", host: "0.0.0.0:8000", referrer: "http://0.0.0.0:8000/"
nginx_1 | 172.26.0.1 - - [10/Sep/2018:02:07:18 +0000] "GET /favicon.ico HTTP/1.1" 502 576 "http://0.0.0.0:8000/" "Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36" "-"
Your Nginx configuration should be
upstream personalwebsite {
server personalwebsite:8000;
}
# now we declare our main server
server {
listen 80;
server_name localhost;
location / {
# everything is passed to Gunicorn
proxy_pass http://personalwebsite;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
}
Is your Nginx service is running inside the container?
Please hit the below command inside the Nginx container and let me know the output
curl -I localhost:80
It's very easy to understand, your proxy_pass URL and upstream keyword should be the same
For deep diving into Nginx upstream configuration go through the Link

docker nginx failed to make connection with web container

My docker nginx container failed to connect with gunicorn container. docker compose logs looks like,
dj | [2017-09-16 12:37:14 +0000] [22] [INFO] Starting gunicorn 19.7.1
dj | [2017-09-16 12:37:14 +0000] [22] [DEBUG] Arbiter booted
dj | [2017-09-16 12:37:14 +0000] [22] [INFO] Listening at: http://127.0.0.1:8000 (22)
dj | [2017-09-16 12:37:14 +0000] [22] [INFO] Using worker: sync
dj | [2017-09-16 12:37:14 +0000] [25] [INFO] Booting worker with pid: 25
dj | [2017-09-16 12:37:14 +0000] [22] [DEBUG] 1 workers
ng | 2017/09/16 12:37:22 [error] 8#8: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.20.0.1, server: localhost, request: "GET /api HTTP/1.1", upstream: "http://127.0.0.1:8000/api/v1", host: "localhost"
ng | 172.20.0.1 - - [16/Sep/2017:12:37:22 +0000] "GET /api HTTP/1.1" 502 537 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/52.0.2743.116 Chrome/52.0.2743.116 Safari/537.36" "-"
ng | 2017/09/16 12:37:31 [error] 8#8: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.20.0.1, server: localhost, request: "GET /admin HTTP/1.1", upstream: "http://127.0.0.1:8000/api/admin", host: "localhost"
ng | 172.20.0.1 - - [16/Sep/2017:12:37:31 +0000] "GET /admin HTTP/1.1" 502 537 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/52.0.2743.116 Chrome/52.0.2743.116 Safari/537.36" "-"
If I make a curl request inside django container, it shows the relevant html text.
$ docker-compose exec api bash
root#e29e3756916c:/code# curl http://127.0.0.1:8000
root#e29e3756916c:/code# curl http://127.0.0.1:8000/api/v1
root#e29e3756916c:/code# curl -L http://127.0.0.1:8000/api/v1
{"_type":"document","_meta":{"url":"http://127.0.0.1:8000/api/v1/","title":"Backend APIs"},"auth":{"convert-token":{"create":{"_type":"link","url":"/api/v1/auth/convert-token/","action":"post","description":"Implements an endpoint to convert a provider token to an access token\n\nThe endpoint is used in the following flows:\n\n* Authorization code\n* Client credentials"}},"revoke-token":{"create":{"_type":"link","url":"/api/v1/auth/revoke-token/","action":"post","description":"Implements an endpoint to revoke access or refresh tokens"}},"sign_in":{"create":{"_type":"link","url":"/api/v1/auth/sign_in/","action":"post","encoding":"application/json","fields":[{"name":"username","required":true,"location":"form","schema":{"_type":"string","title":"Username","description":""}},{"name":"password","required":true,"location":"form","schema":{"_type":"string","title":"Password","description":""}}]}},"sign_up":{"create":{"_type":"link","url":"/api/v1/auth/sign_up/","action":"post","encoding":"application/json","fields":[{"name":"first_name","location":"form","schema":{"_type":"string","title":"First name","description":""}},{"name":"last_name","location":"form","schema":{"_type":"string","title":"Last name","description":""}},{"name":"email","location":"form","schema":{"_type":"string","title":"Email address","description":""}},{"name":"username","required":true,"location":"form","schema":{"_type":"string","title":"Username","description":"Required. 150 characters or fewer. Letters, digits and #/./+/-/_ only."}},{"name":"password","required":true,"location":"form","schema":{"_type":"string","title":"Password","description":""}},{"name":"is_active","location":"form","schema":{"_type":"boolean","title":"Active","description":"Designates whether this user should be treated as active. Unselect this instead of deleting accounts."}}]}},"token":{"create":{"_type":"link","url":"/api/v1/auth/token/","action":"post","description":"Implements an endpoint to provide access tokens\n\nThe endpoint is used in the following flows:\n\n* Authorization code\n* Password\n* Client credentials"}}}}root#e29e3756916c:/code#
root#e29e3756916c:/code#
nginx.conf
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
proxy_force_ranges on;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
location /admin {
proxy_pass http://127.0.0.1:8000/api/admin;
}
location /api {
proxy_pass http://127.0.0.1:8000/api/v1;
}
location /oauth {
proxy_pass http://127.0.0.1:8000/api/oauth;
}
location /static {
proxy_pass http://127.0.0.1:8000/static;
}
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
Dockerfile for nginx container is,
FROM nginx:latest
#RUN apt-get update
ADD ./static /usr/share/nginx/html
ADD nginx.conf /etc/nginx/conf.d/default.conf
ENV NGINX_PORT 80
EXPOSE 80
CMD /bin/bash -c "nginx -g 'daemon off;'"
docker-compose.yaml
version: '2'
services:
nginx:
build: ./nginx
container_name: ng
ports:
- "80:80"
#volumes:
# - ./src:/src
# - ./config/nginx:/etc/nginx/conf.d
depends_on:
- api
links:
- api
volumes_from:
- api
api:
build: ./s2s_api
container_name: dj
command: bash ./wait_for_db.sh
restart: always
depends_on:
- db
ports:
- "8000:8000"
tty: true
links:
- db:mysql
db:
image: mysql
container_name: db
command: mysqld --user=root --verbose
volumes:
- ./dbcreation.sql:/tmp/dbcreation.sql
- ./import.sh:/tmp/import.sh
ports:
- "3306:3306"
restart: always
environment:
MYSQL_DATABASE: "S2S"
MYSQL_USER: "root"
MYSQL_PASSWORD: "avi"
MYSQL_ROOT_PASSWORD: "avi"
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
DB_PORT: 3306
DB_HOST: db
wait_for_db.sh
#!/bin/sh
# Wait for database to get available
M_LOOPS="10"
#wait for mysql
i=0
# http://stackoverflow.com/a/19956266/4848859
while ! curl db:3306 >/dev/null 2>&1 < /dev/null; do
i=`expr $i + 1`
if [ $i -ge $M_LOOPS ]; then
echo "$(date) - db:3306 still not reachable, giving up"
exit 1
fi
echo "$(date) - waiting for db:3306..."
sleep 3
done
echo "$(date) - db:3306 Reachable ! - Starting Daemon"
#start the daemon
#exec $START_CMD
python manage.py makemigrations
python manage.py migrate
gunicorn s2s_api.wsgi:application -b 127.0.0.1:8000 --log-level debug
You issue is obvious from the logs.
dj | [2017-09-16 12:37:14 +0000] [22] [INFO] Listening at: http://127.0.0.1:8000 (22)
ng | 2017/09/16 12:37:22 [error] 8#8: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.20.0.1, server: localhost, request: "GET /api HTTP/1.1", upstream: "http://127.0.0.1:8000/api/v1", host: "localhost"
So there are two issues and both of them at 127.0.0.1. In your dj container, you should be running gunicorn on 0.0.0.0:8000 because the request will be forwarded by the nginx container and it is external to django container
127.0.0.1 in each container points to the container loop back itself. Now when you proxy_pass in nginx to 127.0.0.1:8000, nginx is expecting something to be running in the same container at port 8000. So it doesn't work. You need to change it to name of the service you used in docker-compose. Assuming it was api, you should use
proxy_pass http://api:8000/api/oauth;
Also on a side notem you shouldn't proxy pass static files to Gunicorn, they should be handled in nginx container itself