Что необходимо перед настройкой Nginx
В этом руководстве используются Ubuntu 24.04 LTS, Nginx, PHP-FPM, MariaDB и два примерных домена: site1.com и site2.com. Замените эти имена на свои реальные домены. Такая конфигурация подходит для статических сайтов, WordPress, Laravel, PHP-приложений, сайтов документации и небольших API.
Минимальные требования для production
- CPU: 4 vCPU для нескольких лёгких сайтов; для постоянного трафика или приложений с высокой нагрузкой на CPU используйте выделенные физические ядра.
- Память: минимум 8 ГБ RAM. Выделите больше памяти, если несколько сайтов используют PHP, MariaDB, Redis или поисковые сервисы.
- Хранилище: минимум 100 ГБ NVMe SSD, резервные копии должны храниться отдельно.
- Операционная система: Ubuntu 24.04 LTS с доступом root или sudo.
- Сеть: статический публичный IPv4-адрес и корректно настроенный DNS.
- Доступ: SSH-клиент и локальная копия каждого сайта.
VPS достаточно для нескольких сайтов с небольшим трафиком, однако для постоянного трафика, больших баз данных, строгой изоляции или предсказуемой производительности диска и CPU предпочтительнее выделенный или bare-metal сервер. Один сервер также создаёт единую точку отказа, поэтому храните резервные копии вне сервера и подготовьте план восстановления.
Планирование производительности production-сервера
Используйте приведённую ниже таблицу как отправную точку для выбора конфигурации production-сервера; фактическая производительность зависит от кэширования, кода приложения, запросов к базе данных, размеров изображений и характера трафика.
| Масштаб: активные сайты и суммарная пиковая нагрузка | vCPU | RAM | Диск | Ежемесячный трафик |
|---|---|---|---|---|
| 5 сайтов, до 20 динамических запросов/с | 4 vCPU | 8 ГБ | 160 ГБ NVMe SSD | 5 ТБ |
| 20 сайтов, до 100 динамических запросов/с | 8 vCPU | 32 ГБ | 480 ГБ NVMe SSD | 15 ТБ |
| 50 сайтов, до 300 динамических запросов/с | 16 выделенных ядер | 64 ГБ | 960 ГБ NVMe SSD с RAID1 | 30 ТБ |
Для постоянного трафика, баз данных или клиентов, которым требуется изоляция, выбирайте bare-metal с выделенными ядрами и корпоративным NVMe-хранилищем вместо перегруженного небольшого VPS.
Шаг 1: Обновите Ubuntu и создайте административного пользователя
Подключитесь по SSH, обновите пакеты и создайте учётную запись без прав root. Замените deploy на выбранное имя пользователя.
ssh root@SERVER_IP
apt update && apt -y full-upgrade
apt install -y sudo
adduser deploy
usermod -aG sudo deploy
Скопируйте свой SSH-ключ в новую учётную запись до отключения входа root:
ssh-copy-id deploy@SERVER_IP
ssh deploy@SERVER_IP
sudo hostnamectl set-hostname web01.example.net
После подтверждения работы входа по ключу отредактируйте настройки SSH:
sudo nano /etc/ssh/sshd_configУстановите PermitRootLogin no и, если каждый администратор использует ключи, установите PasswordAuthentication no. Проверьте конфигурацию и перезагрузите настройки:
sudo sshd -t && sudo systemctl reload ssh
Шаг 2: Установите Nginx, PHP-FPM, MariaDB и инструменты firewall
Установите веб-стек и распространённые расширения PHP. Удалите расширения, которые не нужны вашим приложениям.
sudo apt install -y nginx mariadb-server php-fpm php-mysql php-curl php-gd php-mbstring php-xml php-zip php-intl unzip curl ufw fail2ban
sudo systemctl enable --now nginx mariadb php8.3-fpm fail2ban
sudo mariadb-secure-installationПроверьте сокет установленного PHP-FPM, поскольку версия может отличаться в другом выпуске Ubuntu:
ls /run/php/php*-fpm.sock
systemctl status nginx --no-pager
Откройте только необходимые публичные службы. По возможности ограничьте SSH доверенным диапазоном IP-адресов.
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw --force enable
sudo ufw status verboseШаг 3: Создайте отдельные каталоги и настройте права
Назначьте каждому сайту собственный корень документов. Разделение сайтов упрощает развёртывание, настройку прав, работу с журналами и последующую миграцию.
sudo mkdir -p /var/www/site1.com/public
sudo mkdir -p /var/www/site2.com/public
sudo chown -R deploy:www-data /var/www/site1.com /var/www/site2.com
sudo find /var/www/site1.com /var/www/site2.com -type d -exec chmod 755 {} \;
sudo find /var/www/site1.com /var/www/site2.com -type f -exec chmod 644 {} \;
Создайте тестовые файлы:
printf '%s\n' '<h1>site1.com works</h1>' | sudo tee /var/www/site1.com/public/index.html
printf '%s\n' '<h1>site2.com works</h1>' | sudo tee /var/www/site2.com/public/index.html
Для WordPress или другого PHP-приложения загрузите файлы в соответствующий каталог public и убедитесь, что права на запись для веб-процесса имеют только каталоги, которым она необходима, например для загрузки файлов.
Шаг 4: Настройте серверные блоки Nginx
Nginx выбирает серверный блок на основе запрошенного имени хоста. Создайте отдельный конфигурационный файл для каждого сайта.
sudo nano /etc/nginx/sites-available/site1.comИспользуйте эту конфигурацию для статического сайта или PHP-сайта:
server {
listen 80;
listen [::]:80;
server_name site1.com www.site1.com;
root /var/www/site1.com/public;
index index.php index.html;
access_log /var/log/nginx/site1.access.log;
error_log /var/log/nginx/site1.error.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
Создайте второй блок, изменив домен и путь:
sudo cp /etc/nginx/sites-available/site1.com /etc/nginx/sites-available/site2.com
sudo sed -i 's/site1\.com/site2.com/g; s#/var/www/site1.com#/var/www/site2.com#g; s#site1#site2#g' /etc/nginx/sites-available/site2.com
sudo ln -s /etc/nginx/sites-available/site1.com /etc/nginx/sites-enabled/site1.com
sudo ln -s /etc/nginx/sites-available/site2.com /etc/nginx/sites-enabled/site2.com
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx
Правило try_files подходит для многих приложений с front controller. Для полностью статического сайта вместо него можно использовать try_files $uri $uri/ =404;, что исключает передачу неизвестных путей в PHP.
Шаг 5: Направьте DNS-записи на выделенный сервер
У вашего DNS-провайдера создайте следующие записи:
- Запись
Aдляsite1.com, указывающую на IPv4-адрес сервера. - Запись
Aдляwww.site1.com, указывающую на тот же адрес, или CNAME-запись наsite1.com. - Аналогичные записи для
site2.comиwww.site2.com. - Запись
AAAAтолько в том случае, если IPv6 настроен и протестирован на сервере.
Проверьте DNS перед запросом сертификатов:
sudo apt install -y dnsutils
dig +short site1.com A
dig +short site2.com A
curl -I http://site1.com
Изменения DNS могут применяться с задержкой из-за кэшированных значений TTL. Ответ команды dig должен содержать адрес сервера, прежде чем продолжать.
Шаг 6: Включите HTTPS с помощью Let's Encrypt
Установите Certbot и запросите для каждого сайта один сертификат, охватывающий основной домен и имя хоста www.
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d site1.com -d www.site1.com
sudo certbot --nginx -d site2.com -d www.site2.com
Когда Certbot спросит, следует ли перенаправлять HTTP на HTTPS, выберите вариант перенаправления. Проверьте продление без изменения действующих сертификатов:
sudo certbot renew --dry-run
sudo nginx -t
curl -I https://site1.com
curl -I https://site2.com
Оставьте порты 80 и 443 открытыми, поскольку для продления сертификата через HTTP-01 требуется порт 80, если только вы не используете проверку DNS.
Шаг 7: Добавьте изоляцию PHP-FPM и пользователей баз данных
Для нескольких независимых PHP-приложений отдельные пулы PHP-FPM уменьшают доступ между сайтами и упрощают применение ограничений ресурсов. Создайте пул для site1:
sudo nano /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 = 12
pm.start_servers = 2
pm.min_spare_servers = 2
pm.max_spare_servers = 4
php_admin_value[open_basedir] = /var/www/site1.com:/tmp
Создайте системного пользователя и повторите настройку пула со значениями для site2:
sudo useradd --system --home /var/www/site1.com --shell /usr/sbin/nologin site1
sudo chown -R site1:site1 /var/www/site1.com
sudo systemctl restart php8.3-fpm
sudo systemctl status php8.3-fpm --no-pager
Измените строку PHP в Nginx для site1 на fastcgi_pass unix:/run/php/site1.sock;. Не устанавливайте слишком высокое значение pm.max_children: практическая отправная точка — от 2 до 4 рабочих процессов на каждый ГБ RAM, доступный PHP, после чего значение следует скорректировать на основе измеренного потребления памяти рабочими процессами.
Создайте отдельные учётные данные MariaDB вместо использования root:
sudo mariadbCREATE DATABASE site1db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'site1user'@'localhost' IDENTIFIED BY 'CHANGE_THIS_LONG_PASSWORD';
GRANT ALL PRIVILEGES ON site1db.* TO 'site1user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Шаг 8: Проверьте каждый сайт и просматривайте журналы
Проверьте синтаксис конфигурации, HTTP-статус, маршрутизацию виртуальных хостов, выполнение PHP и продление сертификатов:
sudo nginx -t
curl -I https://site1.com
curl -I https://site2.com
curl -s https://site1.com | head
sudo tail -f /var/log/nginx/site1.access.log /var/log/nginx/site1.error.log
Проверьте маршрутизацию по имени хоста напрямую через адрес сервера, если DNS ещё не готов:
curl --resolve site1.com:80:SERVER_IP http://site1.com
curl --resolve site2.com:80:SERVER_IP http://site2.com
Контролируйте нагрузку на ресурсы с помощью:
free -h
uptime
df -h
sudo systemctl --failed
sudo journalctl -u nginx -u php8.3-fpm --since '1 hour ago'
Настройте ротацию журналов, собирайте метрики CPU, RAM, задержки диска, использования диска, кодов HTTP-ответов и срока действия сертификатов, а также храните как минимум одну резервную копию вне сервера. Дамп базы данных можно создать с помощью:
sudo mysqldump --single-transaction site1db | gzip | sudo tee /var/backups/site1db-$(date +%F).sql.gz > /dev/nullУстранение распространённых проблем
Каждый домен отображает один и тот же сайт
Убедитесь, что каждый server_name указан правильно, сайт включён, а блок по умолчанию удалён. Выполните sudo nginx -T и найдите дублирующиеся имена хостов.
Nginx возвращает ошибку 403 Forbidden
Убедитесь, что корень документов существует, каталоги имеют право на выполнение, а пользователь Nginx может пройти по всему пути:
namei -l /var/www/site1.com/public
sudo tail -n 50 /var/log/nginx/site1.error.logPHP возвращает ошибку 502 Bad Gateway
Сокет PHP-FPM может быть указан неправильно или служба может быть остановлена. Выполните:
ls -l /run/php/
sudo systemctl status php8.3-fpm
sudo journalctl -u php8.3-fpm -n 50 --no-pagerCertbot не может подтвердить домен
Проверьте, что DNS указывает на этот сервер, порт 80 доступен, а Nginx загружает правильный серверный блок. Прокси или CDN также должны корректно передавать запросы HTTP-проверки.
Один сайт потребляет все ресурсы
Проверьте журналы доступа и рабочие процессы PHP-FPM, включите кэширование приложения, ограничьте размеры загрузок и уменьшите ограничения пула этого сайта. При наличии проблем с «шумными соседями» или требований соответствия перенесите приложение на отдельный VPS или выделенный сервер.
Рекомендации по эксплуатации
- Используйте файлы развёртывания под контролем версий и перед каждой перезагрузкой проверяйте изменения Nginx с помощью
nginx -t. - Обновляйте приложения, плагины, пакеты Ubuntu и PHP.
- Используйте отдельные пользователей Unix, базы данных, журналы и каталоги развёртывания для каждого сайта.
- Включите автоматическое резервное копирование и периодически выполняйте полную проверку восстановления.
- Используйте CDN или объектное хранилище для крупных статических ресурсов и видео, чтобы не расходовать весь трафик сервера.
- Для почты используйте отдельный специализированный почтовый сервис или сервер, если доставляемость и репутация критичны для бизнеса.