Команды Хостинг vs VPS PEM→PFX
502 Bad Gateway
504 Gateway Timeout
500 Internal Server Error
403 Forbidden
Почта
SSL
БД
DNS

502 Bad Gateway

Nginx получил неверный ответ от upstream-сервера (PHP-FPM, Node.js, proxy). Бэкенд недоступен, упал или возвращает некорректный HTTP-ответ. Чаще всего встречается в связке Nginx + PHP-FPM.

1
Проверить статус PHP-FPM / бэкенда
Цель: Убедиться что PHP-FPM (или другой бэкенд) запущен. Это самая частая причина 502.
systemctl status php8.2-fpm systemctl status php8.1-fpm ps aux | grep php-fpm | grep -v grep
Если видите active (running) — переходите к шагу 2. Если failed/inactive — переходите к шагу 3.
2
Проверить логи ошибок Nginx
Цель: Найти точную причину 502 в логах Nginx. Там будет написано что именно пошло не так: соединение拒绝了, upstream closed connection и т.д.
tail -50 /var/log/nginx/error.log | grep -i "502" tail -50 /var/log/nginx/error.log | grep -i "upstream" tail -50 /var/log/nginx/error.log | grep -i "connect()"
connect() failed (111: Connection refused) — бэкенд не слушает на указанном порту/сокете.
upstream closed prematurely — бэкенд упал во время обработки.
no live upstreams — все бэкенды в пуле нерабочие.
3
Проверить логи PHP-FPM
Цель: Узнать почему PHP-FPM упал или не работает. В логах могут быть ошибки сегментации, нехватка памяти, ошибки конфигурации.
tail -50 /var/log/php8.2-fpm.log journalctl -u php8.2-fpm --since "1 hour ago" --no-pager
Обратите внимание на: segfault, Out of memory, Address already in use, unable to bind.
4
Проверить сокет / порт PHP-FPM
Цель: Убедиться что Nginx и PHP-FPM используют одинаковый сокет/порт. Расхождение — частая причина 502 после обновления PHP.
grep "listen =" /etc/php/*/fpm/pool.d/www.conf grep "fastcgi_pass" /etc/nginx/sites-enabled/* ls -la /run/php/
Если Nginx настроен на php7.4-fpm.sock, а PHP-FPM слушает php8.2-fpm.sock — исправьте конфиг Nginx.
5
Проверить max_children — перегрузка
Цель: Проверить не достиг ли PHP-FPM лимита дочерних процессов. Когда все worker'ы заняты — новые запросы получают 502.
grep "max_children" /etc/php/*/fpm/pool.d/www.conf ps aux | grep php-fpm | grep -c pool grep "max children reached" /var/log/php8.2-fpm.log | tail -5
Если max children reached встречается в логах — увеличьте pm.max_children. Формула: RAM_в_MB / 50 = примерное кол-во процессов. Для 2GB RAM: pm.max_children = 40.
6
Перезапуск и проверка
Цель: Применить исправления и проверить что 502 ушла.
systemctl restart php8.2-fpm nginx -t systemctl reload nginx curl -sI https://example.com | head -1
Если HTTP/1.1 200 — проблема решена. Если всё ещё 502 — проверьте логи PHP приложения (laravel.log, wordpress debug и т.д.).

Частые причины 502

  • PHP-FPM остановлен или crashed
  • Несовпадение сокета в Nginx и PHP-FPM (после обновления PHP)
  • pm.max_children слишком мал — все worker'ы заняты
  • Нехватка RAM — OOM Killer убил PHP-FPM
  • PHP скрипт использует слишком много памяти и worker падает
  • Firewall блокирует соединение между Nginx и бэкендом

504 Gateway Timeout

Nginx дождался ответа от бэкенда, но тот не уложился в отведённое время. Бэкенд работает, но слишком медленно. Типично для тяжёлых запросов: импорт, экспорт, сложные SQL-запросы, медленные API.

