I Don't know how to serve static files...

I tried everything but I can’t manage to solve this issue, Whenever I go to the admin panel or any page in my website its only html… so here is my setup:

  • 2 docker containers one for the database and one for the django app(running on daphne)
  • The nginx server communicates with the django app as http://localhost:8000/

Here is my settings.py:

STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'  # noqa: F821

docker-compose.yml:

version: '3.9'

services:
  db:
    image: postgres:14.2-alpine
    restart: unless-stopped
    ports:
      - '5432:5432'
    environment:
      POSTGRES_DB: ****
      POSTGRES_USER: ****
      POSTGRES_PASSWORD: ****
    volumes:
      - postgresql-data:/var/lib/postgresql/data
  app:
    build: .
    restart: unless-stopped
    ports:
      - '8000:8000'
    depends_on:
      - db
    environment:
      CTFSETTINGS_DATABASES: '{"default":{"HOST":"db"}}'
      CTFSETTINGS_LOCAL_SETTINGS_PATH: 'local/settings.prod.py'

volumes:
  postgresql-data:
    driver: local

Dockerfile:

FROM python:3.10.4-buster

WORKDIR /opt/project

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV PYTHONPATH .
ENV CTFSETTINGS_IN_DOCKER true

# Install dependencies
RUN set -xe \
    && apt-get update \
    && apt-get install -y --no-install-recommends build-essential \
    && pip install virtualenvwrapper poetry==1.8.2 \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# Copy project files
COPY ["README.md", "Makefile", "./"]
COPY local local
COPY blog blog
COPY core core
COPY framework framework
COPY static static
COPY templates templates
COPY web web

# Copy and install Project dependencies
COPY ["poetry.lock", "pyproject.toml", "manage.py", "./"]
RUN poetry lock --no-update
RUN poetry install --no-root

# Expose the Django development server port (adjust if needed)
EXPOSE 8000

# Setup the entry point
COPY scripts/entrypoint.sh /entrypoint.sh
RUN chmod a+x /entrypoint.sh

ENTRYPOINT [ "/entrypoint.sh" ]

entrypoint.sh:

#!/usr/bin/env bash

set -e

RUN_MANAGE_PY='poetry run python manage.py'

echo 'Collecting static files...'
$RUN_MANAGE_PY collectstatic --no-input

echo 'Running migrations...'
$RUN_MANAGE_PY makemigrations --no-input
$RUN_MANAGE_PY migrate --no-input

exec poetry run daphne web.asgi:application -p 8000 -b 0.0.0.0

Here is the nginx configuration:

server {
    listen 80 default_server;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl default_server;
    ssl_certificate /etc/letsencrypt/live/mysite.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mysite.com/privkey.pem;

    ssl_session_cache shared:le_nginx_SSL:10m;
    ssl_session_timeout 1440m;
    ssl_session_tickets off;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;

    client_max_body_size 20M;

    location /static {
        alias /opt/project/staticfiles/;
    }

    location / {
        proxy_pass http://localhost:8000/;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        proxy_redirect   off;
        proxy_buffering  off;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $http_host;

    }

}

Thanks in advance I have been stuck on this for days so any help is appreciated !

You need to create a shared location for the static files.

Create a data volume for them, map your static root to the path defined for it in your project’s container, and map the nginx location to that same volume.

Your “collectstatic” command would then copy the static files out of your project to that shared location, making them available to nginx.

1 Like

Thank you so much it solved the issue!!! The only problem is the /static/ folder in my app(where my custom static files like main.css and main.js are stored) how to serve this folder?

also for anyone wondering how to implement the solution to the original issue:

Note: with the same setup from the docker file above
docker-compose.yml:

version: '3.9'

services:
  db:
    image: postgres:14.2-alpine
    restart: unless-stopped
    ports:
      - '5432:5432'
    environment:
      POSTGRES_DB: ****
      POSTGRES_USER: *****
      POSTGRES_PASSWORD: ***
    volumes:
      - postgresql-data:/var/lib/postgresql/data
  app:
    build: .
    restart: unless-stopped
    ports:
      - '8000:8000'
    depends_on:
      - db
    environment:
      CTFSETTINGS_DATABASES: '{"default":{"HOST":"db"}}'
      CTFSETTINGS_LOCAL_SETTINGS_PATH: 'local/settings.prod.py'
    volumes:
      - staticfiles:/path/in/container

volumes:
  postgresql-data:
    driver: local

  staticfiles:
    driver: local

Then all you have to do is go to /var/lib/docker/volumes/ (because this is where docker stores volumes on the host machine) and change the permission so the nginx can access them, and in the nginx configuration file add this:

location /static {
    alias /var/lib/docker/volumes/your_volume/
}

Nevermind I found the solution and its staticfiles_dirs and here is why

Again thank you for the help, I will add your name to the special thanks section in my site when I release it (ctframework.com) because I was literally stuck on this for days!!

Hi Ken,

I had the same problem and searched for your answer. Can you clarify how to do this? Because I have a similar configuration and still can’t load css and js.

# Use the official Python image as the base image
ARG ARCH=
FROM ${ARCH}python:3.12-slim as builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --default-timeout=100 --no-cache-dir -r requirements.txt
COPY . /app
RUN mkdir -p /app/static
VOLUME /app/static
RUN python manage.py collectstatic --noinput

FROM ${ARCH}python:3.12-slim
WORKDIR /app
COPY --from=builder /app .
COPY --from=builder /app/static .
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin

EXPOSE 8080

ENV PYTHONUNBUFFERED 1

# Specify the command to run your Django app
CMD ["gunicorn", "--workers=3", "--bind=0.0.0.0:8080", "main.wsgi:application" ]

yaml

   spec:
      volumes:
      - name: static-files
        hostPath:
          path: /app/static
      containers:
        - name: auth
          .............
          ports:
            - containerPort: 8080
          volumeMounts:
          - name: static-files
            mountPath: /app/static

ingress

- host: xxxx.com
    http:
      paths:
      - path: /static/
        pathType: Prefix
        backend:
          service:
            name: auth
            port:
              number: 80
      - path: /
        pathType: Prefix
        backend:
          service:
            name: auth
            port:
              number: 80