Установка и настройка web-сервера nginx

Установка

Скачиваем архив nginx-0.1.41.tar.gz (последняя версия на момент написания статьи) с основного сайта проекта http://sysoev.ru/nginx/download.html. Так же нам понадобятся библиотеки ZLIB и PCRE, которые можно взять с сайта производителя (http://www.gzip.org/zlib/ и http://www.pcre.org/). Распакуем библиотеки:
    
    
     #tar -xvzf zlib-1.2.3.tar.gz
    
     #tar -xvzf pcre-6.2.tar.gz
    
     
     
Для установки nginx нам потребуется выполнить следующий порядок действий (учитывая, что архивы библиотек и сервера находятся в одном каталоге):
    
    
     #tar -xvzf nginx-0.1.41.tar.gz
    
     #cd nginx-0.1.41
    
     #configure --prefix=/usr/pkg --sbin-path=/usr/pkg/nginx
    
     --conf-path=/usr/pkg/nginx/nginx.conf
    
     --pid-path=/usr/pkg/nginx/nginx.pid --with-http_ssl_module
    
     --with-pcre=../pcre-6.2 --with-zlib=../zlib-1.2.3
    
     
     
Мы должны получить примерно такой вывод:
    
    
     Configuration summary
    
     + threads are not used
    
     + using PCRE library:. ./pcre-6.2
    
     + using system OpenSSL library
    
     + md5 library is not used
    
     + using zlib library:. ./zlib-1.2.3
    
     
    
     nginx path prefix:  «/usr/pkg/nginx»
    
     nginx binary file:  «/usr/pkg/nginx»
    
     nginx configuration file:  «/usr/pkg/nginx/nginx.conf»
    
     nginx pid file:  «/usr/pkg/nginx/nginx.pid»
    
     nginx error log file:  «/usr/pkg/nginx/logs/error.log»
    
     nginx http access log file:  «/usr/pkg/nginx/logs/access.log»
    
     nginx http client request body temporary files:
    
      «/usr/pkg/nginx/client_body_temp»
    
     nginx http proxy temporary files:  «/usr/pkg/nginx/proxy_temp»
    
     nginx http fastcgi temporary files:  «/usr/pkg/nginx/fastcgi_temp»
    
     
     
Если библиотеки ZLIB и PCRE были установлены из системы портов, то необходимости скачивать архивы этих библиотек нет, достаточно указать следующие параметры утилиты. /configure:
    
    
     --with-ld-opt=  «-L /usr/pkg/lib»
    
     --with-cc-opt=  «-I /usr/pkg/include»
    
     
     
Тогда вывод будет следующим:
    
    
     Configuration summary
    
     + threads are not used
    
     + using system PCRE library
    
     + using system OpenSSL library
    
     + md5 library is not used
    
     + using system zlib library
    
     
    
     nginx path prefix:  «/usr/pkg/nginx»
    
     nginx binary file:  «/usr/pkg/nginx»
    
     nginx configuration file:  «/usr/pkg/nginx/nginx.conf»
    
     nginx pid file:  «/usr/pkg/nginx/nginx.pid»
    
     nginx error log file:  «/usr/pkg/nginx/logs/error.log»
    
     nginx http access log file:  «/usr/pkg/nginx/logs/access.log»
    
     nginx http client request body temporary files:
    
      «/usr/pkg/nginx/client_body_temp»
    
     nginx http proxy temporary files:  «/usr/pkg/nginx/proxy_temp»
    
     nginx http fastcgi temporary files:  «/usr/pkg/nginx/fastcgi_temp»
    
     
     
Компилируем и устанавливаем nginx:
    
    
     #make
    
     #sudo make install
    
     
     
Если планируется редактирование файлов конфигурации или загрузка файлов в каталоги от имени непривилегированного пользователя, то можно воспользоваться такой командой:
    
    
     #sudo chown -R mixa /usr/pkg/nginx
    
     
     
Для получения более подробной информации о параметрах configure, используйте команду:
    
    
     #./configure --help
    
     
    
     
     
Одной из полезных опций является --with-cpu-opt, которая позволяет произвести оптимизацию по типу процессора. Доступными параметрами являются: pentium, pentiumpro, pentium4, sparc64.

Настройка

Приступим к настройке сервера. 

Как таковых, вариантов развития событий у нас три:
  • Использование в качестве веб-сервера
  • Использование в качестве прокси-сервера
  • Использование в качестве почтового прокси
Разберем сперва, как самый экзотический, третий вариант. Задействовать этот режим можно включив опцию --with-imap при запуске. /configure Смысл заключается в следующем: 

