1. Audit Apache behavior before writing Nginx configuration

Back up the Apache virtual host and every .htaccess file, including files in subdirectories. List the rules that actually affect requests: canonical-host redirects, HTTPS redirects, WordPress front-controller fallbacks, application-specific rewrites, access denials, headers, compression, and cache lifetimes. Note the current document root, PHP version, PHP extensions, upload limits, and any application dependency on Apache-only modules.

Create a URL test sheet covering the home page, a working inner page, a deleted page, a URL with query parameters, redirects, media files, a private path, and the login/admin flow. Record expected HTTP status, Location header, and response behavior. Nginx location selection and rewrite processing differ from Apache directory-level processing; a line-by-line syntax swap is rarely safe.

For a broader cutover sequence covering backups, DNS, verification, and rollback, use this guide to migrating your website to a VPS server alongside the configuration steps below.

2. Translate common .htaccess directives

A typical WordPress Apache rule routes requests that are not existing files or directories to index.php. On Nginx, use a front-controller fallback in the root location. Keep the query string: it matters for pagination, search, filters, REST requests, and plugins.

For WordPress, configure the main Nginx location to serve existing files and directories first. When a requested permalink is neither, forward the request internally to WordPress’s index.php while retaining the original query parameters. This is the role of the Nginx try_files directive.

The first two checks serve existing files and directories. If neither exists, Nginx internally routes the request to /index.php. Do not paste Apache RewriteCond or RewriteRule lines into nginx.conf; their syntax and processing model are different. WordPress multisite and plugins with custom rewrite requirements need their own review.

Redirect rules → return, or rewrite where necessary

Prefer return for a straightforward permanent redirect. The following example assumes TLS is terminated on this Nginx server and the HTTPS virtual host is configured separately:

For HTTP-to-HTTPS redirection, configure an Nginx server block that receives requests on port 80 for both the main domain and its www hostname. Return a permanent redirect to the preferred HTTPS hostname while retaining the original path and query string. Apply this only after confirming where TLS terminates.

For a single old path, a focused redirect is often clearer than a general regex:

For a renamed page, configure an exact-match location for the old URL and return a permanent redirect to the new address. This avoids a broad rewrite expression for a simple one-page change.

When a regex transformation is truly required, test captures, query-string handling, and flags. Nginx rewrite last restarts location selection; break stays in the current location. Bad rewrite loops can cause HTTP 500 errors. Never assume that Apache RewriteRule flags correspond directly to Nginx flags.

Directory access controls → deny and explicit locations

Convert Apache “Require all denied” policies into the appropriate Nginx location restrictions. A hidden-file protection rule is helpful, but it must not block the files that your deployment intentionally exposes, such as ACME challenge paths.

Use a narrowly defined Nginx location restriction to deny requests for hidden files and private paths. Allow legitimate certificate-validation requests under .well-known where required; protect backup archives, sensitive exports and credentials separately.

Use exact or narrowly scoped location blocks for backups, private exports, or application-specific files. Remember that location matching order matters: exact matches, selected prefix matches, and regular-expression matches do not behave like nested .htaccess files.

3. Plan the Nginx server block for a PHP WordPress site

This is a starting template, not a drop-in production configuration. Replace the example hostname, root, PHP-FPM socket and certificate/TLS settings with the values on your VPS. This sample assumes HTTPS is handled in another server block or by a trusted load balancer; it intentionally shows only the application-facing HTTP block for clarity.

A WordPress PHP site needs an Nginx server block with the correct hostname, public document root and index file. Requests for actual files should be served directly, while other public permalinks should fall back to the WordPress front controller. PHP requests must pass through a correctly configured FastCGI handler connected to the installed PHP-FPM service. Check that the resolved script path points to the intended file, and deny access to sensitive hidden files. The Nginx virtual host, PHP-FPM socket, TLS setup and document-root paths are specific to each VPS and should not be copied from a generic example.

The socket path is illustrative and varies by distribution and installed PHP version. Confirm that PHP-FPM is running, Nginx can access its socket, and the configured SCRIPT_FILENAME points to the intended PHP file. Inspect the package-provided FastCGI parameter includes to avoid accidentally overriding or duplicating parameters. More complex applications may need controlled PATH_INFO handling.

Keep database credentials and writable directories outside the public document root where your application permits it. For WordPress, review direct access to wp-config.php, backup archives, and upload locations rather than relying on one generic deny regex.

4. Replace Apache caching and compression settings

