BASH
#nginx#directory-structure#virtual-hosts#file-system#organization

Nginx: правильная структура каталогов для нескольких сайтов

Рекомендуемая структура каталогов для хостинга нескольких сайтов на одном сервере. Организация public, logs, releases директорий.

Как использовать

  1. Создайте для каждого сайта каталог /var/www/ДОМЕН/ с подкаталогами public (document root), logs; при деплое — releases.
  2. В nginx в root укажите путь к public; access_log и error_log — в logs/ сайта.
  3. Код приложения, .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 снаружи.

Проверка

  1. Права и доступ 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
  1. Доступ к файлам вне public — убедитесь, что по запросу https://site1.ru/.env или https://site1.ru/../config.php nginx отдаёт 404 или 403, а не содержимое файла. root должен указывать именно на каталог public.

  2. Логи пишутся в нужный каталог — после нескольких запросов проверьте, что в /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.