Предположим, что у нас есть несколько серверов imap/pop3. Перед ними ставится nginx, который по получении имени и пароля ходит по HTTP к специальному авторизационному серверу. 

Если серверу нравится имя и пароль, то он говорит, к какому imap/pop3 серверу нужно присоединиться и продолжить imap/pop3 сессию, после чего nginx просто проксирует данные в обе стороны. 

Если же не нравится, то nginx передает клиенту то, что именно не нравится. 

Конфигурация, в этом случае, будет выглядеть следующим образом:
    
    
     events {
    
     …
    
     }
    
     
    
     imap {
    
     #auth_http  unix:/path/socket:/cgi-bin/auth;
    
     auth_http  localhost:9000/cgi-bin/auth;
    
     
    
     pop3_capabilities  «TOP»  «USER»;
    
     imap_capabilities  «IMAP4rev1»  «UIDPLUS»;
    
     
    
     server {
    
     listen     110;
    
     protocol   pop3;
    
     proxy      on;
    
     }
    
     
    
     server {
    
     listen     143;
    
     protocol   imap;
    
     proxy      on;
    
     }
    
     }
    
     
     
Структура запроса к серверу авторизации: Запрос:
    
    
     
    
     GET /auth HTTP/1.0
    
     Host: localhost
    
     Auth-Method: plain
    
     Auth-Login: user
    
     Auth-Pass: password
    
     Auth-Protocol: imap
    
     Auth-Login-Attempt: 1
    
     Client-IP: 192.168.1.1
    
     
     
Хороший ответ:
    
    
     HTTP/1.0 200 OK # this line ignore
    
     Auth-Status: OK
    
     Auth-Server: 192.168.2.10
    
     Auth-Port: 143
    
     
     
Плохой ответ:
    
    
     HTTP/1.0 200 OK # this line ignore
    
     Auth-Status: Invalid login or password
    
     Auth-Wait: 3
    
     
     
Во втором случае nginx отдаёт клиенту строку «Invalid login or password», ждёт 3 секунды и снова готов принимать login/password. Рассмотрим теперь первый вариант — использование в качестве полноценного web-сервера. В самой простой конфигурации предполагается отдача статического контента. Рассмотрим такой файл конфигурации:
    
    
     user testuser;
    
     worker_processes 5;
    
     
     
Указываем имя пользователя и количество одновременно запущенных процессов.
    
    
     error_log logs/error.log;
    
     pid logs/nginx.pid;
    
     
     
Задаем размещение журнальных файлов и идентификатора процесса.
    
    
     events {
    
     connections 1024;
    
     use kqueue;
    
     }
    
     
     
Как известно, NetBSD 2.0 поддерфивает методы kqueue, select и poll. Два последних являются стандартными для UNIX-систем, но не обеспечивают оптимального быстродействия. Мы будем использовать метод kqueue.
    
    
     http {
    
     include conf/mime.types;
    
     default_type application/octet-stream;
    
     
    
     sendfile on;
    
     tcp_nodelay on;
    
     keepalive_timeout 0;
    
     
    
     gzip on;
    
     gzip_min_length 1100;
    
     gzip_comp_level 9
    
     gzip_types text/plain;
    
     
     
В блоке, приведенном выше, мы включили сжатие, установили минимальную длинну ответа, при которой будет использоваться сжатие, указали коэффициент сжатия (9) и тип сжимаемого контента (учтите, что text/html сжимается всегда). Более подробную информацию можно посмотреть по адресу: http://sysoev.ru/nginx/docs/http/ngx_http_gzip_module.html
    
    
     server {
    
     listen 80;
    
     server_name hpux.dreamcatcher.ru  dreamcatcher.ru  www.dreamcatcher.ru;
    
     charset on;
    
     source_charset windows-1251;
    
     
     
Кодировка документов сайта — windows-1251.
    
    
     access_log logs/dreamcatcher.log;
    
     location / {
    
     root html/dream;
    
     index index.html index.htm;
    
     }
    
     error_page 404 /error/404.html;
    
     location /dream/error/404.html
    
     {
    
     root html;
    
     charset on;
    
     source_charset windows-1251;
    
     }
    
     }
    
     }
    
     
     
Рано или поздно встанет вопрос выполнения динамических страниц. Оговоримся сразу, что поддержка выполнения сценариев cgi вряд либудет когда-либо реализована в силу трудоемкости. В настоящее время есть возможность выполнения php с помощью fastcgi сервера. Для реализации данной идеи следует выполнить следующий нехитрый набор действий: 

