Tengine location matching priority explained
2026-09-29
AdSense Slot
“My location block looks right but the request goes somewhere else.” Every Tengine user hits this eventually. The culprit is almost always location matching priority — Tengine does not use the first matching block, and it does not use the longest one for everything. Here is the actual rule, in the order Tengine evaluates it.
The matching algorithm, simplified
- First, Tengine finds the longest matching prefix location (plain, non-regex).
- If that prefix location uses the
^~modifier, it wins immediately — regex is never checked. - Otherwise, Tengine then checks all regex locations (
~and~*) in config order; the first matching regex wins. - If no regex matches, the longest prefix location from step 1 wins.
- An exact match with
=beats everything for that exact URI.
Example that shows the rule
location = /exact { return 200 "exact\n"; } # exact URI only
location ^~ /api/ { proxy_pass http://backend; } # prefix, blocks regex
location ~* \.(png|jpg)$ { return 200 "img\n"; } # regex, checked in order
location / { return 200 "root\n"; } # longest-prefix fallback
/exact→ exact match wins/api/users→^~ /api/wins, regex never runs/logo.png→ regex wins (prefix locations do not beat regex)/about→ falls back tolocation /
The mistakes I keep seeing
- People expect the longest prefix to always win — true among prefixes, but a regex beats every plain prefix.
- Regex order matters: the first regex in the config wins, not the best one. Keep broad regexes out of the way.
- Putting a regex in front of
location /that accidentally matches everything (like~* .*) silently hijacks all traffic.
Summary
Longest prefix first, then first regex in order, with ^~ and = as shortcuts. Once this clicks, most “rewrite not working” mysteries disappear — which is exactly the topic of my rewrite troubleshooting guide.
AdSense Slot