Ready to know about downtime before your customers?
Status List delivers uptime monitoring and professional hosted status pages for sites of all shapes and sizes.
Trusted by 1000+ companies
Own a website, want to get alerts when it’s not working?
Consider trying out Status List for free. We have thousands of less-stressed customers who rely on us.
Config variables are a powerful tool to control how NGINX routes requests. HTTP request, header and env variables give us precise control on how requests are routed. Let’s dig in!
Configuration variables are typically used in the server block of the NGINX config file. We can use if statements and variables to control how a request is routed within NGINX. Here’s a simple example of what we’re talking about:
server {
listen 80;
# check host
if ($host = www.mydomain.com) {
# remove www by redirecting
return 301 http://mydomain.com$request_uri;
}
# send request to backend
location / {
proxy_pass http://backend;
}
}
In the example above, we check the host variable (a built-in NGINX variable) and route the request either to a redirect or to our backend. This is just a simple example. We can build incredibly complex algorithms with these simple building blocks.
Let’s walk through the variables available to us.
Variable | Description | Example |
---|---|---|
$remote_addr | The http client’s public ip | 210.39.293.293 |
$request_length | Tells us how long the the request is. This includes the headers and request body. | 2930 (bytes) |
$content_length | Similar to $request_length, but only has the length of the request body | 2000 (bytes) |
$request_method | The type of HTTP request received (GET/POST/PUT/DELETE) | GET |
Here’s an example of request-based request routing:
server {
location / {
proxy_pass http://backend/$request_method$request_uri
proxy_set_header X-RemoteIP $request_addr;
}
}
In this example we’re re-writing the request path and setting a header before sending the request to our backend.
The proxy_pass line is pre-appending the request method to the request. This could be useful if your backend didn’t have access to the HTTP method, or wanted to use path-only based routing. (e.g. /post/companies, /get/companies)
The proxy_set_header line is adding an HTTP header with the client’s IP address. This way the backend can still access the client’s IP address even though it’s behind a load balancer. (You could also use the X-ForwardedFor header here, there’s a great write up on the NGINX blog about that)
Trusted by 1000+ companies
Predefined NGINX variables allow us to access the HTTP header values as well.
Variable | Description | Example |
---|---|---|
$content_type | The Content-Type http header | application/json |
$http_user_agent | The http client’s user agent (User-Agent Header) | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 |
$cookie_{name} | The value of the HTTP cookie with the given name (e.g. $cookie_auth) | cookie-value |
$http_{name} | The HTTP header at {name} (e.g. Authorization) | Bearer 31d728c8-7141-42d1-a07d-77e26fac400b |
Here’s an example of header-based routing:
server {
if ($http_user_agent ~ Bot) {
return 403 "Bots are forbidden";
}
if ($http_authorization = "") {
return 403 "Missing bearer token";
}
location / {
proxy_pass http://backend$uri?$query_string&auth=$http_authorization
}
}
In this example, we’re blocking out bad requests and moving the Authorization header into the query string. The Bot check and missing Authorization HTTP header will simply block the request with a 403 response. Requests that meet our requirements will be forward on. In the requests that we forward, we extract the Authorization header and append it to the query string. This can be useful if your backend doesn’t want to touch HTTP Headers, but is able to access the query string.
Location variables allow us to access URI properties. This is really useful for path and query-based routing and redirecting. Here are a few commonly used built-in variables.
Variable Name | Description | Example |
---|---|---|
$request_uri | The full requested path with query string | //contact?ref=gas |
$uri | A normalized version of $request_uri. (e.g. double slashes converted to single slash) This value will change during redirects or rewriting. | /contact |
$scheme | The request scheme (http/https) | https |
$query_string (aka $args) | The query portion of the URL (without the leading ?) | search=hello&user=3920 |
$arg_{name} | The value of a specific query field (e.g. $arg_search) | hello |
$host | The value of the Host header | mydomain.com:9403 |
$hostname | Similar to $host, but doesn’t include the port number | mydomain.com |
Here’s an example of location based routing:
server {
if ($arg_search != "") {
rewrite ^(.*)$ /search/$arg_search break;
}
if ($uri = /contact) {
return 301 /new-contact-page;
}
}
In this example we’re re-routing searches and the contact page. If any query contains the search field, we rewrite the URI to use the /search endpoint. In the second part, we’re creating a static redirect for the /contact page.
$upstream_response_time | Measures how long the backend took to process the request | 3.293 (seconds) |
---|---|---|
$upstream_queue_time | Measures how long this request waited in the queue before being processed by the backend | 1.203 (seconds) |
$upstream_status | The HTTP status code returned by the backend | 200 |
$upstream_addr | The backend address used for this request | 10.0.0.2:3029 |
Here’s an example of how we might use upstream variables:
server {
location / {
proxy_pass http://backend;
add_header X-BackendTime $upstream_response_time;
add_header X-BackendUsed $upstream_addr;
}
}
In this example, we’re adding some diagnostic metrics to our HTTP response header. We add the backend used and how long it took for that backend to process the request. This type of information can be really helpful in tracking down production issues.
Maps are a great way to deal with lookup tables. For example, if we have a set of redirects we’d like to make, we can use a map. NGINX will evaluate the lookup in the background and we can access it as a single variable. Here’s an example
# redirection table
map $uri $redirected_uri {
/ /index.html
/cntact /contact
/pricing /contact-sales
}
server {
if ($redirected_uri) {
rewrite ^ $redirected_uri;
}
}
Environment variables are really helpful when we need to spin up multiple NGINX instances. We can use variables to inject host names, domain names and backend information into our configuration. Unfortunately NGINX doesn’t support environment variables on it’s own. But, we can get around that problem with templating.
Templating is where we create an NGINX configuration file, but use bash variables to inject our environment variables. Here’s an example:
cat /etc/nginx/nginx.template.conf
http {
server {
server_name ${DOMAIN}
listen ${PORT};
location / {
proxy_pass http://${BACKEND};
}
}
}
We can take that template and run it through something like envsubstr to generate our actual configuration.
envsubstr < /etc/nginx/nginx.template.conf > /etc/nginx/nginx.conf
Our nginx.conf will now contain our “rendered” configuration.
We can also create user-defined variables using the set directive. This can be useful for extracting request details and reconstructing the request. You can use the set directive similar to how we use the rewrite/return directives. Here’s an example:
server {
set $uid 0;
if ($uri ~ "^/([0-9]+)/") {
set $uid $1;
}
location / {
proxy_pass http://backend;
proxy_set_header X-UserId $uid;
}
}
In this example, we extract the user’s id for the backend. First we check if the URI has the format that contains a UID. Then we extract that UID and add it to the X-UserId header. That X-UserId header is then passed to the backend.
You can find the full NGINX variable reference here.
© Status List 2024