Tag Archives: Nginx

Установка модуля для Nginx на линуксе (debian)

Поднимаю тут проект один и не оказалось серверов на freebsd, поэтому был выбран debian, потому как он вроде лучший по производительности среди линуксов.

Сходу столкнулся с проблемой: на nginx нужно добавить модуль который по умолчанию не включен (image_filter). На фряхе для этого достаточно было бы сделать make config и отметить нужный модуль, но не на линуксе. Дебиану нужно для этого скачать исходники, вручную их поправить, собрать и установить. А потом еще смотреть что бы не обновить nginx со старым набором модулей.

# получаем исходники
apt-get source nginx
# переходим в папку (у вас может отличаться т.к. включает версию)
cd nginx-1.4.4
# открываем для редактирование файл с конфигом билда
nano debian/rules
# ищем строку ./configure и где то среди прочих параметров добавляем эту строку:
--with-http_image_filter_module \
# сохраняем и выходим с файла

# компилируем модуль
dpkg-buildpackage -us -uc -nc
# устанавливаем
dpkg -i nginx_0.7.65-1ubuntu2_amd64.deb

На этапе выполнения команды

dpkg-buildpackage -us -uc -nc

возникла ошибка:

dpkg-checkbuilddeps: Unmet build dependencies: debhelper (>= 7.0.50~) libssl-dev (>= 0.9.7) libpcre3-dev zlib1g-dev

Не хватает зависимостей. Непонятно почему дебиану не поставить их самостоятельно или спросить нужны они или нет. Но ладно, ставим сами:

apt-get install libssl-dev debhelper  libpcre3-dev zlib1g-dev

Пробуем заново

dpkg-buildpackage -us -uc -nc

Снова получаю ошибку

./configure: error: the HTTP image filter module requires the GD library.
You can either do not enable the module or install the libraries.

make[1]: *** [override_dh_auto_build] Error 1
make[1]: Leaving directory `/root/nginx-1.4.4'

Окей, ставим GD. Здесь еще надо отметить что нужна не libgd2-noxpm, а версия libgd2-noxpm-dev.

Ставим:

 apt-get install libgd2-noxpm-dev

Опять возвращаемся к

dpkg-buildpackage -us -uc -nc

На этот раз очередная ошибка

make[2]: Entering directory `/root/nginx-1.4.4'
make[2]: *** No rule to make target `build', needed by `default'. Stop.
make[2]: Leaving directory `/root/nginx-1.4.4'
dh_auto_build: make -j1 returned exit code 2
make[1]: *** [override_dh_auto_build] Error 2
make[1]: Leaving directory `/root/nginx-1.4.4'
make: *** [build] Error 2
dpkg-buildpackage: error: debian/rules build gave error exit status 2

После этого я удалил папку с исходниками и повторил поцедуру заново (зависимости то уже стоят) и в итоге получил такое

dpkg-deb: building package `nginx' in `../nginx_1.4.4-1~wheezy_amd64.deb'.
dpkg-deb: building package `nginx-debug' in `../nginx-debug_1.4.4-1~wheezy_amd64.deb'.
dpkg-genchanges >../nginx_1.4.4-1~wheezy_amd64.changes
dpkg-genchanges: including full source code in upload
dpkg-source --after-build nginx-1.4.4
dpkg-buildpackage: full upload (original source is included)

Из этого сообщения нам нужно скопировать название файла итогового.  И это nginx_1.4.4-1~wheezy_amd64.deb

Перехоим на директорию выше и устанавливаем модуль:

cd ../
dpkg -i nginx_1.4.4-1~wheezy_amd64.deb

Вроде все поставилось: Setting up nginx (1.4.4-1~wheezy) …

На этом квест закончился. Первое знакомство с линуксом совсем не добавляет к нему симпатии. То что я бы сделал простым включением опции в freebsd на дебиане нужно делать долго и с мучениями.

А вот еще по базовой настройке nginx, php-fpm, mysql без особых модулей можно почитать здесь. Написано хорошо и понятно.

Правильное подключение ssl сертификата на сайт.

Недавно столкнулся с такой проблемой, что у меня с браузером ФФ 25 сайт по https открывается без проблем, а у нескольких коллег выдает предупреждение о недоверенном сертификате. При чем в остальных браузерах у всех все было нормально.

В итоге проблема оказалась в том, что сертификат был подписан промежуточным центром сертификации, который был не во всех браузерах. Для решения этой проблемы нужно всего лишь слить содержимое файла *.crt и *.ca-bundle (которые выдаются обычно вместе).

Сделать это можно примерно такой командой:

cat www.example.com.crt bundle.crt > www.example.com.chained.crt

И затем прописываем в конфигурации этот файл:

server {
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.chained.crt;
    ssl_certificate_key www.example.com.key;
    ...
}

Еще одной новой фишкой nginx стала возможность задать в одной секции server настройки как для http так и для httpS. Это можно делать указанием слова ssl в строке listen. Для этого порта затем будет использовать ssl. И это избавляет от необходимости дублировать конфиг если у вас сайт доступен по обеим портам.

