Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

NGINX makes two separate choices for every HTTP request: it first selects a server block from the listening address, port, and host name, then selects one location block inside that server using the normalized URI. A regex location can override a longer ordinary prefix, while an exact location or a longest prefix marked ^~ can stop regex evaluation.

Keeping those stages separate explains most “wrong virtual host” and “wrong location” problems. Verify the selected listener and server_name before changing any location rule.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

NGINX makes two decisions, in a fixed order

The request-processing path is deterministic:

  1. Server selection: NGINX uses the local listen address and port, then compares the request’s Host value with server_name directives.
  2. Location selection: Inside the chosen server, NGINX normalizes the request URI and applies the location-matching algorithm.

A perfectly configured location cannot handle a request that was assigned to another virtual server. Conversely, once the correct server is selected, changing server_name will not alter which location wins for a given URI.

How NGINX selects a server block

NGINX groups virtual servers by their listen address and port. For a request arriving on a particular socket, only the servers attached to that listener are candidates. It then evaluates their server_name values in priority categories.

Priority category Example How a match is chosen
Exact name example.com An exact host-name match has the highest name priority.
Wildcard beginning with an asterisk *.example.com The longest matching wildcard is selected.
Wildcard ending with an asterisk mail.* The longest matching wildcard is selected after beginning-wildcard names.
Regular-expression name ~^wwwd+.example.com$ The first matching regular expression in configuration order wins.
No name match None NGINX uses the default server for that listen port.

The search terminates when it finds a match in the first applicable category. A regular-expression server_name is therefore considered only after exact and wildcard categories fail, and reordering regex names can change the result.

Listen address and port come before the host name

Suppose one server listens on 0.0.0.0:80 and another on a different address or port. A request sent to the second socket cannot be handled by the first server, even if its server_name is a better textual match. Check the actual destination address, port, and protocol before diagnosing a host-name or location problem.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Default servers handle unmatched hosts

If the Host header does not match any name attached to the selected listener, NGINX routes the request to that listener’s default server. The default is normally the first server declared for the address and port unless a server is explicitly marked with default_server. A request without a Host header is represented by an empty server name and can be handled explicitly with server_name "".

A practical wrong-virtual-host checklist

  1. Confirm the client is reaching the intended IP address and port, including any IPv4 versus IPv6 distinction.
  2. Inspect the active configuration, not only an edited file, and identify every server using that listener.
  3. Check the exact spelling and case of the supplied host value, including whether a port is present in the HTTP header.
  4. Look for an exact or wildcard name that takes precedence over a regex name, and verify the order of regex names.
  5. Test an unmatched or missing host deliberately to see which default server responds.

The command nginx -T is useful for printing the complete loaded configuration. A controlled request such as curl -i -H 'Host: example.com' http://127.0.0.1/path lets you test host selection independently of DNS; use the actual listener address and port in a production check.

NGINX normalizes the URI before matching locations

Location comparison does not use the browser’s raw URL spelling. Before it compares locations, NGINX:

  • Decodes percent-encoded %XX sequences.
  • Resolves . and .. path components.
  • May compress adjacent slashes.

Query-string arguments are separate from the URI used for location matching. For example, /products?id=7 is matched as /products; the ?id=7 portion does not make a location such as location /products?id=7 match.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When debugging, record the normalized path NGINX sees. An encoded slash, a dot segment, or repeated slashes can make two visually different URLs reach the same location, while a query parameter cannot select a different location by itself.

How NGINX selects a location block

After the server is chosen and the URI normalized, NGINX applies these steps:

  1. Exact locations first. A location written as location = /path matches only that URI. If it matches, NGINX stops immediately.
  2. Prefix locations are scanned. NGINX compares ordinary prefixes such as /, /images/, and /images/icons/, remembering the longest prefix that matches.
  3. The ^~ decision is applied. If the remembered longest prefix is declared as location ^~ /images/, NGINX uses it immediately and does not test regex locations.
  4. Regular-expression locations are tested. Unless ^~ protected the longest prefix, regex locations are evaluated in the order they appear. The first matching regex wins.
  5. The remembered prefix is the fallback. If no regex matches, NGINX uses the longest ordinary prefix found in step two.
Form Matching scope Regex interaction Case behavior
location = /path One exact URI Terminates the search immediately Exact string comparison
location /path/ URI prefix and descendants A regex may override it Prefix comparison
location ^~ /path/ URI prefix and descendants Prevents regex evaluation when it is the longest prefix Prefix comparison
location ~ pattern Regular expression First matching regex in file order wins Case-sensitive
location ~* pattern Regular expression First matching regex in file order wins Case-insensitive

Why a longer prefix can lose

NGINX remembers the longest prefix, but that prefix is not automatically final. A plain prefix remains eligible for replacement by the first matching regex. The ^~ modifier is the explicit opt-out from that regex check. This is why a longer path such as /images/ can lose to a regex that matches a file extension, while ^~ /images/ cannot.

