9/10 NGINX Use Cases, URI and Host rewrites

NGINX Rewrite Directives, The 9/10 Solutions

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:

1  location /builds/ {  
2    root /var/lib/jenkins/workspace/;  
3    rewrite ^/builds(.\*)$ $1 break;  
4    autoindex on;  
5  }  

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/)

 1    server {  
 2        listen       443 ssl http2 default\_server;  
 3        listen       \[::\]:443 ssl http2 default\_server;  
 4        server\_name  cicd.lab.engyak.net;  
 5  
 6        ssl\_certificate "CERT;  
 7        ssl\_certificate\_key "KEY";  
 8        ssl\_session\_cache shared:SSL:1m;  
 9        ssl\_session\_timeout  10m;  
10        ssl\_protocols TLSv1.2 TLSv1.3;  
11        ssl\_ciphers ALL:!AES:!RC4:!SHA:!MD5;  
12        ssl\_prefer\_server\_ciphers on;  
13  
14        # Load configuration files for the default server block.  
15        include /etc/nginx/default.d/\*.conf;  
16  
17        location ~ "^/static/\[0\-9a-fA-F\]{8}\\/(.\*)$" {  
18            #rewrite all static files into requests to the root  
19            #E.g /static/12345678/css/something.css will become /css/something.css  
20            rewrite "^/static/\[0\-9a-fA-F\]{8}\\/(.\*)" /$1 last;  
21        }  
22  
23        location /userContent {  
24            \# have nginx handle all the static requests to userContent folder  
25            #note : This is the $JENKINS\_HOME dir  
26            root /var/lib/jenkins/;  
27            if (!-f $request\_filename){  
28            #this file does not exist, might be a directory or a /\*\*view\*\* url  
29            rewrite (.\*) /$1 last;  
30            break;  
31            }  
32            sendfile on;  
33        }  
34        location / {  
35                    sendfile off;  
36                    proxy\_pass http://jenkins/;  
37            \# Required for Jenkins websocket agents  
38            proxy\_set\_header   Connection        $connection\_upgrade;  
39            proxy\_set\_header   Upgrade           $http\_upgrade;  
40  
41            proxy\_set\_header   Host              $host;  
42            proxy\_set\_header   X-Real-IP         $remote\_addr;  
43            proxy\_set\_header   X-Forwarded-For   $proxy\_add\_x\_forwarded\_for;  
44            proxy\_set\_header   X-Forwarded-Proto $scheme;  
45            proxy\_max\_temp\_file\_size 0;  
46  
47            #this is the maximum upload size  
48            client\_max\_body\_size       10m;  
49            client\_body\_buffer\_size    128k;  
50  
51            proxy\_connect\_timeout      90;  
52            proxy\_send\_timeout         90;  
53            proxy\_read\_timeout         90;  
54            proxy\_buffering            off;  
55            proxy\_request\_buffering    off; \# Required for HTTP CLI commands  
56            proxy\_set\_header Connection ""; \# Clear for keepalive  
57        }  
58        error\_page 404 /404.html;  
59            location = /40x.html {  
60        }  
61  
62        error\_page 500 502 503 504 /50x.html;  
63            location = /50x.html {  
64        }  
65    }  

Set Host Headers

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

1  location /builds/ {  
2    proxy\_pass http://localhost:8080;  
3    proxy\_set\_header Host cicd.lab.engyak.net  
4    rewrite ^/fabric-builds(.\*)$ $1 break;  
5  }