# 🔒 Исправление ошибки CSRF 403 в админке через Nginx ## ❌ Проблема ``` Ошибка доступа (403) Ошибка проверки CSRF. Запрос отклонён. ``` Появляется при входе в админку через Nginx (https://smartsoltech.kr/admin/) ## 💡 Причина Django проверяет источник запроса (origin) для защиты от CSRF атак. Когда запрос идёт через Nginx: 1. Django видит заголовок `Origin: https://smartsoltech.kr` 2. Но в `CSRF_TRUSTED_ORIGINS` нет этого домена 3. Nginx не передаёт заголовок `X-Forwarded-Host` (критично для CSRF) 4. Django отклоняет запрос как небезопасный **Ваша конфигурация SSL:** Сертификаты находятся в `/etc/letsencrypt/live/www.smartsoltech.kr/` --- ## ✅ Решение (2 простых шага) ### Шаг 1: Обновить Nginx конфигурацию ```bash # На сервере cd /opt/smartsoltech_site git pull origin master # Применить исправленную конфигурацию (сохраняет ваши SSL сертификаты) sudo cp nginx-smartsoltech-fixed.conf /etc/nginx/sites-available/smartsoltech # Проверить синтаксис sudo nginx -t # Если OK - перезагрузить Nginx sudo systemctl reload nginx ``` **Что исправили в Nginx:** - ✅ Добавлен `X-Forwarded-Host: $host` (критично для CSRF) - ✅ Сохранены ваши SSL сертификаты из `/etc/letsencrypt/live/www.smartsoltech.kr/` - ✅ Правильный порядок location блоков (/static/ перед /) - ✅ Redirect www → non-www - ✅ Redirect HTTP → HTTPS ### Шаг 2: Обновить CSRF_TRUSTED_ORIGINS в .env ```bash # Редактировать .env cd /opt/smartsoltech_site nano .env ``` **НАЙТИ строку:** ```env CSRF_TRUSTED_ORIGINS=http://localhost:8000,https://smartsoltech.kr ``` **ЗАМЕНИТЬ НА:** ```env CSRF_TRUSTED_ORIGINS=http://localhost:8000,http://smartsoltech.kr,https://smartsoltech.kr,https://www.smartsoltech.kr ``` **Сохранить:** Ctrl+O, Enter, Ctrl+X **Перезапустить Django:** ```bash docker restart django_app # Проверить что контейнер запущен docker ps | grep django_app ``` --- ### Вариант 2: Ручное исправление #### Шаг 1: Исправить Nginx конфиг ```bash sudo nano /etc/nginx/sites-available/smartsoltech ``` **Найти секцию location / и добавить заголовки:** ```nginx location / { proxy_pass http://localhost:8000; 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 $host; # ДОБАВИТЬ proxy_set_header X-Forwarded-Port $server_port; # ДОБАВИТЬ proxy_redirect off; proxy_buffering off; ... } ``` **Проверить и перезагрузить:** ```bash sudo nginx -t sudo systemctl reload nginx ``` #### Шаг 2: Исправить .env файл ```bash cd /opt/smartsoltech_site nano .env ``` **Найти строку:** ```env CSRF_TRUSTED_ORIGINS=http://localhost:8000,https://smartsoltech.kr ``` **Заменить на:** ```env CSRF_TRUSTED_ORIGINS=http://localhost:8000,http://smartsoltech.kr,https://smartsoltech.kr ``` **Сохранить:** Ctrl+O, Enter, Ctrl+X #### Шаг 3: Перезапустить Django ```bash docker compose restart django_app # Проверить логи docker logs django_app --tail 50 ``` --- ## 🧪 Проверка работы ### Тест 1: Проверка переменных окружения ```bash # Убедиться что Django видит правильный CSRF_TRUSTED_ORIGINS docker exec django_app env | grep CSRF_TRUSTED_ORIGINS # Должен вывести: # CSRF_TRUSTED_ORIGINS=http://localhost:8000,http://smartsoltech.kr,https://smartsoltech.kr,https://www.smartsoltech.kr ``` ### Тест 2: Проверка входа в админку 1. Открыть браузер: **https://smartsoltech.kr/admin/** 2. Ввести логин и пароль 3. Нажать "Войти" 4. ✅ **Должен успешно войти без ошибки 403** ### Тест 3: Проверка Nginx заголовков ```bash # Проверить что Nginx передаёт все нужные заголовки curl -v https://smartsoltech.kr/admin/ 2>&1 | grep -i forward # Должны быть: # X-Forwarded-Proto: https # X-Forwarded-Host: smartsoltech.kr ``` --- ## 🔧 Если проблема осталась ### Диагностика 1: Проверить Django логи ```bash # Смотреть логи в реальном времени docker logs -f django_app # Искать строки с CSRF: # Forbidden (CSRF cookie not set.) # Forbidden (CSRF token missing or incorrect) # Origin checking failed - https://smartsoltech.kr does not match any trusted origins ``` ### Диагностика 2: Проверить Nginx конфиг ```bash # Проверить что изменения применились sudo nginx -T | grep -A 10 "location /" # Должны быть все proxy_set_header, особенно: # proxy_set_header X-Forwarded-Host $host; ``` ### Диагностика 3: Очистить кэш браузера 1. Открыть DevTools (F12) 2. Перейти в Network 3. Правый клик → "Clear browser cache" 4. Попробовать войти заново ### Диагностика 4: Временно включить DEBUG (ОСТОРОЖНО!) ```bash # ТОЛЬКО ДЛЯ ДИАГНОСТИКИ! Выключить сразу после! nano /opt/smartsoltech_site/.env # Изменить DEBUG=True # Перезапустить docker restart django_app # Открыть админку - увидите детальную ошибку # СРАЗУ ВЕРНУТЬ: DEBUG=False docker restart django_app ``` --- ## 📝 Объяснение что было исправлено ### Проблема в деталях: 1. **Браузер** → отправляет HTTPS запрос: `https://smartsoltech.kr/admin/login/` 2. **Nginx** → принимает HTTPS, проксирует к Django как HTTP: `http://localhost:8000` 3. **Django** → проверяет CSRF токен 4. **Django** → сравнивает Origin с CSRF_TRUSTED_ORIGINS 5. **❌ Ошибка:** В CSRF_TRUSTED_ORIGINS не было `https://smartsoltech.kr` 6. **❌ Ошибка:** Nginx не передавал `X-Forwarded-Host` → Django не знал реальный домен 7. **Результат:** Django отклонял запрос (403 Forbidden) ### Что исправили: 1. ✅ Добавили `https://smartsoltech.kr` в CSRF_TRUSTED_ORIGINS 2. ✅ Добавили `http://smartsoltech.kr` для HTTP→HTTPS redirect 3. ✅ Nginx передаёт `X-Forwarded-Proto: https` 4. ✅ Nginx передаёт `X-Forwarded-Host: smartsoltech.kr` (КРИТИЧНО!) 5. ✅ Django понимает что оригинальный запрос был HTTPS от smartsoltech.kr 6. ✅ CSRF проверка проходит успешно --- ## 🔐 Правильная финальная конфигурация ### 📄 .env (на сервере): ```env DEBUG=False ALLOWED_HOSTS=localhost,127.0.0.1,smartsoltech.kr,www.smartsoltech.kr,192.168.0.102 CSRF_TRUSTED_ORIGINS=http://localhost:8000,http://smartsoltech.kr,https://smartsoltech.kr,https://www.smartsoltech.kr ``` ### 📄 Nginx /etc/nginx/sites-available/smartsoltech: ```nginx upstream django_app { server localhost:8000; } # HTTP → HTTPS redirect server { listen 80; server_name smartsoltech.kr www.smartsoltech.kr; return 301 https://$host$request_uri; } # www → non-www redirect server { listen 443 ssl http2; server_name www.smartsoltech.kr; ssl_certificate /etc/letsencrypt/live/www.smartsoltech.kr/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/www.smartsoltech.kr/privkey.pem; return 301 https://smartsoltech.kr$request_uri; } # Main HTTPS server server { listen 443 ssl http2; server_name smartsoltech.kr; # SSL certificates (ваши существующие сертификаты) ssl_certificate /etc/letsencrypt/live/www.smartsoltech.kr/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/www.smartsoltech.kr/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # Security headers add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; # Static files (ПЕРЕД location /) location /static/ { alias /opt/smartsoltech_site/smartsoltech/staticfiles/; expires 30d; add_header Cache-Control "public, immutable"; } location /media/ { alias /opt/smartsoltech_site/smartsoltech/media/; expires 7d; } # Django proxy (с CSRF заголовками) location / { proxy_pass http://django_app; # КРИТИЧНО для CSRF: 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 $host; # ← ВАЖНО! proxy_redirect off; proxy_buffering off; proxy_read_timeout 60s; proxy_connect_timeout 60s; } } ``` --- ## ⚡ Быстрое решение одной командой ```bash # НА СЕРВЕРЕ (выполнить всё за раз): cd /opt/smartsoltech_site && \ git pull origin master && \ sudo cp nginx-smartsoltech-fixed.conf /etc/nginx/sites-available/smartsoltech && \ sudo nginx -t && sudo systemctl reload nginx && \ sed -i 's|CSRF_TRUSTED_ORIGINS=.*|CSRF_TRUSTED_ORIGINS=http://localhost:8000,http://smartsoltech.kr,https://smartsoltech.kr,https://www.smartsoltech.kr|' .env && \ docker restart django_app && \ sleep 3 && \ echo "✅ CSRF исправлен! Проверьте: https://smartsoltech.kr/admin/" && \ docker ps | grep django_app ``` --- ## ✅ Финальный чеклист - [ ] Git pull выполнен (получен nginx-smartsoltech-fixed.conf) - [ ] Nginx конфиг скопирован в /etc/nginx/sites-available/smartsoltech - [ ] `sudo nginx -t` успешно (OK) - [ ] `sudo systemctl reload nginx` выполнен - [ ] CSRF_TRUSTED_ORIGINS обновлён в .env (добавлены http:// и https:// версии) - [ ] `docker restart django_app` выполнен - [ ] Контейнер django_app запущен (docker ps) - [ ] **Вход в админку работает без ошибки 403** ✅ - [ ] DEBUG=False в .env (безопасность) --- ## 📞 Если нужна помощь Если после всех шагов проблема осталась, отправьте: ```bash # 1. Django логи docker logs django_app --tail 100 # 2. Nginx конфиг sudo nginx -T | grep -A 30 "server_name smartsoltech.kr" # 3. Переменные окружения Django docker exec django_app env | grep -E "(CSRF|ALLOWED|DEBUG)" # 4. Тест curl curl -v https://smartsoltech.kr/admin/ 2>&1 | head -50 ``` --- **Создано:** 24 ноября 2025 г. **Проблема:** CSRF 403 ошибка при входе в админку через Nginx + SSL **Решение:** Добавить домен в CSRF_TRUSTED_ORIGINS + исправить Nginx заголовки (X-Forwarded-Host) **Статус:** ✅ Готово к применению # НЕ должно быть: # HTTP/1.1 403 Forbidden ``` ### Проверка 2: Через браузер 1. Открыть http://smartsoltech.kr/admin/ 2. Ввести логин и пароль 3. Нажать "Войти" 4. ✅ Должно успешно войти в админку 5. ❌ НЕ должно показывать ошибку CSRF 403 ### Проверка 3: Логи Django ```bash docker logs django_app --tail 20 | grep -i csrf # НЕ должно быть: # "CSRF verification failed" # "Forbidden (CSRF token missing or incorrect)" ``` --- ## 📝 Понимание настроек CSRF ### CSRF_TRUSTED_ORIGINS - что это? Django сравнивает HTTP заголовок `Origin` с этим списком: ```python # В Django settings.py читается из .env: CSRF_TRUSTED_ORIGINS = [ 'http://localhost:8000', # Для локальной разработки 'http://smartsoltech.kr', # Для HTTP запросов (до получения SSL) 'https://smartsoltech.kr', # Для HTTPS запросов (после SSL) ] ``` ### Когда нужен каждый origin: | Origin | Когда используется | |--------|-------------------| | `http://localhost:8000` | Django напрямую (без Nginx) | | `http://smartsoltech.kr` | Через Nginx БЕЗ SSL | | `https://smartsoltech.kr` | Через Nginx С SSL | ### После получения SSL сертификата: ```env # Можно убрать HTTP, оставить только HTTPS: CSRF_TRUSTED_ORIGINS=http://localhost:8000,https://smartsoltech.kr,https://www.smartsoltech.kr ``` --- ## 🔧 Дополнительные проверки ### Если ошибка всё ещё есть: #### 1. Проверить что Django видит правильные заголовки ```bash # Включить DEBUG=True временно nano /opt/smartsoltech_site/.env # DEBUG=True docker compose restart django_app # Открыть http://smartsoltech.kr/admin/ в браузере # Django покажет детальную информацию об ошибке ``` #### 2. Проверить ALLOWED_HOSTS ```bash # В .env должно быть: ALLOWED_HOSTS=localhost,127.0.0.1,smartsoltech.kr,www.smartsoltech.kr ``` #### 3. Проверить что Nginx передаёт правильный Host ```bash # В логах Django должен быть правильный host docker logs django_app --tail 50 | grep "GET /admin" # Должно показывать: # [INFO] "GET /admin/ HTTP/1.1" 200 # Host: smartsoltech.kr ``` #### 4. Тест с curl ```bash # Симуляция браузера с Origin заголовком curl -H "Origin: http://smartsoltech.kr" \ -H "Referer: http://smartsoltech.kr/admin/" \ -I http://smartsoltech.kr/admin/login/ # Должно вернуть 200 или 302, НЕ 403 ``` --- ## ⚠️ Важные замечания ### Безопасность 1. **DEBUG=False в продакшене** - всегда! ```env DEBUG=False # ✅ В продакшене DEBUG=True # ❌ Только для отладки локально ``` 2. **HTTPS рекомендуется** - после получения SSL: ```nginx # Редирект всех HTTP на HTTPS server { listen 80; return 301 https://$host$request_uri; } ``` 3. **www.smartsoltech.kr** - если используется: ```env ALLOWED_HOSTS=localhost,127.0.0.1,smartsoltech.kr,www.smartsoltech.kr CSRF_TRUSTED_ORIGINS=http://smartsoltech.kr,http://www.smartsoltech.kr,https://smartsoltech.kr,https://www.smartsoltech.kr ``` ### После получения SSL 1. Обновить Nginx конфиг (раскомментировать SSL строки) 2. Обновить .env: ```env # Можно убрать HTTP origins (оставить только для localhost) CSRF_TRUSTED_ORIGINS=http://localhost:8000,https://smartsoltech.kr,https://www.smartsoltech.kr ``` 3. Перезапустить: ```bash sudo systemctl reload nginx docker compose restart django_app ``` --- ## 🎯 Быстрое решение (одной командой) ```bash # На сервере выполнить всё сразу: cd /opt/smartsoltech_site && \ git pull origin master && \ sudo cp nginx-smartsoltech.conf /etc/nginx/sites-available/smartsoltech && \ sudo nginx -t && \ sudo systemctl reload nginx && \ sed -i 's|CSRF_TRUSTED_ORIGINS=.*|CSRF_TRUSTED_ORIGINS=http://localhost:8000,http://smartsoltech.kr,https://smartsoltech.kr|' .env && \ docker compose restart django_app && \ echo "✅ CSRF исправлен! Проверьте: http://smartsoltech.kr/admin/" ``` --- ## 📊 Чеклист исправления - [ ] Nginx конфиг обновлён (добавлены X-Forwarded-Host и X-Forwarded-Port) - [ ] `sudo nginx -t` успешно - [ ] `sudo systemctl reload nginx` выполнен - [ ] `.env` обновлён (добавлен http://smartsoltech.kr в CSRF_TRUSTED_ORIGINS) - [ ] Django перезапущен (`docker compose restart django_app`) - [ ] Админка открывается без ошибки 403 - [ ] Вход в админку работает - [ ] Логи Django без ошибок CSRF --- **Создано:** 24 ноября 2025 г. **Проблема:** CSRF 403 при входе в админку через Nginx **Решение:** Добавить X-Forwarded заголовки в Nginx + добавить http://smartsoltech.kr в CSRF_TRUSTED_ORIGINS