Reputation: 507
I am proxy passing the Django API server using Nginx. Nginx uses letsencrypt SSL certificates and is currently listening on port 80 and 443. Nginx perfectly serves the react build files while accessing the Django API using Axios in react app results in 502 bad gateway. Axios is trying to access "/api/v1/" as baseURL.
server {
listen 80;
listen [::]:80;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# redirects www to non-www. wasn't work for me without this server block
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
root /var/www/frontend;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://localhost:8000;
proxy_redirect default;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
backend:
build:
context: .
dockerfile: dockerFiles/backend/DockerFile
tty: true
ports:
- "8000:8000"
expose:
- 8000
volumes:
- ./backend:/backend
env_file:
- backend/.env
depends_on:
- db
frontend:
image: node:latest
command: sh start.sh
working_dir: /frontend
tty: true
volumes:
- ./frontend/:/frontend
depends_on:
- backend
links:
- backend
nginx:
image: nginx:latest
tty: true
ports:
- 80:80
- 443:443
volumes:
- ./config/nginx/conf.d:/etc/nginx/conf.d
- ./frontend/dist:/var/www/frontend
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
depends_on:
- backend
- start.sh runs yarn yarn build
- domain.conf is copied from ./config/nginx/conf.d
Upvotes: 3
Views: 6502
Reputation: 507
Adding the Final Working Config and Docker Files:
Nginx Config
upstream backend_server {
server backend:8000;
}
server {
listen 80;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location /api/ {
return 301 https://$host$request_uri;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
root /var/www/frontend;
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location /api/v1/ {
proxy_pass http://backend_server/;
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 $https;
proxy_connect_timeout 360s;
proxy_read_timeout 360s;
}
location / {
try_files $uri /index.html;
}
}
docker-compose also added certbot config with nginx
version: '3.5'
services:
db:
container_name: db
image: postgres:latest
ports:
- "5432"
volumes:
- postgres_data:/var/lib/postgresql/data/
backend:
container_name: backend
build:
context: .
dockerfile: dockerFiles/backend/DockerFile
tty: true
ports:
- "8000:8000"
expose:
- 8000
volumes:
- ./backend:/backend
env_file:
- backend/.env
depends_on:
- db
frontend:
container_name: frontend
image: node:latest
command: sh start.sh
working_dir: /frontend
tty: true
volumes:
- ./frontend/:/frontend
depends_on:
- backend
links:
- backend
nginx:
container_name: nginx
image: nginx:latest
tty: true
ports:
- 80:80
- 443:443
volumes:
- ./config/nginx/conf.d:/etc/nginx/conf.d
- ./frontend/dist:/var/www/frontend
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
depends_on:
- backend
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
certbot:
image: certbot/certbot
restart: unless-stopped
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
volumes:
postgres_data: # <-- declare the postgres volume
start.sh -- for migrating database, collect static files and start gunicorn server
# Start Gunicorn processes
echo Starting Gunicorn.
exec gunicorn <app-name>.wsgi:application -k gevent\
--bind 0.0.0.0:8000 \
--workers
Upvotes: 2
Reputation: 9709
Nginx passes your request through the chain of locations you write in the config, within the same order.
The correct configuration is:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location /api/ {
proxy_pass http://frontend:8000;
proxy_redirect default;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location / {
root /var/www/frontend;
try_files $uri $uri/ /index.html;
}
}
I'm also not sure about server configuration order, but I would either remove your first server that listens 443, or put it after the first one, or at least give it a name with www.
You can also find a working example with nginx and django at pychat.org
edit
still a 502 bad gateway. nginx access.log and error.log are coming empty. The nginx terminal logs says 2019/08/21 19:22:00 [error] 9#9: *2 connect() failed (111: Connection refused) while connecting to upstream, client: 27.7.17.142, server: , request: "POST /api/v1/login/facebook/ HTTP/2.0", upstream: "http://127.0.0.1:8000/api/v1/login/facebook/", host: "example.com", referrer: "https:/example.com/login"
No processes listen for port 8000 inside your nginx container, you have the frontend in a separate container, which is NOT accessible via localhost: you need to specify http://frontend:8000
. Docker has integrated DNS resolution which equals to container name.
Upvotes: 0