403 Forbidden на PHP-сайте: права, nginx и закрытые директории
403 Forbidden означает, что сервер понял запрос, но не разрешил доступ. Для пользователя это выглядит как закрытая страница. Для разработчика это может быть ошибка прав, document root, отсутствующий index.php, правило nginx, запрет в .htaccess или настройка безопасности.
Сначала важно понять, кто отдаёт 403: приложение, nginx, Apache, CDN или панель хостинга. От этого зависит диагностика.
Проверить код ответа и заголовки
Начать можно с curl. Он покажет статус, сервер и часть заголовков.
curl -I https://example.ru/
curl -I https://example.ru/admin/
Если ответ приходит от nginx до запуска PHP, в логах приложения Yii2 может быть пусто. Тогда нужно смотреть error.log веб-сервера.
tail -n 100 /var/log/nginx/error.log
Document root
Для Yii2 document root должен указывать на директорию web, а не на корень проекта. Если сервер смотрит в неправильную папку, он может закрыть доступ или показать список файлов, если индексация директорий включена.
root /var/www/site.ru/web;
index index.php;
Если root указывает на /var/www/site.ru, наружу могут попасть config, vendor, runtime и другие служебные директории. Это не только ошибка, но и риск безопасности.
Index file
Если пользователь открывает директорию, а index.php или index.html не найден, сервер может вернуть 403 вместо списка файлов.
ls -la web/index.php
В конфиге nginx должен быть указан index:
index index.php index.html;
Права на файлы и директории
Веб-сервер должен иметь право читать файлы и проходить по директориям. Для директорий нужен execute-бит. Для файлов обычно достаточно чтения.
namei -l /var/www/site.ru/web/index.php
ls -la /var/www/site.ru/web
Пример нормальной базовой настройки зависит от пользователя сервера, но идея такая: код читается веб-сервером, а на запись открыты только нужные директории.
find /var/www/site.ru -type d -exec chmod 755 {} \;
find /var/www/site.ru -type f -exec chmod 644 {} \;
После такой команды нужно отдельно вернуть права на запись для runtime, web/assets и uploads, если они есть.
Владелец файлов
После деплоя от root файлы могут принадлежать root, а веб-сервер не сможет их читать или писать в нужные директории. Это особенно заметно на runtime и uploads.
ls -la runtime
ls -la web/assets
ls -la web/uploads
Для writable-директорий:
chown -R www-data:www-data runtime web/assets web/uploads
chmod -R ug+rw runtime web/assets web/uploads
Пользователь www-data — пример. На конкретном сервере это может быть nginx, apache или пользователь хостинга.
Запрет в nginx
403 может быть задан явно. Например, часто закрывают доступ к скрытым файлам, конфигам и служебным директориям.
location ~ /\. {
deny all;
}
Это нормальное правило для .env и .git, но если шаблон location написан слишком широко, он может закрыть лишние URL.
Apache и .htaccess
На Apache стоит проверить .htaccess. В нём может быть Deny from all, Require all denied или старое правило доступа.
grep -R "Deny from all" -n .
grep -R "Require all denied" -n .
Если сайт переносили с Apache на nginx, старые .htaccess уже не работают, и правила нужно переносить в конфиг nginx вручную.
Закрытые разделы приложения
Иногда 403 отдаёт не сервер, а само приложение. Например, пользователь не авторизован или не имеет роли. В Yii2 это может быть AccessControl.
'access' => [
'class' => AccessControl::class,
'rules' => [
[
'allow' => true,
'roles' => ['@'],
],
],
],
В этом случае в логах приложения может быть AccessDeniedHttpException, а веб-серверные логи не покажут ничего полезного.
Чек-лист диагностики
- Проверить curl -I и понять, кто отдаёт 403.
- Проверить document root.
- Проверить наличие web/index.php.
- Проверить права на путь через namei -l.
- Проверить владельца runtime, assets и uploads.
- Проверить deny-правила nginx.
- Проверить .htaccess на Apache.
- Проверить AccessControl, если 403 отдаёт приложение.
403 Forbidden полезно разбирать слоями. Если запрос не дошёл до PHP, нет смысла править Yii2. Если 403 отдаёт приложение, не помогут chmod и chown. Сначала источник ответа, потом исправление.
Комментарии (0)
Пока нет комментариев. Будьте первым!