Apache ExpiresByType rules can be expressed with Nginx expires for suitable static assets. Apply long browser lifetimes only to assets with versioned or hashed filenames; otherwise users may retain stale CSS or JavaScript after a deployment.

Replace Apache ExpiresByType rules with Nginx cache expiration settings for appropriate static assets such as CSS, JavaScript, fonts and images. A seven-day browser lifetime may be reasonable for some assets, but longer lifetimes are safer when filenames change on deployment. Keep private and session-dependent responses out of public caches.

This illustrative rule gives listed files a seven-day browser lifetime. Avoid applying a blanket public cache policy to HTML, authenticated pages, carts, checkout responses, or private downloads. Note that Nginx add_header inheritance has subtleties: headers defined within a location can affect headers inherited from higher contexts. Check final response headers, not just configuration text.

For response compression, configure gzip only where the module is available, and choose suitable MIME types. Modern builds may already provide compression at a CDN or proxy, so check for duplicate work and test client support.

Enable Nginx gzip compression where appropriate and supported. Set a sensible minimum response size, vary cache responses by content encoding, and target compressible formats such as CSS, JavaScript, JSON and SVG. Avoid wasting CPU on files that are already compressed.

Avoid assuming compression or caching automatically makes a VPS faster. Measure transfer size, response time, cache hit behavior, CPU, and user-facing page performance before and after the switch.

5. Security headers and TLS considerations

Move any Apache Header directives intentionally. For example, security-related headers should be placed in the HTTPS configuration after confirming your application and proxy topology. HSTS is appropriate only after all required hosts and subdomains are ready for HTTPS; deploying it prematurely can make recovery difficult.

Configure suitable HTTP response headers in Nginx, such as X-Content-Type-Options to prevent MIME sniffing and Referrer-Policy to limit referrer information. Apply them to relevant successful and error responses, checking inheritance and any headers already added by a proxy or CDN.

Do not copy a generic Content-Security-Policy without auditing scripts, styles, embeds, and third-party integrations. Similarly, confirm whether SSL termination is at Nginx, a reverse proxy, or a CDN before forcing redirects; otherwise redirect loops can occur.

6. Validate before the DNS or load-balancer cutover

Run the configuration test first, then reload only after it succeeds:

Before applying changes, run Nginx’s built-in configuration validation and review any reported errors. Reload Nginx only after the syntax and referenced files pass validation; confirm afterward that the service remains healthy.

Validate site behavior against the new VPS before changing DNS. For an HTTPS site, curl --resolve lets you address the VPS while preserving the production hostname for TLS/SNI. Replace the sample IP and domain:

Test the new VPS using requests that connect directly to its IP address while retaining the production hostname for HTTPS certificate selection and virtual-host routing. Check a normal permalink and a URL with query parameters before changing public DNS.

Check successful inner-page URLs, deliberate 404 responses, canonical redirects, forms, uploads, admin sessions, API endpoints, cache headers, and real application logs. Use GET requests in addition to HEAD checks where behavior differs. Watch the Nginx error log and PHP-FPM logs for upstream errors, file permission failures, and incorrect script paths.

If a permalink returns 404, inspect the active server block, selected location, document root, and try_files fallback. If PHP is downloaded or returned as plaintext, stop the rollout immediately: the PHP location/FastCGI handling is unsafe or absent. A 502 usually points to upstream availability or socket/port permissions, whereas a 500 needs the specific application or Nginx log error for diagnosis.

7. Switch traffic with a reversible plan

Keep the Apache origin available during an agreed rollback period. Preserve database consistency if the site accepts writes, and avoid running two writable application origins unintentionally. Record the old and new server configurations, DNS or proxy switch times, and acceptance results. If checks fail, revert the routing change only after confirming where the latest writes occurred; web-server rollback alone does not reconcile orders, uploads, sessions, or background jobs.

Teams handling a full production handover can pair this checklist with server management, migration, monitoring, and backup guidance for the operational tasks outside individual rewrite directives.

Apache-to-Nginx migration: quick reference

Apache behaviorNginx approach
Front-controller fallback / mod_rewritetry_files $uri $uri/ /index.php?$args;
Simple permanent redirectreturn 301 target;
Conditional regex URL rewriterewrite with carefully tested flags
Require all denieddeny all; in the appropriate location
ExpiresByTypeexpires plus reviewed Cache-Control
Header setadd_header with inheritance review
PHP handler via Apache module or proxyPHP-FPM through fastcgi_pass and fastcgi_param