Как добавить свой модуль nginx в контрольной панели ispmanager

от автора

Многие знают и используют контрольную панель 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     2echo "Hello from index.php param=". $_GET["param"];./test1.php     1<?php     2echo "hello from test1.php param = " . $_GET["param"];./test2.php     1<?php     2echo "Hello from test2.php param=" . $_GET["param"];     3     4./test3.php     1<?php     2echo "test3 should be forbidden";.htaccess     1RewriteEngine On     2# --- Rule 1: Add ?param=1 to /index.php (if not already present) ---     3RewriteCond %{QUERY_STRING} !^param=1 [NC]     4RewriteRule ^index\.php$ /index.php?param=1 [L,R=302]     5# --- Rule 2: /test1/* paths redirect to test1.php ---     6RewriteRule ^test1/(.*)$ /test1.php [L]     7# --- Rule 3: /test-ok/* paths redirect to test1.php ---     8RewriteRule ^test-ok/(.*)$ /test1.php [L]     9# --- Rule 4: /test6.php redirects to /test2.php ---    10RewriteRule ^test6\.php$ /test2.php [L]    11# --- Rule 5: /test3.php returns Forbidden (403) via RewriteRule ---    12RewriteCond %{REQUEST_URI} ^/test3\.php [NC]    13RewriteRule ^ / [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.domainHello 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.phptest3 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 -- nginxif [ -e /usr/local/ispmanager-mod_rewrite/settings/installed.cfg ]; then    /usr/local/ispmanager-mod_rewrite/utils/build_mod_rewrite.py --nodepsfi

Далее в обработчике описываются процедура 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.confGlobalLocationRewriteEngine 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.confserver {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.domainHello from index.php param=1

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

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

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

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

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

# curl -L http://user2.test.domain/test6.phpHello 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 — это обеспечивает совместимость и стабильность работы даже после апгрейда серверного ПО.

ссылка на оригинал статьи https://habr.com/ru/articles/1072286/