The Setup
Using docker compose, I have the following:
Nginx Reverse Proxy <> Docker Django Application with React pages (:8000)
In my Nginx Reverse Proxy, the configuration under conf.d is as follows:
server {
listen 80;
server_name localhost;
location / {
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 $scheme;
proxy_set_header Cookie $http_cookie;
proxy_pass http://frontend:8000;
}
}
In my Django Application, I have a view that sets a CSRF token as follows in views.py:
#method_decorator(ensure_csrf_cookie, name='dispatch')`
class GetCSRFToken(APIView): ...
And on my Django app's react pages, I use Axios to call:
axios.get('http://localhost:8000/csrf_cookie').then(...)
This gets my CSRF token and saves it as a cookie on the React page.
The Problem
Before deploying the nginx reverse proxy, while accessing the app via localhost:8000, CSRF token is set when I make the axios call to the above view and everything works.
However, after deploying the nginx reverse proxy, while accessing the app via localhost, the CSRF token is not set when I call the above view.
Another observation is that, with the nginx reverse proxy set up, if I visit localhost:8000 directly, and call axios from there, the CSRF token is set.
It seems to be a issue with the reverse proxy. I can only get the cookie to be set to localhost:8000 when I visit localhost:8000 directly.
But when I visit localhost:8000 via the reverse proxy from localhost, the CSRF token is not set.
Please advise how to solve this error. Much thanks!
My docker-compose setup:
version: "3"
services:
nginx:
image: nginx:latest
ports:
- 80:80
- 443:443
volumes:
- ./nginx/app.conf:/etc/nginx/conf.d/default.conf
db:
image: postgres
volumes:
- ./data/db:/var/lib/postgresql/data
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
depends_on:
- nginx
frontend:
build: ./frontend
command: >
sh -c "python manage.py makemigrations frontendApp &&
python manage.py makemigrations &&
python manage.py migrate &&
python manage.py runserver 0.0.0.0:8000"
volumes:
- .:/code
ports:
- "8000:8000"
environment:
- POSTGRES_NAME=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
depends_on:
- db
Related
I had a perfectly fine Django CMS 3.4.1 setup running behind Nginx as an edge-server with SSL termination. The complete chain was:
nginx (SSL) → nginx (django server) → gunicorn → django
All I did was to replace the first nginx reverse proxy with traefik, for a better integration of other services. Everything is run with docker (compose)
The issue is, that Django now wants to redirect HTTPS calls to admin files (and ajax calls) to HTTP, breaking functionality because those files are blocked by the browser.
I did not change anything with the django installation. In fact, it even is the same docker image as before.
Because it did work with the old setup, I don't think that it is an issue with the Django CMS code using hardcoded http://. SSL was terminated before the django reverse proxy, as well.
Does anyone see something I am missing?
Here are some configuration files, from top to bottom:
traefic.yml:
global:
sendAnonymousUsage: false
api:
dashboard: true
insecure: true
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
watch: true
exposedByDefault: false
log:
level: INFO
format: common
entryPoints:
http:
address: ":80"
http:
redirections:
entryPoint:
to: https
scheme: https
https:
address: ":443"
certificatesResolvers:
letsencrypt:
acme:
email: ***
storage: /etc/acme/acme.json
httpChallenge:
entryPoint: http
relevant parts of django-server docker-compose file:
# ...
services:
cms-nginx:
build: "./nginx"
depends_on:
- postgres
networks:
- proxy
- cms
volumes:
- cms_static:/usr/src/app/static
- cms_media:/usr/src/app/media
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.cms.rule=Host(`***`)"
- "traefik.http.routers.cms.tls=true"
- "traefik.http.routers.cms.tls.certresolver=letsencrypt"
cms:
restart: always
build: ./cms
links:
- postgres:postgres
- static:static
expose:
- "8000"
volumes:
- ./cms:/usr/src/app
- static_out:/usr/src/app/data/generated
- cms_static:/usr/src/app/data/static
- cms_media:/usr/src/app/data/media
depends_on:
- static
env_file:
- .env
- ./cms/.env
command: /bin/sh -c "./docker-init.sh"
networks:
- cms
django server nginx conf:
server {
listen 80;
server_name *** default_server;
charset utf-8;
client_max_body_size 75M;
location ^~ /static/ {
alias /usr/src/app/static/;
}
location ^~ /media/ {
alias /usr/src/app/media/;
}
location / {
proxy_pass http://cms:8000;
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-Protocol $scheme;
}
error_log /var/log/nginx/deckel_error.log;
}
gunicorn start command:
/usr/local/bin/gunicorn cms.wsgi:application -w 2 -b :8000
django settings part:
SESSION_COOKIE_SECURE = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')
CSRF_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True
I am using nginx as a proxy to pass to my django app container. I can successfully access the main url but when it passes control back to the django app and logins in the django app container gives it the local url and it doesn't route back to the correct page.
The redirect uri comes in as http://app
site-enabled
upstream app{
server 0.0.0.0:8888;
}
server {
listen 8080;
server_name app-dev.company.net;
location / {
# django running in uWSGI
proxy_pass http://app;
include uwsgi_params;
uwsgi_read_timeout 300s;
client_max_body_size 320m;
sendfile on;
proxy_read_timeout 1800;
proxy_connect_timeout 1800;
proxy_send_timeout 1800;
send_timeout 1800;
}
}
docker-compose.yml
version: "3.9"
services:
app:
image: ecr/app
container_name: django_app
ports:
- 8888
env_file:
- dev.env
volumes:
- staticfiles:/opt/app/static/
nginx:
build: ./nginx
container_name: django_app
volumes:
- staticfiles:/opt/app/static/
ports:
- 8080:8080
depends_on:
- app
volumes:
staticfiles:
Your docker-compose / nginx configuration file is full with little errors that could cause this kind of problem - so lets try to remove them.
delete the container names if not needed. This will make it easier to understand how to link from one container in another.
Where is your NGINX Dockerfile you need to do build ./nginx.
docker-compose
version: "3.9"
services:
app:
image: ecr/app
ports:
- 8888
env_file:
- dev.env
volumes:
- staticfiles:/opt/app/static/
nginx:
build: ./nginx
volumes:
- staticfiles:/opt/app/static/
ports:
- 8080:8080
depends_on:
- app
volumes:
staticfiles:
NGINX Configuration
You can not use 0.0.0.0 in your upstream block. Normally I use the service name. In your case app. So please change that to server app:8888; and test it one more time.
Location Configuration
You are proxying http traffic to your django app container. There is no need to use uwsgi_read_timeout or include uwsgi_params. In your case a simple http proxy configuration would be enough. For example in all the things you have randomly added to the nginx configuration, one important proxy configuration is missing.
proxy_pass http://django_app;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
Make sure your understand the directives you are using in the NGINX configuration as well as in the docker-compose file, clean up the config files and try again.
I have a dockerized app that works fine in development mode on my host machine. I'm trying to figure out how I can host my app on ec2 using the default ip address created when I launch my instance.
My folder structure is as follows.
backend
|---projectname
|---Dockerfile
|---requirements.txt
|---wait-for-it.sh
config/nginx
|---app.conf
frontend
|---nuxt folders
|---Dockerfile
This is my current docker compose file I'm using
docker-compose.yml
version: '3.4'
services:
db:
restart: always
image: postgres
volumes:
- pgdata:/var/lib/postgresql/data
env_file: .env
ports:
- "5432:5432"
expose:
- 5432
redis:
restart: always
image: redis
volumes:
- redisdata:/data
django:
build:
context: ./backend
env_file: .env
command: >
sh -c "./wait-for-it.sh db:5432 &&
cd autobets && python manage.py collectstatic --noinput &&
gunicorn --workers=2 --bind=0.0.0.0:8000 autobets.wsgi:application"
ports:
- "8000:8000"
volumes:
- ./backend:/app
depends_on:
- db
restart: on-failure
nuxt:
build:
context: ./frontend
environment:
- API_URI=http://django:8000/api
command: bash -c "npm install && npm run dev"
volumes:
- ./frontend:/app
ports:
- "3000:3000"
depends_on:
- django
- redis
volumes:
pgdata:
redisdata:
config/nginx/app.config
upstream django {
ip_hash;
server django:8000;
}
upstream nuxt {
ip_hash;
server nuxt:3000;
}
server {
location ~ /(api|admin|static)/ {
proxy_pass http://django;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $host;
}
location / {
proxy_pass http://nuxt;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $host;
}
listen 8000;
server_name localhost;
}
Say if my ec2 domain name pointer is ec2-52-204-122-132.compute-1.amazonaws.com
How do I set nginx up in my app to accept http connections to the frontend of my app?
On the backend localhost:8000/admin is my admin page I'd like to access this also using the ec2 domain name too.
What's the best way to alter my config so when I push my app after add the domain name pointer I can access my app hosted on ec2?
I've been reading documentation but can't find any helpful info for a dockerized django vue type app running on ec2.
firstly you need to make sure the security group attach to your box is open for incoming connection on port that NGinx listen
For each container you want to put on NGinx config you will need to find their do to so do:
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name_or_id
NGinx is not inside a container,docker-compose so, nginx.conf
upstream django {
ip_hash;
server <container IP>:8000; # <-- Change this, with container IP
}
upstream nuxt {
ip_hash;
server <container IP>:3000; # <-- Change this, with container IP
}
server {
location ~ /(api|admin|static)/ {
proxy_pass #django # <-- Change this, with container IP
proxy_pass <container IP>:8000; # <-- OR Change this, with container IP
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $host;
}
location / {
proxy_pass #nuxt # <-- Change this, add port
proxy_pass <container IP>:3000 # <-- OR Change this, add port
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $host;
}
listen 8000; # <-- Change port number, django already use this host port
server_name localhost ec2-52-204-122-132.compute-1.amazonaws.com; # <-- change this line, add EC2 public domain
}
docker-compose.yml
version: '3.4'
services:
db:
restart: always
image: postgres
volumes:
- pgdata:/var/lib/postgresql/data
env_file: .env
ports:
- "5432:5432"
expose:
- 5432
networks: # <-- Add this
- random_name # <-- Add this
redis:
restart: always
image: redis
volumes:
- redisdata:/data
networks: # <-- Add this
- random_name # <-- Add this
django:
build:
context: ./backend
env_file: .env
command: >
sh -c "./wait-for-it.sh db:5432 &&
cd autobets && python manage.py collectstatic --noinput &&
gunicorn --workers=2 --bind=0.0.0.0:8000 autobets.wsgi:application"
ports:
- "8000:8000"
volumes:
- ./backend:/app
depends_on:
- db
restart: on-failure
networks: # <-- Add this
- random_name # <-- Add this
nuxt:
build:
context: ./frontend
environment:
- API_URI=http://django:8000/api # <-- Wrong
# From you Javascript on the client point of view,
# you will request the public server, not the internal name of
# you backend inside a container, that the public will never see
- API_URI=http://ec2-52-204-122-132.compute-1.amazonaws.com/api # <-- Right
command: bash -c "npm install && npm run dev"
volumes:
- ./frontend:/app
ports:
- "3000:3000"
depends_on:
- django # <-- will become useless if change API_URI=
- redis # <-- bad design
networks: # <-- Add this
- random_name # <-- Add this
volumes:
pgdata:
redisdata:
networks: # <-- Add this
- random_name: # <-- Add this wanto make sure container can communicate
Security group on AWS should be open on the port you'll use for listening on NGinx, host 8000 is already used by django, so use another on
From app architecture POV, your backend should do the cache stuff with Redis, not the Frontend. Complexity or backend response caching should be cache on the backend somewhere on the controllers. You client should cache only statis assets. but you here to make you have working on a server, not to speak archi.
I am - once again - very confused, with nginx, docker and react.
Here is what is what I want: 1.) a Django REST api that exposes a port only locally 2.) I want the staticfiles of the REST api handled by nginx 3.) a ReactJS front end that is served via nginx on port 80 (I dont know if it is nessesary to serve react via nginx - but I've heard it reduces image size).
The problem: It does not work. All containers can run individually but serving them via docker compose will not run properly. I dont seem to be able to proxy to the api and frontend.
I hint to my problem: What I am seeing is that the image I am layering in reactJS "tiangolo/node-frontend:10" also copies a nginx.conf file that may overwrite mine.
Using a million tutorials, I am here:
nginx.conf
upstream website_rest {
server restapi:8000;
}
upstream website_frontend {
server frontend:8080;
}
server {
listen 80;
location /rest_call/ {
proxy_pass http://website_rest;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location / {
proxy_pass http://frontend;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /rest_call/staticfiles/ {
alias /usr/src/website-dj/staticfiles/;
}
}
This is the dockerfile for react:
# Stage 0, "build-stage", based on Node.js, to build and compile the frontend
FROM tiangolo/node-frontend:10 as build-stage
WORKDIR /website-rj
COPY package*.json /website-rj/
RUN npm install
COPY ./ /website-rj/
RUN npm run build
# Stage 1, based on Nginx, to have only the compiled app, ready for production with Nginx
FROM nginx:1.15
COPY --from=build-stage /website-rj/build/ /usr/share/nginx/html
# Copy the default nginx.conf provided by tiangolo/node-frontend
COPY --from=build-stage /nginx.conf /etc/nginx/conf.d/default.conf
Dockercompose:
version: '3.7'
services:
frontend:
expose:
- 8080
build: "./website_rj_docker"
volumes:
- ./website_rj_docker/build:/usr/src/website-rj/
restapi:
build: "./website_dj_docker/"
# command: python /usr/src/website-dj/manage.py runserver 0.0.0.0:8000 --settings=rest.settings.production
command: gunicorn rest.wsgi:application --bind 0.0.0.0:8000
volumes:
- ./website_dj_docker/:/usr/src/website-dj/
- static_volume:/usr/src/website-dj/staticfiles
expose:
- 8000
environment:
- SECRET_KEY='something...'
- SQL_ENGINE=django.db.backends.postgresql
- SQL_DATABASE=postgres
- SQL_USER=something...
- SQL_PASSWORD=something...
- SQL_HOST=db
- SQL_PORT=5432
- DATABASE=postgres
depends_on:
- db
db:
image: postgres:10.5-alpine
volumes:
- postgres_data:/var/lib/postgresql/data/
nginx:
build: ./nginx
volumes:
- static_volume:/usr/src/website-dj/staticfiles
ports:
- 1337:80
depends_on:
- restapi
I'm trying to learn docker and docker-compose, and have run into a roadblock.
The stack is a python:2.7 base image serving up django pages, and this part works fine. I now want to put nginx in front of it as a reverse proxy. When I access localhost:8000 I get django pages as expected. When I load up localhost with no port, I get nothing ("Problem loading page"). I assume the connection between django container's port 8080 and nginx port 80 isn't happening, and I'm so new to docker that it's probably something simple that I'm not seeing.
docker-compose.yml
version: '2'
services:
web:
build: ./app/
command: python manage.py runserver 0.0.0.0:8000
volumes:
- ./app/:/code
ports:
- "8000:8000"
depends_on:
- db
nginx:
restart: always
build: ./nginx/
ports:
- "80:80"
volumes:
- /www/static
volumes_from:
- web
links:
- web:web
# probably not relevant to my issue
db:
image: postgres
redis:
restart: always
image: redis:latest
ports:
- "6380:6380"
volumes:
- ./redisdata/:/data
nginx config:
server {
listen 80;
server_name 127.0.0.1;
charset utf-8;
location /static {
alias /code/static;
}
location / {
proxy_pass http://web:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
The nginx service starts successfully and appears to be running. I checked it's log using
docker-compose logs nginx
And it was empty.