Nginx — примеры преобразования rewrite правил

23/02/2013
от
Поделиться

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 ([email protected]) { exit unless [email protected] =~ /^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);
Поделиться

Метки: , , , , , , , ,

Ответить

Вы должны войти в систему, чтобы оставить комментарий.