Nginx: правильная структура каталогов для нескольких сайтов
Рекомендуемая структура каталогов для хостинга нескольких сайтов на одном сервере. Организация public, logs, releases директорий.
Как использовать
- Создайте для каждого сайта каталог /var/www/ДОМЕН/ с подкаталогами public (document root), logs; при деплое — releases.
- В nginx в root укажите путь к public; access_log и error_log — в logs/ сайта.
- Код приложения, .env, config, vendor держите вне public, чтобы они не были доступны по URL.
При нескольких сайтах на одном сервере удобно держать каждый сайт в отдельном каталоге с единой структурой: document root в подкаталоге (например public/), логи отдельно, при деплое — releases. Проблема: если в root nginx указать корень проекта, в веб попадают .env, config, vendor — риск утечки секретов и исполняемого кода. Симптомы: доступ к .env по URL, 403/404 из-за неверного root, логи вперемешку. Ниже — рекомендуемая структура каталогов, команды создания, пример конфига nginx и проверка прав по практике nginx и деплоя.
Решение
Правильная структура каталогов для хостинга нескольких сайтов: безопасность (только public доступен из веба), отдельные логи, при необходимости — releases для деплоя.
Рекомендуемая структура
/var/www/
├── site1.ru/
│ ├── public/ # Корневая директория сайта (root в nginx)
│ ├── logs/ # Логи сайта
│ └── releases/ # Релизы для деплоя (опционально)
├── site2.ru/
│ ├── public/
│ └── logs/
└── api.site3.ru/
├── public/
└── logs/
Создание структуры для нового сайта
mkdir -p /var/www/site1.ru/{public,logs,releases}
chown -R www-data:www-data /var/www/site1.ru
chmod -R 755 /var/www/site1.ru
echo "Hello from site1.ru" > /var/www/site1.ru/public/index.html
Скрипт для создания структуры сайта
#!/bin/bash
SITE_DOMAIN=$1
[ -z "$SITE_DOMAIN" ] && { echo "Usage: $0 <domain>"; exit 1; }
SITE_DIR="/var/www/$SITE_DOMAIN"
mkdir -p "$SITE_DIR"/{public,logs,releases}
chown -R www-data:www-data "$SITE_DIR"
chmod -R 755 "$SITE_DIR"
echo "<h1>Welcome to $SITE_DOMAIN</h1>" > "$SITE_DIR/public/index.html"
echo "✅ Структура создана: $SITE_DIR"
Использование: chmod +x create-site-structure.sh && ./create-site-structure.sh site1.ru
Почему public — обязательно
Без отдельного document root в веб попадают файлы из корня проекта:
# ❌ Плохо: root = /var/www/site1.ru
# .env, config.php, vendor доступны по URL
# ✅ Хорошо: root = /var/www/site1.ru/public
# Только public доступен из веба
Конфигурация Nginx
server {
listen 80;
server_name site1.ru;
root /var/www/site1.ru/public;
index index.html index.php;
access_log /var/www/site1.ru/logs/access.log;
error_log /var/www/site1.ru/logs/error.log;
location / {
try_files $uri $uri/ =404;
}
}
PHP / Node / Python
Для PHP: в root только public/ (index.php, assets); app/, config/, vendor/, .env — вне public. Для Node/Python: аналогично — статика или точка входа в public, код и .env снаружи.
Проверка
- Права и доступ nginx — пользователь nginx (часто www-data) должен читать public и писать в logs:
ls -la /var/www/site1.ru/
sudo -u www-data cat /var/www/site1.ru/public/index.html
sudo -u www-data touch /var/www/site1.ru/logs/test.log && rm /var/www/site1.ru/logs/test.log
-
Доступ к файлам вне public — убедитесь, что по запросу
https://site1.ru/.envилиhttps://site1.ru/../config.phpnginx отдаёт 404 или 403, а не содержимое файла. root должен указывать именно на каталог public. -
Логи пишутся в нужный каталог — после нескольких запросов проверьте, что в
/var/www/site1.ru/logs/появились access.log и error.log и в них есть записи.
Типичные ошибки
- root указывает на корень сайта, а не на public — тогда по URL доступны все файлы в корне. Всегда задавайте root на подкаталог (public), в котором только то, что разрешено отдавать.
- Логи в общем /var/log/nginx/ — для нескольких сайтов удобнее отдельный лог на сайт (проще ротация и анализ по сайту). Указывайте access_log и error_log с путём в каталог сайта.
- Владелец и права — nginx читает файлы от пользователя, указанного в конфиге (например www-data). chown -R www-data:www-data на каталог сайта; для записи логов nginx должен иметь право записи в logs/.
Где применять
- Prod: VPS/выделенный сервер с несколькими виртуальными хостами nginx; статика, PHP, Node, Python — единая схема с public и logs.
- CI/CD: деплой в releases/ и симлинк current → public упрощает откат и историю релизов.
Связанные сниппеты: Анализ логов nginx: топ IP и URL по 404, Nginx и SSL Let’s Encrypt в BitrixVM, Nginx: WordPress и PHP-FPM.