Пример конфига с работой по 80 (http) и 443 (https) портам:

server {
    listen              80;
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.chained.crt;
    ssl_certificate_key www.example.com.key;
    ...
}

//На самом деле эту информацию конечно же можно найти на официальном сайте (документация). Пишу здесь просто что бы предостеречь от ошибки, когда firefox выдает ошибку сертификата:

*****.com использует недействительный сертификат безопасности. К сертификату нет доверия, так как отсутствует цепочка сертификатов издателя. (Код ошибки: sec_error_unknown_issuer)

Отладка проекта на продакшене

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

Чаще всего это связано с нехваткой каких то модулей для php или чего угодно другого. Суть сводится к тому, что нужно включить вывод ошибок и посмотреть что происходит на сервере в момент ошибки.

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

В этом нам с легкостью поможет nginx (в апаче вроде можно сделать так же, но я им давно не пользуюсь).

Мы будем проверять наличие куки с определенным значением и если находим ее то выставляем переменную окружения APPLICATION_ENV в значение «development», а затем в коде по этому значению будем включать отображение ошибок.

Итак, редактируем файл /path/to/nginxconf/fastcgi_params (для freebsd это /usr/local/etc/nginx/fastcgi_params) и в конце дописываем:

set $appEnv 'production';
if ($http_cookie ~ "dev_cookie=secret_value" ) {
    set  $appEnv 'development';
}
fastcgi_param   APPLICATION_ENV  $appEnv;

Из этого понятно, что проверяться будет наличие куки с именем dev_cookie и значением secret_value. Конечно же для вашей реализации нужно изменить эти значения.

Установка переменной необходима потому как fastcgi_param нельзя использовать внутри if.

И после этого в коде используем такую небольшую конструкцию:

defined('APPLICATION_ENV') || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));

if (APPLICATION_ENV == 'development')
{
	error_reporting(E_ALL ^ E_NOTICE);
	ini_set('display_errors',1);
}
else
{
	error_reporting(0);
	ini_set('display_errors',0);
}

И если где то в коде еще потребуется разделять логику для девелопера/обычных посетителей то можем в любом месте делать проверку

(APPLICATION_ENV == 'development')

 

Теперь, если вам нужно включить для себя отображение ошибок вы должны в браузере для нужного сайта создать куку с именем dev_cookie и значением secret_value и все. Когда закончите отладку можете просто удалить куку.

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

Настройка автоматического обновления баз GeoIP

В дополнение к предыдущей статье по теме GeoIP (определяем страну посетителя через nginx) настроим автоматическое обновление базы.

Для этого пишем простой скрипт на баше:

#!/usr/local/bin/bash

echo Start update at `/bin/date`
cd /usr/local/etc/nginx/data/geo/
/usr/local/bin/wget -q http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
echo Saved, unzip..
/usr/bin/gunzip -f GeoIP.dat.gz
echo Unziped, reload nginx
/usr/local/etc/rc.d/nginx reload
echo

Пути к файлам при необходимости нужно подправить естественно.

После этого сохраняем в файл и добавляем в крон, для примера так:

10 3 * * * /usr/local/bin/bash /usr/local/etc/geoip_update/update.sh >> /usr/log/script/geoip_update.log

В данном случае базы будут обновляться ежедневно в 03:10.

Переносим Cacti и Nagios на другой сервер

Приветствую всех читателей моего уютного бложика!

Решил я на днях отделить систему мониторинга от обычных рядовых серверов и взял под эти нужды простенький впс на базе VDSManager. И стал я все настраивать да переносить, никаких сложностей не возникало, да вот только после того как все подготовительные работы были выполнены, оказалось что графики почему то не рисуются. При чем rrd файлы были на месте, но через веб интерфейс ответ rrdtool был пустым. Я пробовал выполнить от себя команду которая в дебаг режиме пишется в самом какти и в ответ получал либо

No match

либо

Bad system call

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

Несколько дней ожидания и админы дали свой вердикт — судя по всему vdsmanager накладывает какие то свои ограничения на ОС, что не позволяет правильно работать rrdtool которая должна рисовать графики.

Впринципе, для меня это было ожидаемо. Взял я себе тогда другой вдс уже покруче, на базе KVM, правда и стоит он в три раза дороже, но что ж, и тянуть должен бы больше, может еще что навешу на него.

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

Так вот, исходя из этого опыта несколько советов как правильно переехать на новое место обитания мониторинга.

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

  1. На старом сервере пакуем всю папку /usr/local/www/cacti и делаем дамп базы cacti
  2. Делаем дампы rrd файлов (как это сделать немного ниже)
  3. Скидываем надампеное на новый сервер
  4. На новом сервере копируем с заменой файлы config.php и все файлы из scripts/ без замены файлов, то есть добавляем то,  чего не хватает на новом.
  5. Восстанавливаем из дампов rrd файлы
  6. Ставим скрипт кактуса в крон как и при сетапе нового сервера.

Как сделать бекап и восстановление.

Вообще говоря есть стандартная функциональность rrdtool делать dump & restore. Почему мне этого было мало? — файлов несколько десятков, а запускать команду нужно на каждый файл отдельно, это просто издевательство так делать.

