I am fairly new to Nginx and Docker and am currently facing an issue regarding a docker container setup. The setup consists of three containers: Nginx, Django and Postgres. It works as expected for the most part, however, I am not able to access static files through Nginx.
Here is the nginx.conf:
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local]'
'"$request" $status $body_bytes_sent'
'"$http_referer" "$http_user_agent"'
'"$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
upstream server {
server server:8000;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name localhost;
charset utf-8;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ #rewrites;
}
location #rewrites {
rewrite ^(.+)$ /index.html last;
}
location ^~ /static/ {
autoindex on;
alias /usr/share/nginx/html/static/;
}
location ~ ^/api {
proxy_pass http://server;
}
location ~ ^/admin {
proxy_pass http://server;
}
}
}
I would expect Nginx to serve /usr/share/nginx/html/static/ when I access the address localhost:8000/static. I did check the container fs at /usr/share/nginx/html/static/, and the static files are present.
Here is the docker-compose.yml:
version: "3"
services:
nginx:
container_name: nginx
build:
context: .
dockerfile: ./nginx/Dockerfile
image: nginx
restart: always
volumes:
- ./server/static:/usr/share/nginx/html/static
ports:
- 80:80
depends_on:
- server
command: nginx -g 'daemon off';
server:
container_name: server
build:
context: ./server
dockerfile: Dockerfile
hostname: server
ports:
- 8000:8000
volumes:
- ./server:/src/project
depends_on:
- "db"
restart: on-failure
env_file: .env
command: >
bash -c '
python manage.py makemigrations &&
python manage.py migrate &&
gunicorn project.wsgi -b 0.0.0.0:8000'
db:
container_name: postgres
image: postgres:latest
hostname: postgres
ports:
- 5432:5432
volumes:
- /var/lib/postgresql/data
The folder ./server/static contains all static files assembled trough python manage.py collectstatic and adds them to the volume /usr/share/nginx/html/static. However, when I try to access the static files, f.e. at localhost:8000/admin, I receive warnings for missing css files (base.css, login.css, ..).
Update:
For anyone wondering, I had to change to nginx port in the docker-compose file to 8000, so that requests from client to localhost:8000 will be processed by nginx and not the server directly. With that in my mind I also changed the port of the server in the docker-compose file to expose so that it is only internally accessible. This will however prevent you from accessing the admin part of django as well.
Here is the nginx.conf:
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local]'
'"$request" $status $body_bytes_sent'
'"$http_referer" "$http_user_agent"'
'"$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
upstream server {
server server:8000;
}
server {
listen 8000 default_server;
listen [::]:8000 default_server;
server_name localhost;
charset utf-8;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ #rewrites;
}
location #rewrites {
rewrite ^(.+)$ /index.html last;
}
location ^~ /static/ {
autoindex on;
alias /usr/share/nginx/html/static/;
}
location ~ ^/api {
proxy_pass http://server;
}
location ~ ^/admin {
proxy_pass http://server;
}
}
}
Here is the docker-compose.yml:
version: "3"
services:
nginx:
container_name: nginx
build:
context: .
dockerfile: ./nginx/Dockerfile
image: nginx
restart: always
volumes:
- ./server/static:/usr/share/nginx/html/static
ports:
- 8000:8000
- 80:8000
depends_on:
- server
command: nginx -g 'daemon off';
server:
container_name: server
build:
context: ./server
dockerfile: Dockerfile
hostname: server
expose:
- "8000"
volumes:
- ./server:/src/project
depends_on:
- "db"
restart: on-failure
env_file: .env
command: >
bash -c '
python manage.py makemigrations &&
python manage.py migrate &&
gunicorn project.wsgi -b 0.0.0.0:8000'
db:
container_name: postgres
image: postgres:latest
hostname: postgres
ports:
- 5432:5432
volumes:
- /var/lib/postgresql/data
You're finding solutions based on false assumptions, because you have not emerged yourself in the material. That's fine if you just want to have a setup that works and then understand it later. You're not the first person to use Docker for Django development, so look around:
There is what Docker has already done. It's not the only way to do it and certainly not the best way on several fronts.
If you really want an Nginx based setup, then Real Python has a really good example.
The short points of why your setup was not working and your fixes are not an improvement:
You use http protocol and WSGI is much better suited for this
Your solution assumed static files must be served by Django. They must not. Nginx is much better at it, but serving them with Nginx is in fact a bit of a slow down if you're in the early stage of a project where you might be adding a lot of new static files.
And so...you should read the document that virtually anyone seems to skip.
Related
I have an application that I am running with multiple docker containers with a docker-compose file. Two main containers are django_container and nginx_container.
I want to force using https for my application but unfortunately, my Nginx config doesn't seem to work. Basically, my gunicorn server seems to be running OK.
I can see the http://django:8001 from inside the nginx_container, but I can't see http://example.com from inside it or outside.
Here is the content of my Nginx config
server {
listen 80;
server_name example.com;
rewrite ^ https://example.com$request_uri? permanent;
}
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/certs/example_com.crt;
ssl_certificate_key /etc/nginx/certs/cert.key;
access_log /log/nginx.access.log main;
location / {
proxy_pass http://django:8001;
proxy_set_header X-Forwarded-Proto $scheme;
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
To create the containers I use the following docker-compose.yml file, which read the values from the corresponding .env file
version: "3.9"
services:
postgres:
image: postgres:13.0
container_name: postgres_container
restart: always
ports:
- "5432:5432"
volumes:
- $P_VOLUME:/initdb.d/
environment:
P_USER: $P_USER
P_PASSWORD: $P_PASSWORD
P_DB: $P_DB
django:
build:
context: .
dockerfile: ./Dockerfile
container_name: django_container
depends_on:
- postgres
ports:
- "8001:8001"
volumes:
- $ROOT_DIR:/code/
environment:
SECRET_KEY: $SECRET_KEY
ROOT_DIR: $ROOT_DIR
nginx:
image: nginx
container_name: nginx_container
depends_on:
- django
ports:
- "80:80"
- "443:443"
environment:
NGINX_HOST: $NGINX_HOST
NGINX_PORT: 80
volumes:
- $ROOT_DIR/config/$NGINX_CONF:/etc/nginx/conf.d/default.conf
- $ROOT_DIR/log/:/log/
- $ROOT_DIR/certs/:/etc/nginx/certs/
I checked the .env file and it seems the paths and configs are correct.
What am I missing here? Thanks a ton!
I'm developing a website for my association Here. It uses Django 3.0.7 and PostgreSQL. I follow this tutorial to make it works in good condition in development and in production.
In development mode all is good, site is working perfectly, static files and media files are served by the Django built-in web server.
I test the "vanilla" (coming from the tutorial) production on my local machine it works too. But the tutorial is not complete for me so after completing it, I decided to adapt the code to fit my needs. As I follow the tutorial I created a new docker-compose and a new dockerfile for production. But there are 2 differences between the tutorial and the site I want to set in production:
I want to Use TREAFIK to route the traffic on different URL (appli.amis-simserhof.fr) because I will have other projects in the future on the same server with others subdomains..
I want to secure the website using HTTPS. So I use CERTBOT (let's encrypt) to generate certificates. I add this certificates to TREAFFIK in order to use HTTPS and it works.
So I adapted the docker-compose file with my new stuff :
version: '3.7'
services:
**traefik:
image: traefik:v1.7.12
command: [
"--loglevel=INFO",
"--api",
"--docker",
"--docker.domain=amis-simserhof.fr",
"--entrypoints=name:https address::443 tls:/etc/certs/fullchain.pem,/etc/certs/privkey.pem",
"--entrypoints=name:http address::80 redirect.entrypoint:https",
]
ports:
- 80:80 # http
- 443:443 # https
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /etc/letsencrypt/live/amis-simserhof.fr/fullchain.pem:/etc/certs/fullchain.pem
- /etc/letsencrypt/live/amis-simserhof.fr/privkey.pem:/etc/certs/privkey.pem**
web:
image: registry.gitlab.com/guillaumekoenigtncy/aas-web:latest
command: gunicorn aas.wsgi:application --bind 0.0.0.0:8000
expose:
- 8000
volumes:
- static_volume:/home/app/web/staticfiles
- media_volume:/home/app/web/mediafiles
environment:
- DEBUG=0
- SECRET_KEY=change_me
- DJANGO_ALLOWED_HOSTS=localhost appli.amis-simserhof.fr
- SQL_ENGINE=django.db.backends.postgresql
- SQL_DATABASE=postgres
- SQL_USER=postgres
- SQL_PASSWORD=postgres
- SQL_HOST=db
- SQL_PORT=5432
- DATABASE=postgres
labels:
- traefik.frontend.rule=HostRegexp:appli.amis-simserhof.fr
- traefik.frontend.entryPoints=https
depends_on:
- db
db:
image: postgres:12.0-alpine
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
**nginx:
image: registry.gitlab.com/guillaumekoenigtncy/aas-nginx:latest
volumes:
- static_volume:/home/app/web/staticfiles
- media_volume:/home/app/web/mediafiles
expose:
- 80
- 443
depends_on:
- web**
volumes:
postgres_data:
static_volume:
media_volume:
I also created a dockerfile and a config file for nginx :
FROM nginx:1.19.0
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d
upstream website {
server web:8000;
}
server {
listen 80;
listen [::]:80;
access_log off;
server_name appli.amis-simserhof.fr;
location / {
proxy_pass http://website;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /staticfiles/ {
alias /home/app/web/staticfiles/;
}
location /mediafiles/ {
alias /home/app/web/mediafiles/;
}
}
The problem is that now static files are not served in production (I got a 404). When I set the DEBUG to True in the setting.py of the project files are served sot that means static files are present in the correct folder that I have set in the settings.
STATIC_URL = "/staticfiles/"
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
MEDIA_URL = "/mediafiles/"
MEDIA_ROOT = os.path.join(BASE_DIR, "mediafiles")
In production, I have correctly run the python manage.py collectstatic command. I look inside both containers, ngnix and web, and in both the files are present in the correct directory.
So I conclude my configuration is not working but when I made changes in it, I saw this changes in the nginx logs of the containers. There are no errors...
I try everything during the last 2 days: set the ssl in the nginx config and remove it from traefik (site is not accessible), expose or not ports 80 and 443 in nginx or traefik (conflicts on open ports or too many redirect error), add or remove / at the end or at the beginning of blocks or alias in nginx configuration (change nothing), etc.
If you have any hint or tips I would be really grateful...
Have a nice day :)
I'am was able do define static path with following nginx service configuration:
version: '3.7'
services:
server:
container_name: dj
build:
context: ./server/project/
restart: unless-stopped
expose:
- 8000
volumes:
- static_volume:/app/staticfiles
- media_volume:/app/media
command: gunicorn project.wsgi:application --bind 0.0.0.0:8000
networks:
- web
nginx:
container_name: nginx
build:
context: ./
dockerfile: Dockerfile
restart: unless-stopped
volumes:
- static_volume:/app/staticfiles
- media_volume:/app/media
labels:
- "traefik.enable=true"
- "traefik.http.routers.${SERVICE}.rule=(Host(`${DOMAIN_NAME}`) && PathPrefix(`/static`)) || (Host(`${DOMAIN_NAME}`) && PathPrefix(`/media`))"
- "traefik.http.routers.${SERVICE}.tls.certresolver=letsEncrypt"
- "traefik.http.routers.${SERVICE}.entrypoints=web-secure"
- "traefik.http.services.${SERVICE}.loadbalancer.server.port=80"
depends_on:
- server
networks:
- web
volumes:
static_volume:
media_volume:
networks:
web:
external: true
Note this line:
- "traefik.http.routers.static-http.rule=Host(`ex.example.com`) && PathPrefix(`/static`)"
change the ex.example.com to you domain
Here is part of my configuration, The "server" part is not completed yet
UPDATE
To use the same static files between django and nginx use following nxing configuration:
#default.conf
server {
listen 80;
server_name _;
ignore_invalid_headers on;
location / {
root /usr/share/nginx/html;
index index.html;
default_type application/javascript;
try_files $uri $uri/ /index.html =404;
}
location /static {
autoindex on;
alias /app/staticfiles/;
}
location /media {
autoindex on;
alias /app/media/;
}
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
}
Also note that I've updated docker-compose file and added Dockerfile below:
#Dockerfile
FROM nginx:1.19.1-alpine
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
So your Project-Structure should look like:
Project-root/
|-server/
|-nginx/
| |-default.conf
|-Dockerfile
|-docker-compose.yml
Context
I have a single page web app using the following stack:
React for the frontend
Django for the backend
Nginx for the webserver
The web application is dockerized using docker-compose. My React app, fetches data from the Django server (django is built as an api endpoint using Django Rest Framework).
Question/Problem
I am having an issue on deployment where I am unable to serve my media files via Nginx.
What have I tried so far
My initial thought was to serve the media files as shown on this stackoverflow post - which is pretty straight forward. Though, since Nginx runs in its own docker (and so does my django server), I unable to point to my django media files since they are in different containers.
Ideally, I would not want to use webpack, and have Nginx take care of serving media files.
If you look at the nginx Dockerfile below, you will see that I am copying my static files into /usr/share/nginx/html/static/staticfiles to then serve them using nginx (see location ^~ /static/ in nginx.conf). I have tried to do the same thing for my media file (as a test) and it works - though, all the files I am uploding once the site is up are not accessible since the copy happens when I build my container.
File Structure
Root Dirc
|__ docker-compose.yml
|__ backend
|__ root
|__ Project
|__ api
|__ models.py
|__ ...
|__ media
|__ teddycrepineau
|__ settings.py
|__ ...
|__ production
|__ Dockerfile
|__ nginx
|__ Dockerfile
|__ nginx.conf
|__ frontend
|__ ...
Relevant Code
docker-compose.yml
version: '3'
volumes:
postgres_data: {}
postgres_backup: {}
services:
postgres:
image: postgres
volumes:
- postgres_data:/var/lib/postgresql/data
- postgres_backup:/backups
env_file: .env
nginx:
container_name: nginx
build:
context: .
dockerfile: ./nginx/Dockerfile
image: nginx
restart: always
depends_on:
- django
ports:
- "80:80"
django:
container_name: django
build:
context: backend
dockerfile: ./root/production/Dockerfile
hostname: django
ports:
- 8000:8000
volumes:
- ./backend:/app/
depends_on:
- postgres
command: >
bash -c '
python3 ./root/manage.py makemigrations &&
python3 ./root/manage.py migrate &&
python3 ./root/manage.py initadmin &&
gunicorn teddycrepineau.wsgi -b 0.0.0.0:8000 --chdir=./root/'
env_file: .env
nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
upstream app {
server django:8000;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name 0.0.0.0;
charset utf-80;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ #proxy_to_app;
}
location #proxy_to_app {
rewrite ^(.+)$ /index.html last;
}
location ^~ /static/ {
autoindex on;
alias /usr/share/nginx/html/static/;
}
location ~ ^/api {
proxy_pass http://django:8000;
}
location ~ ^/admin {
proxy_pass http://django:8000;
}
}
}
nginx Dockerfile
FROM nginx:latest
ADD ./nginx/nginx.conf /etc/nginx/nginx.conf
COPY ./frontend/build /usr/share/nginx/html
COPY ./backend/root/staticfiles /usr/share/nginx/html/static/staticfiles
Django Dockerfile
FROM python:3.7
ENV PYTHONUNBUFFERED 1
RUN export DEBIAN_FRONTEND=noninteractive
RUN mkdir /app
RUN pip install --upgrade pip
ADD /root/requirements.txt /app/
WORKDIR /app/
ADD . /app/
RUN pip install -r requirements.txt
EXPOSE 8000
Django settings.py
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
APPS_DIR = os.path.join(BASE_DIR, 'project')
....
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(APPS_DIR, 'media/')
Django urls.py
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r'^api/', include('project.api.urls')),
path('summernote/', include('django_summernote.urls')),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Update
When I mount a shared volum and reference it in my nginx.conf I get a 404 page not found when trying to access the image uploaded in the django backend.
docker-compose.yml
version: '3'
volumes:
postgres_data: {}
postgres_backup: {}
services:
postgres:
image: postgres
volumes:
- postgres_data:/var/lib/postgresql/data
- postgres_backup:/backups
env_file: .env
nginx:
container_name: nginx
build:
context: .
dockerfile: ./nginx/Dockerfile
image: nginx
restart: always
depends_on:
- django
ports:
- "80:80"
volumes:
- ./static:/app/backend/root/staticfiles
- ./media:/app/backend/root/project/media
django:
container_name: django
build:
context: backend
dockerfile: ./root/production/Dockerfile
hostname: django
ports:
- 8000:8000
volumes:
- ./backend:/app/
- ./static:/app/backend/root/staticfiles
- ./media:/app/backend/root/project/media
depends_on:
- postgres
command: >
bash -c '
python3 ./root/manage.py collectstatic --no-input &&
python3 ./root/manage.py makemigrations &&
python3 ./root/manage.py migrate &&
python3 ./root/manage.py initadmin &&
gunicorn teddycrepineau.wsgi -b 0.0.0.0:8000 --chdir=./root/'
env_file: .env
nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
upstream app {
server django:8000;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name localhost;
charset utf-80;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ #proxy_to_app;
}
location #proxy_to_app {
rewrite ^(.+)$ /index.html last;
}
location ^~ /static/ {
autoindex on;
alias /usr/share/nginx/html/static/;
}
location ^~ /media/ {
autoindex on;
alias /app/backend/root/project/media/;
}
location ~ ^/api {
proxy_pass http://django:8000;
}
location ~ ^/admin {
proxy_pass http://django:8000;
}
}
}
The problem came from the way I mounted my volumes in the docker-compose.yml (it was a miss understanding from my part).
First, we create a host mounted volume (./backend/) referencing our /app/ folder that exist in our django service. We created this folder and added all the relevant files in our Dockerfile located in the backend folder. This will basically link our /app/ folder that exist on the django Docker image to ./backend folder that exist on the host - refer file structure from OP.
Once we have this volume, whenever an update is made to our /app/ folder (i.e. uploading a new image), it will be reflected in our host mounted volumes (i.e. ./backend/) - and vice versa.
We finally create 2 more sets of host mounted volumes (./backend/root/staticfiles/..., and ./backend/root/project/media/) that we'll use to serve our media and static files via Nginx. We share these host mounted volumes between nginx and django service. Starting with version 2 docker-compose automatically creates a network between you Docker images which allows you to share volumes between services.
Finally in our nginx.conf we reference the host mounted volumes in the docker-compose.yml file for the static and media url.
docker-compose.yml
version: '3'
volumes:
postgres_data: {}
postgres_backup: {}
services:
postgres:
image: postgres
volumes:
- postgres_data:/var/lib/postgresql/data
- postgres_backup:/backups
env_file: .env
django:
container_name: django
build:
context: backend
dockerfile: ./root/production/Dockerfile
hostname: django
ports:
- 8000:8000
volumes:
- ./backend:/app/
- ./backend/root/staticfiles/admin:/usr/share/nginx/html/static/admin
- ./backend/root/staticfiles/rest_framework:/usr/share/nginx/html/static/rest_framework
- ./backend/root/staticfiles/summernote:/usr/share/nginx/html/static/summernote
- ./backend/root/project/media/:/usr/share/nginx/html/media/
depends_on:
- postgres
command: >
bash -c '
python3 ./root/manage.py collectstatic --no-input &&
python3 ./root/manage.py makemigrations &&
python3 ./root/manage.py migrate &&
python3 ./root/manage.py initadmin &&
gunicorn teddycrepineau.wsgi -b 0.0.0.0:8000 --chdir=./root/'
env_file: .env
nginx:
container_name: nginx
build:
context: .
dockerfile: ./nginx/Dockerfile
image: nginx
restart: always
depends_on:
- django
ports:
- "80:80"
volumes:
- ./backend/root/staticfiles/admin:/usr/share/nginx/html/static/admin
- ./backend/root/staticfiles/rest_framework:/usr/share/nginx/html/static/rest_framework
- ./backend/root/staticfiles/summernote:/usr/share/nginx/html/static/summernote
- ./backend/root/project/media/:/usr/share/nginx/html/media/
nginx.conf
....
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name localhost;
charset utf-80;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ #proxy_to_app;
}
location #proxy_to_app {
rewrite ^(.+)$ /index.html last;
}
location ^~ /static/ {
autoindex on;
alias /usr/share/nginx/html/static/;
}
location ^~ /media/ {
autoindex on;
alias /usr/share/nginx/html/media/;
}
location ~ ^/api {
proxy_pass http://django:8000;
}
location ~ ^/admin {
proxy_pass http://django:8000;
}
}
}
I have a web application (Django based) that is utilising multiple containers:
Web Application (Django + Gunicorn)
Traefik (acting as the reverse proxy and SSL termination)
Database which is used with the Web application
Redis which is used with the Web application
According to some of the documentation I have read, I should be serving my static content using something like NGINX. But I don't have any idea on how I would do that. Would I install NGINX on my Web Application container or as a seperate NGINX container. How do I pass the request from Traefik? As far as I am aware you cannot server static content with Traefik.
This is what my docker-compose.yml looks like:
traefik:
image: traefik
ports:
- 80:80
- 8080:8080
- 443:443
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik/traefik.toml:/etc/traefik/traefik.toml:ro
- ./traefik/acme:/etc/traefik/acme
web:
build: .
restart: always
depends_on:
- db
- redis
- traefik
command: python3 /var/www/html/applications/py-saleor/manage.py makemigrations --noinput
command: python3 /var/www/html/applications/py-saleor/manage.py migrate --noinput
command: python3 /var/www/html/applications/py-saleor/manage.py collectstatic --noinput
command: bash -c "cd /var/www/html/applications/py-saleor/ && gunicorn saleor.wsgi -w 2 -b 0.0.0.0:8000"
volumes:
- .:/app
ports:
- 127.0.0.1:8000:8000
labels:
- "traefik.enable=true"
- "traefik.backend=web"
- "traefik.frontend.rule=${TRAEFIK_FRONTEND_RULE}"
environment:
- SECRET_KEY=changemeinprod
redis:
image: redis
db:
image: postgres:latest
restart: always
environment:
POSTGRES_USER: saleoradmin
POSTGRES_PASSWORD: **
POSTGRES_DB: **
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- ~/py-saleor/database:/app
If anybody else needs an answer to this, the answer lies in creating a seperate NGINX service and then directing the front end rules to the static location (xyz.com/static), e.g. see below (part of docker-compose.yml):
nginx:
image: nginx:alpine
container_name: nginx_static_files
restart: always
volumes:
- ./default.conf:/etc/nginx/conf.d/default.conf
- ./saleor/static/:/static
labels:
- "traefik.enable=true"
- "traefik.backend=nginx"
- "traefik.frontend.rule=Host:xyz.co;PathPrefix:/static"
- "traefik.port=80"
You also need to ensure that your Nginx config file (default.conf) is appropriately configured:
server {
listen 80;
server_name _;
client_max_body_size 200M;
set $cache_uri $request_uri;
location = /favicon.ico { log_not_found off; access_log off; }
location = /robots.txt { log_not_found off; access_log off; }
ignore_invalid_headers on;
add_header Access-Control-Allow_Origin *;
location /static {
autoindex on;
alias /static;
}
location /media {
autoindex on;
alias /media;
}
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
}
All credit goes to Pedro Rigotti on the Traefik slack channel for helping me arrive at the solution.
I don't have much idea about Traefik and Docker.
But I can tell you how you can install nginx and use it to serve static files(which is always recommended in order to not choke the django server by serving static files)
Install nginx and follow the steps mentioned to setup nginx .
sudo apt-get install nginx
The site-available file should look something like this:
server {
listen 80;
listen [::]:80;
server_name xyz.com;
client_max_body_size 20M;
# xyz.com/media/any_static_asset_file.jpg
# when anyone hits the above url then the request comes to this part.
location /media/ {
# do make sure that the autoindex is off so that your assets are only accessed when you have proper path
autoindex off;
# this is the folder where your asset files are present.
alias /var/www/services/media/;
}
# whenever any request comes to xyz.com then this part would handle the request
location / {
proxy_pass http://unix:/var/www/services/xyz/django_server.sock;
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;
}
}
I have a Docker + Gunicorn + Nginx + Django setup on AWS EC2 and Route 53. Right now I want to redirect mydomain.com to www.mydomain.com.
Is it appropriate to do a redirect in a Nginx configuration? Or are there are better solutions.
Here is docker-compose-yml, using gunicorn to start the Django server.
version: '2'
services:
nginx:
image: nginx:latest
container_name: dj_nginx
ports:
- "80:8000"
- "443:443"
volumes:
- ./src/my_project/static:/static
- ./src:/src
- ./config/nginx:/etc/nginx/conf.d
depends_on:
- web
web:
build: .
container_name: dj_web
command: bash -c "python manage.py makemigrations && python manage.py migrate && gunicorn my_project.wsgi -b 0.0.0.0:8000"
depends_on:
- db
volumes:
- ./src:/src
- ./apps/django_rapid:/src/my_project/django_rapid
expose:
- "8000"
db:
image: postgres:latest
container_name: dj_db
Here is my Nginx Conf
upstream web {
ip_hash;
server web:8000;
}
# portal
server {
listen 8000;
location / {
proxy_pass http://web/;
}
location /media {
alias /media; # your Django project media files - amend as required
}
location /static {
alias /static; # your Django project static files - amend as required
}
server_name localhost;
}
# portal (https)
server {
listen 443;
server_name localhost;
ssl on;
ssl_certificate /etc/nginx/conf.d/mynginx.crt;
ssl_certificate_key /etc/nginx/conf.d/mynginx.key;
location /media {
alias /media; # your Django project media files - amend as required
}
location /static {
alias /static; # your Django project static files - amend as required
}
location / {
proxy_pass http://web/;
}
}
Yes, it's appropriate to do these kinds of redirects in the webserver. If it's https your certificate needs to cover both domains.
Yes it's appropriate to do nginx redirections, but i find doing PREPEND_WWW more simple.
Add this in your settings.py
PREPEND_WWW = True