Виртуальный хост PHP: варианты настройки веб-сервера

Раздел: Администрирование -> Веб-серверы

Настройка виртуального сервера для PHP

Наиболее эффективное решение для современных проектов — связка Nginx в качестве веб-сервера и PHP-FPM для обработки PHP-скриптов. Такая архитектура обеспечивает высокую производительность, низкое потребление памяти и гибкость настройки.

Цель и случай использования

Подходит для большинства сайтов на PHP, от небольших блогов до высоконагруженных порталов. Используется, когда требуется максимальная скорость отдачи статики и эффективная обработка динамических запросов.

Пошаговая настройка виртуального хоста в Nginx с PHP-FPM

  1. Установка Nginx и PHP-FPM. Выполняются команды (для Debian/Ubuntu):
    sudo apt update
    sudo apt install nginx php-fpm

    виртуальный сервер php (настройка виртуального сервера для php)

  2. Создание директории для сайта:
    sudo mkdir -p /var/www/example.com/public_html

    Web сервер php (веб-сервер php)

  3. Назначение прав:
    sudo chown -R $USER:$USER /var/www/example.com/public_html

    Php apache server (apache сервер php)

  4. Создание конфигурационного файла виртуального хоста в /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 (как получить в коде))

  5. Активация хоста:
    sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
    sudo nginx -t
    sudo systemctl reload nginx
  6. Помещение тестового 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

Настройка виртуального сервера для PHP - comments

En
виртуальный сервер php (php)