- Created nginx-smartsoltech-fixed.conf with proper SSL and CSRF support - Preserved existing SSL certificates from /etc/letsencrypt/live/www.smartsoltech.kr/ - Added X-Forwarded-Host header (critical for Django CSRF validation) - Fixed location block order (static/media before /) - Implemented proper HTTP→HTTPS and www→non-www redirects - Updated CSRF_FIX.md with comprehensive troubleshooting guide
18 KiB
🔒 Исправление ошибки CSRF 403 в админке через Nginx
❌ Проблема
Ошибка доступа (403)
Ошибка проверки CSRF. Запрос отклонён.
Появляется при входе в админку через Nginx (https://smartsoltech.kr/admin/)
💡 Причина
Django проверяет источник запроса (origin) для защиты от CSRF атак. Когда запрос идёт через Nginx:
- Django видит заголовок
Origin: https://smartsoltech.kr - Но в
CSRF_TRUSTED_ORIGINSнет этого домена - Nginx не передаёт заголовок
X-Forwarded-Host(критично для CSRF) - Django отклоняет запрос как небезопасный
Ваша конфигурация SSL: Сертификаты находятся в /etc/letsencrypt/live/www.smartsoltech.kr/
✅ Решение (2 простых шага)
Шаг 1: Обновить Nginx конфигурацию
# На сервере
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
# Редактировать .env
cd /opt/smartsoltech_site
nano .env
НАЙТИ строку:
CSRF_TRUSTED_ORIGINS=http://localhost:8000,https://smartsoltech.kr
ЗАМЕНИТЬ НА:
CSRF_TRUSTED_ORIGINS=http://localhost:8000,http://smartsoltech.kr,https://smartsoltech.kr,https://www.smartsoltech.kr
Сохранить: Ctrl+O, Enter, Ctrl+X
Перезапустить Django:
docker restart django_app
# Проверить что контейнер запущен
docker ps | grep django_app
Вариант 2: Ручное исправление
Шаг 1: Исправить Nginx конфиг
sudo nano /etc/nginx/sites-available/smartsoltech
Найти секцию location / и добавить заголовки:
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;
...
}
Проверить и перезагрузить:
sudo nginx -t
sudo systemctl reload nginx
Шаг 2: Исправить .env файл
cd /opt/smartsoltech_site
nano .env
Найти строку:
CSRF_TRUSTED_ORIGINS=http://localhost:8000,https://smartsoltech.kr
Заменить на:
CSRF_TRUSTED_ORIGINS=http://localhost:8000,http://smartsoltech.kr,https://smartsoltech.kr
Сохранить: Ctrl+O, Enter, Ctrl+X
Шаг 3: Перезапустить Django
docker compose restart django_app
# Проверить логи
docker logs django_app --tail 50
🧪 Проверка работы
Тест 1: Проверка переменных окружения
# Убедиться что 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: Проверка входа в админку
- Открыть браузер: https://smartsoltech.kr/admin/
- Ввести логин и пароль
- Нажать "Войти"
- ✅ Должен успешно войти без ошибки 403
Тест 3: Проверка Nginx заголовков
# Проверить что Nginx передаёт все нужные заголовки
curl -v https://smartsoltech.kr/admin/ 2>&1 | grep -i forward
# Должны быть:
# X-Forwarded-Proto: https
# X-Forwarded-Host: smartsoltech.kr
🔧 Если проблема осталась
Диагностика 1: Проверить Django логи
# Смотреть логи в реальном времени
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 конфиг
# Проверить что изменения применились
sudo nginx -T | grep -A 10 "location /"
# Должны быть все proxy_set_header, особенно:
# proxy_set_header X-Forwarded-Host $host;
Диагностика 3: Очистить кэш браузера
- Открыть DevTools (F12)
- Перейти в Network
- Правый клик → "Clear browser cache"
- Попробовать войти заново
Диагностика 4: Временно включить DEBUG (ОСТОРОЖНО!)
# ТОЛЬКО ДЛЯ ДИАГНОСТИКИ! Выключить сразу после!
nano /opt/smartsoltech_site/.env
# Изменить
DEBUG=True
# Перезапустить
docker restart django_app
# Открыть админку - увидите детальную ошибку
# СРАЗУ ВЕРНУТЬ:
DEBUG=False
docker restart django_app
📝 Объяснение что было исправлено
Проблема в деталях:
- Браузер → отправляет HTTPS запрос:
https://smartsoltech.kr/admin/login/ - Nginx → принимает HTTPS, проксирует к Django как HTTP:
http://localhost:8000 - Django → проверяет CSRF токен
- Django → сравнивает Origin с CSRF_TRUSTED_ORIGINS
- ❌ Ошибка: В CSRF_TRUSTED_ORIGINS не было
https://smartsoltech.kr - ❌ Ошибка: Nginx не передавал
X-Forwarded-Host→ Django не знал реальный домен - Результат: Django отклонял запрос (403 Forbidden)
Что исправили:
- ✅ Добавили
https://smartsoltech.krв CSRF_TRUSTED_ORIGINS - ✅ Добавили
http://smartsoltech.krдля HTTP→HTTPS redirect - ✅ Nginx передаёт
X-Forwarded-Proto: https - ✅ Nginx передаёт
X-Forwarded-Host: smartsoltech.kr(КРИТИЧНО!) - ✅ Django понимает что оригинальный запрос был HTTPS от smartsoltech.kr
- ✅ CSRF проверка проходит успешно
🔐 Правильная финальная конфигурация
📄 .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:
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;
}
}
⚡ Быстрое решение одной командой
# НА СЕРВЕРЕ (выполнить всё за раз):
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 (безопасность)
📞 Если нужна помощь
Если после всех шагов проблема осталась, отправьте:
# 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 с этим списком:
# В 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 сертификата:
# Можно убрать HTTP, оставить только HTTPS:
CSRF_TRUSTED_ORIGINS=http://localhost:8000,https://smartsoltech.kr,https://www.smartsoltech.kr
🔧 Дополнительные проверки
Если ошибка всё ещё есть:
1. Проверить что Django видит правильные заголовки
# Включить DEBUG=True временно
nano /opt/smartsoltech_site/.env
# DEBUG=True
docker compose restart django_app
# Открыть http://smartsoltech.kr/admin/ в браузере
# Django покажет детальную информацию об ошибке
2. Проверить ALLOWED_HOSTS
# В .env должно быть:
ALLOWED_HOSTS=localhost,127.0.0.1,smartsoltech.kr,www.smartsoltech.kr
3. Проверить что Nginx передаёт правильный Host
# В логах Django должен быть правильный host
docker logs django_app --tail 50 | grep "GET /admin"
# Должно показывать:
# [INFO] "GET /admin/ HTTP/1.1" 200
# Host: smartsoltech.kr
4. Тест с curl
# Симуляция браузера с Origin заголовком
curl -H "Origin: http://smartsoltech.kr" \
-H "Referer: http://smartsoltech.kr/admin/" \
-I http://smartsoltech.kr/admin/login/
# Должно вернуть 200 или 302, НЕ 403
⚠️ Важные замечания
Безопасность
-
DEBUG=False в продакшене - всегда!
DEBUG=False # ✅ В продакшене DEBUG=True # ❌ Только для отладки локально -
HTTPS рекомендуется - после получения SSL:
# Редирект всех HTTP на HTTPS server { listen 80; return 301 https://$host$request_uri; } -
www.smartsoltech.kr - если используется:
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
- Обновить Nginx конфиг (раскомментировать SSL строки)
- Обновить .env:
# Можно убрать HTTP origins (оставить только для localhost) CSRF_TRUSTED_ORIGINS=http://localhost:8000,https://smartsoltech.kr,https://www.smartsoltech.kr - Перезапустить:
sudo systemctl reload nginx docker compose restart django_app
🎯 Быстрое решение (одной командой)
# На сервере выполнить всё сразу:
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