Показаны сообщения с ярлыком nginx. Показать все сообщения
Показаны сообщения с ярлыком nginx. Показать все сообщения

вторник, 14 февраля 2012 г.

Настройка nginx для работы exilog.


Небольшая заметка о настройке nginx для работы exilog. Опции exilog я не привожу, исходя из соображений безопасности и тривиальности настройки. Сам nginx не умеет CGI, для этого придется проксировать CGI-запросы на маленький производительный сервис thttpd. Собственно, сами действия:
1. Скачать thttpd

2. Распаковать


3. Конфигурирование
./configure —prefix=/usr

4. Наложить патч (http://wiki.nginx.org/ThttpdRealIP)

По умолчанию, thttpd не пропускает заголовок X-Forwarded-For. Этот патч преобразует X-Forwarded-For в Remote-Addr.

--- thttpd-2.25b/libhttpd.c 2003-12-25 20:06:05.000000000 +0100
+++ thttpd-2.25b-patched/libhttpd.c 2005-01-09 00:26:04.867255248 +0100
@@ -2207,6 +2207,12 @@
if ( strcasecmp( cp, "keep-alive" ) == 0 )
hc->keep_alive = 1;
}
+ else if ( strncasecmp( buf, "X-Forwarded-For:", 16 ) == 0 )
+ { // Use real IP if available
+ cp = &buf[16];
+ cp += strspn( cp, " \t" );
+ inet_aton( cp, &(hc->client_addr.sa_in.sin_addr) );
+ }
#ifdef LOG_UNKNOWN_HEADERS
else if ( strncasecmp( buf, "Accept-Charset:", 15 ) == 0 ||
strncasecmp( buf, "Accept-Language:", 16 ) == 0 ||

5. Компиляция
make
Если вылазит ошибка
htpasswd.c:52: ошибка: несовместимые типы для ‘getline’
Нужно отредактировать файл htpasswd.c и заменить название функции 'getline' by 'my_getline', поскольку такое название уже существует.

6. Установка
make install

cp ./contrib/redhat-rpm/thttpd.init /etc/init.d/thttpd
cp ./contrib/redhat-rpm/thttpd.conf /etc/

7. Отредактировать /etc/thttpd.conf, привести к виду:
dir=/var/www
#chroot
user=apache
logfile=/var/log/thttpd.log
pidfile=/var/run/thttpd.pid
port=9000
cgipat=**.pl
host=127.0.0.1
# charset=iso-8859-1

8. Добавить в автозагрузку thttpd
chkconfig --add thttpd

9. Настройка nginx
location /exilog {
proxy_pass http://127.0.0.1:9000;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}

10. Перезапуск nginx 
service nginx reload

Литература:

суббота, 11 февраля 2012 г.

Nginx+roundcube+ssl+non-standart port.

История о том, как взялся настроить связку nginx+php-fpm+roundcube в одной небольшой конторке. Собственно, во многих своих проектах стараюсь уходить от apache+mod_php к nginx+php-fpm, поскольку ее (связки) производительность и надежность, на мой взгляд, просто замечательная. Итак, задача сводилась к поднятию web-сервера с поддержкой SSL на нестандартном порту 8443. Под управлением данного web-сервера будут крутиться несколько сайтов, в том числе и roundcube.
Настройка конфигурации roundcube взята из моей предыдущей статейки, не буду поэтому повторяться, приводя аналогичные настройки. Генерация собственных сертификатов подробно описана на просторах интернета и вроде как вполне тривиальная задача, приведу просто команды, чтоб самому было легче вспоминать).
Итак,
1. Скачать дистрибутив roundcubemail-0.7.1.tar.gz с официального сайта.
2. Подключить репозиторий nginx и установить web-сервер
wget -c http://nginx.org/packages/rhel/6/noarch/RPMS/nginx-release-rhel-6-0.el6.ngx.noarch.rpm
yum -y install nginx-release-rhel-6-0.el6.ngx.noarch.rpm
yum -y install nginx
3. Подключить репозиторий remi и установить php-fpm

wget -c http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
rpm -Uvh remi-release-6.rpm
rpm --import http://rpms.famillecollet.com/RPM-GPG-KEY-remi
yum -y install php-fpm

4. Сгенерировать SSL-сертификаты/ключи и просмотреть информацию о них, переместить в директорию /etc/nginx/conf.d/

openssl req -new -x509 -extensions v3_ca -keyout private/rootCA.key -out rootCA.crt -days 5000 -config ./openssl.cnf
openssl x509 -in rootCA.crt -noout -purpose
openssl x509 -in rootCA.crt -noout -text
openssl x509 -in rootCA.crt -noout -dates


openssl req -new -nodes -out webmail.DOMAIN.csr -keyout webmail.DOMAIN.key -config ./openssl.cnf
openssl ca -out webmail.DOMAIN.crt -infiles webmail.DOMAIN.csr -config ./openssl.cnf
mv webmail.DOMAIN.{crt,key} /etc/nginx/conf.d/
chown 0.0 /etc/nginx/conf.d/webmail.DOMAIN.{crt,key}
chmod 444 /etc/nginx/conf.d/webmail.DOMAIN.crt
chmod 400 /etc/nginx/conf.d/webmail.DOMAIN.key

5. Настройка nginx+php-fpm. Приведу только измененные строки

server {
    listen       80;
    server_name  webmail.DOMAIN webmail;
    access_log  /var/log/nginx/webmail-access.log main;
    error_log /var/log/nginx/webmail-error.log;
    rewrite ^ https://webmail.DOMAIN:8443$request_uri permanent;
}


server {
    listen       8443;
    server_name  webmail.DOMAIN webmail;


    ssl                  on;
    ssl_certificate      /etc/nginx/conf.d/webmail.DOMAIN.crt;
    ssl_certificate_key  /etc/nginx/conf.d/webmail.DOMAIN.key;
    ssl_session_timeout  10m;
    ssl_session_cache    shared:SSL:10m;
    ssl_protocols  SSLv2 SSLv3 TLSv1;
    ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2;
    ssl_prefer_server_ciphers   on;


    access_log  /var/log/nginx/webmail-access.log main;
    error_log /var/log/nginx/webmail-error.log;
    root /var/www/rcube;
    index index.php;


    error_page 497 https://$host:8443$request_uri;


    location ~ ^/.+\.(jpg|png|gif)$ {
        expires max;
    }


    location ~* ^/(config|logs|temp|bin|sql)/.+$ {
        deny all;
    }


    location ~ \.php$ {
        fastcgi_param HTTPS on;
        include /etc/nginx/conf.d/php-pharm;
    }


    location ~ /\.ht {
        deny  all;
    }
}

6. Дальнейшая настройка roundcube (см. статью).

7. Важные моменты:
Указав, rewrite ^ https://webmail.DOMAIN:8443$request_uri permanent; я думал, что все сделано, но не тут то было. В ответ я получил 400 ошибку:
400 Bad Request
The plain HTTP request was sent to HTTPS port
Если изменить rewrite на обычный 443 порт и директиву listen соот. поменять 8443 на 443, то все работает.
Недолгий поиск в интернете приводит к решению. При переходе по протоколу HTTP по адресу, на котором HTTPS (ssl on), то будет сгенерирована (нестандартная) ошибка 497, соответственно на нее надо повесить error_page с перенаправлением. Ошибки 411, 414, 495, 496 и 497 могут возникнуть только на уровне сервера, НЕ на уровне location.

Литература:
http://forum.nginx.org/read.php?2,155978

суббота, 3 декабря 2011 г.

Chroot php-fpm в rhel6.


Возникла необходимость поставить php-fpm в chroot для увеличения безопасности одного популярного движка сайта. Небольшой рассказ о проделанной работе и возникших проблемах. Итак, php-fpm обладает замечательной возможностью запускать скрипты в chroot-окружении. Немного wikipedia: chroot — операция изменения корневого каталога в Unix-подобных операционных системах. Программа, запущенная с изменённым корневым каталогом, будет иметь доступ только к файлам, содержащимся в данном каталоге. Поэтому, если нужно обеспечить программе доступ к другим каталогам или файловым системам (например, /proc), нужно заранее смонтировать в целевом каталоге необходимые каталоги или устройства.
Немного об используемом ПО. Все крутится под 64-битной RHEL6. Настроена связка php-fpm + nginx, о настройке которой, наверно, будет рассказано в другой заметке. Сайт лежит в /data/www/DOMAIN.COM. Используются популярные библиотеки/программы для работы с видео/графикой, т.е. ffmpeg и ImageMagick.

Установка php-fpm.
a) Установить репозиторий remi:
wget http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
rpm -Uvh remi-release-6.rpm
b) Импорт GPG-ключа
rpmimport http://rpms.famillecollet.com/RPM-GPG-KEY-remi
c) yum -y install php-fpm

