Многие знают и используют контрольную панель ispmanager для управления сервером, но, возможно, не всем известно, что функционал работы панели можно расширить самостоятельно и адаптировать для выполнения своих специфических задач.

В этой статье я хочу показать, как можно расширить возможности ispmanager — с помощью механизма плагинов. Они позволяют добавлять в панель собственный функционал: новые пункты меню, формы, отчёты, автоматизированные действия до и после стандартных операций, а также выводить данные из внешних систем прямо в интерфейс панели.

Предлагается доработать ispmanager, а именно:

  • добавить подключение к nginx модуля-расширения mod_rewrite — который позволит сайту, сконфигурированному в режиме nginx+php-fpm в обход Apache читать правила mod_rewrite из .htaccess и таким образом сделать универсальной работу с разными CMS на сервере

  • разработать плагин, который позволит управлять статусом нового модуля nginx, управлять доступностью модуля для сайта (исходные коды модуля-плагина)

Реализация плагина ориентирована на ОС AlmaLinux 9/10 и совместимые с ними дистрибутивы; Debian и Ubuntu в рамках этой статьи не рассматриваются.

Цель — создать RPM‑пакет для установки на сервер с ISPmanager. Пакет должен решать две задачи:

  • загрузить модуль-расширение mod_rewrite (ngx_http_apache_rewrite_module) для nginx и собрать его, и следить за версией nginx и версией модуля mod_rewrite, своевременно при обновлении nginx пересобирать его;

  • интегрировать в интерфейс панели формы для управления настройками модуля — чтобы администратор мог задавать параметры и контролировать работу расширения без ручной правки конфигураций.

Для проверки работы данного плагина, в рамках статьи, создаем в ispmanager пользователя и для этого пользователя тестовый сайт с .htaccess и небольшим набором правил, сайт сконфигурируем как FastCGI (nginx + PHP-FPM) с включенной галочкой «Включить обработку ЧПУ»:

Обработчик PHP
Обработчик PHP

Вот вывод содержимого тестового сайта, выведен каждый тестовый скрипт сайта с номерами строк и их содержимое:

./index.php
     1	<?php
     2	echo "Hello from index.php param=". $_GET["param"];
./test1.php
     1	<?php
     2	echo "hello from test1.php param = " . $_GET["param"];
./test2.php
     1	<?php
     2	echo "Hello from test2.php param=" . $_GET["param"];
     3	
     4	
./test3.php
     1	<?php
     2	echo "test3 should be forbidden";
.htaccess
     1	RewriteEngine On
     2	# --- Rule 1: Add ?param=1 to /index.php (if not already present) ---
     3	RewriteCond %{QUERY_STRING} !^param=1 [NC]
     4	RewriteRule ^index\.php$ /index.php?param=1 [L,R=302]
     5	# --- Rule 2: /test1/* paths redirect to test1.php ---
     6	RewriteRule ^test1/(.*)$ /test1.php [L]
     7	# --- Rule 3: /test-ok/* paths redirect to test1.php ---
     8	RewriteRule ^test-ok/(.*)$ /test1.php [L]
     9	# --- Rule 4: /test6.php redirects to /test2.php ---
    10	RewriteRule ^test6\.php$ /test2.php [L]
    11	# --- Rule 5: /test3.php returns Forbidden (403) via RewriteRule ---
    12	RewriteCond %{REQUEST_URI} ^/test3\.php [NC]
    13	RewriteRule ^ / [F,L]
  • Правило 1: index.php должен переадресоваться на index.php с параметром.

  • Правило 2 и 3: любой URL начинающийся с test1/ или test-ok/ должен переадресоваться в скрипт test1.php

  • Правило 4: test6.php должен переадресоваться внутренним редиректом на test2.php

  • Правило 5: доступ к test3.php должен быть запрещен.

Apache + mod_rewrite все делает верно. Проверим, как себя поведет nginx+php-fpm с включенным флажком «Включить обработку ЧПУ»:

Правило 1:

# curl -L http://user2.test.domain
Hello from index.php param=

Правило 2:

# curl -L http://user2.test.domain/test1/1.php
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.30.2</center>
</body>
</html>

Правило 3:

# curl -L http://user2.test.domain/test-ok/m.php?param=1
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.30.2</center>
</body>
</html>

