Skip to content
DevOps devops webservers 5 min read

What is a Web Server?

A web server is a program that listens for requests coming from browsers and other clients, then sends back a response. When you type a URL into your browser, something on the other end has to receive that request and reply with a web page, an image, or some data. That “something” is a web server. Understanding what it does — and what it does not do — is the foundation of almost everything else in DevOps, because nearly every deployment puts a web server in front of your application.

What a web server actually does

At its core, a web server speaks HTTP (HyperText Transfer Protocol — the language browsers and servers use to talk to each other) and its secure version, HTTPS (HTTP plus encryption). A client (usually a browser) sends an HTTP request like “GET me the page at /about”, and the server sends back an HTTP response: a status code (like 200 OK or 404 Not Found), some headers, and a body (the actual content).

The web server’s job breaks down into two main patterns:

  1. Serving static files — handing back files that already exist on disk exactly as they are.
  2. Proxying dynamic requests — passing the request to another program (your application) and returning whatever that program produces.

Almost every real website uses both at the same time.

Static content vs dynamic content

Static content is any file that does not change based on who is asking or when. Think HTML files, CSS stylesheets, JavaScript bundles, images, fonts, and PDFs. The server just reads the file from disk and sends it back. This is extremely fast because no thinking is involved — the file is already finished.

Dynamic content is generated on the fly. When you log into a bank and see your balance, that page did not exist as a file. Your application (written in Node.js, Python, PHP, Java, etc.) built it for you in that moment by talking to a database. A plain web server cannot do this by itself — it has to forward the request to your application.

This is where the term reverse proxy comes in: a reverse proxy is a server that sits in front of your application and forwards incoming requests to it, then passes the application’s response back to the client. The web server handles the public-facing HTTP details (TLS encryption, compression, logging) while your app focuses only on business logic.

AspectStatic contentDynamic content
SourceA file already on diskGenerated by your app per request
Examplesstyle.css, logo.png, index.htmlA user’s dashboard, search results
Who handles itWeb server aloneWeb server forwards to app server
SpeedVery fastDepends on your app + database
When to useAssets, marketing pages, JS/CSSAnything personalized or data-driven

Where a web server sits in the stack

Picture the path a request takes from a user’s browser to your code:

Browser  →  Internet  →  Web server (Nginx/Apache)  →  App server (your code)  →  Database

                              └── serves static files directly (no app needed)

The web server is the front door. Everything from the outside world hits it first. For requests like /css/app.css it answers directly from disk. For requests like /api/orders it forwards to your application running on a local port (for example http://127.0.0.1:3000).

An app server (sometimes called an application server or upstream) is the program that runs your code — your Express app, your Django project, your Spring Boot service. It usually listens only on localhost, hidden from the internet, and the web server is the only thing allowed to talk to it.

Why put a web server in front of your app at all? It is tempting to let your Node or Python app face the internet directly. Don’t. A dedicated web server gives you TLS/HTTPS termination, request buffering against slow clients, gzip compression, caching, rate limiting, and clean access logs — all battle-tested and far more secure than rolling your own.

The two dominant choices: Nginx and Apache

For decades, two web servers have dominated Linux servers: Nginx (pronounced “engine-x”) and Apache HTTP Server (often just “Apache” or “httpd”).

  • Nginx was built to handle many connections at once with very little memory. It is the default choice today for serving static files fast and acting as a reverse proxy or load balancer. Its config lives in /etc/nginx.
  • Apache is older, hugely flexible, and famous for its module system and per-directory .htaccess files. It is still extremely common, especially with PHP and shared hosting. Its config lives in /etc/apache2 on Ubuntu.
NginxApache
Best atStatic files, reverse proxy, load balancingFlexible config, .htaccess, legacy PHP
Concurrency modelEvent-driven (handles thousands of connections cheaply)Process/thread per connection (heavier)
Per-directory configNo (central config only)Yes (.htaccess)
Ubuntu config path/etc/nginx/sites-available/etc/apache2/sites-available
When to chooseNew projects, high traffic, microservicesExisting Apache setups, shared hosting, .htaccess needs

On a fresh Ubuntu 22.04 or 24.04 LTS server, you install either one with apt and manage it with systemd:

sudo apt update
sudo apt install nginx -y
sudo systemctl status nginx

Output:

● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Mon 2026-06-15 10:02:11 UTC; 3s ago
   Main PID: 1423 (nginx)
      Tasks: 2 (limit: 1131)
     Memory: 2.6M

Once it is running, open the firewall so visitors can reach it:

sudo ufw allow 'Nginx Full'
sudo ufw status

Output:

Status: active

To                         Action      From
--                         ------      ----
Nginx Full                 ALLOW       Anywhere
Nginx Full (v6)            ALLOW       Anywhere (v6)

Nginx Full opens both port 80 (HTTP) and port 443 (HTTPS). If you only need plain HTTP for testing, use Nginx HTTP instead.

Best Practices

  • Always run a real web server in front of your app — never expose Node, Python, or Java app servers directly to the internet.
  • Serve static assets from the web server, not your app. It is faster and frees your application to do real work.
  • Terminate HTTPS at the web server so your app only ever sees plain localhost traffic.
  • Pick Nginx for new projects unless you specifically need Apache features like .htaccess.
  • Open only the ports you need with ufw (80 and 443), and keep your app’s port closed to the outside world.
  • Check logs in /var/log/nginx or /var/log/apache2 when something breaks — the answer is almost always there.
  • Keep the package updated with sudo apt update && sudo apt upgrade to receive security patches.
Last updated June 15, 2026
Was this helpful?