Доброго всем LOCALTIME ! 🙂
Решил поделиться с общественностью своими скриптами для связки directadmin и nginx.
В свое время для снижения нагрузки на apache было решено поставить nginx. После некоторого гугления была сделана первая попытка связать панель и nginx. На тот момент скрипт умел совсем немного – только создавать и удалять конфигурационные файлы виртуальных хостов. Он не умел работать ни с поддоменами, ни с алиасами, не умел и переименовывать конфиги доменов.
Затем последовала вторая попытка. Этот скрипт уже был немного “умнее”. Он умел создавать, удалять не только домены, но и поддомены. Однако, после того, как количество вирт. хостов выросло и управляться с большим количеством доменов стало как-то трудно, было решено полностью переписать всю схему работы связки directadmin и nginx. Все домены/поддомены/алиасы будут описываться в map-файле, а в конфиге будут использоваться соответствующие переменные, тем самым будет использоваться всего один небольшой общий конфиг, в котором и описывается виртуальный хост.
“Особые” домены описываются в отдельных конфигурационных файлах.
Кроме того, логи для всех вирт. хостов будет писать nginx, освободим нашего монстра apache от этой обязанности и оставим ему писать только error_log. Что положительно скажется на производительности.
Сказано – сделано.
По моей просьбе и некоторому подобию ТЗ, мой друг Александр Русских написал совсем новый и удобный скрипт, который и будет использоваться в этой статье.
Еще одна моя просьба была направлена Кириллу Коринскому, который написал небольшой патч для nginx. Данный патч выдает 503 ошибку, если уровень load average системы выше заданного в конфиге значения. Да, это грубо, но зато может уберечь сервер от ухода в глубокий своп. Поэтому уровень LA необходимо указывать заведомо высокий.
Итак, поехали.
Часть первая (Если nginx уже установлен – смотрим вторую часть)
У нас в распоряжении сервер с установленной панелькой DirectAdmin (отличная, кстати, панель). Чтобы не делать из системы свалку, nginx будет ставиться из репозитария.
Добавляем репозитарий в список, импортируем ключи и ставим nginx:
# echo "deb http://ftp2.debian.org.ua/debian-dou/ lenny main" >> /etc/apt/sources.list # gpg --keyserver keys.gnupg.net --recv-keys 0A3D4789 gpg: requesting key 0A3D4789 from hkp server keys.gnupg.net gpg: key 0A3D4789: public key "Debian.org.ua Custom Repository " imported gpg: Total number processed: 1 gpg: imported: 1 # gpg --armor --export 0A3D4789 | apt-key add - OK # aptitude update # aptitude install nginx
Стоит заметить, что в этот пакет включено два неофициальных патча, которые описаны в блоге автора
После установки nginx не запустится – это нормально, так как на 80-м порту все еще работает apache.
Дальше будем приводить в порядок конфигурационные файлы apache и nginx.
Часть вторая – Настройка nginx.
Открываем файл /etc/nginx/nginx.conf и вносим изменения в секцию http {}
http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] $host $request "$status" $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for" [$user:$domain] "$upstream_response_time"'; log_format domain '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; log_format ip '$remote_addr'; log_format bytes '$body_bytes_sent'; access_log /var/log/nginx/access.log main; server_tokens off; reset_timedout_connection on; .... .... include maps.conf; server { listen 1.2.3.4:80 default deferred; server_name _; location ~ /.svn/ { deny all; } # include custom_vhost.conf; include maps_vhost.conf; } }
Описываемые форматы log-файла нужны для того, чтобы nginx писал логи для каждого вирт. хоста (apache будет писать только error_log)
В файле custom_vhost.conf – можно описать “особенные” домены, для которых нужны какие-то персональные дополнительные настройки.
Файл maps_vhost.conf – это и есть общий конфиг для всех доменов/поддоменов/алиасов:
set $root /home/$user/domains/$domain/public_html/$subdomain;
set $domainlog $domain.$subdomain;
if ($subdomain = "") {
set $root /home/$user/domains/$domain/public_html;
set $domainlog $domain;
}
if ($user = "") {
set $root /var/www/html;
set $domainlog ip;
}
## maintenance mode
# error_page 403 404 500 502 503 504 /maintenance.html;
# location = /maintenance.html {
# log_not_found on;
# access_log off;
# root html;
# }
error_page 500 502 503 504 /50x.html;
location = /50x.html { root html; }
location / {
log_not_found on;
root $root;
access_log /var/log/httpd/domains/$domainlog.bytes bytes;
access_log /var/log/httpd/domains/$domainlog.log domain;
access_log /var/log/nginx/access.log main;
proxy_redirect off;
proxy_set_header Cookie $http_cookie;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:80;
}
location ~ /\.ht { deny all; }
location ~* ^/(webmail|squirrelmail|roundcube|phpMyAdmin)/.+\.(bmp|jpg|jpeg|gif|ico|cur|png|css|doc|txt|js|docx|rtf|ppt|pdf|svg)$ {
expires 24h;
root /var/www/html;
gzip off;
log_not_found off;
access_log /var/log/httpd/domains/$domainlog.bytes bytes;
access_log /var/log/httpd/domains/$domainlog.log domain;
}
location ~* ^.+\.(css|htc|js|bmp|jp?g|gif|ico|cur|png|doc|avi|txt|doc|rtf|swf)$ {
expires 24h;
root $root;
gzip off;
access_log /var/log/httpd/domains/$domainlog.bytes bytes;
access_log /var/log/httpd/domains/$domainlog.log domain;
log_not_found off;
}
Map-файл с описанием доменов выглядит так:
map $http_host $user{
hostnames;
default "";
.adminco.org "admin";
.nginx.ks.ua "admin";
.site2.com "user2";
....
}
map $http_host $domain {
hostnames;
default "";
.adminco.org "adminco.org";
.nginx.ks.ua "nginx.ks.ua";
.site2.com "site2.com";
....
}
map $http_host $subdomain {
hostnames;
default "";
.blog.adminco.org "blog";
....
}
Этот файл управляется скриптом generate_map.pl, о чем будет написано ниже.
Здесь я привожу немного сокращенное описание виртуального хоста, так сказать, для примера.
Первоначально “пустой” файл maps.conf имеет вид:
map $http_host $user{
hostnames;
default "";
}
map $http_host $domain {
hostnames;
default "";
}
map $http_host $subdomain {
hostnames;
default "";
}
Если на Вашем сервере уже имеются созданные юзеры с их доменами, обратите внимание на UPDATE 2 в конце статьи.
Часть третья – Настройка custom script в Directadmin.
Переходим в /usr/local/directadmin/scripts/custom
В этом каталоге есть файл README, где описан каждый custom-скрипт, который может быть выполнен панелью DirectAdmin. Нам нужно будет создать следующие скрипты:
touch user_destroy_post.sh domain_create_post.sh \ domain_destroy_post.sh domain_change_post.sh \ subdomain_create_post.sh subdomain_destroy_post.sh \ domain_pointer_create_post.sh domain_pointer_destroy_post.sh
Эти скрипты будут вызываться панелью при каждом добавлении/удалении домена/поддомена/алиаса или изменении имени домена.
Содержимое файлов.
Скрипт добавления домена – domain_create_post.sh
#!/bin/sh PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin LANG=C export LANG export PATH /usr/local/directadmin/scripts/custom/generate_map.pl -ad $username $domain if [ $? -gt 0 ]; then exit 1; fi /etc/init.d/nginx configtest > /dev/null if [ $? -gt 0 ]; then exit 1; else /etc/init.d/nginx reload fi exit 0;
Результат выполнения – добавление домена и имени юзера в мап-файл, с последующим релоадом nginx
Скрипт удаления юзера – user_destroy_post.sh
#!/bin/sh PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin LANG=C export LANG export PATH /usr/local/directadmin/scripts/custom/generate_map.pl -dd $username $domain if [ $? -gt 0 ]; then exit 1; fi /etc/init.d/nginx configtest > /dev/null if [ $? -gt 0 ]; then exit 1; else /etc/init.d/nginx reload fi exit 0;
При вызове скрипт удаляет из map-файла пользователя, проверяет корректность конфигурации nginx и если все нормально – делает релоад nginx-у.
Аналогичные скрипты для создания/удаления алиасов и поддоменов.
Как видно из скриптов – все действия выполняются с помощью “generate_map.pl”
Этот скрипт отвечает за работу с мап-файлом для nginx-а.
Возможности скрипта:
(l) copyleft Olden Gremlin aka Alexander P. Russkih, oldengremlin(at)gmail.com, 2009-2010
Use: ./generate_map.pl [-d] [-c maps.conf] {[{-ad|-dd|-aa|-da|-as|-ds} {username}
{domain} [newdomainname|subdomain|alias]] [...]}
Внимание! Важен порядок следования модификаторов именно в том порядке в котором он описан в Use.
Конфигурационные модицикаторы
-d выводить в stdout diff итоговой работы
-c maps.conf путь к файлу с конфигами maps (опционально)
"Циклические" командные модификаторы
-ad добавить домен
-rd переименовать домен
-dd удалить домен и все поддомены в нем
-aa добавить алиас alias к domain
-da удалить алиас alias
-as добавить subdomain к domain
-ds удалить только subdomain
Идем дальше.
Готовим custom-шаблоны для виртуальных хостов Directadmin.
Скопируем шаблоны для дальнейней правки:
cd /usr/local/directadmin/data/templates; cp ./virtual_host2* ./custom
в этих шаблонах виртуального хоста нужно изменить строку:
на
Также, уберем запись лог-файлов apache.
Заменим эти строки:
CustomLog /var/log/httpd/domains/|DOMAIN|.bytes bytes CustomLog /var/log/httpd/domains/|DOMAIN|.log combined
на это:
# CustomLog /var/log/httpd/domains/|DOMAIN|.bytes bytes # CustomLog /var/log/httpd/domains/|DOMAIN|.log combined
Аналогично нужно изменить шаблон поддомена
(файл /usr/local/directadmin/data/templates/custom/virtual_host2_sub.conf)
Часть четвертая – Настройка Apache.
Открываем файл /etc/httpd/conf/extra/httpd-vhosts.conf, находим эту строку:
Include /etc/httpd/conf/ips.conf
и заменяем на это:
Include /etc/httpd/conf/ips_cust.conf
Сохранияем изменения, копируем /etc/httpd/conf/ips.conf в /etc/httpd/conf/ips_cust.conf
В новом файле необходимо заменить все внешние ip, которые слушает апач на 80-м порту на одну строчку:
NameVirtualHost 127.0.0.1:80
В итоге этот файл может иметь примерно такой вид:
LogFormat "%O \"%r\"" homedir
NameVirtualHost 127.0.0.1:80
NameVirtualHost 1.1.1.1:443
NameVirtualHost 1.2.3.4:443
SSLEngine on
SSLCertificateFile /etc/httpd/conf/ssl.crt/server.crt
SSLCertificateKeyFile /etc/httpd/conf/ssl.key/server.key
ServerName shared.domain
ScriptAliasMatch ^/~([^/]+)/+cgi-bin/+(.*) /home/$1/public_html/cgi-bin/$2
AliasMatch ^/~([^/]+)(/.*)* /home/$1/public_html$2
DocumentRoot /home/admin/domains/sharedip
SuexecUserGroup admin admin
CustomLog /var/log/httpd/homedir.log homedir
SSLEngine on
SSLCertificateFile /etc/httpd/conf/ssl.crt/server.crt
SSLCertificateKeyFile /etc/httpd/conf/ssl.key/server.key
ServerName shared.domain
ScriptAliasMatch ^/~([^/]+)/+cgi-bin/+(.*) /home/$1/public_html/cgi-bin/$2
AliasMatch ^/~([^/]+)(/.*)* /home/$1/public_html$2
DocumentRoot /home/admin/domains/sharedip
SuexecUserGroup admin admin
CustomLog /var/log/httpd/homedir.log homedir
Делается это для того, чтобы apache слушал 80 порт только локально и при добавлении или измении ip адресов в Directadmin-е не заменялся этот конфиг. В данной реализации конфига SSL-соединения обрабатываются самим apache, поэтому настройки SSL не меняются.
Просим панель пересоздать пользовательские httpd.conf файлы:
echo “action=rewrite&value=httpd” >> /usr/local/directadmin/data/task.queue
После пересоздания пользовательских httpd.conf можно проверить корректность вновь созданных конфигов и перезапустить apache и nginx:
# apachectl configtest ; nginx -t Syntax OK the configuration file /etc/nginx/nginx.conf syntax is ok configuration file /etc/nginx/nginx.conf test is successful
В итоге, apache будет слушать локальный 80 порт и внешний 443.
На внешних 80 портах будет жить nginx, который принимает и обслуживает запросы клиентов.
Статика полностью отдается nginx-ом, а скрипты отправляются на обработку apache.
Дополнительно в конфигурации вирт.хоста nginx-а можно добавить ограничение по количеству запросов в секунду, ограничить количество запросов к апаче с одного IP, кеширование и т.д. и т.п.
Данная конфигурация уже больше года довольно успешно работает более, чем на 10-ти серверах.
Кому будет интересно – оставляйте коментарии, скрипт отправлю по email.
Так же выслушаю любые поправки, коментарии, дополнения и т.д.
UPDATE.
Совершенно забыл написал, что для апачи нужно доставить модуль mod_rpaf, иначе в логах апачи будет фиксироваться локальный ip адрес вместо ip клиентов.
Добавляется модуль просто:
cd /usr/local/directadmin/custombuild wget http://www.stderr.net/apache/rpaf/download/mod_rpaf-0.6.tar.gz tar xf mod_rpaf-0.6.tar.gz cd mod_rpaf-0.6 apxs -i -c -n mod_rpaf-2.0.so mod_rpaf-2.0.c
Теперь чуть подправим конфиг httpd.conf. Добавим в начало файла:
LoadModule rpaf_module /usr/lib/apache/mod_rpaf-2.0.so RPAFenable On RPAFproxy_ips 127.0.0.1 x.x.x.x RPAFsethostname On RPAFheader X-Forwarded-For
x.x.x.x – внешний IP адрес сервера. Если их несколько – добавляются через пробел
Записываем изменения и проверяем синтаксис:
apachectl configtest Syntax OK
UPDATE 2.
Один из читателей попросил скриптик для генерации файла maps.conf для уже существующих аккаунтов на сервере.
Что ж, я не сильный скрипто-писатель, тем не менее скрипт набросал.
Скрипт пересоздает полный maps.conf используя данные из /usr/local/directadmin/data/users/
Взять можно по этой ссылке.
Вот теперь все 🙂
Благодарности.
Хочу выразить спасибо Игорю Сысоеву за создание и написание nginx,
Александру Русских за написание скрипта,
Кириллу Коринскому за написание патчей,
клиентам, которые согласились устраивать эксперименты на их серверах,
а также компании Google за их поисковик 🙂
© Просто БлогЪ, AdminCo, 2010
Используя информацию этой статьи, уважайте чужой труд – указывайте ссылку на источник и авторов
очень интересно, но если не сложно дай свою почту или icq хочу кое-что спросить !
Не сложно.
admin # adminco.org
Доброго времени суток
Спасибо за хорошую статью. Видна рука профессионала)
Буду очень благодарен если вышлете generate_map.pl и другие скрипты.
Xman, скрипт уехал к Вам.
Опробуете – отпишитесь. может какие то дополнения будут 🙂
Можете мне скрипты скинуть. Только поставил новую DA. Очень хочу попробовать. Обязательно отпишусь. Спасибо!
Kirill,
скрипт о описание отправил.
Умно. Работает
Спасибо за статью, очень интернестное решения, хотелось бы взглянуть на сам скрипт, буду очень признателен.
заранее спасибо.
Денис, скрипт отправлен.
Интересная статья! И мне скриптик пожалуйста, если можно)
Максим,
и Вам уехало )
to all.
Обновил статью, забыл сразу написать про дополнительный модуль к апаче.
Спасибо за статью.
Буду очень благодарен за скриптик.
Уехало на мыл.
Спасибо за статью, сейчас буду пробовать
Если не затруднит, скиньте скрипт на почту 🙂
Спасибо за статью.
Буду очень благодарен за скрипт. Пошлите пожалуйста на почту
Отличная статья. и как раз вовремя =) если можно скрипт.
Заранее спасибо!
итак все поставил …. но есть проблемка, скорее всего это проблема с доступом.
не создается файл maps.conf
соот-но ничено не срабатывает.
и ещё вопрос, можно ли заполучть скрипты для субдоменов, т.к. в баше не силен.
если запустить скрипт вручную из консоли, создается map-файл ?
Например:
./generate_map.pl -ad user domain.tld
Убедитесь, что в самом скрипте правильно указан путь к мап-файлу или укажите его месторасположение c помощью ключа: -c /path/to/nginx/maps.conf
Насчет поддоменов – тут все просто и делается по аналогии с созданием доменов.
Почитайте файл /usr/local/directadmin/scripts/custom/README – в нем подробно описаны переменные.
Как пример, создание поддомена:
admin – пожалуйста, вышлите скрипт на мыло, буду признателен.
Спасибо
подскажите, как с этим бороться
nginx -t
[emerg]: unknown log format “bytes” in /etc/nginx/maps_vhost.conf:27
configuration file /etc/nginx/nginx.conf test failed
nginx -v
nginx version: nginx/0.8.52
ставил из
ftp2.debian.org.ua/debian-dou
В секцию http { } в основном конфиге добавить формат лога:
Вышлите пожалуйста и нам скрипт
спасибо все заработало!
Рад, что Вам помогло.
Значит не зря придумывал 🙂
Привет. У меня проблема. Nginx ругается на переменные которые находятся в файле maps_vhost.conf
Пишет следующее: Performing sanity check on nginx configuration:
[emerg]: unknown “username” variable
То есть это те самые переменные что лежат в файле. как быть?
admin, а геде этот сам файл ( include maps.conf ) ? Содержание его? У меня при проверки просит его и выдает ошибку что нет этого файла, что делать?
[emerg]: open() “/etc/nginx/maps.conf” failed (2: No such file or directory) in /etc/nginx/nginx.conf:35
configuration file /etc/nginx/nginx.conf test failed
DeNiTo, попробуйте перечитать еще раз, но чуть более внимательнее.
В статье написано и его содержание, и откуда он берется.
admin, блин, admin, все по инструкции делал что-то все равно он не появляется (
admin, как понял нужен generate_map.pl? Или что? Ничего не пойму где взять maps файл? Застопорился только на этом… Подскажите пожалуйста! несколько раз перечитал так и все сделал как описано, но вылазит ошибка
# apachectl configtest ; nginx -t
[Wed Oct 06 01:21:45 2010] [warn] module php5_module is already loaded, skipping
Syntax OK
[emerg]: unknown directive “(l)” in /etc/nginx/maps.conf:2
configuration file /etc/nginx/nginx.conf test failed
Т.е.
[root@de]# apachectl configtest ; nginx -t
[Wed Oct 06 01:30:06 2010] [warn] module php5_module is already loaded, skipping
Syntax OK
[emerg]: open() “/etc/nginx/maps.conf” failed (2: No such file or directory) in /etc/nginx/nginx.conf:35
configuration file /etc/nginx/nginx.conf test failed
email получил, скрипт отправлю завтра.
admin, спасибо, все работает, но вот только все сайты кидает на айпи срвера почему-то.
PS. И скрипт вызывается и все нормально
Домен создан
Детали
Вывод скрипта: domain_create_post.sh
Домен успешно создан
Но не записывает в мап файл.
Здравствуйте Уважаемый Admin!
Огромное спасибо за статью, действительно стоящее решение!
Вышлите пожалуйста скриптик
Заранее благодарен.
Спасибо за файлик, но всё же упёрся в поддержку map файлов nginx -ом, ставил его из репозитария (у меня Centos) а вот как персобрать его с поддержкой нужного модуля ни как не могу найти, пробежался по Google без результата, да и компилировать что либо редко приходилось, подскажите пожалуйста как пересобрать nginx?
покажите вывод:
nginx -V
-bash-3.2# nginx -V
nginx version: nginx/0.8.52
built by gcc 4.1.2 20080704 (Red Hat 4.1.2-48)
TLS SNI support disabled
configure arguments: –user=nginx –group=nginx –prefix=/usr/share/nginx –sbin-path=/usr/sbin/nginx –conf-path=/etc/nginx/nginx.conf –error-log-path=/var/log/nginx/error.log –http-log-path=/var/log/nginx/access.log –http-client-body-temp-path=/var/lib/nginx/tmp/client_body –http-proxy-temp-path=/var/lib/nginx/tmp/proxy –http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi –pid-path=/var/run/nginx.pid –lock-path=/var/lock/subsys/nginx –with-http_secure_link_module –with-http_random_index_module –with-http_ssl_module –with-http_realip_module –with-http_addition_module –with-http_sub_module –with-http_dav_module –with-http_flv_module –with-http_gzip_static_module –with-http_stub_status_module –with-http_perl_module –with-mail –with-mail_ssl_module –with-cc-opt=’-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector –param=ssp-buffer-size=4 -m64 -mtune=generic’ –with-ipv6 –add-module=/builddir/build/BUILD/nginx-0.8.52/nginx-upstream-fair –add-module=/builddir/build/BUILD/nginx-0.8.52/nginx-upload-progress-module –add-module=/builddir/build/BUILD/nginx-0.8.52/mod_zip-1.1.6 –add-module=/builddir/build/BUILD/nginx-0.8.52/nginx_upload_module-2.2.0 –add-module=/builddir/build/BUILD/nginx-0.8.52/nginx_mod_h264_streaming-2.2.7
Как я писал данный модуль собирается по умолчанию. У Вас он включен.
Отправьте мне на почту ваши конфиги и результат “nginx -t”
Конфиги отправил и вывод тоже, но я что то не пойму с чего Вы решили что –with-http_map_module включён?
повторюсь: http_map_module собирается по умолчанию автоматически, если не указано его отключение директивой
–without-http_map_module (disable ngx_http_map_module)
в вашей сборке –without-http_map_module нет, соответственно модуль используется.
А что касается ошибки “[emerg]: unknown “user” variable”
проверьте формат файла ‘maps.conf’
Как он должен выглядеть описано в статье.
Первоначальный “чистый” файл (без записей) имеет такой вид:
Простите сразу не разобрался, я думал что содержание файла maps.conf Вы дали для образца, и оставил его пустым в надежде что после создания домена панель сама туда пропишет всё что нужно, но ошибся((( сейчас заполнил его и всё вроде заработало (не считая мелочи – ругается на занятость порта, ну это я подправлю сейчас)
Спасибо огромное, и простите за потраченное время!
я рад, что у Вас все получилось 🙂
Удачи!
Я вернулся)
Вобщем заработать то всё заработало, но я для улучшения секурности и для уменьшения проблем юзерам (и для добавления таковых себе) использую Apache mpm-itk и к нему по этой же статейке поставил nginx frontendom и наблюдая за свежесозданным тестовым сайтом http://da.dobrohost.net/
видим что не прогружается логотип.
Как я предпологаю что то с правами доступа, что посоветуете посмотреть, куда копать?
если открыть da.dobrohost.net/logo.jpg то будет:
404 Not Found
Копать в сторону логов nginx-а и смотреть откуда nginx пытается загрузить картинки
Из секции отдачи отдачи статики
на время теста, директиву log_not_found можно включить.
В логах наблюдается такая неприятная картинка
в файле maps_vhost.conf есть кусочек, который и определяет корневую директорию:
а вот как это побороть что то в голову не идёт?
Покажите секцию $user из maps.conf (можно мылом)
В том случае, если имя домена “da.site.ru” (именно домена, а не поддомена), то в файле должно быть нечто такого:
map $http_host $user {
.da.dobrohost.net “datest”;
}
map $http_host $domain {
hostnames;
default “”;
.da.dobrohost.net “da.dobrohost.net”;
}
map $http_host $subdomain {
hostnames;
default “”;
}
Добавьте в секцию $user следующее:
и все заработает 🙂