Правило 4:

# curl -L http://user2.test.domain/test6.php
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.30.2</center>
</body>
</html>

Правило 5:

# curl -L http://user2.test.domain/test3.php
test3 should be forbidden

Все не верно. ЧПУ не помогло, как не поможет и во многих CMS. Нужно только модифицировать настройки server для сайта, что в окружении контрольной панели не так-то просто.

Приступим к реализации плагина для ispmanager.

Согласно руководству разработчика, ключевым этапом является подготовка XML‑файла. Он определяет:

  • структуру форм интерфейса, предоставляемых плагином;

  • перечень событий, на которые плагин будет реагировать;

  • обработчики этих событий.

Файлы плагина размещаются в следующих каталогах:

  • /usr/local/mgr5/etc/xml — здесь хранится XML‑описатель структуры плагина;

  • /usr/local/mgr5/addon — в этой директории размещаются обработчики логики.

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

Важно отметить, что в ispmanager есть понятия модуль и плагин. Плагин просто расширяет функционал, модуль представляется записью в разделе «Модули» и позволяет сделать первичную настройку без добавления меню, а так же позволяет удалить плагин через графический интерфейс.

В статье будут фигурировать три понятия:

  1. Плагин ispmanager — это пункты меню, добавленные формы для управления

  2. Модуль ispmanager — это запись в разделе «Модули», для первичной настройки плагина и удаления плагина

  3. Модуль mod_rewrite или модуль-расширение mod_rewrite — это расширение для nginx, которое собирается и устанавливается в систему.

Описание модуля ispmanager (для первичной настройки)

В текущем случае, первичная настройка — это сборка mod_rewrite для nginx.

Делаем такое описание для модуля ispmanager: - /usr/local/mgr5/etc/plugins/ispmgr/nginx_mod_rewrite_plugin.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<mgrdata>
  <plugin name="nginx_mod_rewrite_plugin">
    <dist>1</dist>
    <free />
	<settings>nginx_mod_rewrite_plugin.settings</settings>
	<msg name="desc_short" lang="ru">Модуль nginx mod_rewrite</msg>
	<msg
            name="desc_full"
            lang="ru"
        >Модуль добавления поддержки mod_rewrite правил и .htaccess в nginx&lt;br/&gt;&lt;a href="https://github.com/bayrepo/ngx_http_apache_rewrite_module" target="_blank"&gt;Документация по настройкам модуля&lt;/a&gt;</msg>
  </plugin>
</mgrdata>

Где определяется обработчик настройки модуля ispmanager:<settings>nginx_mod_rewrite_plugin.settings</settings>. А так же описание модуля и его тип: <free />. Все согласно документации.

После перезапуска контрольной панели модуль появляется в интерфейсе. Выглядит он вот так, в разделе «Модули»:

 Вид нового модуля контрольной панели
Вид нового модуля контрольной панели

Когда уже есть модуль первичной настройки, можно добавить описание плагина в файле - /usr/local/mgr5/etc/xml/ispmgr_mod_nginx_mod_rewrite_plugin.xml.

В нем описываем, как будет выглядеть форма настройки модуля:

<metadata name="nginx_mod_rewrite_plugin.settings" type="form" mgr="ispmgr">
        <form>
           	<field name="nginx_mod_rewrite_plugin_field" noname="yes" fullwidth="yes">
               	<textdata name="nginx_mod_rewrite_plugin_msg" type="banner" status="warning"/>
                <textdata name="nginx_mod_rewrite_plugin_msg_info" type="banner" status="info"/>
           	</field>
            <buttons>
                <button name="ok" type="ok" />
                <button name="cancel" type="cancel" />
            </buttons>
        </form>
</metadata>

Где описываем, что форма будет состоять из «баннера информационного» и «баннера предупреждающего», а так же из двух кнопок. Что и когда отображать, потом решит обработчик, который будет прикреплен к форме.

<handler name="nginx_mod_rewrite_plugin.py" type="xml">
        <func name="nginx_mod_rewrite_plugin.settings" />
</handler>

Данным XML мы указываем, что форму nginx_mod_rewrite_plugin.settings будет обрабатывать скрипт nginx_mod_rewrite_plugin.py, который будет расположен в каталоге /usr/local/mgr5/addon.

