Apache vs nginx: How They Differ and How to Translate Config

Both are mature open source web servers. Apache loads modules into a choice of process models (prefork, worker or event) and lets each directory override settings with .htaccess files. nginx runs one master process and a few event-driven workers, reads only its central config, and is commonly placed in front of application servers as a reverse proxy.

Apache and nginx side by side
TopicApache httpd 2.4nginx
Connection handlingPick an MPM: prefork, worker or event (event is the usual default on modern Unix)One master process plus worker processes using an event-based model
Per-directory config.htaccess files, if AllowOverride permits (default None)None: everything lives in the main config files
Rewritesmod_rewrite: RewriteCond and RewriteRulereturn, rewrite, try_files and location blocks
PHP via FastCGImod_proxy_fcgi to a PHP-FPM poolfastcgi_pass to a PHP-FPM pool
Reverse proxymod_proxy: ProxyPass and ProxyPassReverseproxy_pass inside a location
Load balancingmod_proxy_balancer: byrequests, bytraffic, bybusyness, heartbeatupstream: round robin, least_conn, ip_hash, hash, random
Test and reloadapachectl configtest, then apachectl gracefulnginx -t, then nginx -s reload

Updated

Choosing between them is mostly about where configuration lives and who is allowed to change it. This page skips benchmark claims, which depend entirely on the workload and tuning, and focuses on the differences you meet while running a site: how each server handles connections, why .htaccess exists, and how the rewrite rules you already have translate. Use the translator to see the nginx version of a familiar Apache rule.

Apache to nginx config translator

Pick a common job to see the Apache rule and the nginx equivalent side by side, filled in with your domain.

Force HTTPS

Apache tests the HTTPS flag; nginx uses a separate port 80 server that only redirects.

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

Send the bare domain to www

The nginx docs recommend a dedicated server block with return instead of an if on the host.

RewriteEngine On
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]
server {
    listen 443 ssl;
    server_name example.com;
    return 301 https://www.example.com$request_uri;
}

Single-page app fallback

Serve real files when they exist and index.html for every other path.

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.html [L]
location / {
    try_files $uri $uri/ /index.html;
}

Redirect one old page

mod_alias Redirect needs no rewrite engine; nginx matches the exact path with location =.

Redirect permanent "/old-page" "https://example.com/new-page"
location = /old-page {
    return 301 https://example.com/new-page;
}

Custom 404 page

Both point the error at a page on the same site.

ErrorDocument 404 /404.html
error_page 404 /404.html;

Proxy /api to an app server

Apache needs mod_proxy and mod_proxy_http loaded, with matching trailing slashes on both arguments; nginx proxying is built in.

ProxyPass "/api/" "http://127.0.0.1:3000/"
ProxyPassReverse "/api/" "http://127.0.0.1:3000/"
location /api/ {
    proxy_pass http://127.0.0.1:3000/;
    proxy_set_header Host $host;
}

Block hidden files such as .git

Keeps files whose names start with a dot from being served.

<FilesMatch "^\.">
    Require all denied
</FilesMatch>
location ~ /\. {
    deny all;
}

Add a security header

With always, both servers add the header to error responses as well, not only to successful ones.

Header always set X-Content-Type-Options "nosniff"
add_header X-Content-Type-Options "nosniff" always;

The same site in both servers

Apache virtual host

Static files from one folder plus an SPA fallback, configured in the vhost so no .htaccess is needed.

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/site/dist
    <Directory /var/www/site/dist>
        AllowOverride None
        Require all granted
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^ index.html [L]
    </Directory>
    ErrorDocument 404 /404.html
</VirtualHost>

nginx server block

The same behaviour: root folder, try_files fallback and a custom error page.

server {
    listen 80;
    server_name example.com;
    root /var/www/site/dist;

    location / {
        try_files $uri $uri/ /index.html;
    }

    error_page 404 /404.html;
}

Process models in plain terms

Apache delegates connection handling to a Multi-Processing Module. prefork uses one process per connection and needs no threads. worker runs several processes with many threads each. event builds on worker and uses thread-safe polling so idle keep-alive connections do not tie up a thread. On current Linux and BSD systems event is picked by default.

nginx has one master process that reads the configuration and manages workers, and a small number of worker processes that each handle many connections through an event loop.

Why .htaccess matters

.htaccess lets someone without root access change rules for one directory, which is why shared hosts rely on it. The price is that every request makes Apache check each parent directory for the file, even when none exists. With AllowOverride None, which is the default, those files are ignored entirely.

How it works

  1. Pick a job in the translator, such as forcing HTTPS or sending every unknown path to index.html.
  2. Type your own domain so both versions are ready to paste.
  3. Put the Apache version in the virtual host or .htaccess, or the nginx version inside the matching server block.
  4. Test before reloading: apachectl configtest for Apache, nginx -t for nginx.

Tips

Frequently asked questions

Is nginx faster than Apache?

It depends on the job and the tuning, so be wary of any single number. nginx's event-driven workers are designed to hold many idle connections cheaply. Apache's event MPM narrowed that gap by also using thread-safe polling. Measure your own workload before switching for speed alone.

Does nginx support .htaccess files?

No. nginx has no per-directory override files, so rules from an .htaccess must be moved into the server configuration and nginx reloaded. That is a deliberate trade: no file lookups on each request, but only people with access to the main config can change rules.

Can I convert .htaccess to nginx automatically?

Simple redirects and fallbacks translate cleanly, as the translator on this page shows. Long chains of RewriteCond with flags such as [P] or environment variables need a person to read them, because nginx expresses the same intent with different building blocks.

Which should I pick for a WordPress or PHP site?

If your host only gives you file access, Apache with .htaccess is what lets you change rules at all. On a server you control, either works with PHP-FPM; in nginx you write the pretty-URL fallback once with try_files in the server block.

How do I reload config without dropping connections?

For nginx, run nginx -s reload: the master checks the new config, starts new workers and asks the old ones to finish gracefully. For Apache, apachectl graceful does the equivalent for its child processes.

Related: Caddy vs nginx, nginx load balancing, Redirect rules generator, Redirect checker, HTTP status codes.

Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.

More in Guides

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap