Hacks by Ruddra

Serve Static Files by Nginx from Django using Docker

Serve Static Files by Nginx from Django using Docker

This is more of a follow up post of my previous blog.

Before I start, I am assuming you have successfully deployed django using docker & nginx, but having some problems serving static files.

Steps

No worries, its easy. Just follow these steps:

1. In your django settings.py file, add static file directory i.e. STATIC_ROOT=/static. So what it will do is, when you run collectstatic command(python manage.py collectstatic), it will store the static files in your /static directory of OS.

2. Now in docker-compose.yml folder, lets add a configuration like this:

version: "2"
services:
  nginx:
    image: nginx:latest
    container_name: NGINXDOCKERNAME
    ports:
      - "8000:8000"
    volumes:
      - ./src:/src
      - ./config/nginx:/etc/nginx/conf.d
      - /static:/static  <--- HERE
    depends_on:
      - web
  web:
    build: .
    container_name: DJANGOXDOCKERNAME
    command: bash -c "python manage.py makemigrations && python manage.py migrate && gunicorn mydjango.wsgi -b 0.0.0.0:8000"
    depends_on:
      - db
    volumes:
      - ./src:/src
      - /static:/static    <---- HERE
    expose:
      - "8000"

  db:
    image: postgres:latest
    container_name: PSQLDOCKERNAME

FYI the command argument of the docker compose is same as CMD of Dockerfile. So we can move this inside Dockerfile if we want to(i.e.: CMD python manage.py makemigrations;python manage.py migrate;gunicorn mydjango.wsgi -b 0.0.0.0:8000).

What it will do is that, two containers web and nginx will share a directory named /static.

3. Now lets add few lines in nginx’s config file, i.e mydjango.conf:

upstream web {
  ip_hash;
  server web:8000;
}

server {

    location /static/ {
        autoindex on;
        alias /static/;
    }

    location / {
        proxy_pass http://web/;
    }
    listen 8000;
    server_name localhost;
}

So what it will do is, any request to url like yourhost:yourport/static/* this comes to nginx, it will serve data from /static directory.

4. Now lets run the following command:

docker exec DOCKERNAME /bin/sh -c "python manage.py collectstatic --noinput"

Or update the command key’s value in compose to:

command: bash -c "python manage.py collectstatic --no-input && python manage.py makemigrations && python manage.py migrate && gunicorn mydjango.wsgi -b 0.0.0.0:8000"

It will put static files in /static directory and thats should do the trick. Whenever you hit url with /static will serve static files from that folder. Similarly you can serve media files too. Codes have been updated here at: https://github.com/ruddra/docker-django Cheers!!


Update

If you are interested to run distributed tasks using celery in Docker with Django, then please read this post.

Share Your Thoughts
M ↓   Markdown
Luis Naranjo
Monday, Mar 20, 2017

docker exec dg01 bash -c “python manage.py collectstatic –noinput” This worked for me, not the collectstatic command in the guide

Luis Naranjo
Tuesday, Mar 21, 2017

just kidding this still doesn’t work for me

Mohamed Amr Elgeneidy
Thursday, Mar 30, 2017

@disqus_NRx0k3reSp:disqus from where you have your .yml file try running: docker-compose run <django container name> python manage.py collectstatic. This might also help: https://docs.docker.com/com... bon chance

Giovanni Opromolla
Thursday, Sep 21, 2017

I added: RUN python manage.py collectstatic --noinput to my Dockerfile and it works fine on the web service but the Volume /static still empty in the ngnix service. How can I do to get /static from web copied to /static on nginx ?

Ruddra
Friday, Oct 6, 2017

As far as I know, it should share the directory. I will look into it

Alex
Thursday, Oct 5, 2017

Hi - I’m curious about why in this example the nginx mydjango.conf file specifies listen 8001; while in your previous example it was listen 8000;

Ruddra
Friday, Oct 6, 2017

I don’t think its a big deal, you can change it to :8000 :)

Johannes Nordmann
Monday, Dec 11, 2017

You can ommit/skip step 2. It is not required. Just make sure that in step 3 the alias is the whole path (here /src/static, or in general $WORKDIR/STATIC_ROOT or $WORKDIR/MEDIA_ROOT) and location matches STATIC_URL or MEDIA_URL.

joel
Thursday, Feb 8, 2018

thanks for the post. This helped me a lot!

Thomas Weholt
Wednesday, Feb 28, 2018

I’ve based my current project on the information posted here and it has worked great until I tried deploying my project using docker-machine. It seems like the src-folder containing my app isn’t created properly when running on the remote docker instance but the folders for nginx, which is shared between the djangoproject and nginx are created ok. If I do the exact same and run docker-compose build && docker-compose up locally or log in using ssh and do it on the server it runs just fine. Deploying using docker-machine was sort of the idea to solve my deployment problems so an article based on this one but deploying using docker-machine would be great. Keep up the great work! :-)

Tré Dudman
Monday, Apr 9, 2018

You’re a lifesaver!

TCBullfrog
Friday, Apr 13, 2018

I notice your docker-compose.yml has version:2. I was trying to follow this with version:3, and I was getting errors of

‘Mounts denied: rnThe path /staticrnis not shared from OS X and is not known to Docker.rnYou can configure shared paths from Docker -> Preferences… -> File Sharing’
I ended up changing my docker-compose.yml to use a top-level named volume. So, instead of putting in
 - /static:/static

in web and nginx, I put in

 - static-volume:/static

And at the end of the docker-compose.yml file, I added

volumes:
static-volume:
And it all worked! Thanks for the great tutorials!

Sage Poudel
Friday, May 4, 2018

Thanks for the tutorial. While i was trying to enter docker exec DOCKERNAME /bin/sh -c ‘python manage.py collectstatic –noinput’ Error: No such container: NGINXDOCKERNAME

Humphrey Butau
Wednesday, Jul 11, 2018

This post was a real life server for me. I had been using using uwsgi only to serve my app and the statics and was wondering how to serve the statics with nginx since nginx was on the host OS, and the django app in a docker container.