1
Найти таймаут в логах Nginx
Цель: Подтвердить что это именно таймаут и узнать какой URL вызывает проблему.
grep "timed out" /var/log/nginx/error.log | tail -10 grep "upstream timed out" /var/log/nginx/error.log | tail -10
В логе будет видно какой URL вызвал таймаут и какой upstream не ответил. Запомните URL для следующих шагов.
2
Проверить долгие SQL-запросы
Цель: Часто 504 вызван медленным SQL запросом. Нужно найти и оптимизировать его.
mysqladmin -u root -p processlist mysql -u root -p -e "SHOW FULL PROCESSLIST;"
Запросы со статусом Sending data или COPY to tmp table длящиеся более 30 секунд — кандидаты на оптимизацию. Убейте: KILL query_id;
3
Увеличить таймауты Nginx
Цель: Если запрос легитимно долгий (импорт данных, генерация отчёта) — увеличьте таймаут Nginx.
# Добавить в server или location блок Nginx: proxy_read_timeout 300s; proxy_send_timeout 300s; fastcgi_read_timeout 300s; fastcgi_send_timeout 300s;
nginx -t systemctl reload nginx
Увеличение таймаута — временное решение. Найдите и оптимизируйте медленный запрос.
4
Увеличить лимиты PHP
Цель: PHP тоже имеет свой лимит времени выполнения. Если Nginx ждёт 300с, а PHP останавливается через 30с — будет 504.
grep "max_execution_time" /etc/php/8.2/fpm/php.ini grep "request_terminate_timeout" /etc/php/8.2/fpm/pool.d/www.conf
systemctl restart php8.2-fpm
5
Проверить нагрузку на сервер
Цель: Если сервер перегружен (CPU 100%, диск I/O bottleneck), даже быстрые запросы будут тормозить.
uptime top -bn1 | head -15 iostat -x 1 3 free -h
Если %iowait высокий — диск bottleneck. Если load average > кол-ва ядер — сервер перегружен.

Частые причины 504

  • Медленный SQL запрос без индексов
  • Блокировка таблиц в MySQL (LOCK WAIT)
  • Внешний API не отвечает (curl запрос из PHP)
  • PHP request_terminate_timeout слишком мал
  • Nginx proxy_read_timeout / fastcgi_read_timeout слишком мал
  • Сервер перегружен (CPU/disk I/O)

500 Internal Server Error

Сервер столкнулся с непредвиденной ошибкой. Это «универсальная» ошибка — причина может быть в коде PHP, конфигурации Nginx, .htaccess, правах доступа, нехватке памяти. Диагностика идёт через логи.

1
Логи Nginx — первая точка входа
Цель: Посмотреть что записал Nginx в момент ошибки 500.
tail -50 /var/log/nginx/error.log tail -f /var/log/nginx/error.log
Используйте tail -f и обновите страницу в браузере — увидите ошибку в реальном времени.
2
Логи PHP-FPM и PHP приложения
Цель: PHP-FPM часто пишет детали ошибки в свой лог. Также проверьте логи самого приложения.
tail -50 /var/log/php8.2-fpm.log # Laravel tail -50 /var/www/site/storage/logs/laravel.log # WordPress tail -50 /var/www/site/wp-content/debug.log # Symfony tail -50 /var/www/site/var/log/prod.log
3
Включить отображение ошибок PHP
Цель: Если логи молчат, временно включите отображение ошибок PHP для диагностики.
# Создать тестовый файл: cat > /var/www/site/info.php << 'EOF'
Обязательно отключите display_errors после диагностики! Это раскрывает внутреннюю информацию сервера.
4
Проверить .htaccess (Apache)
Цель: На Apache ошибка 500 часто вызвана синтаксической ошибкой в .htaccess.
# Переименовать .htaccess mv /var/www/site/.htaccess /var/www/site/.htaccess.bak # Проверить логи Apache tail -50 /var/log/apache2/error.log
Если после переименования .htaccess сайт заработал — проблема в нём. Восстановите и исправьте построчно.
5
Проверить права и владение файлов
Цель: PHP не может читать файлы с неправильными правами. Типичные правильные права: файлы 644, директории 755, владелец www-data.
# Исправить права: chown -R www-data:www-data /var/www/site find /var/www/site -type d -exec chmod 755 {} \; find /var/www/site -type f -exec chmod 644 {} \;
6
Проверить PHP модули и зависимости
Цель: После обновления PHP или миграции могут отсутствовать необходимые модули (mbstring, xml, curl и т.д.).
php -m | grep -E "mbstring|xml|curl|json|mysqli|pdo" # Установить недостающие apt install php8.2-mbstring php8.2-xml php8.2-curl php8.2-mysql systemctl restart php8.2-fpm

