Django 3: Serve Django static files with NGINX

NOTE: This article was initially posted on my Substack, at https://andresalvareziglesias.substack.com/

Hi everyone!

In the first post of this Python/Django/Docker tutorial series, we define an idea to test these technologies with a real application: a supercool version of Tic Tac Toe with magical gems, and dragons, and a supersmart CPU player that uses IA. And sparks. A lot of sparks.

The second step in the basic project architecture is to deal with static files, because Gunicorn is a pure python server, so we need another server for this purpose.

Let’s get started!

Articles in this series

About Django static files

Every Django application has dynamic content (the Python part) and static content (images, CSS and JS files, etc).

To use the static files in our project, first we need to edit settings.py inside Django app source code folder, and set STATIC_URL and STATIC_ROOT variables:

STATIC_URL = 'static/'
STATIC_ROOT = '../static'
STATIC_URL = 'static/'
STATIC_ROOT = '../static'
STATIC_URL = 'static/' STATIC_ROOT = '../static'

Enter fullscreen mode Exit fullscreen mode

Then, download the static files with the manage.py command in app folder.:

cd tic-magical-line/app/src/ticmagicalline
python3 manage.py collectstatic
cd tic-magical-line/app/src/ticmagicalline
python3 manage.py collectstatic
cd tic-magical-line/app/src/ticmagicalline python3 manage.py collectstatic

Enter fullscreen mode Exit fullscreen mode

The static files have been downloaded to app/src/static folder. You can use a file browser to check them all.

As you can see, these are the static files (CSS, JS and images) of the Django admin site.

Create a NGINX container to serve the static files

As we said before, Gunicorn only serves dynamic python files, so we will use NGINX to serve the static files and to give our app a single entry point.

First, we will create a dedicated folder for the server at the root of the project:

cd tic-magical-line
mkdir server
mkdir server/static
cd tic-magical-line
mkdir server
mkdir server/static
cd tic-magical-line mkdir server mkdir server/static

Enter fullscreen mode Exit fullscreen mode

Inside the server folder, create the same three files as before to define the container:

cd tic-magical-line/server
touch Dockerfile
touch environment.env
touch requirements.txt
cd tic-magical-line/server
touch Dockerfile
touch environment.env
touch requirements.txt
cd tic-magical-line/server touch Dockerfile touch environment.env touch requirements.txt

Enter fullscreen mode Exit fullscreen mode

Leave environment.env and requirements.txt empty. Write the following content in Dockerfile:

FROM nginx:alpine
ADD ./server/default.conf /etc/nginx/conf.d
ADD ./app/src/static /var/www/html/static
CMD [ "nginx", "-g", "daemon off;" ]
FROM nginx:alpine
ADD ./server/default.conf /etc/nginx/conf.d
ADD ./app/src/static /var/www/html/static
CMD [ "nginx", "-g", "daemon off;" ]
FROM nginx:alpine ADD ./server/default.conf /etc/nginx/conf.d ADD ./app/src/static /var/www/html/static CMD [ "nginx", "-g", "daemon off;" ]

Enter fullscreen mode Exit fullscreen mode

In the line ADD ./app/src/ticmagicalline/static /var/www/html/static, we are including the static content from the app folder.

Now, create the NGINX server configuration:

cd tic-magical-line/server
touch default.conf
cd tic-magical-line/server
touch default.conf
cd tic-magical-line/server touch default.conf

Enter fullscreen mode Exit fullscreen mode

With this content:

upstream ticmagicalline {
server 10.20.30.1:8081;
}
server {
listen 8080;
location / {
proxy_pass http://10.20.30.1:8081;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /static/ {
alias /var/www/html/static/;
}
}
upstream ticmagicalline {
   server 10.20.30.1:8081;
}

