Настройка массового виртуального хостинга Apache2 с mod_rewrite, mod_userdir и mod_suexec на CentOS 5.3
Версия: 1.2
Последнее редактирование: 7 июля 2009
Кратко: этот материал показывает метод массового виртуального хостинга на Apache2 с динамическим сопоставлением директорий через mod_rewrite и запуском CGI под владельцем скрипта с помощью suEXEC и mod_userdir. Подходит для распределённого хостинга, где каждому сайту соответствует системный пользователь. Тестируйте в контролируемой среде — конфигурация не проверялась на production.
Перед началом
Платформа: CentOS 5.3. Для примера предполагается, что домен www.example.com указывает на веб‑сервер с IP 192.168.1.1, а веб‑корень example.com расположен в /home/vhosts/example.com/public_html.
Важно: CentOS 5.3 — устаревшая версия; при перенесении на современные системы проверьте совместимость модулей и пути к бинарникам.
Установка Apache
Установите пакет httpd (в пакете CentOS включены модули mod_rewrite, mod_userdir и mod_suexec):
yum install httpdКонфигурация массового виртуального хостинга
Откройте конфигурацию Apache:
vim /etc/httpd/conf/httpd.confДобавьте загрузку модуля mod_rewrite в верхней части (если ещё не загружен):
LoadModule rewrite_module modules/mod_rewrite.so
Внизу файла вставьте следующие правила (не меняйте пути, если используете ту же структуру):
## get the server name from the Host: header
UseCanonicalName Off
## splittable logs
LogFormat "%{Host}i %h %l %u %t \"%r\" %s %b" vcommon
CustomLog logs/access_log vcommon
RewriteEngine On
## Create a handle to convert upper or mixed-case to lower-case
RewriteMap lowercase int:tolower
##-----------------------------------
## where hostname has www prefix
##-----------------------------------
## Firstly create custom variable that contains the host without the www prefix
RewriteCond %{HTTP_HOST} ^www\.(.*)$
RewriteRule .? - [E=noWWWHost:%1]
## Map the virtualhost to the documentroot
RewriteCond %{REQUEST_URI} !^/~
RewriteCond %{HTTP_HOST} ^www\.
RewriteRule ^/(.*)$ /home/vhosts/${lowercase:%{ENV:noWWWHost}}/public_html/$1
##-----------------------------------
## where hostname *does not* have www prefix
##-----------------------------------
## Map the virtualhost to the documentroot
RewriteCond %{REQUEST_URI} !^/~
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^/(.*)$ /home/vhosts/${lowercase:%{HTTP_HOST}}/public_html/$1
Пояснения к конфигурации:
- Сайты размещаются в /home/vhosts. Каждая подпапка — это доменное имя сайта (без www), например /home/vhosts/example.com.
- Запрос к www.example.com будет динамически переписан на example.com.
- Документная корневая папка называется public_html — это требование suEXEC для работы через mod_userdir. Если вы не планируете использовать suEXEC, можно использовать другое имя и скорректировать правила.
Создайте тестовый index.html в public_html виртуального хоста:
echo "index.html Hello World" > /home/vhosts/example.com/public_html/index.htmlЗапустите Apache:
/etc/init.d/httpd startЗатем при обращении к http://www.example.com/ должен отобразиться текст ‘index.html Hello World’. Если нет — смотрите лог ошибок:
tail /var/log/httpd/error_logЗапуск CGI под владельцем скрипта (suEXEC + mod_userdir)
Цель: в окружении шаред‑хостинга CGI/скрипты должны запускаться от имени владельца сайта, а не от процесса веб‑сервера.
Требование: системный пользователь с именем, равным имени сайта. Пример для example.com:
useradd -d /home/vhosts/example.com example.comЭто создаст пользователя example.com с домашней директорией /home/vhosts/example.com. Веб‑файлы для www.example.com помещайте в /home/vhosts/example.com/public_html.
Можно завести пользователей вручную в /etc/passwd или интегрировать LDAP/AD для автоматической авторизации.
Включите модуль mod_userdir и настройте UserDir:
vim /etc/httpd/conf/httpd.confУбедитесь, что в конфиге присутствуют строки:
LoadModule userdir_module modules/mod_userdir.so
UserDir public_html
Теперь при запросе вида http://192.168.1.1/~example.com Apache по умолчанию будет искать /home/vhosts/example.com/public_html. Но мы хотим, чтобы URL оставался в форме http://www.example.com — для этого добавим скрытую переписку для CGI.
Добавьте после ранее вставленных правил следующее:
## Rewrite script to userdir so we can use suEXEC
RewriteCond %{REQUEST_URI} !^/~
RewriteCond %{SCRIPT_FILENAME} /home/vhosts/(.*)/public_html/(.*\.(pl|cgi))
RewriteRule .* /~%1/%2 [PT,L]
AddHandler cgi-script .pl .cgi
Options +ExecCGI
Перезагрузите конфигурацию Apache:
/etc/init.d/httpd reloadСоздайте тестовый Perl‑скрипт test.pl в public_html:
#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "test.pl Hello World
\n";
Сделайте скрипт исполняемым и установите правильного владельца:
chmod +x test.plchown example.com:example.com test.plТеперь при обращении к http://www.example.com/test.pl вы должны увидеть ‘test.pl Hello World’. Если нет — проверьте логи:
tail /var/log/httpd/error_logtail /var/log/httpd/suexec.logPHP и Python через suEXEC
Добавить поддержку PHP и Python просто: установите необходимые пакеты и настройте обработку как CGI.
Установите интерпретаторы:
yum install php-cliyum install pythonПримеры скриптов в public_html:
test.py
#!/usr/bin/python
print "Content-type: text/html\n\n"
print "test.py Hello world!"
test.php
#!/usr/bin/php-cgi
echo "test.php Hello world!";
?>
Поменяйте владельца и дайте бит исполнения. Каждому скрипту нужно указывать интерпретатор в первой строке (shebang). Чтобы не править каждый файл, можно зарегистрировать binfmt_misc (требуются разрешения и поддержка ядра):
echo ":PHP:E::php::/usr/bin/php-cgi:" > /proc/sys/fs/binfmt_misc/register
echo ":Python:E::py::/usr/bin/python:" > /proc/sys/fs/binfmt_misc/registerРасширьте правило переписывания и обработчик cgi‑script:
## Rewrite script to userdir so we can use suEXEC
RewriteCond %{REQUEST_URI} !^/~
RewriteCond %{SCRIPT_FILENAME} /home/vhosts/(.*)/public_html/(.*\.(pl|cgi|php|py))
RewriteRule .* /~%1/%2 [PT,L]
AddHandler cgi-script .pl .cgi .php .py
Options +ExecCGI
PHP‑примечание: установите cgi.force_redirect = 0 в /etc/php.ini, чтобы избежать ошибок REDIRECT_STATUS при запуске php-cgi.
Перезагрузите Apache:
/etc/init.d/httpd reloadПроверяйте логи при ошибках:
tail /var/log/httpd/error_logtail /var/log/httpd/suexec.logCatchall — обработка несуществующих виртуальных хостов
Если нужно перенаправлять запросы к несуществующим vhost на «пойманный» сайт, добавьте последним правилом в /etc/httpd/conf/httpd.conf:
## Redirect non-existent virtualhosts
RewriteCond %{REQUEST_URI} !^/~
RewriteCond %{SCRIPT_FILENAME} (/home/vhosts/.*)/public_html/.*
RewriteCond %1 !-d
RewriteRule .? http://www.google.com [R,NS,L]
Замените http://www.google.com на адрес вашего catchall‑сайта. Это правило должно быть последним, чтобы не перехватывать реальные хосты.
Безопасность, ограничения и рекомендации
Important: suEXEC выполняет дополнительные проверки безопасности и ограничивает запуск CGI только в определённых условиях (пути, владельцы, права). Проверьте:
- Владелец и группа файлов совпадают с ожидаемыми (chown user:user).
- Права на директории и скрипты не должны быть открыты для группы/остальных (обычно 0755 для директорий и 0755/0750 для скриптов, уточняйте по требованиям suEXEC).
- suEXEC логирует сообщения в /var/log/httpd/suexec.log — используйте его для отладки.
Ограничения suEXEC и mod_userdir:
- suEXEC не поддерживает запуск из произвольных путей — путь и владельцы должны соответствовать ожиданиям.
- suEXEC не выполняет файлы с небезопасными правами.
- Если нужны ресурсоёмкие приложения (persistent PHP-FPM, long‑running Python), лучше использовать отдельные процессы/сокеты вместо suEXEC CGI.
Рекомендации по безопасности:
- Минимизируйте набор исполняемых расширений (.pl, .cgi, .php, .py).
- Используйте SELinux (если включён) и настройте политики для каталога /home/vhosts.
- Отключите ненужные модули Apache и ограничьте число разрешённых директив в .htaccess.
Чек‑лист перед запуском (роль: системный администратор)
- Установлен пакет httpd.
- Загружены модули mod_rewrite, mod_userdir, mod_suexec.
- В каталоге /home/vhosts созданы директории для доменов.
- Пользователи созданы и владеют своими директориями (useradd -d …).
- public_html присутствует и содержит index.html для теста.
- Конфигурация RewriteMap и правил проверена локально.
- Тестовые CGI‑скрипты имеют правильные shebang, права и владельца.
- Логи доступны и индексируются для отладки (/var/log/httpd/*).
Критерии приёмки
- При обращении к существующему домену отображается его index.html.
- CGI/Perl/Python/PHP скрипт запускается и возвращает корректный HTTP‑ответ от имени владельца сайта.
- Логи Apache и suexec не содержат ошибок при штатных запросах.
- Правило catchall срабатывает только для несуществующих сайтов.
Runbook: быстрый порядок действий при сбое
- Проверить статус httpd: systemctl (или /etc/init.d/httpd) start|status.
- Просмотреть последние записи в /var/log/httpd/error_log и /var/log/httpd/suexec.log.
- Проверить, что каталог и файл существуют и имеют правильные права: ls -l /home/vhosts/example.com/public_html/test.pl.
- Убедиться, что shebang у скрипта корректен и интерпретатор установлен.
- Откат: восстановить предыдущую конфигурацию httpd.conf из резервной копии и выполнить reload.
Тестовые случаи и приёмочные проверки
- Тест 1: GET / -> index.html, код 200.
- Тест 2: GET /test.pl -> выполняется тест.pl, отображает H1, владелец процесса соответствует владельцу файла.
- Тест 3: GET /test.php и /test.py -> корректный вывод от php-cgi и python.
- Тест 4: Запрос к несуществующему домену -> редирект на catchall (если включено).
Модель принятия решений (Mermaid)
flowchart TD
A[Запрос на www.example.com] --> B{Существует ли /home/vhosts/domain/public_html}
B -- Да --> C{Запрошен файл с расширением CGI?}
C -- Да --> D[Переписать на /~user/file и запустить suEXEC]
C -- Нет --> E[Отдать файл из /home/vhosts/domain/public_html]
B -- Нет --> F[Сработает правило catchall или 404]Совместимость и миграция
- На новых дистрибутивах пути к php-cgi и python могут отличаться (/usr/bin/php-cgi, /usr/bin/python3). Проверьте shebang.
- CentOS 5.3 — устаревший релиз. При переносе на более новые системы рассмотрите использование PHP‑FPM, systemd и современных механизмов изоляции (containers, cgroups) вместо suEXEC для лучшей масштабируемости.
Частые ошибки и способы устранения
- Ошибка suEXEC: проверьте владельца и права файла.
- Ошибка CGI REDIRECT_STATUS: установите cgi.force_redirect = 0 в /etc/php.ini.
- Переписывание не срабатывает: включён ли мод_rewrite и правильны ли условия RewriteCond.
- Нечитаемые логи: проверьте права на /var/log/httpd и r/o монтирование.
Роль‑ориентированные чек‑листы
Администратор:
- Провести аудит прав и владельцев.
- Настроить ротацию логов.
- Настроить мониторинг доступности.
Разработчик:
- Проверить shebang и зависимости скрипта.
- Убедиться, что скрипт не требует persistent‑процесса.
Короткое резюме
- Массовый виртуальный хостинг реализуется через динамическую переписку путей в mod_rewrite и размещение сайтов в /home/vhosts.
- suEXEC + mod_userdir позволяют запускать CGI от владельца сайта.
- Проверяйте права, shebang и логи; на современных платформах рассмотрите альтернативы suEXEC для лучшей производительности.
Важно: эта инструкция описывает один из подходов. Для production рекомендуется тестирование на staging, контроль прав доступа, бекапы конфигурации и, при необходимости, миграция на современные механизмы обработки скриптов.
Похожие материалы
RDP: полный гид по настройке и безопасности
Android как клавиатура и трекпад для Windows
Советы и приёмы для работы с PDF
Calibration в Lightroom Classic: как и когда использовать
Отключить Siri Suggestions на iPhone