Search code examples
pythondjangocaddycaddyfile

Caddy: How to serve static files from Django


It's my first experience with Caddy and I'm having difficulties configuring it properly concerning static files.

I'm using an Ubuntu server and I'm running Caddy and Django+Gunicorn as Docker containers.

It works perfectly well except that it gives a 404 on static files such as CSS and JS files.

I've collected all static files to their corresponding directories in /home/myusername/static and have the following Caddyfile:

mydomain.com {
  encode gzip
  
  handle_path /static/* {
        root * "/home/myusername/static/"
        file_server
    }

  handle_path /media/* {
        root * "/home/myusername/media/"
        file_server
    }

  reverse_proxy django-gunicorn-container-name:8000
}

What should I do to make Caddy serve static files correctly?

Any suggestions will be much appreciated! Thanks!

EDIT: I'm using the following Dockerfile and Docker-compose.yml

Dockerfile:

FROM python:latest
EXPOSE 8000
WORKDIR /pairs_trade_front_end_docker 
COPY . .
RUN apt-get update
RUN pip install --upgrade pip
RUN pip3 install -r requirements.txt

CMD ["/bin/bash", "-c", "nohup python3 manage.py collectstatic --noinput & nohup python3 manage.py migrate & gunicorn -b 0.0.0.0:8000 setup.wsgi:application"]

docker-compose.yml:

version: '3.9'
services:
  database:
    image: 'postgres:latest'
    container_name: postgres
    ports:
      - 5432:5432
    volumes:
      - ~/postgres-data/:/var/lib/postgresql/data/
      - ./logs:/logs
      - ./postgresql.conf:/etc/postgresql.conf
    env_file:
      - .env
    networks:
       stats-trade-network:
         aliases:
           - postgresForStatsTrade
    healthcheck:
      test: ["CMD-SHELL", "pg_isready"]
      interval: 10s
      timeout: 5s
      retries: 5 
    restart: unless-stopped
           
  webserver:
    image: 'antoniorcampos/pairs-trade:0.9'
    container_name: stats-trade-web-server
    ports:
      - 8000:8000
    volumes:
      - ~/static:/static
    env_file:
      - .env
    networks:
       stats-trade-network:
         aliases:
           - webserverForStatsTrade
    depends_on:
      database:
        condition: service_healthy
    restart: unless-stopped

  caddy:
    image: caddy:latest
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
    networks:
       stats-trade-network:
         aliases:
           - caddyForStatsTrade
    depends_on:
      webserver:
        condition: service_started
      database:
        condition: service_healthy
    restart: unless-stopped

networks:
  stats-trade-network:
    driver: bridge

And then I copy the static files to /home/myusername/static using a basic linux command line cp -r .... I do it using myusername.


Solution

  • The problem: You mount the static folder as volume into your stats-trade-container, so that application can access static. However, you do not mount the static folder into the Caddy container. Change the Caddy section of your docker-compose.yml like so (notice the second line in the volumes part):

    caddy:
        image: caddy:latest
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - ./Caddyfile:/etc/caddy/Caddyfile
          - ~/static:/www/html
        networks:
           stats-trade-network:
             aliases:
               - caddyForStatsTrade
        depends_on:
          webserver:
            condition: service_started
          database:
            condition: service_healthy
        restart: unless-stopped
    

    Now Caddy can access the static files and sees them in the folder /www/html. Next, change the Caddyfile to point Caddy to that folder instead of /home/username….

    handle_path /static/* {
        root * /www/html
        file_server
    }
    

    These changes should make it work.

    P.S.: From the Caddyfile, it looks like you want to do something similar for the "media" folder. You can do it in a similar way, just point it to a different location than /www/html (e.g. /media).