Частые причины 500

  • Синтаксическая ошибка в PHP коде (Parse error)
  • Отсутствует PHP модуль (mbstring, pdo, xml)
  • Неправильные права доступа к файлам
  • Ошибка в .htaccess (Apache)
  • Нехватка памяти: PHP Fatal error: Allowed memory size exhausted
  • Отсутствующие зависимости composer (vendor/)
  • Ошибка подключения к базе данных

403 Forbidden

Сервер понял запрос но отказал в доступе. Это не проблема авторизации (это было бы 401), а проблема прав. Сервер не разрешает доступ к ресурсу по конфигурации, правам файловой системы или правилам файрвола/WAF.

1
Проверить права доступа к файлам
Цель: Самая частая причина 403 — Nginx/Apache не может прочитать файл из-за прав.
ls -la /var/www/site/ ls -la /var/www/site/index.php # Проверить всю цепочку до корня: namei -l /var/www/site/index.php
namei -l покажет права каждого каталога в пути. Для доступа нужны r+x на КАЖДОМ каталоге в цепочке. Владелец файлов должен быть www-data (или тот, под которым работает веб-сервер).
2
Проверить конфиг Nginx — autoindex и deny
Цель: Nginx отдаёт 403 если нет index файла и autoindex выключен, либо есть правило deny.
# Проверить deny правила grep -rn "deny" /etc/nginx/sites-enabled/ grep -rn "autoindex" /etc/nginx/sites-enabled/
Если в директории нет index-файла и autoindex off — Nginx вернёт 403. Добавьте index файл или включите autoindex для листинга директорий.
3
Проверить SELinux / AppArmor
Цель: На CentOS/RHEL SELinux может блокировать доступ веб-сервера к файлам даже при правильных Unix-правах.
# Проверить статус SELinux getenforce # Посмотреть AVC denials ausearch -m AVC -ts recent # Исправить контекст файлов restorecon -Rv /var/www/
Если getenforce возвращает Enforcing — SELinux активен. Команда restorecon восстановит правильные контексты.
4
Проверить IP-блокировки и WAF
Цель: Ваш IP может быть заблокирован файрволом, Fail2ban, Cloudflare или WAF-правилами.
# Проверить свой IP curl -s ifconfig.me # Проверить Fail2ban fail2ban-client status nginx-http-auth # Разбанить свой IP fail2ban-client set sshd unbanip YOUR_IP
5
Проверить логи для точной причины
Цель: Логи точно скажут почему сервер вернул 403.
tail -20 /var/log/nginx/error.log | grep "403" tail -20 /var/log/nginx/access.log | grep "403"
directory index forbidden — нет index файла, autoindex off.
open() ... failed (13: Permission denied) — проблема с правами файловой системы.
access forbidden by rule — правило deny в конфиге Nginx.

Частые причины 403

  • Нет index файла и autoindex отключён
  • Неправильные права доступа (нет r+x для www-data)
  • Правило deny в конфиге Nginx
  • SELinux блокирует доступ (CentOS/RHEL)
  • IP заблокирован Fail2ban или файрволом
  • WAF-правило (Cloudflare, ModSecurity)
  • Файл принадлежит другому пользователю

Почта Письма не доходят / попадают в спам

Одна из самых частых проблем: контактные формы не отправляют письма, уведомления не доходят, или письма попадают в спам. Диагностика идёт от логов почты к DNS-записям.

