Most htaccess to nginx migrations fail not because any single directive is untranslatable but because of accumulated small assumptions — about flag equivalence, condition handling, file scope, URI matching and reload safety — that nobody audits line by line. The shift from Apache's per-directory configuration model to Nginx's centralized server and location blocks changes how every rule is read, where it can live, and which surrounding context is required for it to make sense. Generic online converters compound the problem by emitting plausible-looking lines for rules whose semantics they cannot verify, including RewriteCond dependencies, unknown flags, Alias mappings and the no-substitution dash target. A safer starting point is a deliberately narrow converter that handles an auditable subset, lists every ignored line with its original number, and leaves all conditional, unfamiliar or scope-ambiguous work for manual review against the official Apache and Nginx documentation.

htaccess to nginx tips and common mistakes
htaccess to nginx: tips and common mistakes to avoid

Where htaccess to nginx conversions actually break

Apache reads a .htaccess file whenever a request descends into its directory, parses it freshly, and applies it within a per-request configuration space bounded by AllowOverride. Nginx does not understand that model at all. Configuration is centralized: Nginx parses include files once at startup or reload, builds its server and location tree, and resolves a request against that tree before any rewrite processing runs. The very first mistake in any migration is treating the .htaccess file as a drop-in folder of rules when it is actually one slice of Apache's distributed, request-time behavior.

Two practical consequences follow. 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 leading slash. Nginx rewrite patterns see a URI that starts with a slash. Any converter has to bridge that gap explicitly and only for a root-context excerpt — nested .htaccess files, Alias mappings and location-specific Nginx blocks follow different rules. A direct search-and-replace that drops the leading slash assumption will silently rewrite the wrong paths. For the canonical explanation of how Apache composes these patterns, see the Apache mod_rewrite introduction.

The second consequence is that rewrite processing order differs. Apache runs its rewrite engine after location selection, allowing conditions to inspect files, directories, query strings and headers. Nginx runs rewrites earlier in the request lifecycle, before content handlers, and a small set of variables such as $uri and $request_uri have specific meanings that overlap but do not match Apache's %{REQUEST_URI} in every situation. Even identical regular expressions can behave differently because the string being matched, escaping, query handling and loop behavior differ between the two engines.

RewriteRule flag mistakes that silently change behavior

Flags are the second most common source of migration bugs because they look identical in both engines but resolve to different things. Apache's RewriteRule supports a long list of bracketed flags, including QSA (query string append), END (stop the rewrite engine), F (forbidden), G (gone), B (backreference escape), NC (no case) and several redirection codes. Nginx rewrite supports a much smaller, semantically distinct set: last, break, redirect, permanent, and a few internal markers. A safe converter cannot map QSA, END, F, G, B or NC silently because their behavior is engine-specific, and translating them as if they were equivalent would change what the rule actually does.

The htaccess to Nginx Converter limits the automatic flag set to L, R, R=301 and R=302 by design. A permanent Apache redirect becomes the Nginx permanent flag, a temporary redirect becomes redirect, and an internal last rule becomes last. When a rule uses any flag outside that set, the tool stops conversion for that rule and reports the original line number so the engineer can read both manuals and write the Nginx equivalent by hand.

Two related mistakes deserve their own warnings. First, the Apache no-substitution target represented by a single dash is also withheld. It often combines with flags that alter access or processing without changing the URI, so a literal dash is not a safe Nginx replacement — emitting one would break the rule or, worse, hand it to a location block that has no idea what to do with it. Second, the input may contain patterns that already include their leading slash; the root-context slash insertion only applies to the documented pattern form, and other variants have to be moved by hand into the right Nginx context.

Why RewriteCond lines never translate automatically

The single most common migration mistake is to convert a RewriteRule that follows a RewriteCond without also converting the condition. Apache conditions can inspect HTTPS state, host names, files, directories, query strings, headers and captured groups, and their evaluation order within the engine matters. A rule that looks innocent on its own — RewriteRule ^old/(.*)$ /new/$1 [L,R=301] — can mean entirely different things depending on what comes before it. Forcing it into Nginx as an unconditional redirect could change traffic, create a redirect loop, expose a route that the Apache version never exposed, or skip a case the original handled.

