Выбор порта для PHP сервера: практическое руководство
Настройка порта PHP сервера: варианты и инструкции
Номер порта определяет, на каком сетевом интерфейсе сервер ожидает соединения. Для PHP существуют два основных сценария: встроенный веб-сервер для разработки (php -S) и сервер приложений PHP-FPM для продакшена. Рассмотрим оба подхода.
Встроенный PHP сервер с указанием порта
Наиболее простой и эффективный способ запустить PHP сервер на заданном порту - использовать встроенный сервер из командной строки. Команда php -S localhost:8080 запустит сервер на порту 8080, доступный только с локального компьютера. Если требуется доступ с других устройств, привязка делается к адресу 0.0.0.0:
php -S 0.0.0.0:8000
После запуска в консоли появится сообщение Listening on http://0.0.0.0:8000. Сервер будет обрабатывать запросы до нажатия Ctrl+C.
Типичная ошибка: порт уже занят
Если порт занят другим процессом, появится сообщение Address already in use. Решение: сменить порт (например, php -S localhost:8081) или завершить процесс, занимающий порт. Для поиска процесса используется команда:
lsof -i :8080
Найти PID и выполнить kill -9 PID.
Вариант 1: Изменение порта в PHP-FPM
Как изменить порт для PHP-FPM, если стандартный 9000 занят?
В конфигурации пула (обычно файл /etc/php/8.1/fpm/pool.d/www.conf) параметр listen задаёт адрес и порт. Например, для перехода на порт 9001:
listen = 127.0.0.1:9001
После изменения требуется перезапустить службу:
sudo systemctl restart php8.1-fpm
Проверить успешность можно командой netstat -tlnp | grep php - должен появиться порт 9001.
Проблема: SELinux блокирует порт
Если используется SELinux, нестандартный порт может быть запрещён. Решение - разрешить порт в контексте httpd_port_t:
sudo semanage port -a -t httpd_port_t -p tcp 9001
Вариант 2: Использование unix-сокета вместо TCP порта
Как перевести PHP-FPM на unix-сокет для повышения производительности?
Unix-сокеты быстрее TCP и не занимают порт. Настройка в том же файле пула:
listen = /run/php/php8.1-fpm.sock
Перезапуск службы. Веб-сервер (например, nginx) должен использовать сокет вместо адреса:
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
Ошибка: permission denied
Права на сокет должны соответствовать пользователю веб-сервера. В конфигурации FPM добавляют строки listen.owner = www-data и listen.group = www-data.
Вариант 3: Множественные порты для разных приложений
Как запустить два PHP приложения на разных портах через один экземпляр FPM?
Создаются отдельные конфигурационные файлы пулов в /etc/php/*/fpm/pool.d/. Например, site1.conf с портом 9002 и site2.conf с портом 9003. Каждый пул может иметь свои настройки (путь к скриптам, пользователь).
; site1.conf
[site1]
listen = 127.0.0.1:9002
user = site1user
pm = dynamic
; site2.conf
[site2]
listen = 127.0.0.1:9003
user = site2user
pm = dynamic
Перезапуск FPM, затем nginx направляет запросы на соответствующий порт:
# в конфигурации virtual host
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9002;
}
Проблема: пулы не стартуют из-за одинаковых имён сокетов
Каждый пул должен иметь уникальный идентификатор (имя в квадратных скобках) и уникальный listen.
Вариант 4: Привязка встроенного сервера к определённому интерфейсу
Как сделать PHP сервер доступным только с определённого IP?
Вместо localhost или 0.0.0.0 указывается конкретный IP-адрес. Например, чтобы сервер слушал только на интерфейсе 192.168.1.100:
php -S 192.168.1.100:8080
Это полезно для изоляции доступа в многосетевой среде. Если сервер привязан к неверному адресу, соединения не будут приниматься.
Расширенные примеры настройки порта PHP сервера
Пример 1: Встроенный сервер с файлом-роутером
Можно запустить сервер с PHP-скриптом, который обрабатывает все запросы (роутер). Пример router.php:
// router.php
$uri = $_SERVER['REQUEST_URI'];
if ($uri === '/api') {
http_response_code(200);
echo 'API endpoint';
} else {
return false; // передать обработку статическим файлам
}
Запуск:
php -S localhost:8000 router.php
Результат: при обращении к http://localhost:8000/api сервер вернёт API endpoint, а для остальных путей будет искать файл в текущей директории.
$ curl http://localhost:8000/api API endpoint
Пример 2: Динамический выбор свободного порта с помощью скрипта
Бывает необходимо запустить сервер на случайном свободном порту. Скрипт findport.php находит порт и запускает сервер:
// findport.php
$basePort = 8000;
$maxAttempts = 10;
for ($port = $basePort; $port < $basePort + $maxAttempts; $port++) {
$socket = @fsockopen('127.0.0.1', $port, $errno, $errstr, 1);
if (!$socket) {
echo "Starting server on port $port\n";
exec("php -S localhost:$port");
break;
}
fclose($socket);
}
Запуск: php findport.php. Результат - сервер стартует на первом свободном порту, начиная с 8000.
Starting server on port 8000
Пример 3: Настройка PHP-FPM на нестандартный порт и проверка
Предположим, нужно изменить порт FPM на 9001. Файл /etc/php/8.2/fpm/pool.d/www.conf содержит строку:
listen = 127.0.0.1:9001
Перезапуск и проверка:
sudo systemctl restart php8.2-fpm
netstat -tlnp | grep php
tcp 0 0 127.0.0.1:9001 0.0.0.0:* LISTEN 12345/php-fpm
Если порт не появился, проверяют логи FPM: tail -f /var/log/php8.2-fpm.log.
Пример 4: Использование unix-сокета в nginx
Конфигурация nginx при использовании unix-сокета вместо TCP порта:
server {
listen 80;
server_name example.com;
root /var/www/example;
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
Перезагрузка nginx: sudo systemctl reload nginx. Ошибка соединения обычно проявляется кодом 502 Bad Gateway и записью в логе ошибок nginx.
Пример 5: Запуск встроенного сервера в фоне и его остановка
Чтобы сервер работал после закрытия терминала, используют запуск в фоне:
php -S 0.0.0.0:8080 > /dev/null 2>&1 &
Запомнить PID: echo $! сохраняют в переменной. Остановка по PID:
kill PID
Можно использовать pkill -f 'php -S' для остановки всех процессов.
Пример 6: Проверка занятости порта из PHP
Скрипт проверяет, свободен ли порт:
$port = 8080;
$connection = @fsockopen('127.0.0.1', $port, $errno, $errstr, 1);
if (is_resource($connection)) {
echo "Порт $port занят.";
fclose($connection);
} else {
echo "Порт $port свободен.";
}
Порт 8080 свободен.