What is a Web Server? Apache, Nginx, and How the Internet Delivers Web Pages
A web server accepts HTTP requests and returns responses. Apache has been doing this since 1995. Nginx rebuilt the model in 2004 and took over the cloud. Here's how they work, how they differ, and how to pick between them.
When you type https://coderoasis.com into a browser and press Enter, your browser sends an HTTP request across the internet. Something on the other end has to receive that request, figure out what you asked for, retrieve it, and send back a response. That something is a web server.
The concept is simple. The implementation, at the scale the internet actually operates, is decades of engineering work in two dominant pieces of software: Apache HTTP Server and Nginx. Between them, they run the majority of the world's websites. Understanding how they work, how they differ, and when to use each is foundational knowledge for anyone who deploys software.
What a Web Server Actually Does
A web server is software that listens for incoming network connections, receives HTTP (HyperText Transfer Protocol) requests, and sends back HTTP responses. That's the whole job description.
An HTTP request looks like this — this is what your browser sends:
GET /about HTTP/1.1
Host: coderoasis.com
User-Agent: Mozilla/5.0 ...
Accept: text/html,application/xhtml+xml
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
The server reads this, figures out what /about maps to (a file, a script, a proxied application), and sends back:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 4823
Cache-Control: max-age=3600
<!DOCTYPE html>
<html>
<head><title>About CoderOasis</title></head>
...
</html>
The status code (200 OK) tells the browser whether the request succeeded. The headers tell the browser how to handle the response — the content type, how long to cache it, compression encoding, security policies. The body is the actual content.
Everything that makes the web feel interactive — forms, authentication, database-driven content, APIs — is built on top of this request/response cycle. The web server is the component that handles the network layer: accepting connections, parsing requests, routing them to the right handler, and formatting responses.
What is the Apache HTTP Server
Apache HTTP Server, usually called just Apache, was released in April 1995. The name came from the original NCSA HTTPd server that it was built on — patches accumulated, and developers called the result "a patchy server." Whether that's the real etymology or a retronym is disputed, but it stuck.
By the late 1990s, Apache was running over 50% of all web servers on the internet. At peak dominance around 2009, it served over 70% of all websites. It remains the most historically significant web server software ever written and still powers a substantial portion of the internet today.
Apache's homepage describes it as a project to create "a robust, commercial-grade, featureful, and freely-available source code implementation of an HTTP (Web) server." Apache 2.4.66 is the current stable release.
How Apache Handles Connections
Apache's core architecture is built around Multi-Processing Modules (MPMs), which control how it handles concurrent connections. There are three main ones, and understanding them explains both Apache's strengths and its limitations:
Prefork MPM — Apache's original model. Each incoming connection gets its own dedicated process. When Apache starts, it pre-spawns a pool of worker processes waiting for requests. This is simple and safe: each process is completely isolated, so a crash in one doesn't affect others. But processes are expensive — each one consumes around 8-25MB of memory. Under high concurrency, you end up with hundreds of processes fighting for CPU time and RAM.
Worker MPM — A hybrid model. Each process spawns multiple threads, and each thread handles one connection. Significantly more memory-efficient than Prefork because threads within the same process share memory. But thread safety becomes a concern — not all Apache modules are thread-safe, which is why some configurations still require Prefork.
Event MPM — Apache's modern architecture, the default since Apache 2.4. Separates connection handling from request processing. A small number of listener threads accept connections and hand off actual request processing to worker threads. Idle keep-alive connections don't block worker threads the way they do in the Worker MPM. This brings Apache's performance much closer to Nginx for typical workloads.
For most new deployments, use Event MPM. It's more efficient while retaining full compatibility with Apache's module ecosystem.
Apache's Configuration: .htaccess and Virtual Hosts
Apache's configuration lives in /etc/apache2/ on Debian-based systems, /etc/httpd/ on Red Hat-based systems. The main config file is apache2.conf or httpd.conf, and site-specific configurations go in sites-available/ — the same pattern as Nginx.
The feature most associated with Apache is .htaccess — per-directory configuration files that override the main server config for that directory and its subdirectories:
# /var/www/mysite/.htaccess
Options -Indexes # Disable directory listings
AllowOverride All # Allow .htaccess files to work
Header set X-Content-Type-Options "nosniff"
# URL rewriting for a single-page app
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
This is Apache's killer feature for certain use cases. An application can ship a .htaccess file and configure the web server without requiring server-level access. WordPress, Drupal, Magento, and most PHP applications rely heavily on .htaccess for URL rewriting. Shared hosting providers use it to give individual users control over their own site configurations without affecting other sites on the same server.
Nginx has no equivalent. This is a genuine Apache advantage for any application that depends on .htaccess, and most shared hosting environments run Apache specifically because of it.
A Virtual Host in Apache is a server block configuration for a specific domain:
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example
<Directory /var/www/example>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/example-error.log
CustomLog ${APACHE_LOG_DIR}/example-access.log combined
</VirtualHost>
Apache and PHP: mod_php
Apache's relationship with PHP is uniquely close. mod_php embeds a PHP interpreter directly into each Apache worker process. When a .php file is requested:
- The Apache worker handling that connection loads the file
- The embedded PHP interpreter executes it
- The output is returned as the response
No inter-process communication, no socket overhead, no separate process to manage. This is clean and simple for single-server setups. The tradeoff: every Apache worker process has PHP loaded in memory even when serving static files, which is wasteful. And because PHP runs inside the Apache process, it runs as the Apache user — a PHP vulnerability could directly compromise the web server process.
The modern alternative is PHP-FPM (FastCGI Process Manager), which runs PHP as a separate service that Apache or Nginx communicate with via FastCGI. This gives better isolation and resource management. For new deployments, PHP-FPM is recommended even with Apache.
What is NGINX?
Nginx (pronounced "engine-x") was built by Igor Sysoev starting in 2002 and released publicly in 2004. The origin story is the C10K problem — how do you handle 10,000 simultaneous connections on a single server? Apache's process-per-connection model couldn't scale to that without enormous memory and CPU cost.
Sysoev's answer was an event-driven, asynchronous, non-blocking architecture. Instead of one process or thread per connection, a small fixed number of worker processes each handle thousands of connections simultaneously. When a worker needs to wait for I/O — a file read, a database query response, a backend application — it registers the wait with the operating system's event notification system (epoll on Linux) and immediately moves on to other connections. No blocking, no wasted resources, no idle processes consuming memory.
The practical result: Nginx can handle tens of thousands of concurrent connections with predictable memory usage, while Apache's memory consumption scales with connection count.
We covered this architecture in depth in the What is Nginx article. The configuration, reverse proxy setup, load balancing, SSL termination, caching — all of that is there. The Nginx installation guide, the reverse proxy configuration, and the CertBot/Let's Encrypt setup cover the practical deployment steps.
The key point for this comparison: Nginx doesn't have mod_php. It doesn't embed interpreters. It doesn't have .htaccess. Its configuration requires server-level access to change. But for reverse proxying, load balancing, and high-concurrency static file serving, its architecture is purpose-built in a way Apache wasn't designed for.
Other Web Servers Worth Knowing
Caddy is a newer web server written in Go that handles HTTPS automatically — it obtains and renews Let's Encrypt certificates with zero configuration. If you want HTTPS with minimal setup and don't need Apache's or Nginx's full feature set, Caddy is worth evaluating.
LiteSpeed is a commercial web server with a free OpenLiteSpeed variant. It's Apache configuration-compatible (reads .htaccess files and httpd.conf syntax) but uses an event-driven architecture similar to Nginx. Popular in managed WordPress hosting for this compatibility/performance combination.
IIS (Internet Information Services) is Microsoft's web server, built into Windows Server. The dominant choice for ASP.NET applications on Windows infrastructure.
Node.js and similar runtimes (Deno, Bun) can function as web servers directly using their HTTP modules. For small internal services or APIs, running without a dedicated web server in front is common. For production traffic-facing deployments, putting Nginx in front as a reverse proxy is standard practice.
The Architecture Conversation
The question isn't "which web server is better." It's "which architecture fits this situation."
Choose Apache when:
- Your application relies on
.htaccessfor per-directory configuration — this includes most WordPress sites, many legacy PHP applications, and shared hosting scenarios where users need to configure their own directories - You're running a shared hosting environment where multiple users need isolated web server configuration without root access
mod_rewriterules from existing documentation are critical — Apache's rewrite engine has more documentation and wider historical use- The existing team knows Apache and the cost of relearning isn't justified
Choose Nginx when:
- You're deploying a modern stack where the "web server" is primarily a reverse proxy in front of an application server (Node.js, Python, Go, Java, etc.)
- You need to handle high concurrency with predictable memory usage
- You're serving large volumes of static files from a CDN origin
- You're building an API gateway or load balancer
- You're containerizing with Docker and Kubernetes — Nginx is by far the more commonly used web server in container environments
The default answer in 2026 for most new backend development: Nginx as the reverse proxy, with your application server (whatever language) running behind it. Nginx handles TLS termination, rate limiting, static file serving, and connection management. Your application handles business logic. They communicate over a Unix socket or localhost TCP port.
What Happens During an HTTP Request
To make the web server's role concrete, here's what happens when a browser hits https://example.com/api/users:
1. DNS Resolution — The browser looks up example.com and gets back an IP address. This has nothing to do with the web server — it's the DNS system.
2. TCP Connection — The browser opens a TCP connection to port 443 (HTTPS) on that IP address.
3. TLS Handshake — Before any HTTP traffic, TLS negotiates encryption. The web server presents its certificate (signed by a Certificate Authority like Let's Encrypt), the browser verifies it, and both parties derive session keys. This is encryption in transit.
4. HTTP Request — The browser sends the HTTP request inside the encrypted TLS channel:
GET /api/users HTTP/2
Host: example.com
Authorization: Bearer eyJhbGc...
5. Web Server Processing — Nginx or Apache receives the request. Based on the URL pattern (/api/users), it either:
- Serves a static file directly from disk, or
- Forwards the request to a backend application via
proxy_pass(Nginx) orProxyPass(Apache)
6. Application Processing — The backend application (Node.js, PHP-FPM, Python, etc.) receives the request, queries the database, and returns a response.
7. Response — The web server forwards the response back through the TLS channel to the browser.
The web server is steps 5-7 — the traffic cop between the network and your application. Everything before step 5 is network and DNS infrastructure. Everything after is your application code.
HTTP Versions: 1.1, 2, and 3
HTTP has evolved across three major versions, and web servers implement them differently.
HTTP/1.1 (1997) introduced persistent connections (keep-alive), allowing multiple requests over a single TCP connection. Before this, every request required a new connection. Still widely supported, still used as the protocol between Nginx and many backend applications on localhost.
HTTP/2 (2015) added multiplexing — multiple requests and responses can interleave over a single connection without head-of-line blocking. Server push (the server proactively sends resources the browser will need). Header compression. HTTP/2 is now supported by essentially all modern browsers and web servers, and should be enabled for public-facing HTTPS deployments.
# Enable HTTP/2 in Nginx
server {
listen 443 ssl;
http2 on; # Or listen 443 ssl http2; in older Nginx versions
...
}
HTTP/3 (2022) replaces TCP with QUIC — a protocol built on UDP with built-in encryption, connection migration, and improved head-of-line blocking elimination. Nginx has experimental HTTP/3 support in mainline builds. Apache has HTTP/3 support via mod_http2 work in progress. Adoption is growing but not yet universal — around 30% of web traffic used HTTP/3 as of 2025.
Security Considerations
Web servers sit at the exposed edge of your infrastructure. Several configuration defaults need to be addressed:
Disable server version disclosure. By default, Apache and Nginx include the server name and version in response headers (Server: nginx/1.28.3). Disable this:
server_tokens off; # Nginx
ServerTokens Prod # Apache — shows "Apache" without version
ServerSignature Off
Attackers scan for specific vulnerable versions. Don't make it easy.
Disable directory listings. If a directory has no index file, a default-configured web server will list the directory contents. Turn it off:
autoindex off; # Nginx (default)
Options -Indexes # Apache
Set security headers. These headers protect browsers from common attacks:
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "default-src 'self'" always;
Rate limiting. Web servers can throttle excessive requests to mitigate brute-force attacks and basic DDoS:
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
location /api/ {
limit_req zone=api burst=20 nodelay;
}
These aren't optional hardening for paranoid administrators. They're baseline configuration for any public-facing server.