Serving Django's Static Files with Nginx
Tags: django, python, docker, devops
Published: 2022-05-23 15:30:42

You have developed an excellent Django application, and it's time to deploy. 

You are going for NGINX - a great choice - but your Django project has actually configurations for static files. 
Given that the Django application will be running through NGINX, it's important to have static files configured and served via NGINX. 

## Django static files configuration

If you are not familiar with Django static files, you can read a small article I've written [here](https://dev.to/koladev/static-files-in-django-explained-57nf).

Here's the Django configuration for a simple project. 

```python
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
]
STATIC_ROOT =  os.path.join(BASE_DIR, 'staticfiles')
```

In the deployment process, it's essential to ensure that the `python manage.py collectstatic` command has run. When using this command, Django looks for all static files in the apps and collects them in the `STATIC_ROOT` path, then in the `staticfiles`. 

## NGINX webserver configuration file

```shell
sudo nano /etc/nginx/sites-enabled/django-app.conf
```
Inside the `django-app.conf` file, we need to add a location for the staticfiles in the Django project. 

```conf
location /static/{
    autoindex on;
    alias /home/app/django-app/staticfiles/; // => the path to the static folder
}
```

After that, reload the `NGINX` server, and you are good to go. 

This solution is a little bit long and not automated. Most of the time, I just use `Docker`, and I just move the code from another machine to another one and start the containers. 

## Serving static files with NGINX and Docker

With the same settings of the Django application, let's write a `docker-compose.yaml` file containing the same configuration to serve static files. 

Basically, we need two services: 
- The Django application.
- And the NGINX server.

Here's what the `Dockerfile` will look like first. This `Dockerfile` will be built and used as the image of the Django application service. 

```docker
# pull official base image
FROM python:3.10-alpine

# set work directory
WORKDIR /app

# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

RUN apk update \
    && apk add gcc python3-dev

# install python dependencies
COPY requirements.txt /app/requirements.txt
RUN pip install --upgrade pip
RUN pip install --no-cache-dir -r requirements.txt


# copy project
COPY . .
```

And here's an example of static files. 

```yaml
version: '3.9'
services:
  nginx:
    container_name: core_web
    restart: on-failure
    image: nginx:stable
    volumes:
      - ./nginx/nginx.dev.conf:/etc/nginx/conf.d/default.conf
      - static_volume:/staticfiles
    ports:
      - "80:80"
    depends_on:
      - api
  api:
    container_name: core_app
    build: .
    restart: always
    env_file: .env
    ports:
      - "5000:5000"
    command: >
      sh -c " python manage.py migrate &&
          gunicorn CoreRoot.wsgi:application --bind 0.0.0.0:5000"
    volumes:
     - .:/app
     - static_volume:/staticfiles

volumes:
  static_volume:
```

And also, update the Nginx configuration file to route static file requests to the `staticfiles` folder.

```python

upstream webapp {
    server core_app:5000;
}
server {

    listen 80;
    server_name localhost;

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

    location /static/ {
       autoindex on;
       alias /home/app/django-app/staticfiles/;
    }
}
```

And we are done. :)

Want to add something or have some comments? Let's discuss this in the comments section.


*Article posted using [bloggu.io](https://bloggu.io). Try it for free.*