Разместить несколько сайтов на одном VPS — самый рациональный способ хостить свои проекты: вместо трёх-пяти отдельных тарифов вы платите за один сервер, а Nginx раскладывает запросы по доменам с помощью виртуальных хостов (server-блоков). Блог, лендинг, интернет-магазин и пара клиентских сайтов спокойно уживаются на одной машине, если правильно организовать каталоги, изолировать сайты друг от друга через отдельные PHP-FPM пулы и выдать каждому домену свой SSL-сертификат. В этом руководстве настроим всё это пошагово на Ubuntu 24.04 LTS: рабочие конфиги Nginx, catch-all для запросов по IP и правила, которые уберегут от типичных ошибок.
Сколько сайтов потянет один VPS
Nginx выбирает сайт по заголовку Host из запроса браузера, поэтому количество доменов на один IP технически не ограничено. Реальный лимит — ресурсы: CPU, RAM и диск делятся между всеми сайтами. Грубые ориентиры:
- Статические сайты и лендинги — почти ничего не потребляют, десятки штук даже на слабом VPS;
- WordPress / PHP-сайты — считайте по 256–512 МБ RAM на активный сайт (PHP-FPM пул + доля MySQL);
- Магазины и порталы — от 1–2 ГБ RAM на проект, лучше считать индивидуально.
Например, на тарифе Pro у Cheap-Host (12 vCPU, 16 ГБ RAM, 128 ГБ NVMe за 750 ₽/мес) комфортно живут 10–20 сайтов на WordPress — на NVMe-диске параллельная работа нескольких MySQL-баз не превращается в очередь к диску. Приятный бонус: если проектов станет больше, апгрейд CPU/RAM у Cheap-Host делается без переустановки и потери данных.
Шаг 1. DNS и структура каталогов
Для каждого домена создайте A-запись, указывающую на IP вашего сервера (как это делается — в статье о привязке домена к VPS). Пока DNS обновляется, подготовим файловую структуру. Правило простое: один сайт — один каталог и один системный пользователь.
sudo adduser --disabled-password --gecos "" site1
sudo mkdir -p /var/www/site1.ru/public_html
sudo chown -R site1:site1 /var/www/site1.ru
sudo chmod 755 /var/www/site1.ru
Повторите для каждого сайта (site2, site3...). Такая схема даёт две вещи: порядок (всегда понятно, где что лежит) и изоляцию (файлы сайтов принадлежат разным пользователям). Для проверки положим в каталог тестовую страницу:
echo "<h1>site1.ru работает</h1>" | sudo -u site1 tee /var/www/site1.ru/public_html/index.html
Шаг 2. Создаём виртуальные хосты Nginx
Если Nginx ещё не установлен, начните со статьи об установке Nginx на Ubuntu. В Ubuntu конфиги сайтов принято держать в /etc/nginx/sites-available/ и включать симлинками в sites-enabled/. Создайте файл /etc/nginx/sites-available/site1.ru:
server {
listen 80;
listen [::]:80;
server_name site1.ru www.site1.ru;
root /var/www/site1.ru/public_html;
index index.php index.html;
access_log /var/log/nginx/site1.ru.access.log;
error_log /var/log/nginx/site1.ru.error.log;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/site1.sock;
}
location ~ /\.(?!well-known) {
deny all;
}
}
Ключевая директива — server_name: именно по ней Nginx понимает, какому сайту адресован запрос. Для второго сайта скопируйте файл и замените site1 на site2 во всех строках — конфиги полностью независимы. Включите сайты и примените изменения:
sudo ln -s /etc/nginx/sites-available/site1.ru /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/site2.ru /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Отдельные access_log и error_log на каждый сайт — не формальность: когда что-то сломается, вы будете смотреть логи конкретного проекта, а не искать его строки в общей куче.
Шаг 3. Catch-all: что отвечать по IP и чужим доменам
Если запрос не совпал ни с одним server_name, Nginx отдаст первый server-блок по алфавиту — и по голому IP внезапно откроется один из ваших сайтов. Это некрасиво и вредно для SEO (поисковик может проиндексировать сайт по IP как дубль). Закроем дыру блоком-заглушкой /etc/nginx/sites-available/default:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}
Код 444 — специальный для Nginx: соединение просто обрывается без ответа. Боты, сканирующие диапазоны IP, не увидят ничего.
Шаг 4. Отдельный PHP-FPM пул для каждого сайта
По умолчанию все PHP-сайты работают через один пул www под пользователем www-data. Для нескольких сайтов это плохо: взломанный через дырявый плагин сайт сможет читать и менять файлы соседей, а один «прожорливый» проект — съесть все PHP-воркеры. Создайте пул на каждый сайт: файл /etc/php/8.3/fpm/pool.d/site1.conf:
[site1]
user = site1
group = site1
listen = /run/php/site1.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 8
pm.start_servers = 2
pm.min_spare_servers = 2
pm.max_spare_servers = 4
php_admin_value[open_basedir] = /var/www/site1.ru:/tmp
Пул работает под пользователем сайта, слушает собственный сокет (тот самый /run/php/site1.sock из конфига Nginx), а open_basedir запрещает PHP-скриптам выходить за пределы каталога сайта. Значения pm.max_children подбирайте под вашу RAM — методика расчёта есть в статье об оптимизации PHP-FPM. После создания пулов перезапустите службу:
sudo systemctl restart php8.3-fpm
Шаг 5. SSL-сертификат для каждого домена
Каждому сайту — свой бесплатный сертификат Let's Encrypt. Благодаря механизму SNI все они спокойно работают на одном IP-адресе:
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d site1.ru -d www.site1.ru
sudo certbot --nginx -d site2.ru -d www.site2.ru
Certbot сам допишет в server-блоки директивы listen 443 ssl, пути к сертификатам и редирект с HTTP на HTTPS, а также настроит автопродление. Подробности и разбор нюансов — в отдельной статье про Let's Encrypt и certbot.
Обслуживание: как жить с несколькими сайтами дальше
Несколько правил, которые экономят часы при эксплуатации:
- Один сайт — одна база и один пользователь MySQL. Не давайте сайтам общего пользователя БД:
CREATE USER 'site1'@'localhost' ...; GRANT ALL ON site1_db.* TO 'site1'@'localhost'; - Бэкапы по сайтам. Архивируйте каталог и дамп базы каждого проекта отдельно — восстанавливать один сайт проще, чем весь сервер.
- Следите за ресурсами.
htopпокажет, чей PHP-FPM пул ест CPU: процессы подписаны именем пула. - Тестируйте конфиг перед перезагрузкой. Всегда
nginx -tпередreload: ошибка в конфиге одного сайта уронит все.
Типичная структура: шпаргалка
| Что | Где лежит |
|---|---|
| Файлы сайта | /var/www/site1.ru/public_html/ |
| Конфиг Nginx | /etc/nginx/sites-available/site1.ru |
| Включённые сайты | /etc/nginx/sites-enabled/ (симлинки) |
| PHP-FPM пул | /etc/php/8.3/fpm/pool.d/site1.conf |
| Логи сайта | /var/log/nginx/site1.ru.*.log |
| Сертификаты | /etc/letsencrypt/live/site1.ru/ |
FAQ
Сколько сайтов можно разместить на одном VPS?
Ограничение — не количество доменов, а нагрузка. На VPS с 12 vCPU и 16 ГБ RAM (тариф Pro у Cheap-Host, 750 ₽/мес) спокойно живут 10–20 сайтов на WordPress или 30–50 статических. Сам Nginx обслуживает сотни server-блоков без заметных накладных расходов.
Нужен ли отдельный IP для каждого сайта?
Нет. Nginx различает сайты по заголовку Host, а SSL для разных доменов на одном IP работает через SNI, который поддерживают все современные браузеры. Одного выделенного IPv4 хватает на любое число доменов.
Зачем каждому сайту отдельный PHP-FPM пул?
Безопасность (взломанный сайт не дотянется до файлов соседей), стабильность (лимиты воркеров не дают одному сайту съесть всю память) и удобство (свои логи и настройки PHP у каждого проекта).
Почему по IP-адресу открывается один из моих сайтов?
Без default_server Nginx отдаёт на несовпавшие запросы первый попавшийся server-блок. Добавьте catch-all блок с return 444 — и запросы по IP будут обрываться.
Как понять, что VPS перестал справляться?
Load average стабильно выше числа ядер, RAM занята на 80–90%, время ответа растёт. У Cheap-Host в этой ситуации можно апгрейдить CPU, RAM и диск без переустановки и потери данных.
Вывод
Виртуальные хосты Nginx превращают один VPS в полноценную хостинг-площадку: отдельные каталоги, свои PHP-FPM пулы, независимые логи и сертификаты — каждый сайт живёт своей жизнью, а платите вы за один сервер. Настройка первого сайта занимает полчаса, каждый следующий добавляется за пять минут копированием конфигов. Если для этой задачи нужен сервер — у Cheap-Host тариф Pro за 750 ₽/мес: 12 vCPU, 16 ГБ RAM, 128 ГБ NVMe, KVM, безлимитный трафик и деплой за 45–60 секунд. Все тарифы — на cheap-host.onl.