Конфигурация, используемая далее, взята с сайта www.nginx.info 

Чтобы настроить связку nginx+fastcgi+php необходимо : запустить php как fastcgi сервер (порт или unix сокет), указать nginx отправлять файлы с расширением *.php на fastcgi сервер (пример фалйа конфигурации ниже). php можно запустить, как fastcgi сервер, двумя способами: (в обоих случаях надо сначала собрать php с опцией --enable-fastcgi)
  • непосредсвенно запуская php с опцией -b IP:PORT (Bind Path for external FASTCGI Server mode). В таком случае php можно заставить соединения только по tcp.
  • используя spawn-fcgi+spawn-php.sh из дистрибутива lighttpd
Пример конфигурации для nginx (начиная с 0.1.29): (это все прописывается в секцию требуемого server {…}) В данном случае, fastcgi принимает запросы через сокет UNIX и все файлы php отправляются к fastcgi серверу
    
    
     location ~* ^.+\.  (php)$ {
    
     root /var/www/domain/root;
    
     #fastcgi_pass 127.0.0.1:9000;
    
     fastcgi_pass unix:/usr/local/fastcgi/fcgi; # сокет
    
     fastcgi_index index.php;
    
     fastcgi_connect_timeout 60;
    
     fastcgi_send_timeout 180;
    
     fastcgi_read_timeout 180;
    
     fastcgi_header_buffer_size 32k;
    
     fastcgi_buffers 4 32k;
    
     fastcgi_busy_buffers_size 32k;
    
     fastcgi_temp_file_write_size 32k;
    
     #fastcgi_temp_path /var/tmp;
    
     #fastcgi_next_upstream error timeout invalid_header http_500 http_404;
    
     #fastcgi_next_upstream error timeout;
    
     fastcgi_x_powered_by off; # default on
    
     fastcgi_redirect_errors on; # для отображения своих страниц об ошибках
    
     fastcgi_x_powered_by off; # убираем отображение версии php, X-Powered..
    
     fastcgi_param   DOCUMENT_ROOT   /path/to/host_root;
    
     fastcgi_param   SCRIPT_FILENAME /path/to/host_root$fastcgi_script_name;
    
     fastcgi_param   PATH_TRANSLATED /path/to/host_root$fastcgi_script_name;
    
     fastcgi_param   SCRIPT_NAME  $fastcgi_script_name;
    
     fastcgi_param   QUERY_STRING    $query_string;
    
     fastcgi_param   CONTENT_TYPE    $content_type;
    
     fastcgi_param   CONTENT_LENGTH  $content_length;
    
     fastcgi_param   REDIRECT_STATUS 200; # if php build with option --enable-forece-cgi-redirect
    
     #additional system call is made, without need it is better to not use
    
     fastcgi_param   SERVER_ADDR     $server_addr; 
    
     fastcgi_param   SERVER_PORT     $server_port;
    
     fastcgi_param   SERVER_PROTOCOL $server_protocol;
    
     fastcgi_param   SERVER_SOFTWARE  «nginx/0.1.30»;
    
     fastcgi_param   GATEWAY_INTERFACE       «CGI/1.1»;
    
     fastcgi_param   SERVER_NAME     $server_name;
    
     fastcgi_param   REQUEST_URI     $request_uri;
    
     fastcgi_param   REQUEST_METHOD  $request_method;
    
     fastcgi_param   REMOTE_USER     $remote_user;
    
     fastcgi_param   REMOTE_ADDR     $remote_addr;
    
     fastcgi_param   REMOTE_PORT     $remote_port;
    
     }
    
     
     
