Під час розміщення кількох сайтів на одному сервері важливо не лише правильно налаштувати вебсервер, а й розділити права доступу між окремими проєктами. Якщо всі PHP-скрипти виконуються від імені одного системного користувача вебсервера, помилка або вразливість на одному сайті може створити небезпеку для інших ресурсів.

Одним із поширених рішень для старих версій Ubuntu була зв’язка Apache2, mod_fcgid, PHP5 CGI та suEXEC. Вона дозволяла запускати PHP-скрипти кожного віртуального хоста від імені його власника, а не від загального користувача Apache.

У цьому матеріалі розглядається історичний приклад налаштування такої системи на Ubuntu Server 11.10. Для демонстрації створюються два окремі сайти, кожен із власним системним користувачем, каталогом, FastCGI-обробником і можливістю використовувати індивідуальний файл php.ini.

Варто враховувати, що Ubuntu 11.10, PHP5 і наведені конфігурації Apache давно застаріли. Матеріал корисний передусім для розуміння принципів ізоляції сайтів, роботи FastCGI та розподілу прав доступу.

Підготовка системи

Налаштування виконувалося на сервері Ubuntu 11.10 із повним доменним ім’ям server1.example.com. Для прикладу використовувалася локальна IP-адреса, а також два демонстраційні домени:

www.example1.com;

www.example2.com.

У реальній системі ці адреси потрібно замінити власними доменними іменами та мережевими параметрами.

Перед початком роботи необхідно отримати адміністративні права. У старому керівництві для цього використовувався перехід до оболонки root через sudo.

Також змінювалася системна оболонка /bin/sh. За замовчуванням вона могла посилатися на Dash, тоді як деякі сценарії налаштування очікували Bash. Тому через системний конфігуратор відмовлялися від використання Dash як /bin/sh.

В оригінальній конфігурації також рекомендувалося повністю вимкнути та видалити AppArmor. Для сучасного сервера такий підхід небажаний. Систему обмеження доступу краще налаштувати під потрібні служби, а не відключати без необхідності.

Встановлення Apache2, mod_fcgid і PHP5

Для створення вебсервера встановлювалися Apache2, suEXEC, модуль mod_fcgid і CGI-версія PHP5.

Якщо PHP уже працював як вбудований модуль Apache, його потрібно було вимкнути. Це було необхідно тому, що обробку PHP планувалося виконувати через FastCGI, а не всередині основного процесу Apache.

Після цього активувалися модулі:

rewrite — для правил перенаправлення та роботи файлів .htaccess;

suexec — для запуску CGI-процесів від імені власника сайту;

include — для серверних включень;

fcgid — для обробки FastCGI-запитів.

У конфігурації PHP CGI вмикалася підтримка коректного визначення PATH_INFO. Додатковий параметр для mod_fcgid додавався до загальної конфігурації модуля, а не всередину окремого VirtualHost.

Після внесення змін Apache перезапускався, щоб завантажити нові модулі та параметри.

Створення окремих користувачів для сайтів

Для двох демонстраційних сайтів створювалися окремі системні групи та користувачі:

web1 — власник першого сайту;

web2 — власник другого сайту.

Для цих облікових записів вимикався звичайний інтерактивний вхід до системи, а домашні каталоги розміщувалися всередині /var/www.

Структура сайтів виглядала приблизно так:

/var/www/web1/web;

/var/www/web2/web.

Каталог першого сайту належав користувачеві та групі web1, а каталог другого — користувачеві та групі web2.

Завдяки цьому файли різних сайтів мали окремих власників. PHP-процес кожного віртуального хоста також міг запускатися з відповідними правами.

Робота suEXEC

suEXEC дозволяє Apache запускати CGI-програми не від імені загального користувача www-data, а від імені власника конкретного сайту.

Проте suEXEC має суворі правила безпеки. Виконуваний файл повинен знаходитися всередині дозволеного кореневого каталогу, належати правильному користувачеві та мати безпечні права доступу.

У розглянутій системі коренем suEXEC був каталог /var/www. Стандартний виконуваний файл PHP CGI знаходився поза цим каталогом, тому Apache не міг запускати його безпосередньо через suEXEC.

Також проблему не можна було вирішити звичайним символічним посиланням, оскільки suEXEC не дозволяв використовувати його для обходу встановленого кореневого каталогу.

Для кожного сайту створювався окремий запускний сценарій усередині /var/www. Саме цей сценарій викликав системний PHP CGI.

Підготовка FastCGI-сценаріїв

Для запускних сценаріїв створювалася окрема структура:

/var/www/php-fcgi-scripts/web1;

/var/www/php-fcgi-scripts/web2.

У кожному каталозі розміщувався файл php-fcgi-starter.

У ньому визначалися:

каталог із конфігурацією PHP;

максимальна кількість запитів для одного FastCGI-процесу;

кількість дочірніх PHP-процесів;

шлях до виконуваного PHP CGI.

Параметр PHPRC вказував, де PHP повинен шукати файл php.ini.

PHP_FCGI_MAX_REQUESTS визначав, скільки запитів процес може обробити перед автоматичним завершенням і повторним запуском. Такий перезапуск допомагав звільняти пам’ять після тривалої роботи.

PHP_FCGI_CHILDREN визначав кількість дочірніх PHP-процесів, які могли одночасно обробляти запити.

Запускні сценарії робилися виконуваними. Сценарій першого сайту та його каталог належали web1, а другого — web2.

