9/10 NGINX Use Cases, URI and Host rewrites

When doing ADC/Load Balancer work, nearly all requests fit into two categories:

  • Please rewrite part of the URL/URI
  • Please change the host header for this reverse proxy

These are fairly simple to implement in NGINX, so I’m creating a couple of cheat-sheet code snippets here.

“Strip Part of the URL Out”

URI stripping is fairly common, and the primary motivation for this blog post. As enterprises move to Kubernetes, they’re more likely to use proxy_pass directives (among other things) to multi-plex multiple discrete services into one endpoint.

With URI stripping, an engineer can set an arbitrary URI prefix and then remove it before the web application becomes aware. URI stripping is a useful function to stitch multiple web services together into one coherent endpoint for customer use.

NGINX comes to the rescue here, with a relatively simple solution:

  • location directive: Anchors the micro- or sub- service to an NGINX URI
  • rewrite directive: Rewrites the micro- or sub- service to a new directory, allowing for minimal backend modifications

The below example achieves this by rewriting the URI /build* to /, ensuring that the build service (Jenkins) doesn't need to be re-tooled to work behind a proxy:

location /builds/ { root /var/ rewrite ^/builds(.*)$ $1 break; autoindex on; }

As you can see, this example is an obvious security risk, as the autoindex directive lets clients browse through the build service without authentication and potentially access secrets, and is intended as an illustration and not a direct recommendation for production practice. Here's a little bit more production-appropriate example providing Jenkins over TLS (source: https://www.jenkins.io/doc/book/system-administration/reverse-proxy-configuration-nginx/)

server { listen 443 ssl http2 default_server; listen [::]:443 ssl http2 default_server; server_name cicd.lab.engyak.net; ssl_certificate "CERT; ssl_certificate_key "KEY"; ssl_session_cache shared:SSL:1m; ssl_session_timeout 10m; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ALL:!AES:!RC4:!SHA:!MD5; ssl_prefer_server_ciphers on; # Load configuration files for the default server block. include /etc/nginx/default.d/*.conf; location ~ "^/static/[0 -9a-fA-F]{8}\/(.*)$" { #rewrite all static files into requests to the root #E.g /static/12345678/css/something.css will become /css/something.css rewrite "^/static/[0 -9a-fA-F]{8}\/(.*)" /$1 last; } location /userContent { root /var/lib/jenkins/; if (!-f $request_filename){ rewrite (.*) /$1 last; break; } sendfile on; } location / { sendfile off; proxy_pass http://jenkins/; proxy_set_header Connection $connection_upgrade; proxy_set_header Upgrade $http_upgrade; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_max_temp_file_size 0; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 90; proxy_send_timeout 90; proxy_read_timeout 90; proxy_buffering off; proxy_request_buffering off; proxy_set_header Connection ""; } error_page 404 /404.html; location = /40x.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } }

This is quite a bit easier, using the proxy_set_header directive:

location /builds/ { proxy_pass http://localhost:8080; proxy_set_header Host cicd.lab.engyak.net rewrite ^/fabric-builds(.*)$ $1 break; }

Originally published at https://blog.engyak.net.

I am a network engineer based out of Alaska, pursuing various methods of achieving SRE/NRE