1
Проверить логи почты
Цель: Узнать отправляет ли сервер письма и что происходит с ними.
tail -50 /var/log/mail.log grep "status=sent" /var/log/mail.log | tail -5 grep "status=bounced" /var/log/mail.log | tail -5 mailq
sent — доставлено. bounced — отклонено получателем (смотрите reason в логе). deferred — задержано (сервер получателя временно недоступен).
2
Проверить SPF, DKIM, DMARC записи
Цель: Без SPF/DKIM/DMARC письма почти гарантированно попадут в спам Gmail, Yahoo, Outlook.
dig example.com TXT | grep "v=spf1" dig mail._domainkey.example.com TXT dig _dmarc.example.com TXT
SPF обязателен: v=spf1 mx a ~all. DKIM — криптографическая подпись. DMARC — начните с p=none для мониторинга. Без этих трёх записей Gmail/Yahoo будут отклонять письма с 2024 года.
3
Проверить PTR (reverse DNS)
Цель: PTR запись должна совпадать с hostname сервера. Многие почтовые серверы отклоняют письма без PTR.
curl -s ifconfig.me dig -x YOUR_IP +short
PTR настраивается в панели хостинг-провайдера (не в DNS панели). На VPS: откройте панель управления сервером → Network/rDNS → установите PTR = hostname. PTR должен совпадать с hostname сервера.
4
Использовать внешний SMTP (рекомендуется)
Цель: Отправка через свой сервер — путь в спам. Используйте внешний SMTP: SendGrid, Mailgun, Amazon SES, SMTP хостинга.
# WordPress: плагин WP Mail SMTP # Подключить через SendGrid, Mailgun, Amazon SES # Или SMTP вашего хостинга (порт 587 с TLS)
Рекомендация: Для сайтов на VPS используйте внешний SMTP. Это решает 95% проблем с доставкой. SendGrid (100 писем/день бесплатно), Mailgun (5000/мес бесплатно), Amazon SES ($0.10 за 1000 писем).

Почему письма попадают в спам

  • Отсутствует SPF запись
  • Отсутствует DKIM подпись
  • Отсутствует DMARC запись
  • PTR запись не настроена или не совпадает с hostname
  • IP сервера в чёрном списке (Spamhaus, SORBS)
  • Отправка с динамического IP (residential)
  • Содержимое письма похоже на спам (ссылки, CAPS, вложения)
  • Отсутствует обратный адрес или он не совпадает с доменом

SSL Проблемы с SSL сертификатами

Сертификат истёк, mixed content, невалидный сертификат, HSTS блокирует доступ. Диагностика и быстрое восстановление.

1
Проверить срок действия сертификата
Цель: Узнать когда истекает сертификат и нужно ли срочное обновление.
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -dates
Если сертификат истёк — срочно обновите: certbot renew --force-renewal и systemctl reload nginx.
2
Срочное обновление истёкшего сертификата
Цель: Быстро восстановить HTTPS.
certbot renew --force-renewal nginx -t && systemctl reload nginx
Если certbot не может пройти валидацию — проверьте что порт 80 открыт и домен правильно резолвится на этот сервер. Cloudflare должен быть в режиме «DNS only» (не прокси) на время валидации.
3
Mixed content — сайт показывает «не защищён»
Цель: Найти и исправить HTTP-ресурсы на HTTPS-странице.
# WordPress — заменить URL в БД: wp search-replace "http://example.com" "https://example.com" --all-tables # Nginx — автоматический upgrade: add_header Content-Security-Policy "upgrade-insecure-requests;" always;
Откройте DevTools (F12) → Console — увидите все mixed content ошибки. Проверьте также внешние ресурсы: шрифты Google Fonts, CDN, API.
4
Настроить автообновление и мониторинг
Цель: Автоматизировать обновление и получать уведомления об истечении.
# Cron — автообновление дважды в день: 0 0,12 * * * certbot renew --quiet --post-hook "systemctl reload nginx" # Проверить cron: crontab -l

Частые проблемы с SSL

  • Сертификат истёк — certbot не смог автообновить
  • Mixed content — ресурсы загружаются по HTTP
  • Сертификат не покрывает www поддомен
  • Cloudflare проксирует и показывает свой сертификат
  • HSTS блокирует доступ после истечения сертификата
  • Цепочка сертификатов неполная (missing intermediate)

