Nginx как проксирующий фронт-енд к Apache #2

В продолжение темы о связке + apache + решил все же написать хоть что то 🙂

Данная фича писалась "на коленке" и никоим образом не претендует на полноценное и законченное решение, однако на протяжении года проработало на shared-хостинге, обслуживая более 1000 доменов.

Суть заключается в том, что nginx полностью отвечает за отдачу всей статики (картинки, архивы, файлы стилей и т.д.), а апач занимается обработкой скриптов. Для снижения нагрузки апач не ведет access_log (только error_log),  логи так же ведет nginx. За SSL тоже отвечает nginx.

nginx выступает в роли фронт-енда, в то время как апач - в роли бек-енда. nginx слушает внешние IP адреса, апач - только один, например, 127.0.0.1:80


Итак, копируем некоторые шаблоны DirectAdmin:

# cd /usr/local/directadmin/data/templates
# cp ./virtual_host*  ./custom/  && cp ./ips_virtual_host.conf ./custom && cd ./custom

Далее необходимо отредактировать скопированные шаблоны для наших нужд.

Файл  /usr/local/directadmin/data/templates/custom/ips_virtual_host.conf выглядит так:

<VirtualHost 127.0.0.1:80>
  ServerName shared.domain
  ScriptAliasMatch ^/~([^/]+)/+cgi-bin/+(.*) /home/$1/public_html/cgi-bin/$2
  AliasMatch ^/~([^/]+)(/.*)* /home/$1/public_html$2
  DocumentRoot |DOCROOT|
  |*if APACHE_VER="2.0"|
  SuexecUserGroup |USER| |GROUP|
  |*else|
  User |USER|
  Group |GROUP|
  |*endif|
  CustomLog /var/log/httpd/homedir.log homedir
</VirtualHost>

В файлах virtual_host_* меняем строки: <VirtualHost |IP|:80> на <VirtualHost 127.0.0.1:80>

Далее, создаем (или добавляем туда, если такие уже есть) post-скрипты в /usr/local/directadmin/scripts/custom для создания и удаления конфигов nginx.

