= __Вариант настройки отказоустойчивого сервера FreeSwitch__ = == Исходные данные == Имеется ubuntu-16.04 c настроенным и работающим сервером !FreeSwitch, установленным из нашего репозитория, и используемым для организации диспетчерской связи. Требуется сделать резервирование из двух идентичных серверов !FreeSwitch. == Переносим базы данных !FreeSwitch в MySQL == === Устанавливаем драйвер MyODBC и настраиваем доступ к базе данных === ===== Устанавливаем необходимые пакеты ===== {{{ $ sudo apt-get install libodbc1 odbcinst unixodbc }}} ===== Установим драйвер myodbc ===== * Скачиваем архив mysql-connector-odbc-5.3.7-linux-ubuntu16.04-x86-64bit.tar.gz [https://dev.mysql.com/downloads/connector/odbc/ отсюда]; * Распаковываем архив: {{{ $ tar zxvf mysql-connector-odbc-5.3.7-linux-ubuntu16.04-x86-64bit.tar.gz }}} * Переходим в распакованный каталог: {{{ $ cd mysql-connector-odbc-5.3.7-linux-ubuntu16.04-x86-64bit }}} * Скопируем драйвер в каталог odbc: {{{ $ sudo cp lib/* /usr/lib/x86_64-linux-gnu/odbc/ }}} * Конфигурируем установленный драйвер с помощью инсталлятора: {{{ $ sudo bin/myodbc-installer -d -a -n MySQL -t "DRIVER=/usr/lib/x86_64-linux-gnu/odbc/libmyodbc5w.so;" }}} * Конфигурирвем источник: {{{ $ sudo bin/myodbc-installer -s -a -n freeswitch -t "DRIVER=MySQL;SERVER=127.0.0.1;DATABASE=dispatcher;OPTION=67108864" }}} где "dispatcher" - имя нашей базы данных на сервере MySQL. В результате в каталоге /etc должны быть созданы файлы odbc.ini и odbcinst.ini с приблизительно таким содержанием: odbc.ini: {{{ [freeswitch] Driver=MySQL SERVER=127.0.0.1 DATABASE=dispatcher PORT=3306 MULTI_STATEMENTS=1 }}} odbcinst.ini: {{{ [MySQL] Driver=/usr/lib/x86_64-linux-gnu/odbc/libmyodbc5w.so UsageCount=1 FileUsage=1 }}} ===== Проверим работу с базой данных MySQL серез ODBC ===== {{{ $ isql freeswitch +---------------------------------------+ | Connected! | | | | sql-statement | | help [tablename] | | quit | | | +---------------------------------------+ SQL> show tables; +-----------------------------------------------------------------+ | Tables_in_dispatcher | +-----------------------------------------------------------------+ | cdr | | options | | recordings | +-----------------------------------------------------------------+ SQLRowCount returns 10 10 rows fetched SQL> quit }}} где и - имя и пароль, установленные для доступа !FreeSwitch к базе данных при конфигурации !FreeSwitch. Теперь необходимо установить базе данных charset по умолчанию utf8, чтобы новые таблицы, которые создаст !FreeSwitch, использовали именно его: {{{ mysql> alter database character set utf8; Query OK, 1 row affected (0,00 sec) }}} где - имя базы данных. ==== Конфигурируем !FreeSwitch для хранения его данных в MySQL ==== ===== Конфигурируем SIP профили !FreeSwitch для хранения данных в MySQL ===== В файлах конфигурации SIP профилей в разделе добавляем такой параметр: {{{ }}} где и - имя и пароль, установленные для доступа !FreeSwitch к базе данных при конфигурации !FreeSwitch. Например: {{{ }}} Здесь же включаем track-calls: {{{ }}} Теперь в консоли !FreeSwitch перезапускаем профили командой: {{{ > sofia profile restart }}} где - имя SIP профиля, например: {{{ > sofia profile internal restart }}} Контролируем, что профили перезупустились с помощью команды в консоли FreeSwitch: {{{ > sofia status }}} В нашей базе данных должны создаться новые таблицы. Проверим это: {{{ $ mysql -u -p -e 'show tables' Enter password: +-------------------------------------+ | Tables_in_dispatcher | +-------------------------------------+ | cdr | | options | | recordings | | sip_authentication | | sip_dialogs | | sip_presence | | sip_registrations | | sip_shared_appearance_dialogs | | sip_shared_appearance_subscriptions | | sip_subscriptions | +-------------------------------------+ }}} ===== Конфигурируем хранение core-db в MySQL ===== Одна из таблиц (а именно, channels) при попытке ее создания с использованием кодировки utf8 превосходила лимит на максимальный размер строки в таблице mysql. Поэтому создаем эту таблицу вручную, немного изменив тип некоторых особо "жирных" столбцов: {{{ CREATE TABLE channels ( uuid VARCHAR(256), direction VARCHAR(32), created VARCHAR(128), created_epoch INTEGER, name VARCHAR(1024), state VARCHAR(64), cid_name VARCHAR(1024), cid_num VARCHAR(256), ip_addr VARCHAR(256), dest VARCHAR(1024), application VARCHAR(128), application_data TEXT(4096), dialplan VARCHAR(128), context VARCHAR(128), read_codec VARCHAR(128), read_rate VARCHAR(32), read_bit_rate VARCHAR(32), write_codec VARCHAR(128), write_rate VARCHAR(32), write_bit_rate VARCHAR(32), secure VARCHAR(64), hostname VARCHAR(256), presence_id TEXT(4096), presence_data TEXT(4096), accountcode VARCHAR(256), callstate VARCHAR(64), callee_name VARCHAR(1024), callee_num VARCHAR(256), callee_direction VARCHAR(5), call_uuid VARCHAR(256), sent_callee_name VARCHAR(1024), sent_callee_num VARCHAR(256), initial_cid_name VARCHAR(1024), initial_cid_num VARCHAR(256), initial_ip_addr VARCHAR(256), initial_dest VARCHAR(1024), initial_dialplan VARCHAR(128), initial_context VARCHAR(128) ); }}} В конфиг-файле switch.conf.xml добавляем параметр: {{{ }}} где и - имя и пароль, установленные для доступа !FreeSwitch к базе данных при конфигурации !FreeSwitch. Здесь же устанавливаем имя коммутатора: {{{ }}} Теперь выполняем рестарт !FreeSwitch: {{{ $ sudo service freeswitch restart }}} Убедимся, что в базе данных появились новые таблицы: {{{ $ mysql -u root -p dispatcher -e 'show tables' Enter password: +-------------------------------------+ | Tables_in_dispatcher | +-------------------------------------+ | aliases | | basic_calls | | calls | | cdr | | channels | | complete | | detailed_calls | | interfaces | | nat | | options | | recordings | | recovery | | registrations | | sip_authentication | | sip_dialogs | | sip_presence | | sip_registrations | | sip_shared_appearance_dialogs | | sip_shared_appearance_subscriptions | | sip_subscriptions | | tasks | +-------------------------------------+ }}} == Конфигурируем второй сервер == Устанавливаем и конфигурируем второй сервер полностью аналогично первому. Проверим, что установлены все необходимые модули. Конфигурацию нового сервера (/etc/freeswitch) можно целиком скопировать с первого. == Настраиваем репликацию между двумя серверами mysql == Останавливаем !FreeSwitch на обоих серверах: {{{ $ sudo service freeswitch stop }}} В конфиг-файлы mysqld добавляем следующее: {{{ server-id = 1 log_bin = /var/log/mysql/mysql-bin.log expire_logs_days = 10 max_binlog_size = 100M binlog_do_db = dispatcher }}} где {{{server-id}}} - идентификатор сервера, он должен быть разный у разных серверов. Перезапускаем mysqld на обоих серверах: {{{ $ sudo service mysql restart }}} Подключаемся к mysql серверу и создаем пользователя для репликации: {{{ mysql> CREATE USER 'replicator'@'%' IDENTIFIED BY 'password'; }}} заменив "password" каким-нибудь паролем. Даем пользователю право на репликацию: {{{ mysql> GRANT REPLICATION SLAVE ON *.* TO 'replicator'@'%'; }}} На сервере 1 блокируем базу данных на запись: {{{ mysql> FLUSH TABLES WITH READ LOCK; }}} Выводим состояние мастера: {{{ mysql> SHOW MASTER STATUS; }}} Будет выведена примерно такая таблица: {{{ +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000002 | 62249651 | dispatcher | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec) }}} Не выходя из консоли mysql (при выходе снимется блокировка), из другого терминала дампим базу данных: {{{ $ mysqldump -u root -p dispatcher >dispatcher.dump }}} Когда дамп будет готов, снова выведем {{{SHOW MASTER STATUS;}}} и убедимся, что значение {{{Position}}} не изменилось. Теперь можно снять блокировку: {{{ mysql> UNLOCK TABLES; }}} или просто выйти из консоли mysql. Копируем сделанный дамп базы на второй сервер. Записываем дамп в базу данных: {{{ $ mysql -u root -p dispatcher STOP SLAVE; mysql> CHANGE MASTER TO MASTER_HOST = '' , MASTER_USER = 'replicator', MASTER_PASSWORD = 'password', MASTER_LOG_FILE = 'mysql-bin.000002', MASTER_LOG_POS = 62249651; mysql> START SLAVE; }}} заменив "password" на тот пароль, который установили пользователю replicator ранее. Проверим, что репликация активирована: {{{ mysql> SHOW SLAVE STATUS\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.0.64 Master_User: replicator Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000003 Read_Master_Log_Pos: 118750 Relay_Log_File: r3-relay-bin.000002 Relay_Log_Pos: 82017 Relay_Master_Log_File: mysql-bin.000003 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 118750 Relay_Log_Space: 82221 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 1 Master_UUID: 7603167a-1081-11e6-9637-902b3433882b Master_Info_File: /var/lib/mysql/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: 1 row in set (0.00 sec) }}} Аналогично, только без выполнения/восстановления дампа настраиваем репликацию сервера 2 на сервер 1. == Синхронизация файлов конфигурации и записей переговоров == Синхронизацию файлов конфигурации и записей переговоров сделаем с помощью rsync. Чтобы схема была симметричной, каждый из серверов будет копировать свои обновившиеся файлы на другой сервер. Копирование будет производиться по SSH. Для начала проверим, что в /etc/passwd пользователю freeswitch установлен реальный shell (а не /bin/false или что-то аналогичное). При необходимости установим шелл командой: {{{ $ sudo usermod -s /bin/sh freeswitch }}} Генерируем пользователю freeswitch rsa ключ для ssh: {{{ $ sudo su -l freeswitch $ ssh-keygen -t rsa -b 4096 }}} В результате в домашнем каталоге пользователя freeswitch будет создан файл {{{.ssh/id_rsa.pub}}}. Добавляем содержимое этого файла в файл {{{.ssh/authorized_keys}}} в домашнем каталоге пользователя freeswitch на другом сервере. Проверим, что пользователь freeswitch с одного сервера может войти по ssh на другой сервер без ввода пароля: {{{ $ sudo su -l freeswitch $ ssh
Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-62-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage Last login: Wed Feb 22 11:27:59 2017 from 192.168.0.61 $ }}} Теперь, когда каждый из серверов может соединиться по SSH со своим собратом, настроим синхронизацию файлов конфигурации и записей переговоров. Для этого добавим в /etc/crontab каждого сервера такие записи: {{{ */5 * * * * freeswitch rsync -au -e ssh /etc/freeswitch/
:/etc/freeswitch/ */5 * * * * freeswitch rsync -au -e ssh /var/lib/freeswitch/recordings/
:/var/lib/freeswitch/recordings/ }}} В вышеприведенном примере файлы синхронизируются каждые 5 минут. Для более равномерного распределения нагрузки на сеть можно настроить серверам разное время синхронизации, например: {{{ 0-59/5 * * * * freeswitch rsync -au -e ssh /etc/freeswitch/ ....... 1-59/5 * * * * freeswitch rsync -au -e ssh /var/lib/freeswitch/recordings/ ........ }}} на первом сервере и {{{ 2-59/5 * * * * freeswitch rsync -au -e ssh /etc/freeswitch/ ....... 3-59/5 * * * * freeswitch rsync -au -e ssh /var/lib/freeswitch/recordings/ ........ }}} на втором сервере. Проверим работу синхронизации: на первом сервере создадим новый файл в /var/lib/freeswitch/recordings/ и изменим какой-нибудь файл в /etc/freeswitch/. Подождем 5 минут и убедимся, что на втором сервере появился новый файл в /var/lib/freeswitch/recordings/ и отразилось изменение файла в /etc/freeswitch/. Аналогично проверим копирование в обратном направлении. == Переключение на резерв == Далее будет описано два варианта настройки переключения на резервный сервер: * автоматическое переключение; * ручное переключение. === Автоматическое переключение === В этом варианте конфигурации мы будем использовать два общих IP адреса - один для базы данных MySQL, другой для !FreeSwitch. Общий адрес - это IP адрес, используя который один из двух серверов (активный) будет предоставлять сервис. Пусть для определенности общий адрес !FreeSwitch будет {{{192.168.0.63}}}, а общий адрес MySQL - {{{192.168.0.66}}}. Для автоматического переключения будем использовать протокол VRRP и демон keepalived. Этот демон будет обеспечивать поднятие на одном из серверов (активном, MASTER) общего адреса. Устанавливаем пакет keepalived: {{{ $ sudo apt-get install keepalived }}} Конфигурируем keepalived. Сначала создадим скрипт /etc/keepalived/ka-master.pl, который будет передавать !FreeSwitch команду sofia recover при переходе сервера в состояние MASTER: {{{#!perl #!/usr/bin/perl my $password = "secret"; open(STDOUT, "|/usr/bin/logger -t ka-master"); print "Instance went to master, issuing sofia recover.\n"; system("/usr/bin/fs_cli", "-p$password", "-x", "sofia recover"); }}} где "secret" меняем на наш пароль доступа к event-socket !FreeSwitch. Так как файл содержит пароль, не забываем установить ему права доступа, разрешающие чтение только для пользователя root: {{{ $ sudo chown root:root /etc/keepalived/ka-master.pl $ sudo chmod 700 /etc/keepalived/ka-master.pl }}} Создаем базовый файл конфигурации /etc/keepalived/keepalived.conf: {{{ global_defs { router_id FREESW } vrrp_instance VI_FREESW { state BACKUP interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass labuda25 } notify_master "/etc/keepalived/ka-master.pl" virtual_ipaddress { 192.168.0.63/24 dev eth0 label eth0:0 } } vrrp_instance VI_MYSQL { state BACKUP interface eth0 virtual_router_id 55 priority 100 advert_int 1 authentication { auth_type PASS auth_pass labuda52 } virtual_ipaddress { 192.168.0.66/24 dev eth0 label eth0:1 } } }}} где "eth0" - имя сетевого интерфейса - меняем его в соответствии с именем интерфейса каждого сервера. В данной конфигурации описано два экземпляра объекта vrrp: VI_MYSQL для сервера MySQL и VI_FREESW для сервера !FreeSwitch. Запускаем keepalived на одном из серверов: {{{ $ sudo service keepalived start }}} Контролируем в /var/log/syslog, что демон успешно запустился и, так как на втором сервере keepalived еще не запуцщен, сразу после запуска экземпляры VI_MYSQL и VI_FREESW должны перейти в состояние MASTER. Контролируем, что у сервера появились адреса 192.168.0.63 и 192.168.0.66. Теперь запускаем keepalived на втором сервере. Контролируем, что демон запустился, но экземпляры VI_MYSQL и VI_FREESW находятся в состоянии BACKUP, так как в сети уже есть MASTER. Контролируем переход сервера из состояния BACKUP в состояние MASTER. Для этого на несколько секунд отключаем активный в данный момент MASTER от сети (или просто останавливаем на нем демон keepalived). Контролируцем, что сервер, находившийся в состоянии BACKUP, перешел в состояние MASTER. Теперь необходимо изменить настройки odbc таким образом, чтобы оба сервера !FreeSwitch подключались к базе данных, используя общий адрес и, таким образом, подключались к одному и тому же серверу mysql. Для этого в ранее созданном файле /etc/odbc.ini указываем адрес сервера {{{192.168.0.66}}}. Устанавливаем параметр sysctl net.ipv4.ip_nonlocal_bind в значение 1 чтобы дать возможность неактивному серверу !FreeSwitch слушать адрес, отсутствующий на его интерфейсах: {{{ $ sudo sysctl net.ipv4.ip_nonlocal_bind=1 }}} Для автоматической установки этого значения в файл /etc/sysctl.conf добавляем строку {{{ net.ipv4.ip_nonlocal_bind=1 }}} В конфигурации профилей !FreeSwitch устанавливаем параметры {{{sip-ip}}}, {{{rtp-ip}}}, {{{presence-hosts}}}, {{{ext-sip-ip}}} и {{{ext-rtp-ip}}} в значение {{{192.168.0.63}}}. Теперь можно запустить сервера !FreeSwitch: {{{ $ sudo service freeswitch start }}} На данном этапе у нас настроен переход сервера из резерва в активное состояние по единственному критерию - недоступности мастера, определяемой по протоколу VRRP. Теперь добавим сюда контроль работоспособности !FreeSwitch. Для этого создадим скрипт /etc/keepalived/fs-status.sh: {{{#!sh #!/bin/sh password="secret"; profiles="internal internal6"; RESULT=`/usr/bin/fs_cli -p$password -x "sofia xmlstatus"` for P in $profiles; do echo $RESULT | grep -q "${P}" || exit 1 done exit 0; }}} где "secert" заменяем на пароль доступа к event-socket !FreeSwitch-сервера, а переменной {{{profiles}}} присваиваем имена SIP-профилей, наличие которых необходимо контролировать. Не забываем установить скрипту права доступа, чтобы ничто не мог украсть пароль. Теперь, если все перечисленные в {{{profiles}}} профили запущены, скрипт вернет 0, иначе - 1. Если требуется контролировать только один профиль, скрипт можно сделать более лаконичным: {{{#!sh #!/bin/sh password="secret"; profile="internal"; /usr/bin/fs_cli -p$password -x "sofia xmlstatus" | grep -q "${profile}" || exit 1 exit 0; }}} Проверим функционирование скрипта, запустив его вручную. Если все хорошо, укажем keepalived проверять работоспособность !FreeSwitch каждые 10 секунд. Для этого в /etc/keepalived/keepalived.conf добавляем секцию с описанием скрипта: {{{ vrrp_script chk_fs { script "/etc/keepalived/fs-status.sh" interval 10 } }}} и в секцию {{{vrrp_instance VI_FREESW}}} добавляем указание использовать этот скрипт: {{{ track_script { chk_fs } }}} Перезапустим keepalived: {{{ $ sudo service keepalived restart }}} Контролируем, что сервер в состоянии BACKUP. Теперь подключаемся к консоли !FreeSwitch и останавливаем профиль internal: {{{ > sofia profile internal stop }}} Ждем 10 секунд и контролируем, что экземпляр VI_FREESW перешел в состояние FAULT. === Ручное переключение === В этой схеме сервер, на котором поднят общий адрес, определяется командами администратора. Общий адрес - это IP адрес, используя который один из двух серверов (активный) будет предоставлять сервис. Пусть для определенности это будет адрес {{{192.168.0.63}}}. Для начала установим пакет arping: {{{ $ sudo apt-get install arping }}} Теперь необходимо изменить настройки odbc таким образом, чтобы оба сервера !FreeSwitch подключались к базе данных используя общий адрес и, таким образом, подключались к одному и тому же серверу mysql. Для этого в ранее созданном файле /etc/odbc.ini указываем адрес сервера {{{192.168.0.63}}}. Устанавливаем параметр sysctl net.ipv4.ip_nonlocal_bind в значение 1 чтобы дать возможность неактивному серверу !FreeSwitch слушать адрес, отсутствующий на его интерфейсах: {{{ $ sudo sysctl net.ipv4.ip_nonlocal_bind=1 }}} Для автоматической установки этого значения в файл /etc/sysctl.conf добавляем строку {{{ net.ipv4.ip_nonlocal_bind=1 }}} В конфигурации профилей !FreeSwitch устанавливаем параметры {{{sip-ip}}}, {{{rtp-ip}}}, {{{presence-hosts}}}, {{{ext-sip-ip}}} и {{{ext-rtp-ip}}} в значение {{{192.168.0.63}}}. Теперь можно запустить сервера !FreeSwitch: {{{ $ sudo service freeswitch start }}} Для управления переключением на каждом из серверов установим lighttpd: {{{ $ sudo apt-get install lighttpd }}} На каждом из серверов добавим два cgi-скрипта - один для отображения текущего состояния сервера, другой - для активации/деактивации сервера. Скрипт страницы состояния {{{/var/www/html/cgi-bin/status.sh}}}: {{{#!sh #!/bin/sh # Имя сетевого интерфейса с общим адресом IFNAME="eth2:0" # Название сервера в заголовке страницы HEADER="Сервер 1" # Генерируем веб-страницу с состоянием и кнопкой "Активировать"/"Деактивировать" echo "Content-Type: text/html; charset=utf-8" echo "Cache-Control: no-cache" echo echo '' echo "" echo " " echo ' ' echo " ${HEADER}" echo " " echo " " echo "

${HEADER}

" echo '
' if ifconfig -a | grep -q "^${IFNAME} "; then echo '
Активен
' echo '
' else echo '
В резерве
' echo '
' fi echo '
' echo " " echo "" }}} где переменные {{{IFNAME}}} и {{{HEADER}}} устанавливаем в соответствии с именем именем сетевого интерфейса каждого сервера и желаемым заголовком соответственно. Скрипт активации/деактивации {{{/var/www/html/cgi-bin/onoff.sh}}}: {{{#!sh #!/bin/sh IFNAME="eth0:0" IFADDR="192.168.0.63" PASSWORD="secret" echo "Content-Type: text/html; charset=utf-8" echo "Cache-Control: no-cache" echo "Refresh: 5; url=/cgi-bin/status.sh" echo echo '' echo "" echo " " echo ' ' echo " ${HEADER}" echo " " echo " " case ${QUERY_STRING} in action=on) echo "

Активируем сервер...

" sudo /sbin/ifconfig ${IFNAME} ${IFADDR} sudo /usr/sbin/arping -c3 -W0.2 -PUq -S ${IFADDR} ${IFADDR} /usr/bin/fs_cli -p${PASSWORD} -x "sofia recover" ;; action=off) echo "

Деактивируем сервер...

" sudo /sbin/ifconfig ${IFNAME} down ;; *) ;; esac echo " " echo "" }}} аналогично, переменным {{{IFNAME}}} и {{{IFADDR}}} в начале скрипта присваиваем имя сетевого интерфейса и общий адрес, переменной {{{PASSWORD}}} присваиваем пароль доступа к event-socket сервера !FreeSwitch. Так как скрипт содержит пароль, не забудем ограничить права доступа: {{{ $ sudo chown www-data:www-data /var/www/html/cgi-bin/onoff.sh $ sudo chmod 700 /var/www/html/cgi-bin/onoff.sh }}} Теперь разрешим выполнение команд {{{ifconfig}}} и {{{arping}}} для пользователя www-data, от которого работает процесс lighttpd. Для этого добавляем в файл {{{/etc/sudoers}}} такие строчки: {{{ www-data ALL=(ALL) NOPASSWD:/sbin/ifconfig eth0\:0 * www-data ALL=(ALL) NOPASSWD:/usr/sbin/arping -c3 -W0.2 -PUq -S * * }}} Разрешим выполнение cgi-скриптов серверами lighttpd: {{{ $ sudo ln -s ../conf-available/10-cgi.conf /etc/lighttpd/conf-enabled/ }}} Теперь создадим HTML-страницу {{{/var/www/html/index.html}}}, на которой будет отображаться два фрейма с состоянием наших серверов: {{{#!xml Управление серверами }}} где вместо {{{192.168.0.61}}} и {{{192.168.0.62}}} впишем адреса серверов. Выполним рестарт lighttpd: {{{ $ sudo service lighttpd restart }}} Проверим, что получилось, открыв браузером корневую страницу любого из серверов. Мы увидим что-то типа: [[Image(pic1.jpg)]] Проверим работу cgi-скриптов, нажимая кнопку "Деактивировать"/"Активировать". Нажатие должно приводить к появлению/пропаданию алиаса с общим адресом. Кроме этого, активация должна сопровождаться передачей трех ARP-пакетов для обновления ARP-таблиц сетевых устройств.