Nginx vs Apache vs Caddy: Choosing the Right Web Server

Devops & Infrastructure and What Is

Nginx vs Apache vs Caddy: Choosing the Right Web Server

Every web application needs a web server to handle HTTP requests. Whether you're serving a static site, reverse-proxying to a Node.js backend, or hosting a WordPress installation, your choice of web server affects performance, security, and how much time you spend on configuration.

This guide compares the three most popular options — Nginx, Apache, and Caddy — with real configuration examples and practical advice for choosing the right one.

Quick Comparison

Feature Nginx Apache Caddy
Architecture Event-driven, async Process/thread per connection Event-driven, Go goroutines
Performance Excellent for static files and high concurrency Good, but higher memory under load Very good, slightly behind Nginx
Configuration nginx.conf (custom syntax) httpd.conf + .htaccess (XML-like) Caddyfile (minimal, human-readable)
HTTPS Manual (Let's Encrypt + certbot) Manual (Let's Encrypt + certbot) Automatic (built-in ACME)
Per-directory config No (centralized only) Yes (.htaccess) No (centralized only)
Module system Compiled modules Dynamic modules (loaded at runtime) Plugins (Go modules)
Market share ~34% (most popular) ~29% (declining) ~1% (growing fast)
Best for High-traffic sites, reverse proxy Shared hosting, PHP apps Small-to-medium sites, automatic HTTPS

Nginx

Nginx (pronounced engine-x) was created in 2004 to solve the C10K problem — handling 10,000 concurrent connections. Its event-driven architecture uses a small number of worker processes, each handling thousands of connections asynchronously.

Strengths

  • Performance: Serves static files extremely fast with minimal memory
  • Reverse proxy: The de facto standard for proxying to application servers (Node.js, Python, Ruby, Go)
  • Load balancing: Built-in upstream balancing with multiple algorithms
  • Low memory footprint: Handles thousands of connections with minimal RAM

Configuration Example

Serving a static site:

server {
    listen 80;
    server_name example.com;
    root /var/www/example.com;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }

    # Cache static assets
    location ~* \.(css|js|png|jpg|gif|ico)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

Reverse proxy to a Node.js app:

server {
    listen 80;
    server_name api.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

When to Use Nginx

  • High-traffic websites needing maximum performance
  • Reverse proxying to application servers
  • VPS deployments where you control the server
  • Load balancing across multiple backends
  • Serving static assets alongside dynamic applications

Apache

Apache HTTP Server has been running the web since 1995. It introduced the concept of dynamically loadable modules and per-directory configuration via .htaccess files — features that made shared hosting possible.

Strengths

  • .htaccess support: Per-directory configuration without server restart
  • Module ecosystem: Hundreds of modules (mod_php, mod_rewrite, mod_security)
  • Shared hosting: Still the default on most shared hosting providers
  • Documentation: Decades of community knowledge and tutorials

Configuration Example

Serving a static site:

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/example.com

    <Directory /var/www/example.com>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    # Cache static assets
    <FilesMatch "\.(css|js|png|jpg|gif|ico)$">
        ExpiresActive On
        ExpiresDefault "access plus 30 days"
        Header set Cache-Control "public, immutable"
    </FilesMatch>
</VirtualHost>

Reverse proxy to a Node.js app:

<VirtualHost *:80>
    ServerName api.example.com

    ProxyPreserveHost On
    ProxyPass / http://127.0.0.1:3000/
    ProxyPassReverse / http://127.0.0.1:3000/

    RequestHeader set X-Forwarded-Proto "http"
</VirtualHost>

When to Use Apache

  • Shared hosting environments where Nginx isn't available
  • PHP applications that benefit from mod_php
  • Projects that need .htaccess for per-directory configuration
  • Legacy applications with existing Apache configurations

Caddy

Caddy (v2, released 2020) is the newest of the three. Its headline feature is automatic HTTPS — it obtains and renews TLS certificates from Let's Encrypt without any configuration. The Caddyfile syntax is designed to be as simple as possible.

Strengths

  • Automatic HTTPS: Certificates obtained and renewed automatically via ACME
  • Simple configuration: A basic site takes 2-3 lines
  • Modern defaults: HTTP/2, HTTP/3, TLS 1.3 out of the box
  • Single binary: No dependencies, easy to install and update

Configuration Example

Serving a static site (with automatic HTTPS):

example.com {
    root * /var/www/example.com
    file_server
}

That's it. Caddy automatically obtains a TLS certificate, redirects HTTP to HTTPS, and serves the files.

Reverse proxy to a Node.js app:

api.example.com {
    reverse_proxy 127.0.0.1:3000
}

When to Use Caddy

  • Small-to-medium sites where simplicity matters
  • Projects where automatic HTTPS saves significant ops time
  • Development environments needing local HTTPS
  • APIs and microservices with straightforward routing

Performance Comparison

For static file serving and high concurrency, Nginx leads. Apache's process-per-connection model uses more memory under load. Caddy performs well but sits between the two.

Metric Nginx Apache Caddy
Static file throughput Highest Moderate High
Memory per 10K connections ~2.5 MB ~10+ MB (prefork) ~5 MB
Concurrent connection handling Excellent Good (with worker MPM) Very good
TLS handshake overhead Low (with tuning) Low (with tuning) Low (default)

In practice, the web server is rarely the bottleneck. Your application code, database queries, and network latency have far more impact on user-perceived performance.

How Web Server Choice Affects Deployment

When you deploy with DeployHQ, your code is transferred to the server — the web server configuration ships alongside it. Understanding the relationship between your application code and web server is important:

  • Configuration files deploy with your code. Your nginx.conf, .htaccess, or Caddyfile lives in your Git repository and deploys automatically when you push from GitHub or GitLab
  • Server restart may be needed. After deploying Nginx or Apache config changes, you often need a reload command. DeployHQ's build pipelines can run post-deploy commands to handle this
  • The web server is already running. DeployHQ deploys your application code. The web server itself is installed and managed separately on your server

For teams managing multiple client sites, having a consistent web server across projects simplifies operations. Agencies often standardize on Nginx for its performance and flexibility.

FAQ

Can I run Nginx and Apache together? Yes. A common pattern is Nginx as a reverse proxy in front of Apache. Nginx handles static files and SSL termination; Apache handles PHP via mod_php. This gives you the best of both worlds.

Is Caddy production-ready? Yes. Caddy v2 is stable and used in production by many companies. Its automatic certificate management actually reduces ops risk compared to manual cert renewal.

Which is best for WordPress? Apache is the traditional choice because WordPress relies on .htaccess for URL rewriting. However, Nginx works well with WordPress using a try_files directive, and many high-traffic WordPress sites run on Nginx.

Do I need a web server if I'm using Node.js/Express? Node.js can serve HTTP directly, but a reverse proxy (typically Nginx or Caddy) in front of it provides SSL termination, static file serving, load balancing, and protection against slow clients. For production, always use a reverse proxy.

Which web server is easiest to learn? Caddy, by a wide margin. A functional Caddyfile can be 3 lines. Nginx has a moderate learning curve. Apache's configuration is the most verbose but extremely well-documented.


Your web server is the front door to your application. Whether you choose Nginx for performance, Apache for compatibility, or Caddy for simplicity, the important thing is that your deployment pipeline handles the configuration reliably.

Try DeployHQ free — deploy your web server configuration alongside your application code on every push. See pricing for team plans.


Questions? Reach out at support@deployhq.com or @deployhq.