Автосоздание конфига nginx, файл 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
LIMIT=10
echo "Making config files: "
echo -e "#
# NginX http server.
# Virtual host config ver. 0.2 (14.10.2008), nginx v.5.xx
# autocreated on: `date \"+%d.%m.%Y %H:%M:%S\"`
#
server {
   listen $ip:80;
   server_name $domain www.$domain;
   error_page  500 502 503 504 /50x.html;
   location = /50x.html { root   html;  }
   # images files location
   location ~* ^.+\.(bmp|jpg|jpeg|pjpeg|gif|ico|cur|png|css|doc|txt|js|docx|rtf|ppt|pdf|svg)$ {
      expires     5d;
      set \$root_path  /home/${username}/domains/${domain}/public_html;
      if (\$uri ~* \"/(squirrelmail|atmail|roundcube|phpMyAdmin|webmail)/\") { set \$root_path  /var/www/html; }
         root  \$root_path;
         access_log  /var/log/httpd/domains/${domain}.bytes bytes;
         access_log  /var/log/httpd/domains/${domain}.log domain;
      }
   # Static files location
   location ~* ^.+\.(swf|3gp|dll|msi|cdr|cdd|cue|cdi|mkv|nrg|pdi|mds|mdf|arj|zip|tgz|gz|rar|bz2|7z|xls|exe|tar|wav|avi|mp3|mp4|mov|wmv|vob|iso|mpg|midi|cda|wma)$ {
      expires     10d;
      set \$root_path  /home/${username}/domains/${domain}/public_html;
      if (\$uri ~* \"/(squirrelmail|atmail|roundcube|phpMyAdmin|webmail)/\") { set \$root_path  /var/www/html; }
      root  \$root_path;
      limit_conn one 2;
      limit_rate 220k;
      access_log  /var/log/httpd/domains/${domain}.log domain;
      access_log  /var/log/httpd/domains/${domain}.bytes bytes;
      access_log  /var/log/httpd/nginx/access.log main;
   }
   location / {
     limit_conn  one  ${LIMIT};
     root        /home/${username}/domains/${domain}/public_html;
     access_log  /var/log/httpd/nginx/access.log main;
     access_log  /var/log/httpd/domains/${domain}.bytes bytes;
     access_log  /var/log/httpd/domains/${domain}.log domain;
     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;
     proxy_redirect off;
   }
   location ~ /\.ht { deny  all; }
}
" >  /usr/local/nginx/conf/vhosts/$domain.conf
if [ -f /usr/local/nginx/conf/vhosts/$domain.conf ]; then
   chown root.root /usr/local/nginx/conf/vhosts/$domain.conf
   chmod 644 /usr/local/nginx/conf/vhosts/$domain.conf
   /etc/init.d/nginx reload
   echo "[ OK ]"
fi
exit 0

файл domain_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
rm -f /usr/local/nginx/conf/vhosts/$domain.conf
/etc/init.d/nginx reload
exit 0

В основном конфиге nginx некоторые измения для ведения логов, совместимых с апачем:

    log_format  main    '$remote_addr - $remote_user [$time_local] $host $request "$status" $body_bytes_sent "$http_referer" '
                        '"$http_user_agent" "$http_x_forwarded_for"';
    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  bytes   '$body_bytes_sent';
    limit_zone   one  $binary_remote_addr  10m;
    server {
        listen IP_сервера:80 default backlog=2048  deferred;
        .....
        .....
    }
    include conf/vhosts/*.conf;

Остальные настройки nginx уже настраивайте под себя.

На этом, собственно все.

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

Надеюсь пригодится не только мне 😉

20 comments on “Nginx как проксирующий фронт-енд к Apache #2

  1. Прикол.)) ОЧень интересно. Попробую реализовать у себя.
    А каким образом ДиректАдмин запускает скрипты добавления доменна? Вообщем буду пробовать..

  2. Читаем файлик: /usr/local/directadmin/scripts/custom/README.
    В нем все предельно ясно описано какой скрипт и что делает.
    Например:

    domain_create_pre.sh — Runs BEFORE a domain is created
    domain_create_post.sh — Runs AFTER a domain is created
    domain_destroy_pre.sh — Runs BEFORE a domain is destroyed
    domain_destroy_post.sh — Runs AFTER a domain is destroyed

    environmental variables:
    bandwidth=# or unlimited
    cgi=ON or OFF
    defaultdomain=yes or no
    domain=domain.com
    ssl=ON or OFF
    suspended=yes or no
    username=ownerofdomain

    Дальше, думаю, понятно ? 🙂

  3. ДА. Более чем.. Просто этот ДиректАдмин еще схавать нужно. А так вообще монополизировала всю систему..)) README говоришь…хм.. нужно будет покопаться поглубже..)) спс ман!

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

  5. У нас оно и допилено до нужного состояния 😉

    Конфиг полностью переработан. Используется всего один общий конфиг + map-ы вместо генерации кучи файлов для каждого домена/субдомена

    Здесь же я всего лишь привел одну из ранних реализаций.

  6. Ну, например, можно так-то так:

    Файл nginx.conf
    ——————-

    http {
    ....
        include maps.conf;
    ....
        server {
            listen 1.2.3.4:80 default backlog=4096 deferred;
            server_name _;
            location ~ /.svn/ {
                deny all;
            }
            include vhost.conf;
        }
    }
    

    Файл vhost.conf:
    ——————-

        location ~* ^.+\.(bmp|jpg|jpeg|pjpeg|gif|ico|cur|png|css|doc|txt|js|docx|rtf|ppt|pdf|svg|swf)$ {
            expires     24h;
            root        /var/www/$user/$domain/public_hml;
            gzip   off;
            log_not_found off;
       }
    ......
       location / {
           log_not_found on;
           gzip   on;
          # if ($loadavg_1m > 30) { return 503; }
           root        /var/www/$user/$domain/public_hml;
           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; }
    

    Ну и собственно, сам файл maps.conf, в котором описаны юзеры и их домены:

    map $http_host $user {
            hostnames;
            default             "";
            .domain1.ks.ua    "user1";
            .domain2.ru       "user2";
            .domain3.ru       "user4";
            .domain4.ru       "user1";
    }
    map $http_host $domain {
            hostnames;
            default             "";
            .domain1.ks.ua    "domain1.ks.ua";
            .domain2.ru       "domain2.ru";
            .domain3.ru       "domain3.ru";
            .domain4.ru       "domain4.ru";
    }
    

    В результате имеем всего один конфиг для nginx и только один файл (maps.conf), который изменяется при добавлении/удалении пользователей и доменов.

    Идея, думаю, понятна ?
    🙂

  7. Вариант, но мне больше нравится вариант для каждого юзера свой конфиг. Так можно каждому конкретно свои настройки вбивать.
    Например для эффективной борьбы ддос играть с location.

  8. Если доменов чуть-чуть, можно для каждого свой конфиг.
    Но вот когда таких конфигов, скажем, за 500 и более, то уже не совсем хорошо.

    Кроме того, ничто не мешает использовать map и отдельные конфиги для выбранных доменов совместно.
    У нас так и есть. Основная масса в мап-файле, «особые» домены вынесены в собственные конфиги.
    🙂

    ps. строку «if ($loadavg_1m > 30) { return 503; }» не нужно включать в конфиг.
    Стандартный nginx не знает этой директивы.

  9. А не поделитесь скриптом добавления и удаления в maps.conf записей?

    • Не хотелось бы раскрывать определенные собственные «фишки» и наработки … 🙂

      Но если что, велкам в приватное мыло.

  10. Извините, а где находится maps.conf? Не могу найти, я чайник

  11. Это файл создавать надо самому.
    Формат файла описан выше + читайте документацию

  12. [root@de]# apachectl configtest ; nginx -t
    [Wed Oct 06 02:56:34 2010] [warn] module php5_module is already loaded, skipping
    Syntax OK
    [emerg]: unexpected «>» in condition in /etc/nginx/maps_vhost.conf:25
    configuration file /etc/nginx/nginx.conf test failed

    Моздал, теперь это пишет

  13. admin, ругается на эту строку в файле
    maps_vhost.conf (25):
    if ($loadavg_1m > 30) { return 503; } # do not use with original nginx

    Что тут не так?
    PS. Все равно не записывает в файл maps.conf при добавлении домена инцормацию.

    Спасибо что прислали скрипт.

    • нужно закоментировать эту строчку.
      Написано же:
      «do not use with original nginx»

  14. admin, спасибо 🙂

    Еще какая то ошибка вылезла

    [root@de ~]# apachectl configtest ; nginx -t
    Syntax OK
    [emerg]: unknown «user» variable
    configuration file /etc/nginx/nginx.conf test failed

    Как ее побороть?

    • Побороть просто — правильно написать конфиг и немного почитать документацию, а не заниматься простым «копи-пастом» 🙂
      -в основном конфиге nginx не инклудится мап-файл;
      -nginx собран без http_map_module

Обсуждение закрыто.

2 Отклики /Обратные ссылки для "Nginx как проксирующий фронт-енд к Apache #2"