Настройка php-fpm.
Отмечу только те моменты, которые стоит изменить.

cat /etc/php-fpm.d/www.conf
; Название пула процессов
[www]
****
; Задаем пользователя, под которым будет работать php-fpm.
user = pf
; Тоже самое для группы.
group = pf
; При старте делать chroot в заданную директорию.
chroot = /data
chdir = /www/DOMAIN.COM
; Путь и параметры для отправки почты с помощью функции php mail()
php_admin_value[sendmail_path] = /usr/bin/mini_sendmail -t -fUSER@DOMAIN.COM -s192.168.0.x

****

Настройка nginx.

Параметры, которые будут передаваться FastCGI-серверу, т.е. Php-fpm. Обратите внимание, на закомментированные и рабочие строки. Nginx должен передать php-fpm параметры относительно корня chroot, т.е. НЕ /data/www/DOMAIN.COM, а /www/DOMAIN.COM.

cat /etc/nginx/fastcgi_params

fastcgi_param DOCUMENT_ROOT /www/DOMAIN.COM;
#fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SCRIPT_FILENAME /www/DOMAIN.COM$fastcgi_script_name;
#fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

Создание окружения для запуска скриптов (папки, файлы, библиотеки...)

Одна из самых интересных частей. Суть ее заключается в следующем: создаем необходимые папки в chroot-окружении, копируем необходимые библиотеки/файлы для работы сайта. Объем библиотек достаточно большой, надо внимательно скопировать нужные, в сети много скриптов, которые могут сделают за вас эту работу, но в первый раз рекомендую сделать вручную, чтобы понять что к чему.

