Виртуальный хост PHP: варианты настройки веб-сервера
Настройка виртуального сервера для PHP
Наиболее эффективное решение для современных проектов — связка Nginx в качестве веб-сервера и PHP-FPM для обработки PHP-скриптов. Такая архитектура обеспечивает высокую производительность, низкое потребление памяти и гибкость настройки.
Цель и случай использования
Подходит для большинства сайтов на PHP, от небольших блогов до высоконагруженных порталов. Используется, когда требуется максимальная скорость отдачи статики и эффективная обработка динамических запросов.
Пошаговая настройка виртуального хоста в Nginx с PHP-FPM
- Установка Nginx и PHP-FPM. Выполняются команды (для Debian/Ubuntu):
sudo apt update sudo apt install nginx php-fpmвиртуальный сервер php (настройка виртуального сервера для php)
- Создание директории для сайта:
sudo mkdir -p /var/www/example.com/public_htmlWeb сервер php (веб-сервер php)
- Назначение прав:
sudo chown -R $USER:$USER /var/www/example.com/public_htmlPhp apache server (apache сервер php)
- Создание конфигурационного файла виртуального хоста в /etc/nginx/sites-available/example.com:
server { listen 80; server_name example.com www.example.com; root /var/www/example.com/public_html; index index.php index.html; location / { try_files $uri $uri/ =404; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; } location ~ /\.ht { deny all; } }адрес сервера php (адрес сервера php (как получить в коде))
- Активация хоста:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx - Помещение тестового PHP-файла:
echo "<?php phpinfo(); ?>" > /var/www/example.com/public_html/index.php
Типичная ошибка: ошибка 502 Bad Gateway. Причина — неправильный путь к сокету PHP-FPM или неработающий сервис. Проверка:
sudo systemctl status php8.1-fpm
ls -la /var/run/php/Если сокет отсутствует, перезапуск PHP-FPM:
sudo systemctl restart php8.1-fpmТакже ошибка 403 возникает при неправильных правах на корневую директорию. Решение: проверить, что пользователь www-data имеет доступ на чтение.
Ниже рассмотрены альтернативные подходы, применимые в разных сценариях.
Вариант 1. Виртуальный хост в Apache с mod_php
Вопрос: Как настроить виртуальный сервер в Apache, если нет необходимости в отдельном процессе PHP?
Случай использования: простые проекты с небольшими нагрузками, когда удобство настройки важнее производительности. Apache с mod_php (mod_php7 или mod_php8) интегрирует PHP прямо в процесс сервера, что упрощает конфигурацию.
Пример конфигурации виртуального хоста в /etc/apache2/sites-available/example.com.conf:
<VirtualHost *:80>
ServerAdmin admin@example.com
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public_html
<Directory /var/www/example.com/public_html>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>Активация:
sudo a2ensite example.com.conf
sudo systemctl reload apache2Проблема:
При использовании mod_php каждый процесс Apache содержит интерпретатор PHP, что потребляет больше памяти при большом количестве одновременных соединений. Также невозможно гибко переключать версии PHP для разных сайтов.
Вариант 2. Apache с PHP-FPM через FastCGI
Вопрос: Как улучшить производительность Apache, оставив его как фронтальный сервер, но с отдельным PHP-FPM?
Случай использования: когда нужен Apache (например, из-за .htaccess) и при этом высокая производительность PHP. Используется модуль mod_proxy_fcgi.
Пример конфигурации виртуального хоста:
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/example.com/public_html
<FilesMatch \.php$>
SetHandler proxy:fcgi://127.0.0.1:9000
</FilesMatch>
<Directory /var/www/example.com/public_html>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>PHP-FPM должен слушать на TCP-порту 9000. Настройка пула в /etc/php/8.1/fpm/pool.d/www.conf:
listen = 127.0.0.1:9000Ошибка:
Если порт занят или PHP-FPM не прослушивается, Apache возвращает ошибку 503. Проверка:
sudo netstat -tlnp | grep 9000Вариант 3. Nginx с PHP-FPM через TCP-сокет
Вопрос: В каких случаях стоит заменить Unix-сокет на TCP-соединение в паре Nginx+PHP-FPM?
Случай использования: когда PHP-FPM работает на другом сервере (распределённая архитектура) или необходимо пробросить соединение через сетевой интерфейс.
Пример конфигурации Nginx:
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}Необходимо убедиться, что PHP-FPM слушает на порту:
listen = 127.0.0.1:9000Проблема:
TCP-соединение медленнее Unix-сокета из-за сетевых накладных расходов. Использовать только при необходимости удалённого доступа.
Вариант 4. Изоляция с помощью Docker
Вопрос: Как настроить несколько независимых виртуальных серверов на одной машине с разными версиями PHP и окружениями?
Случай использования: разработка, тестирование, продуктирование с жёсткой изоляцией; микросервисная архитектура.
Пример docker-compose.yml для двух сайтов:
version: '3'
services:
site1:
image: nginx:latest
volumes:
- ./site1/html:/usr/share/nginx/html
- ./site1/nginx.conf:/etc/nginx/conf.d/default.conf
ports:
- "8080:80"
php1:
image: php:8.1-fpm
volumes:
- ./site1/html:/usr/share/nginx/html
site2:
image: nginx:latest
volumes:
- ./site2/html:/usr/share/nginx/html
- ./site2/nginx.conf:/etc/nginx/conf.d/default.conf
ports:
- "8081:80"
php2:
image: php:8.0-fpm
volumes:
- ./site2/html:/usr/share/nginx/htmlКаждый сайт использует свою версию PHP.
Сложность:
Необходимо знание Docker и оркестрации; увеличение потребления ресурсов из-за дублирования образов.
Вариант 5. OpenLiteSpeed
Вопрос: Как использовать легковесный веб-сервер с встроенной поддержкой PHP и простой панелью управления?
Случай использования: хостинг-провайдеры, пользователи, предпочитающие графический интерфейс и высокую производительность при низких затратах.
Настройка виртуального хоста через веб-панель или через конфигурационный файл:
# /usr/local/lsws/conf/vhosts/example.com/vhconf.conf
docRoot /home/example.com/public_html
vhName example.com
adminEmail admin@example.com
enableGzip 1
enableBr 1
indexFiles index.php
rewrite {
enable 1
autoLoadHtaccess 1
rules <<<END_rules
END_rules
}
scriptHandler {
add lsapi:lsphp81 php
}После изменений перезагрузка LiteSpeed:
sudo systemctl restart lswsОшибка:
Неправильный путь к обработчику lsphp может привести к ошибке 500. Необходимо проверить установку LSAPI версии PHP.
Пример 1. Nginx + PHP-FPM с HTTPS, кешированием FastCGI и ограничением доступа
server {
listen 443 ssl http2;
server_name example.com;
root /var/www/example.com/public_html;
index index.php;
ssl_certificate /etc/ssl/certs/example.com.crt;
ssl_certificate_key /etc/ssl/private/example.com.key;
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=phpcache:10m max_size=10g inactive=60m use_temp_path=off;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_cache phpcache;
fastcgi_cache_valid 200 60m;
fastcgi_cache_use_stale error timeout updating invalid_header http_500;
fastcgi_cache_key $scheme$request_method$host$request_uri;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
}
location ~ /\. {
deny all;
}
}Результат: при повторных запросах к одним и тем же PHP-страницам ответ будет выдаваться из кеша, что снижает нагрузку на PHP-FPM.
HTTP/2 200 OK X-Cache: HIT (from proxy cache)
Пример 2. Apache + PHP-FPM с использованием .htaccess для переопределения
# .htaccess в корне сайта
RewriteEngine On
RewriteRule ^old-page$ new-page [L,R=301]
SetEnv APP_ENV productionКонфигурация виртуального хоста Apache должна разрешать .htaccess: AllowOverride All. Результат: все директивы из .htaccess применяются, включая перенаправления и переменные окружения.
Пример 3. Docker Compose с несколькими версиями PHP и общей сетью
version: '3.8'
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- ./sites:/var/www
depends_on:
- php74
- php80
php74:
image: php:7.4-fpm
volumes:
- ./sites:/var/www
environment:
- PHP_VERSION=7.4
php80:
image: php:8.0-fpm
volumes:
- ./sites:/var/www
environment:
- PHP_VERSION=8.0Конфигурация Nginx (nginx.conf):
server {
listen 80;
server_name site74.test;
root /var/www/site74;
location ~ \.php$ {
fastcgi_pass php74:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
server {
listen 80;
server_name site80.test;
root /var/www/site80;
location ~ \.php$ {
fastcgi_pass php80:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}Результат: два независимых виртуальных хоста, каждый со своей версией PHP.
$ curl -H "Host: site74.test" localhost/index.php -> PHP 7.4 $ curl -H "Host: site80.test" localhost/index.php -> PHP 8.0
Пример 4. Настройка OpenLiteSpeed через конфигурационный файл с поддержкой WebSocket
# /usr/local/lsws/conf/vhosts/websocket/vhconf.conf
vhName websocket
docRoot /home/websocket/public_html
indexFiles index.html
rewrite {
enable 1
rules <<<END_rules
RewriteRule ^/ws(.*) /ws.php [L]
END_rules
}
scriptHandler {
add lsapi:lsphp81 php
add lsapi:lsphp81 ws
}
context /ws/ {
type ws
wsHandler lsphp81
addDefaultCharset off
extraHeaders <<<END_extraHeaders
END_extraHeaders
}Результат: WebSocket-соединения обрабатываются через PHP-скрипт ws.php.
WebSocket handshake successful