Regex order is part of the configuration

Regex locations are not ranked by specificity or length. NGINX tests them in file order and stops at the first match. Two overlapping expressions can therefore produce different results after a simple reordering, even when their text is unchanged. Keep mutually exclusive expressions where possible, or place the intended winner first and document the dependency.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Worked example

server {
listen 80;
server_name example.com;

location = / {
return 200 "home";
}

location ^~ /assets/ {
root /srv/www;
}

location / {
proxy_pass http://app;
}

location ~* .php$ {
fastcgi_pass unix:/run/php/php-fpm.sock;
}
}
Request URI Candidate processing Winning location
/ The exact location matches and ends the search. location = /
/assets/logo.php /assets/ is the longest prefix and has ^~, so the PHP regex is skipped. location ^~ /assets/
/shop/item.php The remembered prefix is /; the case-insensitive PHP regex then matches. location ~* .php$
/shop/item.css No regex matches, so the remembered root prefix is used. location /

The example demonstrates all three practical outcomes: exact termination, a protected prefix, and a regex overriding an ordinary prefix.

Choosing the right location form

Use an exact location for a single high-value URI

The = modifier is appropriate for one known path such as a health endpoint, a special redirect, or the site root. It avoids all later location checks, making the intent and precedence unambiguous. It does not match child paths: location = / matches /, not /about.

Use a plain prefix for a path family

A prefix is easiest to read and maintain when every descendant should share behavior, such as a proxied application under /api/. Remember that a regex can intercept it unless the prefix is protected with ^~.

Use ^~ when the prefix must own its descendants

Choose ^~ for a path tree that should never be diverted by extension or other regex rules, such as static assets. It still participates in longest-prefix selection; it only suppresses regex testing after that selection.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use regex locations for patterns, not ordinary directories

Regex is useful when the match depends on a filename pattern or another expression. The ~ modifier is case-sensitive; ~* ignores case. Because regexes are order-dependent and harder to audit, keep expressions narrow and avoid using them where a straightforward prefix expresses the same policy.

A repeatable method for testing a routing change

  1. Write down the complete request target. Include scheme, destination address, port, host, path, encoding, and query string.
  2. Resolve the server first. Identify the listener, compare the host against exact and wildcard names, then inspect regex names and the default-server fallback.
  3. Normalize the path on paper. Decode percent escapes, resolve dot segments, account for slash compression, and remove the query string from the location comparison.
  4. List all candidate locations. Mark the exact match, every matching prefix, the longest prefix, and every regex that could match.
  5. Apply modifiers and order. Stop for an exact match; otherwise honor ^~, then select the first matching regex, or fall back to the remembered prefix.
  6. Send controlled requests. Use a fixed destination with an explicit Host header, and test encoded paths, case variants, query strings, and extension changes separately.
  7. Reload safely. Validate the configuration before reloading and confirm the response after the reload, because an edited file is irrelevant until the running NGINX process has loaded it.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Common failure patterns and fixes

A PHP or image regex catches a path you expected to stay under a prefix

Check whether the prefix is plain. If it is, the regex is allowed to override it. Make the prefix ^~ when that path family must win, or narrow the regex so it excludes the protected path.

The wrong case variant matches

Inspect whether the expression uses ~ or ~*. A case-insensitive expression can match names that a case-sensitive expression would reject, and its position relative to other regex locations still determines the winner.

A query parameter appears to change routing

Compare the path without the query string. Location selection uses the URI path, so differences such as ?format=json require application logic or separate processing after the location has already been chosen.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

An encoded or dotted path reaches an unexpected block

Calculate the normalized URI rather than comparing raw browser text. Percent decoding, dot-segment resolution, and slash compression can turn seemingly different inputs into the same location key.

A configuration reorder changes behavior

Review regex locations and regex server_name entries. Both are order-sensitive in their respective selection stages; moving one can change which first match terminates the search.

Performance and maintainability trade-offs

Exact locations and protected ^~ prefixes can terminate processing early, avoiding regex evaluation. Prefix rules are generally easier to read than complex expressions, while regex provides flexibility for true pattern matching at the cost of order sensitivity and more difficult review. Choose the least powerful form that expresses the required scope, then reserve regex for cases a literal path or prefix cannot represent.

“To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations).” — NGINX core-module documentation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

“The search is performed in the following order of priority and terminates on the first matching variant:” — NGINX server-names documentation.

Bottom line

Always solve NGINX routing in two passes: establish the listener and selected virtual server, then apply URI normalization and the location algorithm. Exact matches terminate immediately; the longest prefix is only provisional unless ^~ protects it; otherwise the first matching regex in configuration order wins. That model predicts which block will run and gives you a precise checklist when a request appears to go somewhere else.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.