Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

  1. Web Application (Django + Gunicorn)
  2. Traefik (acting as the reverse proxy and SSL termination)
  3. Database which is used with the Web application
  4. 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
like image 874
Rutnet Avatar asked Aug 16 '18 20:08

Rutnet


People also ask

Can Traefik serve static files?

Traefik doesn't serve static files (it's a not a web server it's a reverse proxy/load balancer). You must use a container, which contains a web server with your files.

Does Gunicorn serve static files?

Does Gunicorn serve static files? Your application will now serve static assets directly from Gunicorn in production.

Does Gunicorn need nginx?

It is recommended in Gunicorn docs to run it behind a proxy server. Technically, you don't really need Nginx. BUT it's the Internet: your server will receive plenty of malformed HTTP requests which are made by bots and vulnerability scanner scripts.


1 Answers

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.

like image 158
Rutnet Avatar answered Nov 15 '22 04:11

Rutnet