nginx Built-in Variables Reference

All nginx $variable names with source module and description.

Searchable nginx built-in variable reference covering core HTTP, proxy, upstream, SSL and GeoIP variables, including the dynamic $http_, $arg_, $cookie_ and $sent_http_ name patterns. It runs free in your browser on Gera Tools, with nothing uploaded.

Last updated Source: Gera Tools

What is the difference between $uri and $request_uri?

$request_uri is the full original request URI including the query string and exactly as the client sent it. $uri is the current normalised URI without the query string, and it can change during internal redirects and rewrites, so the two often differ after a rewrite.

nginx built-in variables

nginx exposes a large set of $variables you can reference in directives like log_format, proxy_set_header, return, map and if. They expose request metadata, proxy and upstream details, and TLS information. This reference groups the common ones by source module and explains each.

How it works

Variables are evaluated per request. Some are fixed names ($remote_addr, $status); others follow a dynamic pattern where part of the name is supplied by you:

log_format main '$remote_addr "$request" $status '
                '$body_bytes_sent "$http_user_agent" '
                'rt=$request_time urt=$upstream_response_time';

location /api/ {
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://backend;
}

The dynamic prefixes are $http_NAME (request headers), $sent_http_NAME (response headers), $arg_NAME (query arguments) and $cookie_NAME (cookies), where NAME is lowercased with hyphens replaced by underscores.

Module groups at a glance

ModuleTypical variables
ngx_http_core_module$uri, $request_uri, $host, $remote_addr, $status, $request_time
ngx_http_proxy_module$proxy_add_x_forwarded_for, $proxy_host
ngx_http_upstream_module$upstream_addr, $upstream_status, $upstream_response_time, $upstream_connect_time
ngx_http_ssl_module$ssl_protocol, $ssl_cipher, $ssl_client_s_dn, $ssl_server_name
ngx_http_geo_module / ngx_http_geoip_module$geoip_country_code, $geoip_city
ngx_http_realip_module$realip_remote_addr

Common real-world patterns

Structured access log for a reverse proxy

log_format json_combined escape=json
  '{"time":"$time_iso8601",'
  '"remote_addr":"$remote_addr",'
  '"method":"$request_method",'
  '"uri":"$uri",'
  '"status":$status,'
  '"bytes":$body_bytes_sent,'
  '"rt":$request_time,'
  '"urt":"$upstream_response_time",'
  '"ua":"$http_user_agent"}';

This logs every request as a JSON object, which most log-aggregation systems (Loki, Elasticsearch, Datadog) can ingest without a parser.

Passing real client IP through a load balancer

# upstream load balancer sets X-Real-IP; nginx trusts it and exposes it
real_ip_header X-Real-IP;
set_real_ip_from 10.0.0.0/8;

location / {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP       $remote_addr;
    proxy_pass http://backend;
}

After set_real_ip_from, $remote_addr reflects the original client IP rather than the load balancer’s IP.

Routing by TLS version or cipher

if ($ssl_protocol = "TLSv1") {
    return 403 "TLS 1.0 not accepted";
}

$ssl_protocol is only populated inside an ssl server block after the handshake completes.

map $cookie_session $no_cache {
    ""      0;
    default 1;
}

proxy_no_cache    $no_cache;
proxy_cache_bypass $no_cache;

$cookie_NAME gives the value of any named cookie without a separate add_header round trip.

Tips and notes

  • $request_uri keeps the query string and original form; $uri is normalised and rewrite-aware. After a rewrite they diverge — use $uri in proxy_pass and $request_uri for logging the client’s original request.
  • Use $proxy_add_x_forwarded_for (not $remote_addr) to correctly chain the IP through multiple nginx tiers.
  • Upstream timing variables ($upstream_response_time, $upstream_connect_time) are populated after the upstream finishes. They are empty — not zero — if the upstream was never contacted (for example, a cached response).
  • The $ssl_ family only has values on HTTPS server blocks with TLS fully negotiated. Referencing them in an HTTP block produces an empty string, not an error.
  • Variables inside if blocks have some caveats in nginx’s config model; prefer map for complex conditional logic.