Возможен мониторинг состояния nginx с помощью Munin. Вот пример конфигурационных файлов nginx_request.txt
    
    
     #!/usr/bin/perl -w
    
     #
    
     # Magic markers:
    
     #%# family=auto
    
     #%# capabilities=autoconf
    
     
    
     my $ret = undef;
    
     
    
     if  (! eval  «require LWP::UserAgent;„){
    
     $ret = „LWP::UserAgent not found“;
    
     }
    
     
    
     chomp  (my $fqdn=`hostname -f`);
    
     
    
     my $URL = exists $ENV{'url'}?  $ENV{'url'} : „http://$fqdn/nginx_status“;
    
     
    
     if  (exists $ARGV[0] and $ARGV[0] eq „autoconf“) 
    
     {
    
     if  ($ret){
    
     print „no  ($ret)\n“;
    
     exit 1;
    
     }
    
     
    
     my $ua = LWP::UserAgent→new  (timeout ≥ 30);
    
     my $response = $ua→request  (HTTP::Request→new  ('GET',$URL));
    
     
    
     unless  ($response→is_success and $response→content =~ /server/im)
    
     {
    
     print „no  (no nginx status on $URL)\n“;
    
     exit 1;
    
     }
    
     else
    
     {
    
     print „yes\n“;
    
     exit 0;
    
     }
    
     }
    
     
    
     if  (exists $ARGV[0] and $ARGV[0] eq „config“) 
    
     {
    
     print „graph_title NGINX requests\n“;
    
     print „graph_args --base 1000\n“;
    
     print  «graph_category nginx\n“;
    
     print  «graph_vlabel Request per second\n»;
    
     
    
     print  «request.label req/sec\n»;
    
     print  «request.type COUNTER\n»;
    
     print  «request.label requests $port\n»;
    
     print  «request.draw LINE2\n»;
    
     
    
     exit 0;
    
     }
    
     
    
     my $ua = LWP::UserAgent→new  (timeout ≥ 30);
    
     
    
     my $response = $ua→request  (HTTP::Request→new  ('GET',$URL));
    
     
    
     if  ($response→content =~ /^\s+  (\d+)\s+  (\d+)\s+  (\d+)/m) {
    
     print  «request.value $3\n»;
    
     } else {
    
     print  «request.value U\n»;
    
     }
    
     
    
     # vim:syntax=perl
    
     
     
и nginx_status.txt
    
    
     #!/usr/bin/perl -w
    
     #
    
     # Magic markers:
    
     #%# family=auto
    
     #%# capabilities=autoconf
    
     
    
     my $ret = undef;
    
     
    
     if  (! eval  «require LWP::UserAgent;„){
    
     $ret = „LWP::UserAgent not found“;
    
     }
    
     
    
     chomp  (my $fqdn=`hostname -f`);
    
     
    
     my $URL = exists $ENV{'url'}?  $ENV{'url'} : „http://$fqdn/nginx_status“;
    
     
    
     if  (exists $ARGV[0] and $ARGV[0] eq „autoconf“) 
    
     {
    
     if  ($ret){
    
     print „no  ($ret)\n“;
    
     exit 1;
    
     }
    
     
    
     my $ua = LWP::UserAgent→new  (timeout ≥ 30);
    
     my $response = $ua→request  (HTTP::Request→new  ('GET',$URL));
    
     
    
     unless  ($response→is_success and $response→content =~ /server/im)
    
     {
    
     print „no  (no nginx status on $URL)\n“;
    
     exit 1;
    
     }
    
     else
    
     {
    
     print „yes\n“;
    
     exit 0;
    
     }
    
     }
    
     
    
     if  (exists $ARGV[0] and $ARGV[0] eq „config“) 
    
     {
    
     print „graph_title NGINX status\n“;
    
     print „graph_args --base 1000\n“;
    
     print  «graph_category nginx\n“;
    
     print  «graph_vlabel Connections\n»;
    
     
    
     print  «total.label Active connections\n»;
    
     print  «total.info  Active connections\n»;
    
     print  «total.draw LINE2\n»;
    
     
    
     print  «reading.label Reading\n»;
    
     print  «reading.info  Reading\n»;
    
     print  «reading.draw LINE2\n»; 
    
     
    
     print  «writing.label Writing\n»;
    
     print  «writing.info  Writing\n»;
    
     print  «writing.draw LINE2\n»; 
    
     
    
     print  «waiting.label Waiting\n»;
    
     print  «waiting.info  Waiting\n»;
    
     print  «waiting.draw LINE2\n»; 
    
     
    
     exit 0;
    
     }
    
     
    
     my $ua = LWP::UserAgent→new  (timeout ≥ 30);
    
     
    
     my $response = $ua→request  (HTTP::Request→new  ('GET',$URL));
    
     
    
     #Active connections: 1845 
    
     #server accepts handled requests
    
     # 4566318 4566318 84218236 
    
     # Reading: 2 Writing: 278 Waiting: 1565 
    
     if  ($response→content =~ /Active connections:\s+  (\d+).*Reading:\s+  (\d+).*Writing:\s+  (\d+).*Waiting:\s+  (\d+)/s) {
    
     print  «total.value $1\n»;
    
     print  «reading.value $2\n»;
    
     print  «writing.value $3\n»;
    
     print  «waiting.value $4\n»;
    
     } else {
    
     foreach  (qw  (total reading writing waiting)){
    
     print  «$_.value U\n»;
    
     }
    
     }
    
     
    
     # vim:syntax=perl