For that reason the htaccess to Nginx Converter reports every RewriteCond line with its original number rather than translating it, and when a RewriteRule follows a condition the tool suppresses the rule as well. The output carries no guessed semantics; the engineer is expected to read both documents, recreate the conditional logic in Nginx using if, map or a server or location branch where appropriate, and validate the result before reload. A converter that silently writes plausible-looking but non-equivalent configuration is more dangerous than one that leaves explicit work. For a fuller catalog of what the converter deliberately leaves alone, see the guide on the limits of automated htaccess to nginx conversion.

Authentication, authorization, hotlink protection, proxy logic, CMS front-controller rules and complex conditions are the clearest signals that a migration is engineering work, not bulk text replacement. Treat any rule whose Apache behavior depends on a runtime variable as something that requires its own Nginx block, its own test plan and, where possible, a temporary rather than permanent redirect during the validation window so an incorrect behavior can still be reversed without clearing browser caches.

Non-rewrite directives the converter does map

Three non-rewrite mappings sit inside the conversion contract because their Apache and Nginx counterparts are documented and stable. The table below summarizes them, what each side does, and the line the converter emits.

Apache directiveApache effectConverter output
Options -IndexesDisables directory listing for the current directory treeautoindex off;
ErrorDocument 404 /custom-404.htmlServes a local 404 document for missing resourceserror_page 404 /custom-404.html;
Header set X-Robots-Tag "noindex, nofollow"Adds an X-Robots-Tag header to responsesadd_header X-Robots-Tag "noindex, nofollow";

Outside those three, the converter does not invent Nginx equivalents. Other status codes, external error documents, conditional headers, environment variables and directive containers such as <If> or <Directory> require manual migration, and any directive whose Nginx equivalent depends on installed modules (for instance, the headers module is a dynamic module in many distributions) needs an extra check during nginx -t. The mapping for local 404 routes through the Nginx core error_page directive documentation; the local path is preserved as written.

Reload mistakes that turn an htaccess to nginx migration into an outage

Even a perfectly reviewed output can fail at reload time if the surrounding discipline is missing. The migration step that most often produces a broken public site is skipping nginx -t, skipping a backup of the active configuration, or deploying in a way that prevents instant rollback. The converter does not execute nginx -t, does not inspect installed modules, does not discover include order and does not access the server. A line can be syntactically valid yet wrong for its context, and the assembled configuration is what really needs validation.

The disciplined sequence is: back up the active configuration, keep an open recovery session, validate the entire assembled file with nginx -t, and stage representative requests against a running instance before reload. A failed reload or a redirect loop can make a public site unavailable, and the cost is rarely the test itself but rather the unarchived state of the live config when a change goes wrong.

Permanent redirects deserve extra care because browsers and intermediaries may cache the 301 response aggressively. Start with temporary redirects in a controlled environment when practical, then switch to permanent only after testing old paths, new paths, query strings, alternate hosts and HTTPS behavior. Confirm the response Location header rather than relying on the browser address bar alone — a cached redirect in a shared network device can disagree with what the browser shows, and only the raw response tells the truth.

How to convert a focused .htaccess excerpt with the htaccess to nginx tool

  1. Paste a small, document-root .htaccess excerpt into the htaccess to Nginx Converter, no larger than the directory and rule set you can review in one sitting. The parser works one bounded line at a time, ignores RewriteEngine On and preserves comments while it scans.
  2. Review every emitted line and read each line-numbered warning against the Apache and Nginx documentation. Unknown flags such as QSA, END, F, G, B or NC, RewriteCond conditions, no-substitution dash targets and any directive outside the supported mapping will appear as warnings rather than guessed output.
  3. Merge the resulting fragment into the correct Nginx context — a server block for global redirects and header rules, a location block for path-scoped rewrite patterns — based on the official Nginx directive documentation and the actual application architecture. The output is not a complete nginx.conf; it does not define TLS, roots, upstreams or logs.
  4. Back up the active configuration, run nginx -t to validate the assembled file, and test representative requests against a staged instance before reloading production. Start with temporary redirects when practical so any incorrect behavior remains reversible.
  5. 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 — use the converter as an inventory assistant, not a one-click migration.

For a deeper look, see Common Mistakes When Using an HTML Page Weight Analyzer.