БД Ошибка подключения к базе данных

«Error establishing a database connection», «Too many connections», MySQL упал. Диагностика от базовых проверок к оптимизации.

1
Проверить статус MySQL
Цель: Убедиться что MySQL запущен и отвечает.
systemctl status mysql mysqladmin -u root -p ping dmesg | grep -i "oom\|kill" | tail -10
Если OOM Killer убил MySQL — увеличьте RAM, добавьте swap, уменьшите innodb_buffer_pool_size. Если MySQL не запускается — смотрите логи.
2
Проверить credentials и подключение
Цель: Убедиться что имя БД, пользователь и пароль правильные.
# Проверить wp-config.php: grep -E "DB_NAME|DB_USER|DB_PASSWORD|DB_HOST" /var/www/site/wp-config.php # Тест подключения: mysql -u db_user -p -h localhost db_name
3
Too many connections — увеличить лимит
Цель: Увеличить max_connections и найти что создаёт столько подключений.
# Проверить лимиты: SHOW VARIABLES LIKE 'max_connections'; SHOW STATUS LIKE 'Threads_connected'; # Увеличить: SET GLOBAL max_connections = 300;
Каждое подключение MySQL потребляет ~2-5MB RAM. max_connections = 300 = до 1.5GB RAM только на подключения. Используйте пул соединений (PGBouncer для PostgreSQL, ProxySQL для MySQL).
4
Таблицы повреждены — восстановить
Цель: Проверить и восстановить повреждённые таблицы.
# Проверить и восстановить: mysqlcheck -u root -p --check --all-databases mysqlcheck -u root -p --repair --all-databases # Для InnoDB: ALTER TABLE dbname.table_name FORCE;
Всегда делайте бэкап перед repair! Если таблица сильно повреждена — восстановите из бэкапа. Для InnoDB используйте ALTER TABLE ... FORCE вместо REPAIR TABLE.

Частые причины проблем с БД

  • MySQL упал из-за OOM Killer (нехватка RAM)
  • Неверные credentials в конфиге сайта
  • max_connections достигнут — новые подключения отклоняются
  • Таблица повреждена после abrupt shutdown
  • Диск заполнен — MySQL не может писать
  • Медленные запросы блокируют таблицу (LOCK WAIT)
  • InnoDB buffer pool слишком мал — постоянные disk I/O

DNS DNS проблемы

Домен не резолвится, DNS propagation затянулся, сайт недоступен после смены DNS. Диагностика и ускорение propagation.

1
Проверить DNS записи
Цель: Проверить все типы DNS записей для домена.
dig example.com A +short dig example.com MX +short dig example.com NS +short dig example.com TXT +short # Через конкретный DNS: dig @8.8.8.8 example.com A +short
A — IPv4 адрес. AAAA — IPv6. MX — почтовые серверы. NS — серверы имён. TXT — SPF, DKIM, DMARC. CNAME — алиас.
2
Проверить DNS propagation
Цель: Узнать распространились ли изменения DNS по всему миру.
# Проверить TTL: dig example.com A +noall +answer # У разных провайдеров: dig @8.8.8.8 example.com A +short dig @1.1.1.1 example.com A +short
DNS propagation занимает время = TTL старой записи. Если TTL был 86400 (24 часа) — ждите до 24 часов. Перед сменой DNS установите TTL на 300 (5 минут) за 24 часа до изменения.
3
Очистить локальный DNS кеш
Цель: Сбросить кеш на сервере и локальном компьютере.
# Linux (systemd-resolved): sudo systemd-resolve --flush-caches # macOS: sudo dscacheutil -flushcache # Windows: ipconfig /flushdns

Частые DNS проблемы

  • DNS propagation ещё не завершена (ждите TTL)
  • NS серверы указаны неправильно у регистратора
  • A запись указывает на старый IP сервера
  • Отсутствует www CNAME запись
  • MX записи отсутствуют — почта не работает
  • Cloudflare проксирует (оранжевый облако) — валидация SSL не проходит
  • Локальный DNS кеш показывает старые данные