Docker static files django not serving

I'm trying to set up my Django application in Docker with Nginx to serve static and media files, and Traefik to act as a reverse proxy. I've been struggling to get static and media files to load correctly, despite trying multiple configurations.

I want Nginx to handle static and media files while Traefik manages the reverse proxy and SSL. Below is my docker-compose.yml file.

docker-compose.yml

  # PostgreSQL Database Service
  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${DATABASE_USER}
      POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
      POSTGRES_DB: ${DATABASE_NAME}
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./pg_hba.conf:/var/lib/postgresql/data/pg_hba.conf
    networks:
      - backend-network
    healthcheck:
      test: [ "CMD-SHELL", "pg_isready -U ${DATABASE_USER}" ]
      interval: 10s
      timeout: 5s
      retries: 5
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 2G

  # Redis Cache Service
  redis:
    image: redis:7-alpine
    restart: unless-stopped
    command: [ "redis-server", "--appendonly", "yes", "--requirepass", "${REDIS_PASSWORD}" ]
    volumes:
      - redis_data:/data
    networks:
      - backend-network
    healthcheck:
      test: [ "CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "PING" ]
      interval: 10s
      timeout: 5s
      retries: 5
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M

  # Django Web Application Service
  web:
    image: ganiyevuz/tana-backend:latest
    restart: unless-stopped
    command: >
      /bin/bash -c "
      ./wait_for_db.sh db 5432 &&
      python manage.py collectstatic --noinput &&
      python manage.py migrate &&
      gunicorn conf.wsgi:application --bind 0.0.0.0:8000 --workers 4 --threads 4
      "
    volumes:
      - static_volume:/app/static
      - media_volume:/app/media
    expose:
      - "8000"
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    environment:
      DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY}
      DJANGO_DEBUG: "True"
      DATABASE_USER: ${DATABASE_USER}
      DATABASE_PASSWORD: ${DATABASE_PASSWORD}
      DATABASE_NAME: ${DATABASE_NAME}
      DATABASE_HOST: db
      DATABASE_PORT: 5432
      CELERY_BROKER_URL: redis://:${REDIS_PASSWORD}@redis:6379/0
      CACHE_BACKEND_URL: redis://:${REDIS_PASSWORD}@redis:6379/1
      REDIS_PASSWORD: ${REDIS_PASSWORD}
      ESKIZ_EMAIL: ${ESKIZ_EMAIL}
      ESKIZ_PASSWORD: ${ESKIZ_PASSWORD}
      ESKIZ_AUTH_URL: ${ESKIZ_AUTH_URL}
      ESKIZ_SEND_URL: ${ESKIZ_SEND_URL}
      OPENAI_API_KEY: ${OPENAI_API_KEY}
    networks:
      - backend-network
      - frontend-network
      - monitoring
    labels:
      traefik.enable: "true"
      traefik.http.routers.web.rule: "Host(`${DOMAIN}`)"
      traefik.http.routers.web.entrypoints: "websecure"
      traefik.http.routers.web.tls.certresolver: "le"
      traefik.http.services.web.loadbalancer.server.port: "8000"
      traefik.http.services.web.loadbalancer.sticky: "true"
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '1.0'
          memory: 1G
      restart_policy:
        condition: on-failure

  # Nginx for Serving Static and Media Files
  nginx:
    image: nginx:stable-alpine
    restart: unless-stopped
    volumes:
      - static_volume:/usr/share/nginx/html/static
      - media_volume:/usr/share/nginx/html/media
      - ./nginx_logs:/var/log/nginx
      - ./server/nginx.conf:/etc/nginx/conf.d/default.conf
    networks:
      - frontend-network
    depends_on:
      web:
        condition: service_started
    labels:
      traefik.enable: "true"
      traefik.http.routers.staticfiles.rule: "Host(`${DOMAIN}`) && (PathPrefix(`/static`) || PathPrefix(`/media`))"
      traefik.http.routers.staticfiles.entrypoints: "websecure"
      traefik.http.routers.staticfiles.tls.certresolver: "le"
      traefik.http.services.staticfiles.loadbalancer.server.port: "80"
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 256M

  # Traefik Reverse Proxy and Load Balancer
  traefik:
    image: traefik:v2.10
    restart: unless-stopped
    command:
      - "--api.dashboard=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.le.acme.httpchallenge=true"
      - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
      - "--certificatesresolvers.le.acme.email=ssl@${DOMAIN}"
      - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      - "--log.level=INFO"
      - "--accesslog=true"
      - "--metrics.prometheus=true"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./letsencrypt:/letsencrypt"
    networks:
      - frontend-network
      - backend-network
      - monitoring
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
    labels:
      traefik.enable: "true"
      traefik.http.routers.traefik-dashboard.rule: "Host(`dashboard.tanahealth.uz`)"
      traefik.http.routers.traefik-dashboard.entrypoints: "websecure"
      traefik.http.routers.traefik-dashboard.tls.certresolver: "le"
      traefik.http.services.traefik-dashboard.loadbalancer.server.port: "8080"

  # Prometheus Monitoring Service
  prometheus:
    image: prom/prometheus:latest
    restart: unless-stopped
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
    ports:
      - "9090:9090"
    networks:
      - monitoring
    depends_on:
      - web
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G

  # Grafana Visualization Service
  grafana:
    image: grafana/grafana:latest
    restart: unless-stopped
    ports:
      - "3000:3000"
    volumes:
      - grafana_data:/var/lib/grafana
    networks:
      - monitoring
    depends_on:
      - prometheus
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M

  # PostgreSQL Exporter for Prometheus
  postgres-exporter:
    image: prometheuscommunity/postgres-exporter
    restart: unless-stopped
    environment:
      DATA_SOURCE_NAME: "postgresql://${DATABASE_USER}:${DATABASE_PASSWORD}@db:5432/${DATABASE_NAME}?sslmode=disable"
    networks:
      - backend-network
      - monitoring
    depends_on:
      db:
        condition: service_healthy


  # Redis Exporter for Prometheus
  redis-exporter:
    image: oliver006/redis_exporter
    restart: unless-stopped
    command:
      - "--redis.addr=redis:6379"
      - "--redis.password=${REDIS_PASSWORD}"
    networks:
      - backend-network
      - monitoring
    depends_on:
      redis:
        condition: service_healthy

volumes:
  postgres_data:
  redis_data:
  static_volume:
  media_volume:
  grafana_data:

networks:
  frontend-network:
  backend-network:
  monitoring:

I’ve tried multiple ways to get static and media files working, but so far, none have succeeded. My main issues are:

Configuring Nginx to serve static and media files correctly from the Django container. Ensuring Traefik handles HTTPS and routes requests to the appropriate services (Django app for main traffic, Nginx for static/media).

Here are some specific questions I’m hoping for guidance on:

  • Is the Nginx setup in my docker-compose.yml file correct for serving static and media files?
  • Are the Traefik labels configured properly to handle static/media requests separately from the Django app?

Do I need any additional configuration in Django for static/media files in this setup? Thank you for any insights!

Вернуться на верх