Це було принципово важливо для suEXEC. Якщо власник або права не відповідали конфігурації віртуального хоста, Apache відмовлявся запускати PHP.

Створення віртуальних хостів Apache

Для кожного сайту створювалася окрема конфігурація VirtualHost.

У ній зазначалися:

основне доменне ім’я;

додатковий домен без www;

адреса адміністратора;

кореневий каталог сайту;

системний користувач і група;

шлях до FastCGI-сценарію;

правила доступу до каталогу;

налаштування журналів.

Для першого сайту директива SuexecUserGroup використовувала користувача і групу web1. Для другого — web2.

PHP-файли передавалися обробнику fcgid, а FCGIWrapper указував шлях до відповідного php-fcgi-starter.

Таким чином, PHP-код першого сайту виконувався з правами web1, а PHP-код другого — з правами web2.

Після створення конфігурацій сайти активувалися командами керування Apache, а вебсервер перечитував налаштування.

Під час підготовки віртуальних хостів необхідно уважно перевіряти шляхи, користувачів і групи. Навіть невелика помилка може призвести до відмови suEXEC, помилки FastCGI або відповіді сервера з кодом 500.

Перевірка роботи PHP

Для перевірки на першому сайті створювався невеликий PHP-файл із викликом phpinfo.

Після відкриття сторінки у браузері в інформації PHP потрібно було знайти рядок Server API. Якщо налаштування виконано правильно, у ньому відображався режим CGI/FastCGI.

Це підтверджувало, що PHP працює через mod_fcgid, а не як звичайний вбудований модуль Apache.

Після перевірки файл phpinfo необхідно видалити. Він показує багато технічної інформації про сервер, модулі, шляхи та конфігурацію, тому залишати його у відкритому доступі небезпечно.

Окремий php.ini для кожного сайту

Однією з переваг окремих php-fcgi-starter було використання різних налаштувань PHP для кожного віртуального хоста.

Для другого сайту стандартний php.ini копіювався до каталогу /var/www/web2. Після цього власником файлу призначався користувач web2.

У запускному FastCGI-сценарії значення PHPRC змінювалося так, щоб PHP шукав конфігурацію саме в каталозі другого сайту.

Після перезавантаження Apache другий сайт починав використовувати власний php.ini, тоді як перший продовжував працювати із загальною системною конфігурацією.

Це дозволяло для різних сайтів установлювати окремі:

ліміти пам’яті;

розміри завантажуваних файлів;

час виконання скриптів;

параметри журналювання;

налаштування сесій;

дозволені та заборонені функції;

параметри відображення помилок.

Правильність підключення перевірялася через phpinfo. У рядку Loaded Configuration File мав відображатися шлях до індивідуального php.ini.

Зміна окремих параметрів PHP

Створювати повну копію php.ini для кожного сайту було необов’язково. Окремі параметри можна було передавати безпосередньо під час запуску PHP CGI.

Для цього до команди запуску PHP у php-fcgi-starter додавалася опція -d з назвою параметра та потрібним значенням.

В оригінальному прикладі таким способом вимикалася застаріла функція magic_quotes_gpc для одного з сайтів.

Після зміни запускного сценарію Apache перечитував конфігурацію, а результат перевірявся через phpinfo.

Подібний підхід дозволяв змінити лише кілька параметрів, не створюючи повну окрему копію php.ini.

Переваги такої конфігурації

Головною перевагою зв’язки Apache, mod_fcgid і suEXEC було розділення сайтів за системними користувачами.

Кожен сайт:

мав власний каталог і власника;

запускав PHP від окремого користувача;

міг мати індивідуальний php.ini;

отримував окремий FastCGI-сценарій;

не потребував надання загальному користувачеві Apache повних прав на всі файли.

Це також спрощувало роботу з файлами, створеними PHP. Вони одразу належали власнику сайту, а не користувачеві www-data.

Обмеження та недоліки

Конфігурація вимагала створення окремого запускного сценарію для кожного сайту. Адміністратору потрібно було уважно стежити за власниками, групами, дозволами та шляхами.

Неправильні права могли блокувати запуск PHP. Помилка у FCGIWrapper або SuexecUserGroup призводила до внутрішньої помилки сервера.

Окремі PHP-процеси також споживали додаткову оперативну пам’ять. Значення кількості дочірніх процесів потрібно було підбирати відповідно до ресурсів сервера й навантаження сайтів.

Сучасне використання

Описана схема відображає підхід, який застосовувався зі старими версіями Apache, Ubuntu і PHP.

На сучасних серверах частіше використовують PHP-FPM з окремими пулами для сайтів. Для кожного пулу можна призначити власного користувача, групу, сокет, ліміти ресурсів та індивідуальні параметри PHP.

Принцип залишається схожим: кожен сайт працює у власному середовищі та не повинен отримувати зайвого доступу до файлів інших проєктів.

Підсумок

Зв’язка Apache2, mod_fcgid, PHP5 CGI та suEXEC дозволяла організувати ізольоване виконання PHP для кількох віртуальних хостів на Ubuntu Server 11.10.

Для кожного сайту створювалися окремий системний користувач, каталог, FastCGI-сценарій і конфігурація Apache. PHP запускався з правами власника конкретного сайту, а за потреби кожен ресурс міг використовувати власний php.ini.

Хоча програмні версії та окремі команди з оригінальної інструкції вже не підходять для нового сервера, матеріал добре пояснює базові принципи ізоляції сайтів, виконання PHP через FastCGI та правильного розподілу прав доступу.