Выход прост — нагуглил уже готовый скрипт для масового переноса —  вот на этом форуме (второй пост)

Для надежности продублирую скрипт еще тут

 

#!/bin/bash

set_dump_values () {
        src_ftype="rrd"
        dest_ftype="xml"
}

set_restore_values () {
        src_ftype="xml"
        dest_ftype="rrd"
}

set_search_path () {
        search_path=$1
        log_path="${search_path}/rra_batch.log"
}

print_usage () {
        echo "Usage: $0 [COMMAND] [-c | -d [PATH]]"
        echo " "
        echo "Summary:"
        echo "Does either an rrdtool dump or an rrdtool restore of all files in the search directory."
        echo "This script will not look for .rrd files or .xml files to use outside of the specified search directory, but will recursively search throught the specified directory."
        echo " "
        echo "Commands:"
        echo "dump     Dumps files with .rrd in the file name to an XML file."
        echo "dump-nh  Dumps files with .rrd in the file name to an XML file."
        echo "         This command puts no headers in the output XML for compatibility with rrdtools 1.2.x."
        echo "restore  Restores files with .xml in the file name to an RRD file."
        echo " "
        echo "Options:"
        echo "-c  Search current working directory."
        echo "-d  Specify search directory."
        exit 0
}

log () {
        echo "[`date +%Y%m%d%H%M%S`] $1" >> ${log_path}
}

rrdtool_command () {
        case $1 in
                dump)
                        log "Dumping \"$name\" to ${new_name}.${dest_ftype}"
                        rrdtool $1 "$name" > "${new_name}.${dest_ftype}"
                        ;;
                dump-nh)
                        log "Dumping with no header \"$name\" to ${new_name}.${dest_ftype}"
                        rrdtool dump "$name" --no-header > "${new_name}.${dest_ftype}"
                        ;;
                restore)
                        log "Restoring \"$name\" to ${new_name}.${dest_ftype}"
                        rrdtool $1 "$name" "${new_name}.${dest_ftype}"
                        ;;
                *)
                        log "Illegal command: ${1}"
                        exit 1
                        ;;
        esac
}

case $1 in
        dump)
                set_dump_values
                ;;
        dump-nh)
                set_dump_values
                ;;
        restore)
                set_restore_values
                ;;
        *)
                print_usage $0
                ;;
esac

case $2 in
        -d)
                set_search_path $3
                ;;
        -c)
                set_search_path `pwd`
                ;;
        *)
                print_usage $0
                ;;
esac

echo "Logging output to $log_path..."
log "Search path set to \"$search_path\"."

for name in $(find $search_path -type f -print | grep [.]${src_ftype})
do
        if [ $name != "." ] ; then
                new_name=""
                OIFS=$IFS
                IFS='.'
                for name_element in $name
                do
                        if [ $name_element != $src_ftype ] ; then
                                if [ -z $new_name ] ; then
                                        new_name=$name_element
                                else
                                        new_name="${new_name}.${name_element}"
                                fi
                        fi
                done
                IFS=$OIFS
                if [ -n $name ] ; then
                        rrdtool_command $1
                fi
        fi
done

log "Finished batch."
echo "Done."
exit 0

Пользоваться им очень просто. Сохраняем скрипт где угодно, пусть это будет ~/rrdmove.sh

После этого на старом сервере:

bash ~/rrdmove.sh dump -d /usr/local/www/cacti/rra/
# создаем архив с дампами
tar -czf ~/rrd.tar.gz /usr/local/www/cacti/rra/*.xml
# кидаем файл на новый сервер
scp ~/rrd.tar.gz user@server:~/

После чего на новом сервер надо закинуть этот же скрипт куда либо, я для примера возьму тот же самый файл ~/rrdmove.sh и делаем следующее:

cd /usr/local/www/cacti/rra/
# распаковываем дампы
tar -xzf ~/rrd.tar.gz
# запускаем скрипт восстановления
bash ~/rrdmove.sh restore -d /usr/local/www/cacti/rra/
# удаляем дампы, они больше не нужны
rm /usr/local/www/cacti/rra/*.xml

Кто то может спросить — почему бы просто не скопировать rrd файлы и не дрочить мозг? — И я отвечу, что именно такой способ у меня возник первым. Но, как оказалось, rrd файлы платформо-зависимы, что означает что не всякие rrd файлы подойдут для новой системы. Отсюда и необходимость в их дампе/ресторе.

Касательно Nagios — там все просто — нужно скопировать и перенести папку /usr/local/etc/nagios/

Только не трогать /usr/local/www/nagios, во всяком случае cgi скрипты там, потому что они тоже платформо-зависимы и я потратил пару часов на то, что бы определить, почему бляха cgi скрипты не работают. Там только конфиг файл стоит перенести со старого, да и то, лучше его поправить заново ручками, а то может на новом сервере нагиос другой версии и там файл немного отличается.

Позже еще будет пост о настройке nagios, а то сразу я его поставил и он стоял без дела фактически  =)