docker, nginx, django and how to serve static files

docker, nginx, django and how to serve static files

Goal: The set of docker containers for a production django website deployment.
My hang up in this process is that usually nginx directly serves the static files… Based on my understanding of a good architecture using docker, you would have a container for your wsgi server (probably gunicorn), a separate nginx container with an upstream server configuration pointing to your gunicorn container. The nginx container can load balance between multiple gunicorn containers.
But what this implies is that I have to install my django app’s static files in the nginx container, which seems like bad practice since it’s primary goal is really load balancing
Is it better to have three containers: nginx, gunicorn, and a dedicated static server (possibly nginx or lighthttpd) for static files?


Solution 1:

With reference to serving static files, your options depend on the functionality of your application. There’s a very nifty tool called dj-static which will help you serve static files by adding very minimal code.

The documentation is fairly simple and all you have to do is follow these steps.

Solution 2:

I found this answer from Michael Hampton:
“This only works if the processes are in the same host, VM or container, because it tries to make a connection to the same machine. When they are in different containers, it does not work.

You need to alter your nginx configuration so that it uses the internal IP address of the uwsgi container.” Link from the post

And definitely is something you have to keep in mind if you will have Nginx in a different container, also you have to set the nginx.conf, pointing your statics file directory as alias preventing a security issue.

I hope this code work for everybody, it took me a couple of ours to figure about how to compose Gunicorn, docker, and Nginx:

# nginx.conf
  upstream djangoA {
       server $DOCKER_CONTAINER_SERVICE:9000 max_fails=3 fail_timeout=0;
       # In my case looks like: web:9000
Server {
    include mime.types;
    # The port your site will be served on      
    listen 80;
    # the domain name it will serve for
    server_name $YOUR_SERVER_NAME;# substitute your machine's IP address or FQDN
    charset utf-8;
    #Max upload size
    client_max_body_size 512M;   # adjust to taste
    location /site_media {
       alias $DIRECTORY_STATIC_FILES/site_media;#your Django project's media   files have to be inside of the container have nginxs, you can copy them with volumes.
    expires 30d;

    location / {
      try_files $uri @proxy_to_app;

   # Finally, send all non-media requests to the Django server.
   location @proxy_to_app {
     proxy_set_header X-Real-IP $remote_addr;
     proxy_redirect off;
     proxy_set_header Host $host;
     proxy_pass http://djangoA;

And for the docker-compose:

version: '2'

      file: base.yml
      service: db

    image: nginx:latest
      - ./nginx:/etc/nginx/conf.d/
      - ./$STATIC_FILE_ROOT/site_media:/$STATIC_FILE_ROOT/site_media
      - "80:80"
      - web

      file: base.yml
      service: web
        - DJANGO_ENV=production
    command: bash -c "python collectstatic --noinput && chmod 775 -R project/site_media/static && gunicorn project.wsgi:application"
      - "9000:9000"
      - db

    external: true