← Назад к вопросам

Как реализовывал статику на продакшн?

2.0 Middle🔥 121 комментариев
#DevOps и инфраструктура#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как реализовывал статику на продакшн

Управление статическими файлами (CSS, JS, изображения, шрифты) на production — критически важная часть развёртывания Django приложений. Разберёмся со всеми компонентами.

Проблема: Django не сервирует статику на production

Django в development режиме автоматически сервирует статические файлы через встроенный django.contrib.staticfiles. Но на production это небезопасно и неэффективно:

# development (works автоматически)
DEBUG = True  # django.contrib.staticfiles слушает статику

# production (НЕ работает!)
DEBUG = False  # Статика 404, если её не обслуживает nginx/apache

Шаг 1: Конфигурация Django settings

# settings/production.py

import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

# Основная конфигурация
DEBUG = False
ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com']

# Статические файлы
STATIC_URL = '/static/'  # URL по которому доступна статика
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')  # Где собираются файлы

# Для production с CDN
if not DEBUG:
    STATIC_URL = 'https://cdn.yourdomain.com/static/'  # CDN URL
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

# Media файлы (загрузки пользователей)
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

# Whitenoise для сервирования статики (если без nginx)
MIDDLEWARE = [
    'whitenoise.middleware.WhiteNoiseMiddleware',  # Добавляем первым
    'django.middleware.security.SecurityMiddleware',
    # ... остальное middleware
]

# Кэширование статики (1 год)
if not DEBUG:
    WHITENOISE_AUTOREFRESH = False
    WHITENOISE_USE_FINDERS = True

Шаг 2: Сбор статических файлов

# Локально перед деплоем
python manage.py collectstatic --noinput --clear

# Что это делает:
# 1. Находит все static файлы в приложениях
# 2. Копирует их в STATIC_ROOT
# 3. Минифицирует CSS/JS (если установлен WhiteNoise)
# 4. Создаёт manifest для кэширования

Результат структуры:

projectroot/
├── staticfiles/          # STATIC_ROOT
│   ├── admin/
│   ├── css/
│   │   ├── style.min.css
│   │   └── style.min.css.gz  # Gzip версия
│   ├── js/
│   ├── images/
│   └── staticfiles.json  # Manifest для хэширования
├── myapp/
│   ├── static/
│   │   ├── css/
│   │   ├── js/
│   │   └── images/

Шаг 3: Сервирование статики на production

Вариант A: С Nginx (Рекомендуется)

# /etc/nginx/sites-available/yourdomain.com

upstream django_app {
    server 127.0.0.1:8000;
}

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    
    # Статические файлы
    location /static/ {
        alias /home/appuser/myproject/staticfiles/;
        # Кэширование на 1 год для хэшированных файлов
        expires 1y;
        add_header Cache-Control "public, immutable";
        # Gzip уже включен на уровне Nginx
    }
    
    # Media (загрузки пользователей)
    location /media/ {
        alias /home/appuser/myproject/media/;
        expires 7d;
        add_header Cache-Control "public";
    }
    
    # Django приложение
    location / {
        proxy_pass http://django_app;
        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;
    }
}

Проверка Nginx конфига:

sudo nginx -t
sudo systemctl reload nginx

Вариант B: С WhiteNoise (Простой, без Nginx)

Dля маленьких приложений или тестирования:

# settings.py
MIDDLEWARE = [
    'whitenoise.middleware.WhiteNoiseMiddleware',
    # ... остальное
]

# settings/production.py
if not DEBUG:
    # WhiteNoise с хэшированием файлов
    STATIC_URL = '/static/'
    WHITENOISE_AUTOREFRESH = False
    WHITENOISE_USE_FINDERS = True
    WHITENOISE_MIMETYPES = {
        '.webp': 'image/webp',
        '.woff2': 'font/woff2',
    }

Установка:

pip install whitenoise

Вариант C: С CDN (CloudFlare, AWS S3)