# cd /data/
# mkdir -p /data/{bin,etc,var,lib64,tmp,usr}
# mkdir -p /data/usr/{share,bin,lib64}
# chmod 1777 tmp
для запуска ffmpeg и convert php требуется shell, придется копировать внутрь chroot bash или dash на ваш выбор.
# cp /bin/bash bin
# ln -s bash bin/sh
# cp /etc/{hosts,localtime,nsswitch.conf,resolv.conf} etc
# cp -R /usr/share/zoneinfo usr/share
# cp /usr/bin/{ffmpeg,convert} usr/bin
# cp /lib64/libnss_dns* lib64
# cp /lib64/libnss_files* lib64

Теперь важный момент — часто php-скриптам требуется определять днс-имена и временные зоны. Нужно скопировать в chroot-окружение библиотеки libnss. Для проверки определения имен я использую print_r(dns_get_record('google.com'));
Для каждого выполняемого файла в chroot-окружении необходимо скопировать нужные библиотеки (если только файл не скомпилирован статически, что бывает достаточно редко).
# ldd /usr/bin/ffmpeg
# ldd /usr/bin/convert
# ldd /bin/bash
На экран будет выведен список необходимых библиотек для указанных программ. Данные библиотеки вместе с символическими ссылками копируете в chroot-окружение (то, что лежит в /lib64 -> /data/lib64; то, что лежит в /usr/lib64 -> /data/usr/lib64).

Запуск и разбор возникающих ошибок

1. Функция php mail().
Для использования в php-скриптах функции mail() нужно либо копировать sendmail со всеми необходимыми библиотеками, либо статически слинковать mini_sendmail. Поскольку готового пакета mini_sendmail для rhel6 в репозиториях нет, придется качать и компилировать вручную.


# make
Если нижеследующей ошибки не возникает — можно пропустить.
gcc -O -s -static mini_sendmail.o -o mini_sendmail
/usr/bin/ld: cannot find -lc

Решение:
Нужно установить пакет glibc-static, который содержит все необходимые библиотеки для статической линковки программ.
# yum install glibc-static

Необязательный пункт, но все же.
Отредактируйте файл mini_sendmail.c, найдите строку:
username = getlogin();
заменить на:
username = "mini_sendmail";//getlogin();
Причем, на что вы измените имя юзера (username) роли не играет, просто это позволит избежать вызова функции getlogin() для определения вызывающего пользователя.
Для запуска необходим bash (sh) - нужно скопировать в chroot-директорию, а также скопировать нужные ему библиотеки.

