Nginx Rewrite Rule Generator
Build a correct nginx location block for a redirect or an internal rewrite — and see why return beats rewrite for a plain redirect.
nginx config
How to use this tool
- Choose literal path for a single exact URL, or regex when you need to capture and reuse part of the URL, like a numeric ID.
- Enter the source and target, then pick a flag: 301/302 for a real redirect the browser follows, or last/break for an internal rewrite the client never sees.
- For 301/302, the tool always emits
returnrather thanrewrite ... permanent— that is the current nginx best practice and the note underneath explains why for your specific case. - For last/break,
returnis not an option at all, since neither flag sends a response to the client — the tool falls back torewriteautomatically. - Paste the block inside your
server {}context. If you already have alocation /block, this one should usually come before it, since nginx picks the most specific matching location.
nginx gives you two different tools that can both look like a redirect at first glance, and picking the wrong one is a common source of confusing bugs. return sends a response immediately and stops processing that request in this block entirely — simple, fast, predictable. rewrite runs a regex against the URI and, depending on its flag, either changes the URI and keeps processing the current request internally (last, break) or turns the result into an HTTP redirect (redirect, permanent). The overlap is exactly that last pair, and it is where rewrite gets reached for out of habit when return would do the same job more directly.
nginx’s own documentation is explicit that return is preferred to rewrite for straightforward redirects. The practical reason is evaluation cost and clarity: rewrite runs a regex engine against every request that reaches that block, and when used inside an if block — a pattern that shows up constantly in copied-and-pasted configs — it interacts with nginx’s request-processing phases in ways that produce genuinely surprising results, well known enough in the nginx community to have its own name: “if is evil”. return sidesteps essentially all of that, including inside a regex location ~ block, where it can still reference capture groups exactly like rewrite can.
last and break exist for the case return genuinely cannot cover: changing what URI nginx serves without telling the client anything happened. last stops the current round of rewrite rules and restarts nginx’s location matching against the new URI, which lets a rewritten URI land in a completely different location block — useful, but also a well-known way to build an infinite loop if two locations rewrite into each other. break stops rewrite processing the same way but does not restart location matching, so the rest of the current block still runs against the new URI without ever leaving it.
The choice between location = (exact match) and location ~ (regex match) matters independently of the redirect-versus-rewrite decision. An exact-match location is resolved fastest, since nginx does not need to run any pattern matching at all, and it is the right tool whenever the source is a single fixed path with no variable portion. Reach for a regex location only when you actually need to capture part of the URL — a numeric ID, a locale prefix, a filename — and reuse it in the target.
One detail that trips people up migrating old Apache-style rewrite rules: nginx’s rewrite replacement string is evaluated as a URI, and if it does not start with http:// or https://, nginx treats it as relative to the current server and, critically, appends nothing automatically — you almost always want $request_uri or a specific replacement, not an assumption that query strings or the rest of the path survive unless you explicitly carry them over.
Frequently asked questions
Why does nginx recommend return over rewrite for redirects?
Speed and predictability. return sends the response immediately without running a regex engine, and it avoids the well-documented pitfalls of rewrite combined with if blocks. It can still use regex capture groups when placed inside a location ~ block, so there is rarely a reason to reach for rewrite just to redirect.
When do I actually need rewrite instead of return?
When you want to change the URI internally without sending any response to the client at all — the last and break flags. return always sends an HTTP response, so it cannot express an internal-only rewrite.
What is the difference between the last and break flags?
last stops the current rewrite rules and restarts nginx’s location matching against the new URI, potentially landing in a different location block. break stops rewrite processing too, but keeps executing the rest of the current block against the new URI without re-matching.
Why use location = instead of a regex location for a single path?
An exact-match location = is resolved without running any pattern matching, so it is the fastest match nginx can do and the clearest to read. Reserve regex locations for when you actually need to capture part of the URL.
My rewrite rule causes a redirect loop — why?
Almost always two last rewrites (or a rewrite and a location block) that send the URI back into each other’s matching path. Trace the URI through each location by hand, or switch the inner rewrite to break so it stops re-triggering location matching.