Сам обработчик nginx_mod_rewrite_plugin.py — это Python скрипт, который выполняет необходимые действия в системе, в ответ на события от пользователя в веб-интерфейсе ispmanager.

Примерная структура данного обработчика:

  • процедура логирования действий;

  • сборка mod_rewrite для nginx;

  • установка флажка, что сборка уже произошла и можно активировать хук пересборки mod_rewrite при обновлении пакета nginx.

Вот как выглядит сам хук пересборки в spec файле — ispmanager-plugin-nginx_mod_rewrite_plugin.spec:

%triggerin -- nginx
if [ -e /usr/local/ispmanager-mod_rewrite/settings/installed.cfg ]; then
    /usr/local/ispmanager-mod_rewrite/utils/build_mod_rewrite.py --nodeps
fi

Далее в обработчике описываются процедура main и Handle, и вот эти вот две процедуры влияют на то, что будет отображаться в веб-интерфейсе, при настройке плагина.

В них анализируются такие переменные окружения как PARAM_func и PARAM_plugin_settings, чтобы распознать, что обращение производится именно к форме настроек установщика плагина (согласно документации).

Сам обработчик читает поступающий на stdin текст — это обычно описание форм в виде XML. И разбирает его.

Если обработчик идентифицировал, что функция верная и нажата кнопка:

 if os.getenv("PARAM_clicked_button") == "ok":
            Handle(root)

то активизируется процедура сборки модуля. При этом из xml файла /usr/local/mgr5/etc/xml/ispmgr_mod_nginx_mod_rewrite_plugin.xml, поданного на stdin, удаляются не нужные баннеры, по имени тэга и атрибуту «name»:

for parent in root.iter():
    for child in list(parent):
        if child.tag == 'textdata' and child.get('name') == 'nginx_mod_rewrite_plugin_msg_info':
            parent.remove(child)

и происходит сборка модуля для nginx. Далее, по завершении сборки возвращается сообщение об ошибке или признак успешности:

etree.SubElement(root, 'ok')

Данный элемент ok — говорит, что форма больше не нужна и ее можно закрыть.

Т.е это будет выглядеть как:

  • Перешли в настройки модуля ispmanager

  • Нажали кнопку сборки

  • Сборка завершилась и форма настройки автоматически закрылась

 Настройка модуля контрольной панели
Настройка модуля контрольной панели

Если же после сборки mod_rewrite снова зайти в настройки, то отрабатывает вторая ветка из скрипта обработчика, которая говорит, что mod_rewrite уже собран, а так же скрипт удаляет лишние кнопки и баннеры:

 mod_rewrite уже собран
mod_rewrite уже собран

И под конец обработки в stdout отправляется модифицированный XML:

etree.dump(root)

Описание форм настройки включения и выключения mod_rewrite в плагине

Теперь, когда mod_rewrite для nginx собран, необходимо добавить настройку включения его для доменов.

Здесь есть два пути как встроить новые настройки в конфигурацию, которую создает ispmanager:

1) ispmanager для nginx разрешает добавлять собственные настройки с помощью include, вот как выглядит типичный хост в nginx:

server {
	server_name userX.domain www.userX.domain;
	charset off;
	index index.php index.html;
	disable_symlinks if_not_owner from=$root_path;
	include /etc/nginx/vhosts-includes/*.conf;
	include /etc/nginx/vhosts-resources/userX.domain/*.conf;
	include /etc/nginx/users-resources/userX/*.conf;
	...
}

Можно использовать пути /etc/nginx/vhosts-resources/userX.domain/*.conf или /etc/nginx/users-resources/userX/*.conf. Так как нам нужна настройка для домена, а не глобально для пользователя, то можно взять путь /etc/nginx/vhosts-resources/userX.domain/*.conf, куда подкладывать файл с настройками mod_rewrite для nginx. И согласно документации к mod_rewrite для nginx нужно добавить такие директивы:

# cat /etc/nginx/vhosts-resources/userX.domain/mod_rewrite.conf
GlobalLocationRewriteEngine on;
HtaccessEnable on;

В данном случае включится обработка .htaccess файла, а так же для всех Location текущего сайта включится поиск правил mod_rewrite в .htaccess. Данный файл будет создаваться по событию создания или редактирования сайта в панели ispmanager. Т.е нужна будет галочка, создавать этот дополнительный файл или нет.

2) Второй вариант несколько сложнее, но позволяет более точечно включать mod_rewrite. Здесь потребуется изменить шаблон создания хоста в nginx. Согласно документации ispmanager, есть шаблоны - /usr/local/mgr5/etc/templates/default/nginx-vhosts.template и /usr/local/mgr5/etc/templates/default/nginx-vhosts-ssl.template. Их можно скопировать в папку /usr/local/mgr5/etc/templates/. И уже в этой папке их можно модифицировать и контрольная панель при обновлении их не удалит и не изменит. Таким образом, шаблон для хоста nginx можно перенастроить, чтоб генерировался следующий контент:

# cat /etc/nginx/vhosts/userX/userX.domain.conf
server {
	server_name domain;
	...
	location / {
		...
		RewriteEngine on;
	}
	location @php {
			...
		RewriteEngine on;
	}
	...
	HtaccessEnable on;
}

Для повышения гибкости настройки можно вынести обработку статических файлов (изображений, HTML) за пределы корневого Location — это позволит исключить применение правил mod_rewrite к статике. Такой подход даёт более тонкую настройку маршрутизации и снижает нагрузку на сервер. Но при таком способе встраивания, нужно учитывать, что шаблоны по умолчанию могут обновиться и измененные шаблоны так же нужно обновлять. Этот вариaнт можно организовать с помощью патчей, которые будут накладываться при активации mod_rewrite для nginx в настройках, при этом шаблоны по умолчанию при копировании в каталог /usr/local/mgr5/etc/templates/ будут изменены.

В итоге задание ясно, для будущего плагина нужна форма глобальных настроек, где:

  • можно отключить загрузку mod_rewrite в nginx;

  • выбрать тип, как именно встраиваться в конфигурационные файлы nginx (Вариант 1 или Вариант 2 описанные выше);

  • установить флаг для включения отладки работы плагина для ispmanager.

Форма будет описана так:

<metadata name="nginx_mod_rewrite_plugin_menu_settings" type="form">
      <form needconfirm="yes">
        <field name="nginx_mod_rewrite_plugin_menu_module_enable">
            <input type="checkbox" name="nginx_mod_rewrite_plugin_menu_module_enable"/>
        </field>
        <field name="nginx_mod_rewrite_plugin_menu_global_module_enable">
          <input type="checkbox" name="nginx_mod_rewrite_plugin_menu_global_module_enable"/>
        </field>
        <field name="nginx_mod_rewrite_plugin_menu_debug_enable">
          <input type="checkbox" name="nginx_mod_rewrite_plugin_menu_debug_enable"/>
        </field>
      </form>
    </metadata>

А так же нужно встроиться в форму редактирования сайта в ispmanager, чтоб добавить новый флажок:

<metadata name="webdomain.edit" type="form">
        <form>
            <page name="optimization">
                <field name="nginx_mod_rewrite_plugin_site_edit_enable">
                    <input type="checkbox" name="nginx_mod_rewrite_plugin_site_edit_enable"/>
                </field>
            </page>
        </form>
    </metadata>

В данных XML мы указываем, что нужно добавить на страницу редактирования сайта - webdomain.edit в подраздел <page name="optimization"> новое поле типа чекбокс.

Так же нам необходим пункт меню, который приведет администратора к глобальной форме настроек плагина:

<mainmenu level="admin+">
      <modernmenu>
        <node name="nginx_mod_rewrite_plugin_menu" customicon="/manimg/icons/mod_rewrite_menu.svg">
          <node name="nginx_mod_rewrite_plugin_menu_settings" customicon="/manimg/icons/mod_rewrite_tool.svg"/>
        </node>
      </modernmenu>
</mainmenu>

Вот как это выглядит в интерфейсе ispmanager:

Новое меню настроек
Новое меню настроек
Глобальное меню настроек
Глобальное меню настроек

Теперь можно добавить обработчик этих новых форм:

<handler name="nginx_form_rewrite_plugin.py" type="xml">
        <event name="webdomain.edit" after="yes"/>
        <func name="nginx_mod_rewrite_plugin_menu_settings"/>
</handler>

где func обработчик — это новая функция для обработки нового глобального меню, а event позволяет расширить функционал стандартной функции webdomain.edit, сработать после нее и обработать генерируемый ею XML. Этот обработчик так же представлен Python скриптом в каталоге /usr/local/mgr5/addon.

В этом Python обработчике на основе переменных окружения анализируются события, и выбирается тип действия, которое нужно произвести:

  • включить или отключить mod_rewrite

  • использовать шаблон или глобальную настройку для хоста nginx

  • включить или отключить отладку работы плагина ispmanager

  • обработать событие создания или изменения сайта

В момент переключения флажка «Использовать шаблон для настройки сайта» происходит копирование шаблонов nginx и их модификация.

И вот как теперь выглядит форма создания сайта при наличии плагина:

Настройка сайта
Настройка сайта

При включении указанной на рисунке выше галочки, для сайта срабатывает обработчик, который анализирует настройки и либо создает файл /etc/nginx/vhosts-resources/userX.domain/mod_rewrite.conf с глобальными настройками для хоста, или устанавливаются переменные для шаблона таким образом:

new_element = etree.Element("nginx_mod_rewrite_plugin_site_edit_enable")
new_element.text = "on"
root.append(new_element)

а сам шаблон /usr/local/mgr5/etc/templates/nginx-vhosts-ssl.template содержит такие настройки:

location / {
{% if $nginx_MOD_REWRITE_PLUGIN_SITE_EDIT_ENABLE == on %}
                RewriteEngine on;
{% endif %}

Сборка пакета плагина

И еще важное замечание, данный плагин ispmanager лучше устанавливать именно пакетом, а не просто раскладыванием файлов по каталогам в ручную. Т.к пакет устанавливает триггер(хук). И сама система управления программными пакетами отслеживает обновления nginx и запускает пересборку mod_rewrite для нового nginx.

Сборка RPM-пакета плагина происходит с помощью docker, больше ничего не требуется.

Для сборки пакета RPM плагина для ispmanager необходимо выполнить следующую команду:

bash build_package.sh almalinux:9

Где almalinux:9 – это может быть любой образ RPM‑based ОС.

Если сборка прошла успешно, в каталоге _packages появятся rpm‑файлы, пример таких файлов:

_packages/ispmanager-plugin-nginx_mod_rewrite_plugin-0.0.1-1.el9.src.rpm
_packages/ispmanager-plugin-nginx_mod_rewrite_plugin-0.0.1-1.el9.x86_64.rpm

На этом сборка окончена.

В итоге после установки пакета получаем модифицированный nginx с модулем mod_rewrite.

Результат работы mod_rewrite

Активируем mod_rewrite для подопытного сайта, который исследовали ранее.

Правило 1: index.php должен переадресоваться на index.php с параметром:

# curl -L http://user2.test.domain
Hello from index.php param=1

Правило 2: любой URL начинающийся с test1/ или test-ok/ должен переадресоваться в скрипт test1.php:

# curl -L http://user2.test.domain/test1/1.php
hello from test1.php param = 

Правило 3: любой URL начинающийся с test1/ или test-ok/ должен переадресоваться в скрипт test1.php:

# curl -L http://user2.test.domain/test-ok/m.php?param=1
hello from test1.php param = 1

Правило 4: test6.php должен переадресоваться внутренним редиректом на test2.php:

# curl -L http://user2.test.domain/test6.php
Hello from test2.php param=

Правило 5: а доступ к test3.php вообще должен быть запрещен:

# curl -L http://user2.test.domain/test3.php
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.30.2</center>
</body>
</html>

Теперь все верно.

​Итог

Благодаря разработанному плагину удалось существенно расширить функционал панели ispmanager: в стек серверного ПО интегрирован новый модуль-расширение для nginx. При этом за счёт оформления решения в виде модуля панели и использования пакетного менеджера реализована автоматическая пересборка модуля при обновлениях системного nginx — это обеспечивает совместимость и стабильность работы даже после апгрейда серверного ПО.

Комментарии (1)


  1. Iron_Butterfly
    20.08.2026 09:21

    Круто! Очень детально все расписано. Можно прямо брать и использовать как руководство для разработки других кастомных решений для ispmanager.