2. Ошибка «php timezone database is corrupt»
Проверьте скопировали ли вы файлы /usr/share/zoneinfo в chroot.

3. Не пишутся логи ошибок php-fpm
проверьте есть ли директория /var/log/php-fpm/ внутри chroot и есть ли права у пользователя, под которым запускается php-fpm, на запись/создание файлов в данной папке.

4. Пляски вокруг ImageMagick
Появляются ошибки вида:

convert: UnableToOpenConfigureFile `delegates.xml' @ warning/configure.c/GetConfigureOptions/589.

Пришлось много гуглить, кто предлагает переустановить ImageMagick, кто скачать и перекомпилировать исходники, кто пользоваться библиотекой gd, вообщем рецептов много — выбирай на вкус. Оказалось все гораздо проще — надо скопировать необходимые конфигурационные файлы (*.xml) из папки /usr/lib64/ImageMagick-$version/ в /data/usr/lib64/ImageMagick-$version/

5. Сессии.

Почти внезапно перестали работать сессии. Связано с тем, что необходимого каталога нет в chroot-окружении. Выходов есть несколько: либо вести сессии в базе данных, либо создать необходимые папки с правами в chroot-окружении, либо изменить значение пути где хранятся сессии на /tmp.

Литература:

суббота, 22 октября 2011 г.

Небольшая заметка о настройке анализатора логов AWStats для web-сервера Nginx.


Во-первых, что такое AWStats?
AWStats является генератором отчетов веб-аналитики с открытым исходным кодом, пригодным для анализа данных интернет-сервисов, таких как веб, потокового мультимедиа, почта и FTP серверов. AWStats проводит разбор и анализ log файлов сервера, генерируя HTML отчеты. Данные визуально представлены в отчетах таблицами и гистограммами. Статические отчеты могут быть созданы через интерфейс командной строки, или через CGI-сценарии.
AWStats поддерживает большинство основных форматов Log-файлов веб-серверов, включая Apache (NCSA комбинированного / XLF / ELF log формат или обычный СLF log формат), WebStar, IIS (W3C log формат) и многих других распространенных log форматов веб-серверов.

Теперь об исходных данных. Настройка будет проходить на 64-битной OS RHEL6.1. Домен, для которого нужно создавать отчеты — DOMAIN.COM. Для просмотра статистики я создал дополнительный поддомен awstats.DOMAIN.COM с ограниченным доступом по IP и паролю.
Предполагается, что web-сервер nginx уже установлен и использует формат логов combined.
В конфигурации nginx всегда существует предопределённый формат "combined" (см. http://nginx.org/ru/docs/http/ngx_http_log_module.html):
log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';

Установка:
1. подключить репозиторий rpmforge
2. Установить пакеты awstats и perl-Geo-IPfree
yum -y install awstats perl-Geo-IPfree

Настройка Nginx:
Создаем отдельный виртуальный хост для awstats, в моем случае awstats.DOMAIN.COM
# cat /etc/nginx/conf.d/awstat.DOMAIN.COM.conf
server {
listen 80;
server_name awstats.DOMAIN.COM;
root /var/www/awstats/DOMAIN.COM;
index awstats.DOMAIN.COM.html;
access_log /var/log/nginx/awstats.DOMAIN.COM-access.log main;
error_log /var/log/nginx/awstats.DOMAIN.COM-error.log;

location = /favicon.ico {
access_log off;
log_not_found off;
}

location / {
auth_basic "Auth required";
auth_basic_user_file /etc/nginx/conf.d/htpasswd;

allow 192.168.0.0/16;
allow X.X.X.X;
allow Y.Y.Y.Y;
allow Z.Z.Z.Z;
deny all;
}

location /awstats/ {
alias /var/www/awstats/;
}

}

Пароли в файле /etc/nginx/conf.d/htpasswd должны быть зашифрованы функцией crypt(3). Для создания файла с паролями можно воспользоваться программой htpasswd из дистрибутива Apache. Например, htpasswd -c /etc/nginx/conf.d/htpasswd jack или если файл уже есть htpasswd /etc/nginx/conf.d/htpasswd jack.

Настройка awstats:
При установке создаются 2 файла в директории /etc/awstats
/etc/awstats/awstats.localhost.localdomain.conf
/etc/awstats/awstats.model.conf

Создаем новый профиль для нашего домена
cp /etc/awstats/awstats.localhost.localdomain.conf /etc/awstats/awstats.DOMAIN.COM.conf
Редактируем файл /etc/awstats/awstats.DOMAIN.COM.conf, он достаточно хорошо прокомментирован, я приведу лишь часть настроек, которые были изменены.

Рекомендую использовать для данной директивы только абсолютный путь к лог-файлу.
LogFile="/var/log/nginx/access.log"
Тип лог-файла, для web-сервера W, F — для ftp и т.п.:
LogType=W
Лог-файл в формате Apache combined, либо указать явно строку с форматом лога.
LogFormat=1
Информация в лог-файле разделена пробелами.
LogSeparator=" "
Указываем имя домена
SiteDomain="DOMAIN.COM"
Указываем все возможные псевдонимы домена
HostAliases="localhost 127.0.0.1 www.DOMAIN.COM"
В какой папке будут лежать БД awstats, на основе этих данных awstats сгенерирует отображаемую статистику.
DirData="/var/www/awstats/DOMAIN.COM"
Путь к папке с иконками
DirIcons="/awstats/icon/"

Подключаем плагины (если есть)
LoadPlugin="geoipfree"
LoadPlugin="geoip_city_maxmind GEOIP_STANDARD /var/www/awstats/GeoIPCity.dat"

Запуск Awstats
Заключается в запуске утилиты awstats.pl с необходимыми параметрами для сбора статистики. Для визуализации может использоваться awstats.pl, запущенная как CGI-скрипт, либо awstats_buildstaticpages.pl, создающая статические страницы на основе информации от awstats.pl.

cd /var/www/awstats
./awstats.pl -config=DOMAN.COM -update
Если вылазит ошибка
Error: Plugin load for plugin 'geoipfree' failed with return code: Error: Can't locate Geo/IPfree.pm in @INC

Решение: установить perl-Geo-IPfree (yum -y install perl-Geo-IPfree), либо закомментировать в конфигурации загрузку плагина geoipfree (#LoadPlugin="geoipfree")

Пример

/var/www/awstats/awstats.pl -config=DOMAIN.COM -update
Create/Update database for config "/etc/awstats/awstats.DOMAIN.COM.conf" by AWStats version 7.0 (build 1.971)
From data in log file "/var/log/nginx/access.log"...
Phase 1 : First bypass old records, searching new record...
Searching new records from beginning of log file...
Phase 2 : Now process new records (Flush history on disk after 20000 hosts)...
Jumped lines in file: 0
Parsed lines in file: 177287
Found 1130 dropped records,
Found 0 comments,
Found 0 blank records,
Found 380 corrupted records,
Found 0 old records,
Found 175777 new qualified records.

Dropped records — записи, отвергнутые по причине того, что они либо НЕ "user HTTP requests", либо отфильтрованы директивами SkipHosts, SkipUserAgents, SkipFiles, OnlyHosts, OnlyUserAgents и OnlyFiles.
Corrupted records - записи, не подходящие под формат лог-файла из директивы LogFormat
Old records - ранее обработанные записи
New records — новые записи

awstats_buildstaticpages.pl -config=DOMAIN.COM -update -lang=ru -awstatsprog=/var/www/awstats/awstats.pl -dir=/var/www/awstats/DOMAIN.COM/

Заходим браузером на http;//awstats.DOMAIN.COM и в случае успеха наблюдаем визуализированную статистику.

Добавляем в cron:
crontab -e
30 * * * * /var/www/awstats/awstats.pl -config=DOMAIN.COM -update >/dev/null
40 * * * * awstats_buildstaticpages.pl -config=DOMAIN.COM -update -lang=ru -awstatsprog=/var/www/awstats/awstats.pl -dir=/var/www/awstats/DOMAIN.COM/ >/dev/null

Не забываем перезапустить crond.
service crond restart

Добавляем в скрипт ротации логов Nginx
# cat /etc/logrotate.d/nginx
var/log/nginx/*log {
daily
rotate 10
missingok
notifempty
compress
sharedscripts
prerotate
/var/www/awstats/awstats.pl -update -config=DOMAIN.COM >/dev/null
endscript
postrotate
[ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid`
endscript
}

Литература: