pdf
|<<
<
>
>>|
/
Introduction to nginx.conf scripting ---- Introduction to {{#x|nginx.conf}} {{#i|scripting}} ☺{{#author|agentzh@gmail.com}}☺ {{#author|章亦春 (agentzh)}} {{#date|2010.4}} ---- {{#v|$}} nginx -c {{#x|/path/to/nginx.conf}} {{img src="images/nginx-logo.png" width="350" height="90"}} ---- {{#v|$}} ps aux | grep nginx root 2003 0.0 0.0 25208 412 ? Ss 10:08 0:00 nginx: {{#x|master process}} nginx nobody 2004 0.0 0.0 25608 1044 ? S 10:08 0:00 nginx: {{#x|worker process}} nobody 2005 0.0 0.0 25608 1044 ? S 10:08 0:00 nginx: {{#x|worker process}} ---- {{#cm|# nginx.conf }} {{#kw|worker_processes}} 2; {{#kw|events}} { {{#kw|worker_connections}} 1024; } {{#kw|http}} { ... {{#kw|server}} { {{#kw|listen}} 80; {{#kw|server_name}} localhost; ... {{#kw|location}} / { {{#kw|root}} /var/www; {{#kw|index}} index.html index.htm; } } } ---- {{#x|♡}} {{#i|Hello World}} on the {{#ci|nginx}} land {{img src="images/hello.png" width="400" height="300"}} ---- {{#cm|# enable the ngx_echo module in your nginx build}} {{#v|$}} ./configure --prefix=/opt/nginx \ --add-module=/path/to/{{#x|echo-nginx-module}} ---- {{#kw|location}} = '/hello' { {{#kw|echo}} {{#x|"hello, world!"}}; } ---- {{#v|$}} curl 'http://localhost/hello' {{#x|hello, world!}} ---- {{#x|♡}} Introducing {{#ci|parameterized}} hello ---- {{#kw|location}} = '/hello' { {{#kw|echo}} {{#x|"hello, }}{{#v|$arg_person}}{{#x|!"}}; } ---- {{#v|$}} curl 'http://localhost/hello?{{#x|person=agentzh}}' hello, {{#x|agentzh}}! {{#v|$}} curl 'http://localhost/hello' hello, ! ---- {{#x|♡}} Add a {{#ci|default}} value to the {{#i|person}} parameter ---- {{#kw|location}} = '/hello' { {{#kw|if}} ({{#v|$arg_person}} = {{#x|''}}) { {{#kw|echo}} {{#x|"hello, anonymous!"}}; {{#kw|break}}; } {{#kw|echo}} {{#x|"hello, }}{{#v|$arg_person}}{{#x|!"}}; } ---- {{#v|$}} curl 'http://localhost/hello?{{#x|person=agentzh}}' hello, {{#x|agentzh}}! {{#v|$}} curl 'http://localhost/hello' hello, {{#x|anonymous}}! ---- {{#x|♡}} ...or {{#ci|avoid}} using the {{#x|if}} statement ---- {{#cm|# enable the ngx_set_misc module and}} {{#cm|# Marcus Clyne's ngx_devel_kit in your nginx build}} {{#v|$}} ./configure --prefix=/opt/nginx \ --add-module=/path/to/echo-nginx-module \ --add-module=/path/to/{{#x|ngx_devel_kit}} \ --add-module=/path/to/{{#x|set-misc-nginx-module}} ---- {{#kw|location}} = '/hello' { {{#kw|set}} {{#v|$person}} {{#v|$arg_person}}; {{#kw|set_if_empty}} {{#v|$person}} {{#x|'anonymous'}}; {{#kw|echo}} {{#x|"hello, }}{{#v|$person}}{{#x|!"}}; } ---- {{#v|$}} curl 'http://localhost/hello?{{#x|person=agentzh}}' hello, {{#x|agentzh}}! {{#v|$}} curl 'http://localhost/hello' hello, {{#x|anonymous}}! ---- {{#x|♡}} Some {{#ci|UTF-8}} love in the {{#x|person}} parameter? {{img src="images/han.jpg" width="127" height="106"}} ---- {{#cm|# sigh...}} {{#v|$}} curl 'http://localhost/hello?{{#x|person=%E7%AB%A0%E4%BA%A6%E6%98%A5}}' hello, {{#x|%E7%AB%A0%E4%BA%A6%E6%98%A5}} ---- {{#x|♡}} Let's {{#ci|fix}} it using the {{#x|set_unescape_uri}} directive! ---- {{#kw|location}} = '/hello' { {{#kw|set_unescape_uri}} {{#v|$person}} {{#v|$arg_person}}; {{#kw|set_if_empty}} {{#v|$person}} {{#x|'anonymous'}}; {{#kw|echo}} {{#x|"hello, }}{{#v|$person}}{{#x|!"}}; } ---- {{#cm|# Yay!}} {{#v|$}} curl 'http://localhost/hello?{{#x|person=%E7%AB%A0%E4%BA%A6%E6%98%A5}}' hello, {{#x|章亦春}} ---- {{#x|♡}} Nginx {{#ci|variables}} are very powerful, but how about {{#x|arrays}}? ---- {{#cm|# enable the ngx_array_var module in your nginx build}} {{#v|$}} ./configure --prefix=/opt/nginx \ --add-module=/path/to/echo-nginx-module \ --add-module=/path/to/ngx_devel_kit \ --add-module=/path/to/set-misc-nginx-module \ --add-module=/path/to/{{#x|array-var-nginx-module}} ---- {{#kw|location}} ~ {{#x|'^/foo/(.*)'}} { {{#kw|set}} {{#v|$list}} {{#v|$1}}; {{#kw|array_split}} {{#x|','}} {{#v|$list}}; {{#kw|array_map}} {{#x|'[}}{{#v|$array_it}}{{#x|]'}} {{#v|$list}}; {{#kw|array_join}} {{#x|' '}} {{#v|$list}}; {{#kw|echo}} {{#v|$list}}; } ---- {{#v|$}} curl 'http://localhost/foo/{{#x|Bob,Marry,John}}' {{#x|[Bob] [Marry] [John]}} ---- {{#x|♡}} Using {{#ci|subrequests}} to do mashup ---- {{#kw|location}} = '/merge' { {{#kw|echo}} {{#x|'['}}; {{#kw|echo_location_async}} /moon; {{#kw|echo}} {{#x|','}}; {{#kw|echo_location_async}} /earth; {{#kw|echo}} {{#x|']'}}; } {{#kw|location}} /moon { {{#kw|echo}} {{#x|'"moon"'}}; } {{#kw|location}} /earth { {{#kw|echo}} {{#x|'"earth"'}}; } ---- {{#v|$}} curl 'http://localhost/merge' {{#x|[}} {{#x|"moon"}} {{#x|,}} {{#x|"earth"}} {{#x|]}} ---- {{#x|♡}} or even {{#x|dynamic}} mashups... ---- {{#kw|location}} ~ '^/merge/(.*)' { {{#kw|set}} {{#v|$list}} {{#v|$1}}; {{#kw|echo}} {{#x|'['}}; {{#kw|echo_foreach_split}} {{#x|','}} {{#v|$list}}; {{#kw|echo_location_async}} {{#x|"/}}{{#v|$echo_it}}{{#x|"}}; {{#kw|echo}} {{#x|","}}; {{#kw|echo_end}}; {{#kw|echo}} {{#x|'null'}}; {{#kw|echo}} {{#x|']'}}; } ---- {{#v|$}} curl 'http://localhost/merge/earch,moon' {{#x|[}} {{#x|"earth"}} {{#x|,}} {{#x|"moon"}} {{#x|,}} {{#x|null}} {{#x|]}} ---- {{#x|♡}} Some {{#i|non-blocking}} {{#x|memcached}} love ---- {{#cm|# enable the ngx_memc module in your nginx build}} {{#v|$}} ./configure --prefix=/opt/nginx \ --add-module=/path/to/echo-nginx-module \ --add-module=/path/to/{{#x|memc-nginx-module}} ---- {{#cm|# (not quite) REST interface to our memcached server}} {{#cm|# at 127.0.0.1:11211}} {{#kw|location}} = /memc { {{#kw|set}} {{#v|$memc_cmd}} {{#v|$arg_cmd}}; {{#kw|set}} {{#v|$memc_key}} {{#v|$arg_key}}; {{#kw|set}} {{#v|$memc_value}} {{#v|$arg_val}}; {{#kw|set}} {{#v|$memc_exptime}} {{#v|$arg_exptime}}; {{#kw|memc_pass}} {{#x|127.0.0.1:11211}}; } ---- {{#v|$}} curl 'http://localhost/memc?{{#x|cmd=flush_all}}'; {{#x|OK}} {{#v|$}} curl 'http://localhost/memc?{{#x|cmd=replace&key=foo&val=FOO}}'; {{#x|NOT_STORED}} ---- {{#v|$}} curl 'http://localhost/memc?{{#x|cmd=add&key=foo&val=Bar&exptime=60}}'; {{#x|STORED}} {{#v|$}} curl 'http://localhost/memc?{{#x|cmd=replace&key=foo&val=Foo}}'; {{#x|STORED}} {{#v|$}} curl 'http://localhost/memc?{{#x|cmd=set&key=foo&val=Hello}}'; {{#x|STORED}} ---- {{#v|$}} curl 'http://localhost/memc?{{#x|cmd=get&key=foo}}'; {{#x|Hello}} {{#v|$}} curl 'http://localhost/memc?{{#x|cmd=delete&key=foo}}'; {{#x|DELETED}} ---- {{#v|$}} curl 'http://localhost/memc?{{#x|cmd=flush_all}}'; {{#x|OK}} {{#v|$}} curl 'http://localhost/memc?{{#x|cmd=incr&key=counter&val=1}}'; <html> <head><title>{{#x|404 Not Found}}</title></head> <body bgcolor=\"white\"> <center><h1>{{#x|404 Not Found}}</h1></center> <hr><center>nginx/0.8.35</center> </body> </html> ---- {{#v|$}} curl 'http://localhost/memc?{{#x|cmd=add&key=counter&val=0}}'; {{#x|STORED}} {{#v|$}} curl 'http://localhost/memc?{{#x|cmd=incr&key=counter&val=1}}'; {{#x|STORED}} ---- {{#x|♡}} {{#ci|Safe}} memcached {{#x|incr}} operation ---- {{#kw|location}} = /safe-incr { {{#kw|if}} ({{#v|$arg_key}} = {{#x|''}}) { {{#kw|return}} {{#x|400}}; {{#kw|break}}; } {{#kw|if}} ({{#v|$arg_val}} !~ {{#x|'^\d+$'}}) { {{#kw|return}} {{#x|400}}; {{#kw|break}}; } {{#kw|echo_exec}} {{#x|/safe-memc?cmd=incr&key=}}{{#v|$arg_key}}{{#x|&val=}}{{#v|$arg_val}}; } ---- {{#kw|location}} = /safe-memc { {{#kw|internal}}; {{#kw|set}} {{#v|$memc_cmd}} {{#v|$arg_cmd}}; {{#kw|set}} {{#v|$memc_key}} {{#v|$arg_key}}; {{#kw|set}} {{#v|$memc_value}} {{#v|$arg_val}}; {{#kw|set}} {{#v|$memc_exptime}} {{#v|$arg_exptime}}; {{#kw|memc_pass}} {{#x|127.0.0.1:11211}}; {{#kw|error_page}} 404 = {{#x|/add-and-retry}}; } ---- {{#kw|location}} = /add-and-retry { {{#kw|internal}}; {{#kw|echo_location}} {{#x|/memc?cmd=add&key=}}{{#v|$arg_key}}{{#x|&val=0}}; {{#kw|echo_location}} {{#x|/memc?}}{{#v|$query_string}}; } ---- {{#v|$}} curl 'http://localhost/memc?cmd={{#x|flush_all}}'; {{#x|OK}} {{#v|$}} curl 'http://localhost/{{#x|safe-incr}}?key=counter&val=1'; {{#x|STORED}} {{#x|STORED}} ---- {{#x|♡}} Memcached {{#x|connection pool}} support {{img src="images/pool2.jpg" width="145" height="109"}} ---- {{#cm|# enable Maxim Dounin's ngx_http_upstream_keepalive module}} {{#cm|# in your nginx build}} {{#v|$}} ./configure --prefix=/opt/nginx \ --add-module=/path/to/echo-nginx-module \ --add-module=/path/to/memc-nginx-module \ --add-module=/path/to/{{#x|ngx_http_upstream_keepalive}} ---- {{#kw|http}} { ... {{#kw|upstream}} {{#x|my_memc_backend}} { {{#kw|server}} 127.0.0.1:11211; {{#cm|# a connection pool that can cache}} {{#cm|# up to 1024 connections}} {{#kw|keepalive}} {{#x|1024}} single; } ... } ---- {{#kw|location}} = /memc { ... {{#kw|memc_pass}} {{#x|my_memc_backend}}; } ---- {{#x|♡}} Memcached server {{#ci|hashing}} based on user keys (Hey, memcached {{#x|cluster}}!) {{img src="images/cluster-abs.gif" width="124" height="84"}} ---- {{#cm|# enable the ngx_set_misc module and Marcus Clyne's}} {{#cm|# ngx_devel_kit again in your nginx build}} {{#v|$}} ./configure --prefix=/opt/nginx \ --add-module=/path/to/memc-nginx-module \ --add-module=/path/to/{{#x|ngx_devel_kit}} \ --add-module=/path/to/{{#x|set-misc-nginx-module}} ---- {{#kw|http}} { {{#kw|upstream}} {{#x|A}} { {{#kw|server}} 10.32.110.5:11211; } {{#kw|upstream}} {{#x|B}} { {{#kw|server}} 10.32.110.16:11211; } {{#kw|upstream}} {{#x|C}} { {{#kw|server}} 10.32.110.27:11211; } {{#kw|upstream_list}} {{#x|my_cluster A B C}}; ... } ---- location = /memc { set $memc_cmd $arg_cmd; set $memc_key $arg_key; set $memc_value $arg_val; set $memc_exptime $arg_exptime; {{#cm|# hashing the $arg_key to an upstream backend}} {{#cm|# in the my_cluster upstream list, and set $backend:}} {{#kw|set_hashed_upstream}} {{#v|$backend}} {{#x|my_cluster}} {{#v|$arg_key}}; {{#cm|# pass $backend to memc_pass:}} {{#kw|memc_pass}} {{#v|$backend}}; } ---- {{#x|♡}} {{#ci|Capture}} subrequests' responses into nginx {{#x|variables}} {{img src="images/capture.jpg" width="124" height="121"}} ---- {{#cm|# enable Valery Kholodkov's nginx_eval_module}} {{#cm|# in your nginx build}} {{#v|$}} ./configure --prefix=/opt/nginx \ --add-module=/path/to/echo-nginx-module \ --add-module=/path/to/memc-nginx-module \ --add-module=/path/to/{{#x|nginx_eval_module}} ---- {{#kw|location}} = /save { {{#kw|eval_override_content_type}} {{#x|'text/plain'}}; {{#kw|eval}} {{#v|$res}} { set $memc_cmd 'set'; set $memc_key $arg_id; set $memc_val $arg_name; memc_pass 127.0.0.1:11211; } {{#kw|if}} ({{#v|$res}} !~ {{#x|'^STORED$'}}) { {{#kw|return}} {{#x|500}}; {{#kw|break}}; } {{#kw|echo}} {{#x|'Done!'}}; } ---- {{#x|♡}} Use my {{#i|fork}} of {{#x|ngx_eval}} module to capture {{#ci|arbitrary}} location's response (with filters!) {{http://github.com/agentzh/nginx-eval-module}} ---- {{#kw|location}} = /hello { {{#kw|eval_override_content_type}} {{#x|'text/plain'}}; {{#kw|eval_subrequest_in_memory}} {{#x|off}}; {{#kw|eval_buffer_size}} {{#x|1k}}; {{#kw|eval}} {{#v|$out}} { {{#kw|echo_before_body}} {{#x|hello}}; {{#kw|echo}} {{#x|world}}; } {{#kw|echo}} {{#x|"[}}{{#v|$out}}{{#x|]"}}; } ---- {{#v|$}} curl 'http://localhost/hello' {{#x|[hello}} {{#x|world]}} ---- {{#x|♡}} Some {{#i|non-blocking}} {{#x|MySQL}} love {{img src="images/mysql.png" width="128" height="130"}} ---- {{#cm|# install libdrizzle first and then}} {{#cm|# enable the ngx_drizzle and ngx_rds_json}} {{#cm|# modules in your nginx build}} {{#v|$}} ./configure --prefix=/opt/nginx \ --add-module=/path/to/{{#x|drizzle-nginx-module}} \ --add-module=/path/to/{{#x|rds-json-nginx-module}} ---- {{#kw|http}} { {{#kw|upstream}} my_mysql_backend { {{#kw|drizzle_server}} {{#c|127.0.0.1:3306}} dbname={{#c|test}} password={{#c|some_pass}} user={{#c|monty}} protocol={{#c|mysql}}; } ... } ---- {{#kw|location}} = /cats { {{#kw|drizzle_query}} {{#x|'select * from cats'}}; {{#kw|drizzle_pass}} {{#x|my_mysql_backend}}; {{#kw|rds_json}} on; } ---- {{#v|$}} curl 'http://localhost/cats' {{#x|[{"name":"Jerry","age":1},{"name":"Tom","age":3}]}} ---- {{#x|♡}} Database {{#x|connection pool}} support {{img src="images/pool.jpg" width="130" height="88"}} ---- http { upstream my_mysql_backend { drizzle_server 127.0.0.1:3306 dbname=test password=some_pass user=monty protocol=mysql; {{#cm|# a connection pool that can cache up to}} {{#cm|# 200 mysql TCP connections}} {{#kw|drizzle_keepalive}} max={{#x|200}} overflow={{#x|reject}}; } ... } ---- {{#x|♡}} Mysql {{#x|cluster}} {{#i|hashing}} love {{img src="images/cluster.jpg" width="150" height="107"}} ---- {{#cm|# re-enable the ngx_set_misc module and Marcus Clyne's}} {{#cm|# ngx_devel_kit in your nginx build}} {{#v|$}} ./configure --prefix=/opt/nginx \ --add-module=/path/to/drizzle-nginx-module \ --add-module=/path/to/rds-json-nginx-module \ --add-module=/path/to/{{#x|ngx_devel_kit}} \ --add-module=/path/to/{{#x|set-misc-nginx-module}} ---- {{#kw|http}} { {{#kw|upstream}} {{#x|A}} { {{#kw|drizzle_server}} ...; } {{#kw|upstream}} {{#x|B}} { {{#kw|drizzle_server}} ...; } {{#kw|upstream}} {{#x|C}} { {{#kw|drizzle_server}} ...; } {{#kw|upstream_list}} {{#x|my_cluster A B C}}; ... } ---- {{#kw|location}} ~ {{#x|'^/cat/(.*)'}} { {{#kw|set}} {{#v|$name}} {{#v|$1}}; {{#kw|set_quote_sql_str}} {{#v|$quoted_name}} {{#v|$name}}; {{#kw|drizzle_query}} {{#x|"select *}} {{#x|from cats}} {{#x|where name=}}{{#v|$quoted_name}}{{#x|"}}; {{#kw|set_hashed_upstream}} {{#v|$backend}} {{#x|my_cluster}} {{#v|$name}}; {{#kw|drizzle_pass}} {{#v|$backend}}; {{#kw|rds_json}} on; } ---- {{#x|♡}} Highly {{#ci|dynamic}} SQL query {{#x|construction}} ---- {{#kw|location}} ~ {{#x|'^/cats/(.*)'}} { {{#kw|set}} {{#v|$list}} {{#v|$1}}; {{#kw|array_split}} {{#x|','}} {{#v|$list}}; {{#kw|array_map_op}} {{#kw|set_quote_sql_str}} {{#v|$list}}; {{#kw|array_map}} {{#x|'name=}}{{#v|$array_it}}{{#x|'}} {{#v|$list}}; {{#kw|array_join}} {{#x|' or '}} {{#v|$list}} to={{#v|$cond}}; {{#kw|drizzle_query}} {{#x|"select *}} {{#x|from cats}} {{#x|where }}{{#v|$cond}}{{#x|"}}; {{#kw|drizzle_pass}} my_mysql_backend; {{#kw|rds_json}} on; } ---- {{#cm|# Let's do}} {{#cm|# select * from cats}} {{#cm|# where name='Jerry' or name='Tom'}} {{#v|$}} curl 'http://localhost/cats/Jerry,Tom' {{#x|[{"name":"Jerry","age":1},{"name":"Tom","age":3}]}} ---- {{#x|♡}} Piotr Sikora's {{#ci|ngx_postgres}} is drawing near :D {{img src="images/elephant.png" width="143" height="147"}} ---- {{#kw|upstream}} my_pg_backend { {{#kw|postgres_server}} {{#x|10.62.136.3:5432}} dbname={{#x|test}} user={{#x|someone}} password={{#x|123456}}; } ---- {{#kw|location}} /cats { {{#kw|postgres_query}} {{#x|'select * from cats'}}; {{#kw|postgres_pass}} {{#x|my_pg_backend}}; {{#kw|rds_json}} on; } ---- {{#x|♡}} chaoslawful is already {{#ci|working}} on {{#x|ngx_lua}} :D {{img src="images/lua.jpg" width="118" height="118"}} ---- {{#x|♡}} A quick {{#ci|summary}} of our existing modules {{#cm|✓}} {{#x|ngx_echo}}: Brings \"echo\", \"sleep\", \"time\", \"exec\", {{#ci|background job}} and even more shell-style goodies to Nginx config file. {{http://wiki.nginx.org/NginxHttpEchoModule}} {{#cm|✓}} {{#x|ngx_chunkin}}: HTTP 1.1 {{#ci|chunked}}-encoding request body support for Nginx. {{http://wiki.nginx.org/NginxHttpChunkinModule}} {{#cm|✓}} {{#x|ngx_headers_more}}: Set and clear input and output {{#ci|headers}}...more than \"add\"! {{http://wiki.nginx.org/NginxHttpHeadersMoreModule}} ---- and even more... {{#cm|✓}} {{#x|ngx_memc}}: An extended version of the standard {{#ci|memcached}} module that supports set, add, delete, and many more memcached commands. {{http://wiki.nginx.org/NginxHttpMemcModule}} {{#cm|✓}} {{#x|ngx_drizzle}}: ngx_drizzlen nginx upstream module that talks to {{#ci|mysql}}, drizzle, and sqlite3 by libdrizzle. {{http://github.com/chaoslawful/drizzle-nginx-module}} {{#cm|✓}} {{#x|ngx_rds_json}}: An nginx output filter that formats Resty DBD Streams generated by ngx_drizzle and others to JSON. {{http://github.com/agentzh/rds-json-nginx-module}} ---- Well, still continued... {{#cm|✓}} {{#x|ngx_xss}}: Native support for {{#ci|cross-site scripting}} (XSS) in an nginx. {{http://github.com/agentzh/xss-nginx-module}} {{#cm|✓}} {{#x|ngx_set_misc}}: Various nginx.conf variable transformation utilities. {{http://github.com/agentzh/set-misc-nginx-module}} {{#cm|✓}} {{#x|ngx_array_var}}: Add support for array variables to nginx config files. {{http://github.com/agentzh/array-var-nginx-module}} ---- {{#x|♡}} {{#ci|New}} nginx modules on our {{#x|TODO}} list {{#cm|✓}} ngx_form_input {{#cm|✓}} ngx_iconv {{#cm|✓}} ngx_srcache {{#cm|✓}} ngx_encrypted_session {{#cm|✓}} ngx_rds {{#cm|✓}} ngx_rds_tt2 ---- {{#c|♡}} Update: {{#x|recent developments}} {{http://agentzh.org/misc/slides/recent-dev-nginx-conf/}} ---- {{#ci|☺}} {{#i|Any questions}}? {{#ci|☺}}