# теория · шаг 1 из 5
Как URI превращается в путь
Коротко
Server-блок выбран, location выбран. Если внутри нет ни proxy_pass, ни
return, nginx ищет файл на диске - и путь к нему строится сложением.
root+ весь URI = путь на диске. Имя location в пути не участвует никак: оно решило, какой блок отвечает, и на этом его роль кончилась.- Пиши
rootодин раз вserver. Продублированный в каждом блоке, он однажды будет забыт, и сайт покажет приветственную страницу дистрибутива. - Каталог без index-файла даёт 403, а не 404. Это не про права.
- Точный путь, который nginx пробовал открыть, всегда лежит в
error_log, и там же написано, чего не хватило: файла или прав.
Если формула root + URI и три исхода на каталоге очевидны - листай до «Теперь сам».
Сначала ответь сам
server {
listen 80;
server_name shop.local;
root /var/www/shop;
location /images/ {
root /var/www/static;
}
}
Запрос GET /images/logo.png. Какой файл откроет nginx?
Инстинктивный ответ - /var/www/static/logo.png: location же «про картинки»,
значит /images/ он и обозначает. Настоящий -
/var/www/static/images/logo.png. Префикс из URI никуда не делся.
На что это похоже
root - это не «переход в каталог», а приставка к адресу.
Представь адрес на конверте: «Ленина, 12, кв. 5». Указание «искать в Заречном районе» не отменяет улицу и дом - оно приписывается спереди: «Заречный район, Ленина, 12, кв. 5». Никто не ждёт, что от адреса при этом отвалится улица.
Ошибка возникает от другой привычки - от cd. В командной строке «зайти в
каталог» действительно меняет точку отсчёта и укорачивает путь. root работает
не так: он ничего не укорачивает, он приписывает.
Механизм: сложение, буква в букву
Строка запроса отрезается заранее: /logo.png?v=3 ищется как /logo.png.
Правило
root + весь URI = путь на диске. Пиши root один раз в server и
переопределяй только там, где каталог действительно другой.
Конфиг, где root продублирован в каждом блоке, ломается предсказуемо: однажды
его забудут в новом location, и запросы уедут в каталог по умолчанию, где лежит
приветственная страница дистрибутива. Симптом «вместо сайта показывается
Welcome to nginx» почти всегда означает именно это.
Разбор: три исхода на запросе к каталогу
Если URI кончается слешем, файла с таким именем не существует по определению -
это каталог. Тут вступает index. Проверено на nginx 1.31.5, в заголовок ответа
выведен $request_filename - путь, который nginx собрался открыть.
root /www;
index index.html;
add_header X-Path "$request_filename" always;
index - какой файл отдать, если запрошен каталог; можно перечислить
несколько, возьмётся первый существующий.
for u in /about.html /docs/ /empty/ /net-takogo; do echo "== $u"; curl -sI localhost$u | grep -E 'HTTP|X-Path'; done
== /about.html
HTTP/1.1 200 OK
X-Path: /www/about.html
== /docs/
HTTP/1.1 200 OK
X-Path: /www/docs/index.html
== /empty/
HTTP/1.1 403 Forbidden
X-Path: /www/empty/
== /net-takogo
HTTP/1.1 404 Not Found
X-Path: /www/net-takogo
grep -E 'HTTP|X-Path' оставляет из заголовков строку статуса и X-Path:
-E разрешает в шаблоне |, «или».
Третий запрос - источник постоянной путаницы. Каталог empty существует, но
index-файла в нём нет, а листинг по умолчанию запрещён. Человек видит 403 и
идёт чинить права доступа, хотя nginx сообщает совсем другое: показывать нечего.
| Что на диске | Директивы | Ответ |
|---|---|---|
docs/index.html есть |
любые | 200, файл |
| каталога нет вовсе | любые | 404 |
| каталог есть, index-файла нет | autoindex off (по умолчанию) |
403 |
| каталог есть, index-файла нет | autoindex on |
200, листинг файлов |
autoindex on - это публикация каталога
Листинг покажет всё, что лежит в каталоге: забытые дампы, .bak, архивы с
исходниками. Включать его стоит осознанно и точечно - на конкретном location с
файлами, которые и должны быть публичными: location /files/ { autoindex on; }.
Разбор: где наивное правило подводит
Наивное правило: «403 - значит, права на файл не те».
Прав может не хватать, но проверять это надо не догадкой. error_log пишет
полный путь и причину. Два запроса на одном сервере:
2026/09/10 19:49:50 [error] 23#23: *4 open() "/www/net-takogo" failed (2: No such file or directory), client: 172.17.0.1, server: , request: "GET /net-takogo HTTP/1.1", host: "localhost"
2026/09/10 19:49:50 [error] 20#20: *5 open() "/www/zakryto/file.txt" failed (13: Permission denied), client: 172.17.0.1, server: , request: "GET /zakryto/file.txt HTTP/1.1", host: "localhost"
Это два разных разговора. Вторая ошибка (13: Permission denied) действительно
про права (r - читать, x у каталога - пройти насквозь, режим 700 - всё
владельцу и ничего остальным; буквы разбирались в уроке установки), и вот там
есть подвох: воркеру мало права r на сам файл. Ему нужно
право x на все каталоги по пути - /var, /var/www, /var/www/shop,
/var/www/shop/images. Классическая засада - файлы разложили в домашний каталог
/home/user/site, а /home/user закрыт режимом 700.
Проверяется это одной командой:
sudo -u www-data namei -l /var/www/shop/images/logo.png
sudo -u www-data запускает команду от имени пользователя, под которым работают
воркеры (в официальном образе Docker он называется nginx), а namei -l
печатает права на каждом уровне пути и сразу показывает, где обрыв.
Что ломается без этого
- «Вместо сайта показывается Welcome to nginx». В этом location забыли
root, и он взялся из настроек по умолчанию. - 403 на каталоге. Нет index-файла, а листинг выключен. Это не про права.
- 404 при том, что файл точно на месте. Смотри
error_log: скорее всего, nginx искал его по другому пути -rootсложился не с тем URI, который ты держишь в голове. - 403 при верных правах на файл. Проверь права на прохождение всех каталогов пути.
Зачем это в работе
Разбор «файл не отдаётся» почти всегда начинается с одного вопроса: какой путь nginx попробовал открыть на самом деле. Пока на него нет ответа, всё остальное - гадание.
Ответ достаётся двумя способами, и оба занимают меньше минуты. На своём
сервере - tail -f /var/log/nginx/error.log и один запрос: в строке будет и
путь, и причина, и какой server-блок отвечал. Там, где в лог не заглянуть, -
временный заголовок с $request_filename, который печатает тот же путь прямо в
ответ.
Убирать такой заголовок перед выкладкой обязательно: раскладка файловой системы наружу не нужна никому, кроме того, кто ищет, что у тебя ещё лежит рядом.
Теперь сам
1. root /var/www; в server и location /static/ { } без своего root.
Где будет искаться /static/app.css?
/var/www/static/app.css. root наследуется, URI приклеивается целиком.
Каталог static внутри /var/www обязан существовать.
2. Хочется отдавать /downloads/ из /mnt/big-disk, причём на диске файлы
лежат прямо в корне, без подкаталога downloads. Сработает ли
location /downloads/ { root /mnt/big-disk; }?
Нет: получится /mnt/big-disk/downloads/..., а такого каталога нет. Либо
завести его на диске, либо взять alias - о нём следующий урок.
3. Запрос /docs/ вернул 403. Каталог существует, права 755. Что
проверить первым?
Наличие index-файла. При autoindex off каталог без него и даёт 403 - и это
самая частая причина. Права проверяются вторыми, командой namei -l от имени
пользователя, под которым работают воркеры.
Главное
root не заменяет путь, а складывает: root + весь URI = файл на диске, и имя
location в пути не участвует. Каталог без index-файла даёт 403, а не 404, а
точный путь и причину отказа всегда пишет error_log.
Комментарии
Пока нет комментариев. Будь первым!
Оставить комментарий