Nginx
Материал из OpenWiki
Ссылки с примерами настройки nginx
- Home Page, портал nginx.info, Nginx English Wiki
- Список встроенных переменных
- Nginx, Fastcgi, PHP, rewrite config for Drupal
- Nginx With PHP As FastCGI Howto
- Nginx, my new favorite front end for mongrel cluster
- Nginx rewrite rules For WordPress redux
- Proxying Gotchas (and tricks) with Nginx
- nginx tips
- Настройка совместной работы Apache и nginx
- Настройка Nginx для поддержки PHP при помощи FastCGI
- Использование Nginx Как Reverse-Proxy Сервера На Загруженных Сайтах
- Установка и настройка web-сервера nginx
- Пример конфигурации nginx для NameBased виртуальных хостов с хостингом
- Варианты настройки Ruby On Rails на максимальную производительность: mongrel vs lighttpd vs nginx
Пример преобразования rewrite правил:
Apache mod_rewrite:
RewriteCond %{QUERY_STRING} !^nobranding$ RewriteCond %{REQUEST_FILENAME} ^/assets/XL/([^.]+)\.([jpegif]+)$ RewriteCond /usr/local/www/assets-nz/XL/%1.branded.%2 -f RewriteRule ^/([^.]+)\.([jpeg]+)$ /$1.branded.$2
nginx:
location /assets { if ($args = nobranding) { rewrite ^(.+)$ /nobranding$1 break; } rewrite ^/assets/XL/(.+)\.(jpeg|jpg|gif) /XL/$1.branded.$2; root /usr/local/www/assets-nz; error_page 404 = /nobranding/assets$uri; } location /nobranding/assets { internal; alias /usr/local/www/assets-nz/; }
Другие примеры rewrite:
# Запрос индекса, отдаем index.php location = / { root /path/to/drupal; # Again, replace this. index index.php; } # Обработка всего остального location / { root /path/to/drupal; index index.php index.html; if (!-f $request_filename) { rewrite ^(.*)$ /index.php?q=$1 break; break; } if (!-d $request_filename) { rewrite ^(.*)$ /index.php?q=$1 break; break; } } # Локальная отдача статики, без записи в лог location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico)$ { access_log off; expires 30d; root /path/to/img; } # Редирект location ~ .php$ { fastcgi_pass 127.0.0.1:8888; # By all means use a different server for the fcgi processes if you need to fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /path/to/drupal$fastcgi_script_name; # !! <--- Another path reference for you. fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; }
location ~ ^/$ { if (-f /index.html){ rewrite (.*) /index.html break; } proxy_pass http://mongrel; } location / { if (!-f $request_filename.html) { proxy_pass http://mongrel; } rewrite (.*) $1.html break; } location ~ .html { root /Users/ez/nginx/public; } location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js|mov)$ { root /Users/ez/nginx/public; } location / { proxy_pass http://mongrel; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
location /blog/ { index index.php; if (-e $request_filename) { break; } rewrite ^/blog/(.+)$ /blog/index.php?q=$1 break; }
if ($host != 'example.com' ) { rewrite ^/(.*)$ http://example.com/$1 permanent; proxy_set_header Host "example.com"; } if ($http_user_agent ~ MSIE) { rewrite ^(.*)$ /msie/$1 break; } if ($http_cookie ~* "id=([^;]+)(?:;|$)" ) { set $id $1; } if ($request_method = POST ) { return 405; } if (!-f $request_filename) { break; proxy_pass http://127.0.0.1; } geo $slow { default no; include conf/geo.conf; 127.0.0.0/24 us; 127.0.0.1/32 ru; 10.1.0.0/16 ru; 192.168.1.0/24 uk; } if ($slow) { limit_rate 10k; } valid_referers none blocked server_names **.example.com www.example.info/galleries/ ~\.google\. ; if ($invalid_referer) { return 403; }
Приммеры rewrite для Gallery2:
location /v/ { rewrite ^/v/(.*)$/wp-gallery2.php?g2_view=core.ShowItem&g2_path=$1; } location /d/ { # rewrite ^/d/([0-9]{1,20})-([0-9]{1,20})/(.*)$/gallery2/index.php?g2_view=core.DownloadItem&g2_itemId=$1&g2_serialNumber=$2&g2_fileName=$3; rewrite ^/d/([0-9]+)-([0-9]+)/(.*)$/gallery2/index.php?g2_view=core.DownloadItem&g2_itemId=$1&g2_serialNumber=$2&g2_fileName=$3; } location /rss/ { rewrite ^/rss/(.*)$/wp-gallery2.php?g2_view=rss.Render&g2_name=$1; } location /srss/ { rewrite ^/srss/(.*)$/wp-gallery2.php?g2_view=rss.Render&g2_name=$1; } location /c/add/ { rewrite ^([0-9]+).html(.*)$/wp-gallery2.php?g2_view=comment.AddComment&g2_itemId=$1; } location /c/view/ { rewrite ^/c/view/([0-9]+).html(.*)$/wp-gallery2.php?g2_view=comment.ShowAllComments&g2_itemId=$1; } location /admin/ { rewrite ^/admin/(.*)$ /wp-gallery2.php?g2_view=core.SiteAdmin; } location /gallery2/ { root /var/www/brainstorm/htdocs/; index index.php index.html index.htm; location ~ /.ht { deny all; } location /gallery2/images/{ root /var/www/brainstorm/htdocs/; } location /gallery2/core/ { root /var/www/brainstorm/htdocs/; } location /gallery2/modules/ { root /var/www/brainstorm/htdocs/; } rewrite ^/gallery2/v/(.*)$/gallery2/index.php?g2_view=core.ShowItem&g2_path=$1; rewrite ^/gallery2/d/([0-9]+)-([0-9]+)/(.*)$/gallery2/index.php?g2_view=core.DownloadItem&g2_itemId=$1&g2_serialNumber=$2&g2_fileName=$3; rewrite ^/gallery2/rss/(.*)$/gallery2/index.php?g2_view=rss.Render&g2_name=$1; rewrite ^/gallery2/srss/(.*)$/gallery2/index.php?g2_view=rss.SimpleRender&g2_itemId=$1; rewrite ^/gallery2/c/add/([0-9]+).html(.*)$/gallery2/index.php?g2_view=comment.AddComment&g2_itemId=$1; rewrite ^/gallery2/c/view/([0-9]+).html(.*)$/gallery2/index.php?g2_view=comment.ShowAllComments&g2_itemId=$1; rewrite ^/gallery2/admin/(.*)$/gallery2/index.php?g2_view=core.SiteAdmin; rewrite ^/gallery2/sitemap(.*)$/gallery2/index.php?g2_view=sitemap.Sitemap; } location / { root /var/www/brainstorm/htdocs; index index.php index.html index.htm; #wordpress bullshit if (!-e $request_filename ) { rewrite ^(.*)$ /index.php; } rewrite ^/sitemap(.*)$/wp-gallery2.php?g2_view=sitemap.Sitemap;
Образец реврайтов для drupal:
location / { root /path/to/drupal/install/doc/root; index index.php index.html; if (!-f $request_filename) { rewrite ^(.*)$ /index.php?q=$1 break; break; } if (!-d $request_filename) { rewrite ^(.*)$ /index.php?q=$1 break; break; } }
user www www; worker_processes 5; error_log logs/error.log debug; pid logs/nginx.pid; events { worker_connections 8192; use epoll; # linux only! } http { include conf/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] $status ' '"$request" $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log logs/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; server_names_hash_bucket_size 128; # this seems to be required for vhosts server { # php/fastcgi listen 80; server_name domain1.com www.domain1.com; access_log logs/domain1.access.log main; location / { root html; index index.html index.htm index.php; } location ~ \.php$ { include /etc/nginx/fastcgi.conf; fastcgi_pass 127.0.0.1:1025; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /usr/local/nginx/html$fastcgi_script_name; } } server { # simple reverse-proxy listen 80; server_name domain2.com www.domain2.com; access_log logs/domain2.access.log main; # serve static files location ~ ^/(images|javascript|js|css|flash|media|static)/ { root /var/www/virtual/big.server.com/htdocs; expires 30d; } # pass requests for dynamic content to rails/turbogears/zope, et al location / { proxy_pass http://127.0.0.1:8080; include /etc/nginx/proxy.conf; } } upstream big_server_com { server 127.0.0.3:8000 weight=5; server 127.0.0.3:8001 weight=5; server 192.168.0.1:8000; server 192.168.0.1:8001; } server { # simple load balancing listen 80; server_name big.server.com; access_log logs/big.server.access.log main; location / { proxy_pass http://big_server_com; include /etc/nginx/proxy.conf; } } }
user www www; worker_processes 2; pid /var/run/nginx.pid; # [ debug | info | notice | warn | error | crit ] error_log /var/log/nginx.error_log info; events { connections 2000; # use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; use kqueue; } http { include conf/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] ' '"$request" $status $bytes_sent ' '"$http_referer" "$http_user_agent" ' '"$gzip_ratio"'; log_format download '$remote_addr - $remote_user [$time_local] ' '"$request" $status $bytes_sent ' '"$http_referer" "$http_user_agent" ' '"$http_range" "$sent_http_content_range"'; client_header_timeout 3m; client_body_timeout 3m; send_timeout 3m; client_header_buffer_size 1k; large_client_header_buffers 4 4k; gzip on; gzip_min_length 1100; gzip_buffers 4 8k; gzip_types text/plain; output_buffers 1 32k; postpone_output 1460; sendfile on; tcp_nopush on; tcp_nodelay on; send_lowat 12000; keepalive_timeout 75 20; #lingering_time 30; #lingering_timeout 10; #reset_timedout_connection on; server { listen one.example.com; server_name one.example.com www.one.example.com; access_log /var/log/nginx.access_log main; location / { proxy_pass http://127.0.0.1/; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 10m; client_body_buffer_size 128k; client_body_temp_path /var/nginx/client_body_temp; proxy_connect_timeout 90; proxy_send_timeout 90; proxy_read_timeout 90; proxy_send_lowat 12000; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; proxy_temp_path /var/nginx/proxy_temp; charset koi8-r; } error_page 404 /404.html; location /404.html { root /spool/www; charset on; source_charset koi8-r; } location /old_stuff/ { rewrite ^/old_stuff/(.*)$ /new_stuff/$1 permanent; } location /download/ { valid_referers none blocked server_names *.example.com; if ($invalid_referer) { #rewrite ^/ http://www.example.com/; return 403; } #rewrite_log on; # rewrite /download/*/mp3/*.any_ext to /download/*/mp3/*.mp3 rewrite ^/(download/.*)/mp3/(.*)\..*$ /$1/mp3/$2.mp3 break; root /spool/www; #autoindex on; access_log /var/log/nginx-download.access_log download; } location ~* ^.+\.(jpg|jpeg|gif)$ { root /spool/www; access_log off; expires 30d; } } }
worker_processes 20; events { worker_connections 8192; use epoll; } http { ... limit_zone one $binary_remote_addr 10m; limit_conn one 64; limit_zone too $http_host 10m; upstream apache0 { ip_hash; ... } server { .... location ~* ^(.+\.(php|html)|.*/)$ { proxy_pass http://apache0; proxy_set_header Host <ZZZ>; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; index index.php index.html; limit_conn too 100; } location / { root /data/<ZZZ>/htdocs; } server { ... limit_conn too 200; ... } }
Как ограничить число одновременных соединений по сетевой маске
limit_zone one $my_addr 32k; server { if ($remote_addr ~ "^(\d+\.\d+\.\d+)") { set $my_addr $1; } limit_conn one 1;
Сеть класса С можно делать так:
http { perl_set $cnet ' sub { my $r = shift; return pack "c3", split /\./, $r->remote_addr; } '; limit_zone one $cnet 10m;
Ещё вариант:
if ($binary_remote_addr ~ "^(...)") {
Каким образом организовать копирование запросов на тестовый бэкэнд так чтобы ответ с него НЕ возвращался пользователю:
location ~ \.php$ { set $ouri $uri; fastcgi ... post_action /post; } location = post { fastcgi ... fastcgi_param SCRIPT_FILENAME /home/www/scripts/php$ouri; }
server { server_name www.* ; root /home/default-site/www/; ... location = /favicon.ico { if ($http_host ~ ^www\.([^.]+)$) { set $root /home/$1/$1.$2/www; } break; root $root; } error_page 404 = @default; } location @default { }
location / { proxy_pass http://127.0.0.1:81; } location = /cache { proxy_set_header Nginx-Uri $request_uri; proxy_set_header Nginx-Host $host; proxy_pass http://127.0.0.1:81/cache.php; } location ~* \.(php)$ { root /tmp/cache; error_page 404 = /cache; }
memcached:
location =/ajax/SOME_URL.html { #без этого content_type кривой будет default_type text/html; #идем в memcached #ключ в memcached '/ajax/SOME_URL.html' #если у запроса нужны аргументы надо не забыть их сохранить для случая memcached miss #через set $ArgsCopy $args; #и потом добавить их через rewrite в location /_backend_/ memcached_pass SOME_MEMCACHED_IP:SOME_MEMCACHED_PORT; #если в memcached не попали то через 404 error_page запрашиваем данные у backend #который нам их отдает и записывает итог в memcached error_page 404 = /_backend_/ajax/SOME_URL.html; } #внутренний URL для обработки случаем memcached miss на этот location location /_backend_/ { internal; #идем на backend proxy_pass http://BACKEND_IP:BACKEND_PORT/; }
Избавление от лишних FIN_WAIT_1:
send_timeout 30s; # менять по вкусу keepalive_timeout 75 20; reset_timedout_connection on;
pf.conf
pass in quick proto tcp from any to $ext_if port 80 flags S/SA keep state (source-track rule, max-src-conn-rate 8/20, tcp.established 60, tcp.closing 5, overload <bad_hosts> flush global)
Perl + FastCGI + nginx
Полноформатная статья: FastCGI-приложение на Perl
Примеры
- Способ 1 - запустить mod_fastcgi на бакенде с apache и редиректить туда.
- Способ 2 (оптимальный)- по аналогии с php, запустить через spawn-fcgi (из комплекта lighttpd) нужное число Perl процессов.
- Способ 3 - запуск perl скрипта как fastcgi-сервера. Например (для паралелльного запуска нескольких обработчиков нужно использовать FCGI::ProcManager):
#!/usr/bin/perl use strict; use FCGI; # use FCGI::ProcManager; # my $proc_manager = new FCGI::ProcManager({ n_processes => 2, die_timeout => 10 }); my $socket = FCGI::OpenSocket( ":9000", 5 ); # 5 - разрем очереди запросов. my $request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket ); # В случае с ProcManager цикл обработки запросов будет выглядеть примерно так: # $proc_manager->pm_manage(); # while (my $cgi = CGI::Fast->new()) { # $proc_manager->pm_pre_dispatch(); # # ... # $proc_manager->pm_post_dispatch(); #} my $count; while( $request->Accept() >= 0 ) { print "Content-type: text/html\r\n\r\n"; print ++$count; } FCGI::CloseSocket( $socket );
Настройка nginx
location /cgi-bin/script.fcgi { fastcgi_pass localhost:9000; fastcgi_root /path/to/cgi-bin/script.fcgi; }
Пример с codemongers.com:
#!/usr/bin/perl use FCGI; #perl -MCPAN -e 'install FCGI' use Socket; #this keeps the program alive or something after exec'ing perl scripts END() { } BEGIN() { } *CORE::GLOBAL::exit = sub { die "fakeexit\nrc=".shift()."\n"; }; eval q{exit}; if ($@) { exit unless $@ =~ /^fakeexit/; } ; &main; sub main { #$socket = FCGI::OpenSocket( ":3461", 10 ); #use IP sockets $socket = FCGI::OpenSocket( "/var/run/nginx/perl_cgi-dispatch.sock", 10 ); #use UNIX sockets - user running this script must have w access to the 'nginx' folder!! $request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%req_params, $socket ); if ($request) { request_loop()}; FCGI::CloseSocket( $socket ); } sub request_loop { while( $request->Accept() >= 0 ) { #processing any STDIN input from WebServer (for CGI-POST actions) $stdin_passthrough =''; $req_len = 0 + $req_params{'CONTENT_LENGTH'}; if (($req_params{'REQUEST_METHOD'} eq 'POST') && ($req_len != 0) ){ while ($req_len) { $stdin_passthrough .= getc(STDIN); $req_len--; } } #running the cgi app if ( (-x $req_params{SCRIPT_FILENAME}) && #can I execute this? (-s $req_params{SCRIPT_FILENAME}) && #Is this file empty? (-r $req_params{SCRIPT_FILENAME}) #can I read this file? ){ foreach $key ( keys %req_params){ $ENV{$key} = $req_params{$key}; } #http://perldoc.perl.org/perlipc.html#Safe-Pipe-Opens open $cgi_app, '-|', $req_params{SCRIPT_FILENAME}, $stdin_passthrough or print("Content-type: text/plain\r\n\r\n"); print "Error: CGI app returned no output - Executing $req_params{SCRIPT_FILENAME} failed !\n"; if ($cgi_app) {print <$cgi_app>; close $cgi_app;} } else { print("Content-type: text/plain\r\n\r\n"); print "Error: No such CGI app - $req_params{SCRIPT_FILENAME} may not exist or is not executable by this process.\n"; } } }
http { root /var/www/htdocs; index index.html; location ~ ^/cgi-bin/.*\.cgi$ { fastcgi_pass unix:/var/run/nginx/perl_cgi-dispatch.sock; fastcgi_index index.cgi; fastcgi_param SCRIPT_FILENAME /var/www/cgi-bin$fastcgi_script_name; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; } }
Пример с kiev.pm.org
use FCGI; use FCGI::ProcManager; use CGI; my $proc_manager = FCGI::ProcManager->new({ n_processes => 10 }); my $socket = FCGI::OpenSocket(":9000", 5); my $request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket); $proc_manager->pm_manage(); my $count = 0; while($request->Accept() >= 0) { $count++; print <<TEXT; Content-Type: text/html <h1>hello</h1> $count <hr> TEXT print "$_ = $ENV{$_}<br>\n" foreach sort keys %ENV; print "<hr>\n"; my $query = CGI->new(); print "$_ = ", $query->param($_), "<br>\n" foreach sort $query->param(); } FCGI::CloseSocket($socket);
Разное
- Чтобы избежать timewait-ов при запросе к бэкенду: sysctl net.inet.tcp.nolocaltimewait=1
- Время запроса к бэкенду: $upstream_response_time, $request_time
- Российская GEO база: