Error 404 Nginx can't find media files. +Django - django

I was setting up basic Django site with nginx. When i navigate to the url of the file i get error 404 Not Found
nginx/1.18.0 (Ubuntu)
This is the conf file
upstream django {
server unix:///home/jo/testproject/testproject.sock;
}
# configuration of the server
server {
listen 80;
server_name _;
charset utf-8;
# max upload size
client_max_body_size 75M;
# Django media and static files
location /media/ {
alias /home/jo/testproject/media/;
}
location /static {
alias /home/jo/testproject/static;
}
# Send all non-media requests to the Django server.
location / {
uwsgi_pass django;
include /home/jo/testproject/uwsgi_params;
}
}
the media folder is in /home/jo/testproject/media and inside it i have media.gif, but ip/media/media.gif doesnt work
when i write the ip in the browser i get
Welcome to nginx!
If you see this page, the nginx web server is successfully installed and working. Further configuration is required.
For online documentation and support please refer to nginx.org.
Commercial support is available at nginx.com.
Thank you for using nginx.
I think everything else i setup correctly

Docker + NGINX + Gunicorn + Django
Django project:
djangoapp
- ...
- media
- static
- manage.py
- requirements.txt
nginx
- Dockerfile
- nginx.conf
docker-compose.yml
Dockerfile
Dockerfile:
FROM ubuntu:20.04
# Prevents Python from writing pyc files to disc
ENV PYTHONDONTWRITEBYTECODE 1
# Prevents Python from buffering stdout and stderr
ENV PYTHONUNBUFFERED 1
ENV DEBUG 0
# https://hub.docker.com/r/fnndsc/ubuntu-python3/dockerfile
RUN apt-get update \
&& apt-get install -y python3-pip gunicorn
RUN mkdir /app
COPY djangoapp/requirements.txt requirements.txt
COPY djangoapp /app/
RUN pip3 install -r requirements.txt
WORKDIR /app/
EXPOSE 8000
CMD ["gunicorn3", "-b", "0.0.0.0:8000", "djangoapp.wsgi:application", "--workers=2"]
docker-compose.yml:
version: '3'
services:
djangoapp:
build: .
container_name: djangoapp1
volumes:
- .:/djangoapp
- static:/app/static
- media:/app/media
nginx:
build: ./nginx
container_name: nginx
environment:
- SERVER_NAME=8.43.162.54
ports:
- "80:80"
volumes:
- .:/djangoapp
- static:/app/static
- media:/app/media
restart: always
networks:
default:
driver: bridge
volumes:
media:
static:
nginx/Dockerfile:
FROM nginx
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d/
nginx/nginx.conf:
server {
listen 80;
server_name $SERVER_NAME;
location /static/ {
alias /app/static/;
}
location /media/ {
alias /app/media/;
}
location / {
proxy_set_header Host $host;
proxy_pass http://djangoapp1:8000;
}
}
settings.py:
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATICFILES_DIRS = []
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

sudo nano /etc/nginx/sites-enabled/inventory.conf
the upstream component nginx needs to connect to
upstream django {
server unix:///home/user/Inventory-System/inventory.sock;
}
#configuration of the server
server {
listen 80;
server_name trading.code www.trading.code;
charset utf-8;
# max upload size
client_max_body_size 75M;
# Django media and static files
location /media {
autoindex on;
alias home/user/Inventory-System/media/;
}
location /static {
autoindex on;
alias home/user/Inventory-System/static/;
}
# Send all non-media requests to the Django server.
location / {
uwsgi_pass django;
include home/user/Inventory-System/uwsgi_params;
} }
then
user#user: /etc/nginx/sites-enabled$ sudo rm default
user#user: $ sudo /etc/init.d/nginx restart
finally
check http://127.0.0.0/media/

