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](https://deployhq.com/blog/deploy-wordpress-with-deployhq) 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](https://deployhq.com/blog/how-to-deploy-to-a-vps-with-deployhq) 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](https://deployhq.com/features), 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](https://deployhq.com/deploy-from-github) or [GitLab](https://deployhq.com/deploy-from-gitlab)
- **Server restart may be needed**. After deploying Nginx or Apache config changes, you often need a reload command. DeployHQ's [build pipelines](https://deployhq.com/features/build-pipelines) can run post-deploy commands to handle this
- **The web server is already running**. [DeployHQ](https://www.deployhq.com) 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](https://deployhq.com/for-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](https://deployhq.com/signup)[DeployHQ](https://www.deployhq.com) free** — deploy your web server configuration alongside your application code on every push. See [pricing](https://deployhq.com/pricing) for team plans.

* * *

Questions? Reach out at [support@deployhq.com](mailto:support@deployhq.com) or [@deployhq](https://x.com/deployhq).

