Nginx redirects: return, rewrite and the default 302
An nginx redirect is set in the server's configuration with one of two directives, return or rewrite. Both send a temporary 302 unless you name a permanent code: nginx documents a bare return URL as "a URL for temporary redirect with the code 302". Among the ways to redirect, it is the server rule for nginx sites.
Where nginx redirects live
Nginx reads redirects from its own configuration files, inside a server block or a location block within it. Both directives belong to the ngx_http_rewrite_module, and its documentation lists their context as server, location and if.
There is no per-directory file. Nginx does not read .htaccess, so rules written for Apache do nothing here and have to be translated; the .htaccess redirect page covers the Apache side. On managed hosting the configuration may be edited for you, through a control panel or a support request, rather than by hand.
The return directive
return is the direct way to answer a request with a redirect. The nginx documentation, checked on , gives its syntax in three forms:
return code [text];
return code URL;
return URL;With a code and an address, it sends exactly that code: the documentation says it is possible to specify "a redirect URL (for codes 301, 302, 303, 307, and 308)". So return 301 followed by the new address is a permanent redirect, and return 308 is its method-preserving equivalent.
The third form is the trap. With only an address, nginx treats it as "a URL for temporary redirect with the code 302". A rule written as the shortest possible line therefore tells search the move is temporary.
The rewrite directive
rewrite matches the requested address against a regular expression and changes it. It becomes a redirect in two cases, both from the module's documentation:
- When the replacement is a full address: "If a replacement string starts with "http://", "https://", or "$scheme", the processing stops and the redirect is returned to a client."
- When a redirect flag is given: "redirect returns a temporary redirect with the 302 code" and "permanent returns a permanent redirect with the 301 code."
A rewrite to a full address with no flag is a redirect, and a temporary one. For a permanent move the rule needs the permanent flag. The syntax line, as documented:
rewrite regex replacement [flag];Note the order: the pattern comes first and the new address second. Examples elsewhere sometimes reverse them, which produces a rule that never matches.
return or rewrite
Use return when one address, or every address in a location, goes to one place. It is short, it is read without a regular expression, and the code is written right next to the destination.
Use rewrite when the new address is built from parts of the old one, such as a captured product name moved into a new path. The NGINX blog post on creating rewrite rules, which Google's redirect documentation points to, works through both directives and says that return "is the simpler of the two general‑purpose directives and for that reason we recommend using it instead of rewrite when possible."
A move of every address to HTTPS is usually a return in its own server block for port 80; HTTP to HTTPS redirects covers the whole switch.
Whichever you use, the rule about codes is the same: name it. The 301 redirect page explains when a permanent move is the right answer, and the 302 redirect page when a temporary one is.
Order and reloading
Rewrite rules run "sequentially in order of their appearance in the configuration file," so a broad pattern above a narrow one can catch requests the narrow rule was meant for. Put specific rules first, and keep redirects for one site together rather than scattered across included files, so the order is visible in one place.
A change takes effect only when nginx loads it. Its beginner's guide puts it directly: "Changes made in the configuration file will not be applied until the command to reload configuration is sent to nginx or it is restarted." On reload, nginx checks the new file's syntax before applying it, so a rule that looks saved may not be live; check the response after every reload.
Moving rules over from Apache
A site that moves from Apache to nginx brings its redirects as a list to translate, not as a file to copy. Each Apache Redirect line becomes a return in a matching location; each RewriteRule with a redirect flag becomes a rewrite with the same pattern, or a return if the pattern turns out to be fixed.
Carry the status across explicitly. Apache's Redirect and nginx's bare return URL share the same default, a temporary 302, so a rule that was temporary by accident on Apache stays temporary by accident on nginx unless someone writes the code. Translation is the moment to fix that.
Translate from the live behaviour rather than from the old file alone: request each old address on the Apache server before the switch, record the status and target it returned, and check that the nginx rule returns the same pair, or the corrected one.
Checking the rule
Check the response, not the file. Request the old address and read the status line and the Location header: a moved page should answer with 301 or 308 and the new address, in one hop. A 302 where you meant a permanent move usually means a bare return URL or a rewrite without the permanent flag. How a trace reads each hop and its status is covered under redirect tracing.
FAQ
How do I make an nginx redirect permanent?
Name the code. With return, write return 301 or return 308 followed by the new address. With rewrite, add the permanent flag at the end of the rule. Without a code, a bare return URL and a rewrite to a full address both send a temporary 302.
Why is my nginx redirect a 302?
Because that is nginx's default for the shortest forms of both directives. Its documentation describes return with only an address as a temporary redirect with the code 302, and a rewrite to a full address without a flag also returns a temporary redirect. Add the code or the flag, reload the configuration, and check the response.
Should I use return or rewrite?
Use return for a fixed destination: it is simpler, it needs no regular expression, and the code sits beside the address. Use rewrite when the new address is built from parts of the old one. In both, state the code, since each defaults to a temporary redirect when it is left out.
Does nginx read .htaccess files?
No. Nginx takes its configuration only from its own files, so rules in an .htaccess file are ignored without any error. A site moving from Apache to nginx needs every redirect from .htaccess rewritten as an nginx rule, with its code stated, and checked against the live response.