server {
   listen 8080;

   location / {
       proxy_pass http://10.20.30.1:8081;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header Host $host;
       proxy_redirect off;
   }

   location /static/ {
       alias /var/www/html/static/;
   }
}
upstream ticmagicalline { server 10.20.30.1:8081; } server { listen 8080; location / { proxy_pass http://10.20.30.1:8081; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_redirect off; } location /static/ { alias /var/www/html/static/; } }

Enter fullscreen mode Exit fullscreen mode

These IPs will be each machine IP in our inner docker network, keep reading to know more.

IMPORTANT! We will change the initial port chosen in the Django app from 8080 to 8081, to allow NGINX to serve the app in the port 8080. We can also remove the exposed port in Django Dockerfile, because it is not needed anymore. And we will make a minor change in paths to Dockerfile of the Django app, to change the base path used in docker-compose build phase. You can see al the changes in the project public repository.

About traffic origins in the internal Docker network

Now the traffic to Gunicorn is redirecter internally by NGINX, as defined in these lines:

upstream ticmagicalline {
server 10.20.30.1:8081;
}
upstream ticmagicalline {
   server 10.20.30.1:8081;
}
upstream ticmagicalline { server 10.20.30.1:8081; }

Enter fullscreen mode Exit fullscreen mode

We need to define the NGINX internal IP as an allowed domain in the Django app. Edit settings.py inside Django app source code folder, and set CSRF_TRUSTED_ORIGINS variable:

CSRF_TRUSTED_ORIGINS = [
'http://10.20.30.2:8080',
'http://localhost:8080',
'http://127.0.0.1:8080'
]
CSRF_TRUSTED_ORIGINS = [
   'http://10.20.30.2:8080',
   'http://localhost:8080',
   'http://127.0.0.1:8080'
]
CSRF_TRUSTED_ORIGINS = [ 'http://10.20.30.2:8080', 'http://localhost:8080', 'http://127.0.0.1:8080' ]

Enter fullscreen mode Exit fullscreen mode

Glue them all with docker-compose

To join these two machines (the Gunicorn server with our Django app and the NGINX server with the static content), we will write a docker-compose file, that is a definition of a more complex system composed by several containers.

To write this docker-compose file, go to the root of the project and create the compose file:

cd tic-magical-line
touch docker-compose.yml
cd tic-magical-line
touch docker-compose.yml
cd tic-magical-line touch docker-compose.yml

Enter fullscreen mode Exit fullscreen mode

Write this content inside:

version: '3.8'
services:
app:
build:
context: ./app/
dockerfile: ./app/Dockerfile
container_name: app
hostname: app
restart: always
volumes:
- ./app/src/:/usr/src/app/
depends_on:
- server
env_file:
- ./app/environment.env
networks:
django_net:
ipv4_address: 10.20.30.1
server:
build:
context: ./
dockerfile: ./server/Dockerfile
container_name: server
hostname: server
restart: always
env_file:
- ./server/environment.env
ports:
- 8080:8080
networks:
django_net:
ipv4_address: 10.20.30.2
networks:
django_net:
ipam:
config:
- subnet: 10.20.30.0/24
gateway: 10.20.30.254
version: '3.8'

services:

 app:
   build:
     context: ./app/
     dockerfile: ./app/Dockerfile
   container_name: app
   hostname: app
   restart: always
   volumes:
     - ./app/src/:/usr/src/app/
   depends_on:
     - server
   env_file:
     - ./app/environment.env
   networks:
     django_net:
       ipv4_address: 10.20.30.1

 server:
   build:
     context: ./
     dockerfile: ./server/Dockerfile
   container_name: server
   hostname: server
   restart: always
   env_file:
     - ./server/environment.env
   ports:
     - 8080:8080
   networks:
     django_net:
       ipv4_address: 10.20.30.2

networks:

 django_net:
   ipam:
     config:
       - subnet: 10.20.30.0/24
         gateway: 10.20.30.254
version: '3.8' services: app: build: context: ./app/ dockerfile: ./app/Dockerfile container_name: app hostname: app restart: always volumes: - ./app/src/:/usr/src/app/ depends_on: - server env_file: - ./app/environment.env networks: django_net: ipv4_address: 10.20.30.1 server: build: context: ./ dockerfile: ./server/Dockerfile container_name: server hostname: server restart: always env_file: - ./server/environment.env ports: - 8080:8080 networks: django_net: ipv4_address: 10.20.30.2 networks: django_net: ipam: config: - subnet: 10.20.30.0/24 gateway: 10.20.30.254

Enter fullscreen mode Exit fullscreen mode

Now, we can build all the images:

docker compose build
docker compose build
docker compose build

Enter fullscreen mode Exit fullscreen mode

After the build phase ends, the system is ready for testing. Run all containers with:

docker-compose up
docker-compose up
docker-compose up

Enter fullscreen mode Exit fullscreen mode

If all goes as desired, we will see the output of the two containers, and our Django app will be accessible in http://127.0.0.1:8080, as before.

About the list

Among the Python and Docker posts, I will also write about other related topics (always tech and programming topics, I promise… with the fingers crossed), like:

  • Software architecture
  • Programming environments
  • Linux operating system
  • Etc.

If you found some interesting technology, programming language or whatever, please, let me know! I’m always open to learning something new!

About the author

I’m Andrés, a full-stack software developer based in Palma, on a personal journey to improve my coding skills. I’m also a self-published fantasy writer with four published novels to my name. Feel free to ask me anything!

原文链接:Django 3: Serve Django static files with NGINX

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
Pain changes people. However, love will finally guide them back.
伤痛会改变一个人,但爱最终总会让你找回最初的自己
评论 抢沙发

请登录后发表评论

    暂无评论内容