An htaccess to Nginx rewrite converter translates a deliberately narrow subset of Apache .htaccess directives into review-ready Nginx lines and reports every unsupported rule with its original line number, rather than guessing at output that could silently change traffic. The point of the tool is to act as an inventory assistant during a server migration: you paste a focused document-root excerpt, the converter emits only the directives it can safely map, and every RewriteCond, unfamiliar flag, or ambiguous line is returned to you as a manual-review item instead of a confident rewrite. That restraint matters because Apache's per-directory configuration model and Nginx's centralized context model are not interchangeable, and a converter that silently writes plausible-looking but non-equivalent configuration is more dangerous than one that leaves explicit work.
People migrating from Apache to Nginx — or running Nginx in front of Apache — usually arrive at this tool with a stack of rewrite rules, redirect directives, and assorted Options, ErrorDocument, and header lines that worked on Apache. The natural assumption is that a single conversion will deliver a working nginx.conf. The reality is that even identical regular expressions can behave differently because the string being matched, escaping rules, query handling, and loop behavior differ between the two servers. A review-first converter acknowledges that gap and turns the migration into a documented engineering step instead of a bulk text replacement.

What the converter actually does
The htaccess to Nginx Converter runs entirely in your browser. Your pasted excerpt is not sent to any server, so sensitive rule sets can be reviewed locally. Its scope is deliberately small: it parses one bounded line at a time, ignores RewriteEngine On, preserves comments, and treats anything outside its supported subset as a warning rather than output.
Within that narrow scope, the converter handles three categories of directives:
- RewriteRule with a restricted flag set. The supported form is an Apache RewriteRule pattern, a substitution, and a bracketed flag list limited to L, R, R=301, and R=302. A permanent Apache redirect becomes the Nginx permanent flag, a temporary redirect becomes redirect, and an internal last rule becomes last.
- Three non-rewrite directives. Options -Indexes becomes autoindex off;, a local ErrorDocument 404 path becomes error_page 404 with the same path, and a quoted X-Robots-Tag Header set value becomes an add_header line.
- Documented scope assumptions. Patterns in a document-root .htaccess normally match a path after the directory prefix has been removed, so they commonly begin with a caret but no slash. Nginx rewrite patterns see a URI that begins with a slash. The converter inserts that leading slash for the supported root-context pattern.
Everything else is reported, not emitted. RewriteCond lines are never translated automatically, because their variables, captures, evaluation order, and deployment context can change meaning; suppressing the rule that follows the condition prevents an unconditional redirect from altering traffic. Unknown flags such as QSA, END, F, G, B, or NC stop conversion for that rule because their details cannot be erased safely. The Apache no-substitution target represented by a single dash is also withheld, because it often combines with flags that alter access or processing without changing the URI.
How to convert a focused .htaccess excerpt
- Paste a focused document-root excerpt. Open the htaccess to Nginx Converter, paste the specific block you want to migrate, and leave unrelated fragments for a separate pass. Keep the input small enough that every emitted line can be reviewed by hand.
- Review every emitted Nginx line. Walk down the output one line at a time and confirm that the flag mapping matches your intent: permanent redirects land on permanent, temporary on redirect, and internal last on last. Capture backreferences such as $1 should be preserved verbatim because Nginx uses the same $1 syntax.
- Resolve every line-numbered warning. Each warning points to the original Apache line number. Open the Apache mod_rewrite introduction and the Nginx rewrite module reference for that line, decide what the rule is actually doing, and migrate it by hand if the rule belongs in your Nginx configuration at all.
- Merge into the correct Nginx context. The output is a fragment, not a complete nginx.conf. Place each reviewed line in the appropriate server or location block according to your actual application architecture. Server-level redirects belong in a server { } block; path-specific rewrites belong inside a location { } block.
- Back up and validate. Save a copy of the active configuration, run nginx -t against the assembled file, and keep a recovery session open. Only test representative requests against staging or a reversible maintenance window — never against the live production site.
What gets mapped versus what gets warned
The boundary between output and warning is the most important thing to understand about this converter. The table below summarises the documented behaviour for the most common directives you will encounter.
| Apache directive | Converter behaviour | Nginx result |
|---|---|---|
| RewriteRule pattern target [L] | Emitted | rewrite ^pattern target last; with leading slash inserted |
| RewriteRule pattern target [R=301] | Emitted | rewrite ^pattern target permanent; |
| RewriteRule pattern target [R=302] | Emitted | rewrite ^pattern target redirect; |
| RewriteRule pattern target [QSA,END,F,G,B,NC] | Warning, no output | Manual migration required |
| RewriteRule pattern - [L] (dash target) | Warning, no output | Manual migration required |
| RewriteCond ... | Warning, rule suppressed | Manual migration required |
| Options -Indexes | Emitted | autoindex off; |
| ErrorDocument 404 /path.html | Emitted | error_page 404 /path.html; |
| Header set X-Robots-Tag "value" | Emitted | add_header X-Robots-Tag "value"; |
| Other status codes, external ErrorDocument, conditional headers, environment variables, directive containers | Warning, no output | Manual migration required |
The phrase manual migration required deserves emphasis. It does not mean the directive cannot be ported; it means the converter cannot do it safely in isolation. Authentication, authorization, hotlink protection, proxy logic, CMS front-controller rules, and complex conditions all sit in that category, and treating them as bulk text replacement is the most common cause of broken migrations.
Why manual review of warnings is the point
The warnings are not noise. They are the converter's main contribution, because every suppressed rule is a place where a guessed rewrite could change traffic, create a redirect loop, or expose a route. RewriteCond lines are the largest source of suppressed rules in practice: Apache conditions can inspect HTTPS state, host names, files, directories, query strings, headers, and captured groups, and the evaluation order matters. When a RewriteRule follows a condition, the converter suppresses the rule too rather than emitting an unconditional redirect.
The no-substitution dash target is the other classic trap. A rule like RewriteRule pattern - [F] often combines with flags that alter access or processing without changing the URI, and a literal dash is not a safe Nginx replacement. Emitting rewrite ^pattern - last; would be syntactically valid and semantically wrong. For a deeper reference on these edge cases, the htaccess to nginx cheat sheet on rules, limits, and warnings covers the patterns that surface most often in real migrations.
Assembling the fragment safely into nginx.conf
Once the converter has produced its fragment and every warning has been resolved, the work of placing lines in the right context begins. Server-level redirects — including the canonical R=301 cases — typically belong inside a server { } block. Path-specific rewrites belong inside a location { } block, and the official Nginx documentation for error_page should be consulted to confirm where error_page 404 is appropriate for your layout.
The fragment does not create an http, server, or location block, choose a listen port, set server_name, configure TLS, locate a document root, preserve PHP routing, forward a proxy, or define logs. Treat it as raw material: assemble the result in a version-controlled Nginx file, validate the entire assembled configuration with nginx -t, and stage representative requests — old paths, new paths, query strings, alternate hosts, HTTPS behaviour — before reloading. Permanent redirects deserve extra care because browsers and intermediaries may cache them, so start with temporary redirects in a controlled environment when practical, then switch to permanent only after the test set passes. Confirm the response Location header rather than relying on the browser address bar alone.
If the source contains authentication, authorization, hotlink protection, proxy logic, CMS front-controller rules, or complex conditions, treat the migration as engineering work rather than bulk text replacement. Read both the Apache and Nginx manuals for every nontrivial rule. A failed reload or redirect loop can make a public site unavailable, and the safest workflow is the one where every line in the new configuration was either emitted by a verified converter pass or written by hand against the official documentation.
Related reading: Robots.txt Generator: Command Line vs Online Compared.