Slide 1

Slide 1 text

Essential Patterns

Slide 2

Slide 2 text

Traffic Mirror Feature Flags Split Traffic Load Balancing …And More

Slide 3

Slide 3 text

Reverse Proxy Private Network Public nginx Service A Service B 192.168.18.21:3000 192.168.18.21:3001

Slide 4

Slide 4 text

Reverse Proxy server { listen 80; server_name services.example.com; location /service_a/ { proxy_pass http://192.168.18.21:3000/; } } Private Network Service A Service B 192.168.18.21:3000 192.168.18.21:3001 Public nginx services.example.com $ curl http://services.example.com/service_a/foo Using SubDirectories

Slide 5

Slide 5 text

Reverse Proxy server { listen 80; server_name services.example.com; location /service_a/ { proxy_pass http://192.168.18.21:3000/; } } Private Network Service A Service B 192.168.18.21:3000 192.168.18.21:3001 Public nginx services.example.com The trailing slash is important to avoid forwarding the /service_a/ part to the target service Using SubDirectories

Slide 6

Slide 6 text

Reverse Proxy server { listen 80; server_name services.example.com; location /service_a/ { proxy_set_header 'X-Foo' 'test-injected-value'; proxy_pass http://192.168.18.21:3000/; } } Private Network Service A Service B 192.168.18.21:3000 192.168.18.21:3001 Public nginx services.example.com You can add/modify/delete headers before forwarding the request to the service Using SubDirectories

Slide 7

Slide 7 text

Reverse Proxy server { listen 80; server_name services.example.com; location /service_a/ { proxy_set_header 'X-Foo' 'test-injected-value'; proxy_pass http://192.168.18.21:3000/; add_header 'X-Resp-Bar' 'test-injected-rvalue'; } } Private Network Service A Service B 192.168.18.21:3000 192.168.18.21:3001 Public nginx services.example.com You can add/modify/delete headers before sending the response back to the client Using SubDirectories

Slide 8

Slide 8 text

Reverse Proxy server { listen 80; server_name services.example.com; location /service_a/ { client_max_body_size 2M; proxy_set_header 'X-Foo' 'test-injected-value'; proxy_pass http://192.168.18.21:3000/; add_header 'X-Resp-Bar' 'test-injected-rvalue'; } } Private Network Service A Service B 192.168.18.21:3000 192.168.18.21:3001 Public nginx services.example.com You can force a limit on the request body size. A 413 Request Entity Too Large will be returned by nginx before forwarding the request to the backend. Using SubDirectories

Slide 9

Slide 9 text

Reverse Proxy server { listen 80; server_name services.example.com; location /service_a/ { proxy_pass http://192.168.18.21:3000/; } location /service_b/ { proxy_pass http://192.168.18.21:3001/; } } Private Network Service A Service B 192.168.18.21:3000 192.168.18.21:3001 Public nginx services.example.com $ curl http://services.example.com/service_a/foo $ curl http://services.example.com/service_b/bar Using SubDirectories

Slide 10

Slide 10 text

Reverse Proxy server { listen 80; server_name service-a.example.com; location / { proxy_pass http://192.168.18.21:3000/; } } server { listen 80; server_name service-b.example.com; location / { proxy_pass http://192.168.18.21:3001/; } } Private Network Service A Service B 192.168.18.21:3000 192.168.18.21:3001 Public nginx service-a.example.com
 service-b.example.com $ curl http://service-a.example.com/foo $ curl http://service-b.example.com/bar Using SubDomains

Slide 11

Slide 11 text

upstream my_backend_foo { server 192.168.18.21:3000; } upstream my_backend_bar { server 192.168.18.21:3001; } server { listen 80; server_name ~^(?.+)\.example\.com; location / { proxy_pass http://my_backend_$serviceName; } } Reverse Proxy Private Network Service Foo Service Bar 192.168.18.21:3000 192.168.18.21:3001 Public nginx foo.example.com
 bar.example.com Using SubDomains $ curl http://foo.example.com/x2 $ curl http://bar.example.com/x2

Slide 12

Slide 12 text

Load Balancing upstream my_backend_machines { server 192.168.18.21:3000 weight=2; server 192.168.18.21:3001; server 192.168.18.22:3000 backup; } server { listen 80; server_name _; location / { proxy_pass http://my_backend_machines; } } Round Robin Service 192.168.18.21:3000 Service 192.168.18.21:3001 Service 192.168.18.22:3000

Slide 13

Slide 13 text

Load Balancing IP Hash upstream my_backend_machines { ip_hash; server 192.168.18.21:3000; server 192.168.18.21:3001; server 192.168.18.22:3000; } server { listen 80; server_name _; location / { proxy_pass http://my_backend_machines; } } Service 192.168.18.21:3000 Service 192.168.18.21:3001 Service 192.168.18.22:3000 Machine Selection Policy

Slide 14

Slide 14 text

Load Balancing Field Hash Service 192.168.18.21:3000 Service 192.168.18.21:3001 Service 192.168.18.22:3000 You can hash on any field/variable upstream my_backend_machines { hash $http_x_my_field consistent; server 192.168.18.21:3000; server 192.168.18.21:3001; server 192.168.18.22:3000; } server { listen 80; server_name _; location / { proxy_pass http://my_backend_machines; } } In this case, header: X-My-Field: foo

Slide 15

Slide 15 text

Split Traffic upstream my_service_standard { server 192.168.18.21:3000; } upstream my_service_test_p10 { server 192.168.18.21:3001; } upstream my_service_test_p20 { server 192.168.18.22:3000; } split_clients "${remote_addr}" $variant { 10.0% test_p10; 20.0% test_p20; * standard; } server { listen 80; server_name _; location / { proxy_pass http://my_service_$variant; } } 10% 20% 70% You can hash on any field/variable

Slide 16

Slide 16 text

server { listen 80; server_name _; location / { mirror /mirror; mirror_request_body on; proxy_pass http://192.168.18.21:3001; } location = /mirror { internal; proxy_pass http://192.168.18.21:3002$request_uri; } } Mirror Traffic Responses to mirror subrequests are ignored Service 192.168.18.21:3001 Mirror Service 192.168.18.21:3002

Slide 17

Slide 17 text

Feature Flags server { listen 80; server_name _; location / { if ($http_x_features ~* "(^|,)foo(,|$)") { proxy_pass http://192.168.18.21:3001; break; } if ($http_x_features ~ "(^|,)bar(,|$)") { proxy_pass http://192.168.18.21:3002; break; } proxy_pass http://192.168.18.21:3000; } } standard with "foo" with "bar"

Slide 18

Slide 18 text

Feature Flags upstream my_service_with_bar { server 192.168.18.21:3002; } upstream my_service_with_foo { server 192.168.18.21:3001; } upstream my_service_standard { server 192.168.18.21:3000; } map $http_x_features $feature_match { default standard; ~(^|,)foo(,|$) with_foo; ~(^|,)bar(,|$) with_bar; } server { listen 80; server_name _; location / { proxy_pass http://my_service_$feature_match; } } standard with "foo" with "bar"

Slide 19

Slide 19 text

upstream my_service_v10 { server 192.168.18.21:3002; } upstream my_service_v15 { server 192.168.18.21:3001; } upstream my_service_v20 { server 192.168.18.21:3000; } server { listen 80; server_name _; location / { set $backend ""; access_by_lua_block { local headers = ngx.req.get_headers() local min_version = tonumber(headers["X-Min-Required-Version"]) or 0 if min_version > 15 then ngx.var.backend = "service_v20" elseif min_version > 10 then ngx.var.backend = "service_v15" else ngx.var.backend = "service_v10" end } proxy_pass http://$backend; } } Min Required Version LUA Extension v10 v15 v20

Slide 20

Slide 20 text

upstream my_service_v10 { server 192.168.18.21:3002; } upstream my_service_v15 { server 192.168.18.21:3001; } upstream my_service_v20 { server 192.168.18.21:3000; } js_import my_module.js; server { listen 80; server_name _; location / { js_set $backend my_module.determine_backend; proxy_pass http://$backend; } } Min Required Version NJS Extension v10 v15 v20 // my_module.js function determine_backend(r) { const minVersion = parseInt(r.headersIn[‘X-Min-Required-Version']) || 0; if (minVersion > 15) { return 'my_service_v20'; } else if (minVersion > 10) { return 'my_service_v15'; } else { return 'my_service_v10'; } } export default { determine_backend };

Slide 21

Slide 21 text

>= 1.27.3 Dynamic Upstream with SRV DNS Record upstream my_backend_machines { zone my_backends 64k; resolver 8.8.8.8; server backends.example.com service=http resolve; } $ nslookup -q=SRV _http._tcp.backends.example.com _http._tcp.backends.example.com. priority=10 weight=5 port=3000 backend-0.example.com. _http._tcp.backends.example.com. priority=10 weight=5 port=3001 backend-0.example.com. _http._tcp.backends.example.com. priority=10 weight=5 port=3000 backend-1.example.com. _http._tcp.backends.example.com. priority=10 weight=5 port=3000 backend-2.example.com. upstream my_backend_machines { server 192.168.18.11:3000; # backend-0 server 192.168.18.11:3001; # backend-0 server 192.168.18.12:3000; # backend-1 server 192.168.18.13:3000; # backend-2 }

Slide 22

Slide 22 text

Handling Redirects location /foo/ { proxy_pass http://192.168.20.21:3000/; proxy_intercept_errors on; error_page 301 302 307 = @handle_redirects; } location @handle_redirects { set $original_uri $uri; set $orig_loc $upstream_http_location; proxy_pass $orig_loc; } Inside nginx

Slide 23

Slide 23 text

Location Directive server { listen 80; server_name _; location /hello { return 200 'hello and something'; } } none The Location will be matched against the beginning of the requested URI. $ curl http://localhost/hello
 $ curl http://localhost/helloween $ curl http://localhost/hello/foo

Slide 24

Slide 24 text

Location Directive server { listen 80; server_name _; location /hello { return 200 'hello and something'; } location /hello/ { return 200 'hello slash something'; } } none The Location will be matched against the beginning of the requested URI. $ curl http://localhost/hello/ $ curl http://localhost/hello/foo

Slide 25

Slide 25 text

Location Directive server { listen 80; server_name _; location /hello { return 200 'hello and something'; } location /hello/ { return 200 'hello slash something'; } location = /hello { return 200 'hello exact'; } } none The Location will be matched against the beginning of the requested URI. = Match a Location exactly against the requested URI. $ curl http://localhost/hello

Slide 26

Slide 26 text

Location Directive server { listen 80; server_name _; location /hello { return 200 'hello and something'; } location /hello/ { return 200 'hello slash something'; } location = /hello { return 200 'hello exact'; } location ~ /hello/([_a-z0-9-]+)/ { return 200 'hello/$1 regex slash something'; } } none The Location will be matched against the beginning of the requested URI. = Match a Location exactly against the requested URI. ~ Case-Sensitive regular expression match against the requested URI. $ curl http://localhost/hello/data/ $ curl http://localhost/hello/data/foo


Slide 27

Slide 27 text

Location Directive server { listen 80; server_name _; location /hello { return 200 'hello and something'; } location /hello/ { return 200 'hello slash something'; } location = /hello { return 200 'hello exact'; } location ~ /hello/([_a-z0-9-]+)/ { return 200 'hello/$1 regex slash something'; } location ^~ /hello/world/foo { return 200 'hello/world/foo and something'; } } none The Location will be matched against the beginning of the requested URI. = Match a Location exactly against the requested URI. ~ Case-Sensitive regular expression match against the requested URI. ^~ Longest non-regular expression match against the requested URI. 
 If the requested URI matches, no further matching will takes place. $ curl http://localhost/hello/world/foo $ curl http://localhost/hello/world/foo2
 $ curl http://localhost/hello/world/foo/bar

Slide 28

Slide 28 text

Location Directive server { listen 80; server_name _; location /hello { return 200 'hello and something'; } location /hello/ { return 200 'hello slash something'; } location = /hello { return 200 'hello exact'; } location ~ /hello/([_a-z0-9-]+)/ { return 200 'hello/$1 regex slash something'; } location ^~ /hello/world/foo { return 200 'hello/world/foo and something'; } location ~* /([_a-z0-9-]+)/xyz { return 200 '$1/xyz regex and something'; } } none The Location will be matched against the beginning of the requested URI. = Match a Location exactly against the requested URI. ~ Case-Sensitive regular expression match against the requested URI. ^~ Longest non-regular expression match against the requested URI. 
 If the requested URI matches, no further matching will takes place. ~* Case-Insensitive regular expression match against the requested URI. $ curl http://localhost/data/xyz $ curl http://localhost/data/xyzkw
 $ curl http://localhost/data/xyz/foo

Slide 29

Slide 29 text

Location Directive server { listen 80; server_name _; location /hello { return 200 'hello and something'; } location /hello/ { return 200 'hello slash something'; } location = /hello { return 200 'hello exact'; } location ~ /hello/([_a-z0-9-]+)/ { return 200 'hello/$1 regex slash something'; } location ^~ /hello/world/foo { return 200 'hello/world/foo and something'; } location ~* /([_a-z0-9-]+)/xyz { return 200 '$1/xyz regex and something'; } location ~ /foo/(.*)/bar { return 200 '/foo/ and $1 and /bar and something'; } } none The Location will be matched against the beginning of the requested URI. = Match a Location exactly against the requested URI. ~ Case-Sensitive regular expression match against the requested URI. ^~ Longest non-regular expression match against the requested URI. 
 If the requested URI matches, no further matching will takes place. ~* Case-Insensitive regular expression match against the requested URI. $ curl http://localhost/foo/data/bar
 $ curl http://localhost/foo/data/barry
 $ curl http://localhost/foo/data/bar/abc

Slide 30

Slide 30 text

Static Files server { listen 80; server_name foo.example.com; root /opt/data/foo/; index index.html; location / { try_files $uri $uri/ /index.html; } } server { listen 80; server_name _; location /foo/ { autoindex off; alias /opt/data/foo/; try_files $uri $uri/ /foo/index.html; } } $ curl http://foo.example.com $ curl http://foo.example.com/page/aaa $ curl http://example.com/foo/ $ curl http://example.com/foo/page/aaa

Slide 31

Slide 31 text

log_format upstream_log '$time_local -> $remote_addr -> $server_name - $upstream_addr - ' '$http_user_agent - $bytes_sent/$upstream_bytes_received - "$request" $status - ' '$request_time/$upstream_response_time'; access_log /var/log/nginx/access.log upstream_log buffer=64k flush=5s; log_format logger_json escape=json '{"time": $msec, "address": "$remote_addr", "server_name": "$server_name",' '"upstream_addr": "$upstream_addr", "user_agent": "$http_user_agent",' '"bytes_sent": $bytes_sent, "upstream_bytes_received": $upstream_bytes_received,' '"method": "$request_method", "uri": "$request_uri", "host": "$http_host",' '"status": $status,"request_length": $request_length, "resp_time": $request_time,' '"upstream_response_time": $upstream_response_time }'; access_log /var/log/nginx/access.log logger_json buffer=64k flush=5s; Json Human Logging server { location /demo/ { access_log off; proxy_pass http://my_service; } } Disable Logs On a Specific Path