Для скорости и масштабируемости:

# settings/production.py
import os

if os.getenv('USE_S3') == 'True':
    # AWS S3
    import boto3
    
    AWS_STORAGE_BUCKET_NAME = 'my-bucket-name'
    AWS_S3_REGION_NAME = 'eu-central-1'
    AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
    
    STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/static/'
    STATIC_ROOT = 'static/'
    
    # Использование django-storages
    STORAGES = {
        'default': 'storages.backends.s3boto3.S3Boto3Storage',
        'staticfiles': 'storages.backends.s3boto3.S3StaticStorage',
    }
    
    AWS_QUERYSTRING_AUTH = False  # Публичные файлы
    AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
else:
    # Локальная статика
    STATIC_URL = '/static/'
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

Установка:

pip install django-storages[s3]
pip install boto3

Загрузка в S3:

python manage.py collectstatic --noinput

Шаг 4: Оптимизация для production

Минификация CSS/JS

# settings/production.py

if not DEBUG:
    # Минификация через WhiteNoise
    STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
    
    # Или если используешь webpack/gulp — просто указываешь готовые файлы
    # Структура:
    # static/
    #   ├── js/
    #   │   └── main.min.js
    #   ├── css/
    #   │   └── style.min.css

Хеширование файлов (Cache busting)

# settings/production.py
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'

# В templates:
# {% load static %}
# <link rel="stylesheet" href="{% static 'css/style.css' %}">
# Результат: <link rel="stylesheet" href="/static/css/style.a1b2c3d4.css">

Сжатие Gzip

# nginx.conf
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
gzip_min_length 1000;
gzip_comp_level 6;

Шаг 5: Deploy процесс

#!/bin/bash
# deploy.sh

set -e

echo "Pulling code..."
git pull origin main

echo "Installing dependencies..."
pip install -r requirements.txt

echo "Running migrations..."
python manage.py migrate

echo "Collecting static files..."
python manage.py collectstatic --noinput --clear

echo "Restarting service..."
sudo systemctl restart gunicorn
sudo systemctl restart nginx

echo "Deploy complete!"

Шаг 6: Проверка на production

# 1. Проверить, что статика собрана
ls -la staticfiles/

# 2. Проверить CSS в браузере
curl -I https://yourdomain.com/static/admin/css/base.css
# HTTP/1.1 200 OK
# Cache-Control: public, max-age=31536000, immutable

# 3. Проверить источник страницы
# <link rel="stylesheet" href="/static/admin/css/base.a1b2c3.css">

# 4. Проверить размер и сжатие
du -sh staticfiles/

Полный checklist

  • DEBUG = False в production settings
  • STATIC_URL и STATIC_ROOT правильно сконфигурированы
  • Запущен python manage.py collectstatic
  • Nginx/Apache сконфигурирован для сервирования /static/
  • Кэширование заголовков установлено (Cache-Control, Expires)
  • Gzip сжатие включено
  • HTTPS используется
  • CDN/S3 настроен (если нужен)
  • Медиа файлы также обслуживаются
  • Тестирование: всё ли работает из браузера

Типичные ошибки

# ❌ Ошибка 1: Забыл collectstatic
python manage.py runserver  # static работает
# Но на production — 404!

# ✅ Решение
python manage.py collectstatic --noinput

# ❌ Ошибка 2: DEBUG = True на production
DEBUG = True  # Django сервирует статику, но медленно

# ✅ Решение
DEBUG = False
# Используй Nginx для статики

# ❌ Ошибка 3: STATIC_ROOT и STATIC_URL в одной папке
STATIC_URL = '/static/'
STATIC_ROOT = '/var/www/static/'  # Неправильно, если оба указывают одну папку

# ✅ Решение
STATIC_URL = '/static/'
STATIC_ROOT = '/var/www/staticfiles/'  # Отдельная папка
Как реализовывал статику на продакшн? | PrepBro