I also faced this problem and I add this in my sudo nano /etc/nginx/sites-available/project file
server {
listen 80;
server_name 45.76.42.234;
location = /favicon.ico { access_log off; log_not_found off; }
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
location /static/ {
root /home/django/Django_tutorials/21_Django-deployment;
}
location /media/ {
root /home/django/Django_tutorials/21_Django-deployment;
}
location /Images/ {
alias /home/django/Django_tutorials/21_Django-deployment/Images/;
}
}
where Images is my image folder that contains uploaded images

Related

serve django staticfiles with nginx

i have django back-end and reactjs front-end.
i want to load static files of django back-end with nginx but he can't find anything .
gunicorn can find django pages but can't load staticfiles
so i want nginx to serve django page and staticfiles.
this is my settings.py :
STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(BASE_DIR, '/static')
docker-compose :
version: "3.9"
services:
backend:
build:
context: ./backend
ports:
- "8000:8000"
entrypoint: ./entrypoint.sh
# command: gunicorn server.wsgi:application --bind 0.0.0.0:8000
volumes:
- static:/static
nginx:
build:
context: .
dockerfile: ./webserver/Dockerfile
restart: always
ports:
- "80:80"
volumes:
- static:/static
depends_on:
- backend
volumes:
static:
and this is my default.conf :
upstream api {
server backend:8000;
}
server {
listen 80;
server_name myapp.loc;
root /usr/share/nginx/html/frontend1;
location / {
try_files $uri /index.html;
}
location /admin/ {
proxy_pass http://api;
}
location /static/ {
alias /static/;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
server {
listen 80;
server_name newapp.loc;
root /usr/share/nginx/html/frontend2;
location / {
try_files $uri /index.html;
}
location /admin/ {
proxy_pass http://api;
}
location /static/ {
alias /static/;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
I think the problem occurs in the nginx config file.
location /static/ {
alias /static/;
}
Just now, it will alias to FRONTEND_ROOT/static/ (in this case, it is /usr/share/nginx/html/frontend1/static/), but what we expected is it should alias to BACKEND_ROOT/static/.
So the easiest way to solve this problem is to write absolute path here, to avoid alias to the frontend directory.
Create seperate entry in /etc/hosts for django.loc
Also make nginx configure for your back which will redirect you, changes in default.conf
server {
listen 80;
server_name django.loc;
location / {
proxy_pass http://localhost:8000/;
}
location /static/ {
alias /path/to/backend/static/;
} #OR YOU DONT NEED THIS, TELL BACKEND THAT ALLOW ACCESS TO STATIC
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Either specify complete path in static block, or else remove static path, and mention static directory in your framework.
Try this if not working let me know

Unable to serve static file in Django deployed to production in Digital ocean

Currently I deployed my django app in Digital ocean droplet. In localhost it works well but it cant serve js/css files in static folder when deployed to prod. Here are configs:
server {
server_name keywordprocessor.prodsite.com www.keywordprocessor.prodsite.com>
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /root/projects/backend/crawler;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
...
}
BY digital oceans default, the project resides inside root directory
`cd projects` `pwd` returns /root/projects/
Settings
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0/howto/static-files/
STATIC_URL = "/static/"
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]
STATIC_ROOT = os.path.join(BASE_DIR, "/")
THis is how the project folder looks like
backend/
crawler/
static/
templates
.gitignore
requirements.txt
/etc/systemd/service/gunicorn.service
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
User=root
Group=root
WorkingDirectory=/root/projects/backend/crawler
ExecStart=/usr/local/bin/gunicorn \
--access-logfile - \
--workers 3 \
--bind unix:/run/gunicorn.sock \
crawler.wsgi:application
[Install]
WantedBy=multi-user.target
All js and css files cant be served
`Failed to load resource: the server responded with a status of 404 (Not Found)`
It does load the page but css messed up. I did some googling for possible solutions, nothing works for me.
copy your static files to /var/www/static and change your nginx conf
1.Copy command in project directory cp -r ./static /var/www/static/
2.Permission to static folder which is in /var/www/static/command
sudo chmod 755 static
3.Change your nginx.conf like
server {
listen 80;
server_name Your-IP;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
alias /var/www/static/;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
}
4.Do this commands for nginx and gunicorn
a) sudo nginx -t
b) sudo systemctl restart nginx
c) sudo systemctl restart gunicorn
5.If you will get any error check logs using sudo tail -F /var/log/nginx/error.log and try again.

How to configure NGINX for Vue and Django?

I was following this tutorial to create a backend and it worked.
I made simple a Django REST admin panel to upload images, it worked.
Then I created Vue frontend app, run npm run serve while in 'VScode remote' and it worked (images are fetched from Django and styled by Vue in my localhost).
The PROBLEM is it's not obvious how to make all this work in the production VPS server (i mean from Vue 'dist' folder after vue run build).
Everything I tried just gives me a 404 error or ruins the Django admin panel.
Here are my NGINX settings :
server {
server_name kruglovks.xyz www.kruglovks.xyz;
client_max_body_size 100m;
location = /favicon.ico { access_log off; log_not_found off; }
location /static {
root /home/kirill/myprojectdir/myproject;
}
location /media {
root /home/kirill/myprojectdir/myproject;
}
location /dist {
try_files $uri $uri/ /index.html;
alias /home/kirill/myprojectdir/myproject;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
Vue router is set to history mode.
Please, I need some info on how to make Vue work in this configuration.
P.S. Maybe there is an alternative way of using Vue alongside Django?
Thank you so much and have a nice day!
That was a huge step forward, not a 404 but blank page called 'frontend' and browser refused to find css and js.
Later with a friends help and thisguide i could reconfigure nginx settings to this :
server {
listen 80;
server_name kruglovks.xyz www.kruglovks.xyz;
root /home/sasha/myprojectdir/myproject/dist/;
client_max_body_size 100m;
location = /favicon.ico { access_log off; log_not_found off; }
location /static {
alias /home/sasha/myprojectdir/myproject/static;
}
location /media {
alias /home/sasha/myprojectdir/myproject/media;
}
location / {
try_files $uri $uri/ /index.html;
}
location ^~ /api/ {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
location ^~ /admin {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
and it works now !
Thank you so muck #Danizavtz, you saved me like weeks of life ...
You are not listening to any ports.
Notice that in location /dist you also have to change the order of operations
Try to change your default to this configuration:
server {
listen 80;
server_name kruglovks.xyz www.kruglovks.xyz;
root /var/www;
#... configurations
location /dist {
alias /home/kirill/myprojectdir/myproject;
try_files $uri $uri/ /index.html;
}
And the vuejs application will be served in www.kruglovks.xyz/dist.
This is for production, not intended for development environment. Django application deployed using Guncorn
# settings.py
ALLOWED_HOSTS=['yourdomain.com', 'localhost'] # 'localhost' is optional
...
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
If using 'corsheaders' then add yourdomain.com
# settings.py
CORS_ALLOWED_ORIGINS = `[`
"https://yourdomain.com",
"http://yourdomain.com", # Use this if SSL in not configured
"http://localhost"
]
Update 'urls.py' for the project, and choose path for your application; mine is 'app/api/' so it will direct to http://yourdomain.com/app/api/
urlpatterns = [
path('app/api/', include('api.urls')),
path('app/admin/', admin.site.urls),
]
NGINX Configurations
# /etc/nginx/sites-available/yourdomain.com.conf
server {
root /var/www/app/dist; # Vue app production build
index index.html index.htm index.nginx.debian.html;
server_name yourdomain.com www.yourdomain.com;
# Django folder
location /static/ {
root /path/to/django/project/folder;
}
# Django web requests handled here
location /app/ {
# Gunicorn and other configurations
...
}
# Everything else handled by Vue
location / {
try_files /$uri /$uri/ /index.html$args;
}
...
}
You can also use Nginx to serve Vue and another Nginx instance to work as reverse proxy to serve Django statics (Gunicorn will serve Django dynamic content i.e API calls/ responses) - you will get faster serving of static content and improved security layer on the way.
Here is why tu use Nginx -> https://djangoadventures.com/what-is-the-point-of-using-nginx-in-front-of-a-django-application/
Nice example here for Docker, Django, Postres, Nginx -> https://testdriven.io/blog/dockerizing-django-with-postgres-gunicorn-and-nginx/
For Vue - Nginx can also serve that. Remember to edit settings.py with Cors and allowed hosts.
If you want incorporate nginx proxy to the frontend then you can do that by 2 separate nginx files like:
frontend file -> nginx.conf
server {
listen 8080;
location / {
root /code;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
backend file -> default.conf
upstream backend {
server backend:8000;
}
upstream frontend {
server frontend:8080;
}
server {
listen 80;
root /usr/share/nginx/html;
include /etc/nginx/mime.types;
# Vue frontend.
location / {
proxy_pass http://frontend;
}
# Django API.
location /api {
proxy_pass http://backend;
autoindex off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
# Django static assests.
location /static/ {
autoindex on;
alias /code/staticfiles/;
}
}
Dockerfile for Django
# Build from minimal image for speed and security
FROM python:3.10.2-slim-bullseye
ENV WORKDIR=/code
ENV USER=code
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR $WORKDIR
COPY requirements.txt $WORKDIR
# make static files dirs in order to avoid error from collectstatic
RUN mkdir $WORKDIR/staticfiles && \
mkdir $WORKDIR/staticfiles/admin && \
mkdir $WORKDIR/staticfiles/rest_framework
RUN pip install --upgrade pip && \
pip install -r requirements.txt && \
adduser --system --group $USER && \
chown -R $USER:$USER $WORKDIR
COPY ./app/backend $WORKDIR
USER $USER
EXPOSE 8000
Dockerfile for vue
FROM node:lts-alpine as build-stage
ENV WORKDIR=/code
WORKDIR $WORKDIR
# copy both 'package.json' and 'package-lock.json' (if available) from you project dir
COPY app/frontend/package*.json $WORKDIR/
# install project dependencies
RUN npm install --legacy-peer-deps
COPY app/frontend $WORKDIR
RUN npm run build
# Serve Vue
FROM nginx:alpine as production-stage
RUN mkdir $WORKDIR
COPY app/nginx/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build-stage $WORKDIR/dist $WORKDIR
EXPOSE 8080
Then Docker compose
version: "3.5"
volumes:
postgres_data:
static_volume:
services:
backend:
container_name: django_backend
env_file:
- .env
build:
context: .
dockerfile: Dockerfile.django
restart: unless-stopped
# Should go into separate *.sh file but for simplicity - you starting Gunicorn to serve Django
command: >
sh -c "python manage.py wait_for_db &&
python manage.py migrate --noinput &&
python manage.py collectstatic --no-input &&
gunicorn your_project.wsgi:application --bind 0.0.0.0:8000"
volumes:
- static_volume:/code/staticfiles
depends_on:
- database
frontend:
container_name: vue_frontend
build:
context: .
dockerfile: Dockerfile.vue
restart: unless-stopped
nginx:
container_name: nginx_proxy_server
build:
context: .
dockerfile: Dockerfile.nginx_proxy
restart: unless-stopped
ports:
- 80:80
volumes:
- static_volume:/code/staticfiles
depends_on:
- frontend
- backend
database:
container_name: postgres_db
build:
context: .
dockerfile: Dockerfile.postgres
volumes:
- postgres_data:/var/lib/postgresql/data/
# from .env
environment:
- POSTGRES_HOST=${DATABASE_HOST}
- POSTGRES_USER=${DATABASE_USER}
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
- POSTGRES_DB=${DATABASE_NAME}

Serve Django Media Files via Nginx (Django/React/Nginx/Docker-Compose)

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;
}
}
}

How to serve static content with Nginx and Django Gunicorn when using Traefik

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;
}
}