Understanding Web Servers: My Apache Learning Journey
Security

Understanding Web Servers: My Apache Learning Journey

After diving deep into DNS in my previous post, I've been exploring web servers - specifically Apache. Here's everything I learned about how these digital workhorses actually function, with practical examples and security insights that surprised me.

P
Parham Forati
Author
September 8, 2025
15 min read
1287 views
Network SecurityOWASPWeb ServerWeb DevelopmentApacheDevOps

Understanding Web Servers: My Apache Learning Journey

MARKDOWN
1<!-- meta: Learn how Web Servers really works! web server security owasp , beginner apache configuration -->

What Actually Is a Web Server?

A web server is basically a program that serves up resources (files like HTML pages, images, CSS) to users over the HTTP (or HTTPS) protocol. Think of it like a waiter at a restaurant - clients come in with requests, and the server delivers what they ordered.

When you type something like google.com in your browser, here's what happens behind the scenes:

  • Clients (that's your browser) reach the server via an IP address (or domain name)
  • They connect over TCP
  • If HTTPS is used, a TLS/SSL handshake happens before any HTTP data gets exchanged

Examples of web servers: Apache (what I'm focusing on in this course) and nginx (which is often used as a load-balancer or reverse proxy).

Loading diagram...

My goal here: Get familiar with Apache configuration and basic behavior so when I open an Apache config file, I don't get lost. I want to recognize the important parts and understand what they actually do.

How Apache Configuration Actually Works

Apache has this neat modular setup. There's a main configuration file (commonly called apache2.conf or httpd.conf) and many sub-configuration files that get pulled in. It's like having a main recipe that references other recipe cards for different parts of the meal.

Apache uses things called directives - these are basically configuration commands that change settings. Two really useful include-style directives I learned about:

Include vs IncludeOptional

  • Include: unconditionally include another config file
  • IncludeOptional: include another config file if it exists (no error if missing)

Here's a simple example:

APACHE
1IncludeOptional sites-enabled/*.conf

This means "load all files matching sites-enabled/*.conf if they exist." Pretty neat, right?

Loading diagram...

The Important Directives I Had to Learn

Let me walk you through each directive with simple examples that actually make sense:

DocumentRoot - Where Your Website Files Live

This is the directory where served files live - basically the root folder for requests.

APACHE
1DocumentRoot "/var/www/site1"

Here's how it works: If a user requests / and Apache finds /var/www/site1/index.html, it returns that file. Simple as that!

Let me give you a concrete example:

  • Someone types http://mysite.com/about.html in their browser
  • Apache looks in /var/www/site1/about.html
  • If the file exists → sends back the file with 200 OK
  • If it doesn't exist → sends back 404 Not Found

OWASP security note I learned: Keep sensitive files outside DocumentRoot. Don't store .env files, database backups, or private keys in the document root where people can potentially access them!

ServerName - Your Website's Identity

This is the hostname for a virtual host (used for name-based virtual hosts).

APACHE
1ServerName example.com

Think of this as your website's ID card. When multiple sites share the same server, Apache uses this to figure out which site someone is trying to reach.

Listen - Opening the Door

This tells Apache which IP and port to accept connections on.

APACHE
1Listen 80 2Listen 443 3# or bind to a specific IP: 4Listen 192.0.2.10:8080

Port 80 is for regular HTTP, port 443 is for HTTPS (the secure stuff). The specific IP example is useful if your server has multiple network interfaces.

ErrorLog - When Things Go Wrong

This is the path where error logs go.

APACHE
1ErrorLog ${APACHE_LOG_DIR}/site1-error.log

OWASP note: Keep logs for auditing and incident investigation. But also protect log files from unauthorized access - you don't want attackers reading your logs to learn about your system!

Include and IncludeOptional (Again, Because They're Important)

As I mentioned above: include external config files. IncludeOptional avoids errors if the file is missing.

APACHE
1Include /etc/apache2/common.conf 2IncludeOptional /etc/apache2/sites-enabled/*.conf

This is super useful for organizing your configuration. Instead of one giant file, you can break things up logically.

Directory - The Security Guards

This is an enclosure that applies directives to a filesystem directory. Super useful to control access, options, and overrides.

APACHE
1<Directory "/var/www/site1"> 2 Options -Indexes +FollowSymLinks 3 AllowOverride None 4 Require all granted 5</Directory>

Let me break down each part:

  • Options -Indexes: disable directory listing (this is important for security!)
  • AllowOverride None: disable .htaccess overrides (recommended for predictability)
  • Require all granted: allow access from everyone

OWASP security insight: Never allow Indexes unless you actually want people browsing through your directory contents. Also, limiting AllowOverride reduces your attack surface.

Files - File-Level Control

This limits the scope of enclosed directives by filename pattern.

APACHE
1<Files ~ "\.env$"> 2 Require all denied 3</Files>

This example denies access to any .env file. Super important for keeping environment variables with database passwords and API keys safe!

Here's another useful example:

APACHE
1<Files ~ "\.git"> 2 Require all denied 3</Files>

This blocks access to git repository files that might contain sensitive information.

IfModule - Conditional Configuration

This applies enclosed directives only if a module is loaded.

APACHE
1<IfModule mod_headers.c> 2 Header always set X-Content-Type-Options "nosniff" 3</IfModule>

This is great because if someone doesn't have the headers module installed, the config won't break - it just skips this section.

Other Useful Directives and Settings I Discovered

Here are some other important ones that came up in my learning:

  • ServerTokens Prod — reduce information leaked in server response headers (makes it harder for attackers to fingerprint your server)
  • ServerSignature Off — disable server signature on error pages (again, less info for attackers)
  • CustomLog — define access log format and location
  • Timeout — request timeout (how long to wait for slow requests)
  • KeepAlive/MaxKeepAliveRequests — tuning persistent connections (performance stuff)

OWASP note: Minimizing server fingerprinting helps reduce reconnaissance value to attackers. Basically, the less they know about your setup, the harder it is for them to find vulnerabilities.

Virtual Hosts - Multiple Sites, One Server

This was one of the coolest things I learned! Virtual hosts let you host multiple domains on one server (same IP and port). Most web hosting companies use this approach.

There are two common types:

  • Name-based virtual hosts: multiple hostnames share the same IP and port; Apache uses the Host header to pick the right virtual host
  • IP-based virtual hosts: different IP addresses per host (less common nowadays)
Loading diagram...

Simple Apache Name-Based Virtual Host Example

Here's how I set up two different sites on one server:

Site 1: /etc/apache2/sites-available/site1.conf

APACHE
1<VirtualHost *:80> 2 ServerName site1.example 3 ServerAlias www.site1.example 4 DocumentRoot /var/www/site1 5 ErrorLog ${APACHE_LOG_DIR}/site1-error.log 6 CustomLog ${APACHE_LOG_DIR}/site1-access.log combined 7 <Directory /var/www/site1> 8 Options -Indexes +FollowSymLinks 9 AllowOverride None 10 Require all granted 11 </Directory> 12</VirtualHost>

Site 2: /etc/apache2/sites-available/site2.conf

APACHE
1<VirtualHost *:80> 2 ServerName site2.example 3 DocumentRoot /var/www/site2 4 ErrorLog ${APACHE_LOG_DIR}/site2-error.log 5 CustomLog ${APACHE_LOG_DIR}/site2-access.log combined 6</VirtualHost>

To enable both sites (on Debian/Ubuntu systems):

BASH
1sudo a2ensite site1 && sudo a2ensite site2 && sudo systemctl reload apache2

If you're not using Debian/Ubuntu, the same idea applies: drop the virtual host file into your config and reload Apache.

OWASP note: Each virtual host should have separate logs and a minimal set of enabled modules. Use HTTPS for every virtual host - there's really no excuse not to these days!

What Happens When Someone Visits Your Website?

Let me walk through the complete journey of what happens when someone (let's call him Mamad) wants to visit google.com. I'll expand this example with clear steps:

Loading diagram...

Detailed step-by-step breakdown:

  1. DNS lookup: Mamad's browser asks DNS for google.com → receives an IP address
    OWASP note: DNS spoofing can be mitigated with DNSSEC and using trusted resolvers

  2. TCP handshake: Browser opens a TCP connection to the IP on port 80/443 (SYN, SYN-ACK, ACK)

  3. TLS/SSL handshake (if HTTPS): negotiate encryption, validate certificate, establish secure channel

  4. HTTP request: Browser sends an HTTP request like GET / HTTP/1.1 with Host: google.com header

  5. Apache processing:

    • Accepts connection on the Listen address
    • Matches VirtualHost by ServerName/ServerAlias or falls back to default virtual host
    • Maps the request path to a filesystem path under DocumentRoot, or forwards request to backend (proxy, fastcgi, etc)
    • Applies directory/File/IfModule rules, authentication, rewrites, and access controls
    • Serves the static file or forwards to application server (PHP, Python, etc) and gathers response
  6. Response & Logging: Apache returns HTTP response, sets headers, and logs access/errors

  7. Browser renders page and may make additional requests for images, JavaScript, CSS, then repeat the whole flow for each resource

DocumentRoot - How File Mapping Actually Works

Let me give you a super simple example of how this mapping works:

If your virtual host has:

APACHE
1<VirtualHost *:80> 2 ServerName site1.example 3 DocumentRoot /var/www/site1 4</VirtualHost>

And someone makes this request:

  • Request: GET /images/logo.png HTTP/1.1 with Host: site1.example
  • Apache looks for: /var/www/site1/images/logo.png
  • If file exists → send 200 OK and contents
  • If it doesn't exist → send 404 Not Found (unless other rules rewrite it)
Loading diagram...

OWASP note: Put only public assets in DocumentRoot. Application code that shouldn't be served directly should live outside it (or be protected via configuration).

Security Deep Dive (The OWASP Stuff)

This is where things get really interesting from a security perspective:

How Apache Handles Privileges

Apache typically starts as root to bind privileged ports (like 80, 443), then switches to an unprivileged user (commonly www-data or apache) using setuid/process privilege drop. This is normal and expected behavior!

Here's what setuid means: it allows executing a program with the privileges of its owner. So Apache's parent process uses root privileges to bind to port 80, but the worker processes that actually handle requests run as unprivileged users. Smart design!

File Ownership and Permissions

This was a big learning point for me:

  • Web files should be owned by a deploy user
  • Make them group readable by the Apache user
  • Never, ever use chmod 777 (that's like leaving your house unlocked)

Example command:

BASH
1chown -R deploy:deploy /var/www/site1 2chmod -R 644 /var/www/site1 # Files readable by owner and group 3chmod -R 755 /var/www/site1 # Directories executable by owner and group

Essential Security Measures

Disable unnecessary modules: Fewer modules = smaller attack surface. Only load what you need.

Use a Web Application Firewall (WAF): Something like mod_security for extra protections.

Ensure TLS configuration is modern: Strong ciphers, certificates from trusted Certificate Authorities, and enable HSTS (HTTP Strict Transport Security).

Security Headers Configuration

Add these security headers to protect your users:

APACHE
1<IfModule mod_headers.c> 2 # Prevent MIME-type sniffing attacks 3 Header always set X-Content-Type-Options "nosniff" 4 5 # Prevent clickjacking attacks 6 Header always set X-Frame-Options "SAMEORIGIN" 7 8 # Control referrer information leakage 9 Header always set Referrer-Policy "no-referrer-when-downgrade" 10 11 # Enable browser XSS filtering 12 Header always set X-XSS-Protection "1; mode=block" 13 14 # Content Security Policy (start simple, then tighten) 15 Header always set Content-Security-Policy "default-src 'self'" 16 17 # Force HTTPS (only for HTTPS sites) 18 Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" 19</IfModule>

Let me explain what each of these does:

  • X-Content-Type-Options: Stops browsers from trying to guess file types (which can be exploited)
  • X-Frame-Options: Prevents your site from being embedded in frames on other sites (clickjacking protection)
  • Referrer-Policy: Controls what referrer information gets sent to other sites
  • X-XSS-Protection: Enables the browser's built-in XSS filter
  • Content-Security-Policy: Controls what resources the browser can load (very powerful!)
  • Strict-Transport-Security: Forces browsers to use HTTPS for your site

Additional Security Configurations

Disable directory indexing and .htaccess overrides:

APACHE
1<Directory "/var/www"> 2 Options -Indexes +FollowSymLinks 3 AllowOverride None 4 Require all denied 5</Directory> 6 7<Directory "/var/www/html"> 8 Require all granted 9</Directory>

Block sensitive files:

APACHE
1# Block version control directories 2<DirectoryMatch "\.git"> 3 Require all denied 4</DirectoryMatch> 5 6# Block common sensitive file patterns 7<FilesMatch "^\."> 8 Require all denied 9</FilesMatch> 10 11<Files ~ "\.(env|log|ini|conf|bak)$"> 12 Require all denied 13</Files>

Hide server information:

APACHE
1ServerTokens Prod 2ServerSignature Off

Keep Apache and modules up to date: This is crucial - security patches are released regularly.

My Complete Security Checklist

Here's my mini security checklist that I use now:

  • ✅ Disable directory listing: Options -Indexes
  • ✅ Disable server tokens: ServerTokens Prod and ServerSignature Off
  • ✅ Use AllowOverride None (prefer central config over .htaccess)
  • ✅ Restrict access with <Directory> and <Files> blocks
  • ✅ Use mod_headers to set security headers
  • ✅ Use mod_security (WAF) if available
  • ✅ Configure strong TLS (disable old TLS/SSL versions)
  • ✅ Regularly patch Apache and all modules
  • ✅ Protect log files and implement log rotation
  • ✅ Keep secrets out of DocumentRoot
  • ✅ Set proper file ownership and permissions
  • ✅ Only load necessary modules

Quick Examples for Each Directive

Let me give you quick, clear examples for each directive I mentioned:

DocumentRoot example:

APACHE
1DocumentRoot "/var/www/html" 2# Now requests to / look in /var/www/html/

ServerName example:

APACHE
1ServerName mysite.example 2# This virtual host responds to mysite.example

Listen example:

APACHE
1Listen 443 2# Apache accepts HTTPS connections on port 443

ErrorLog example:

APACHE
1ErrorLog /var/log/apache2/error.log 2# Errors get written to this file

Include/IncludeOptional example:

APACHE
1IncludeOptional conf.d/*.conf 2# Load all .conf files in conf.d/ if they exist

Directory example:

APACHE
1<Directory "/var/www/html"> 2 Options -Indexes 3 Require all granted 4</Directory> 5# No directory listing, but allow access to files

Files example:

APACHE
1<Files "secret.txt"> 2 Require all denied 3</Files> 4# Nobody can access secret.txt

IfModule example:

APACHE
1<IfModule mod_rewrite.c> 2 RewriteEngine On 3</IfModule> 4# Only enable URL rewriting if the module is loaded

Glossary - Key Terms I Had to Learn

  • Web server: software that serves web content over HTTP(S)
  • DocumentRoot: folder where public files live
  • Virtual host: configuration that serves one hostname (domain)
  • Directive: a configuration command (like Listen, ServerName)
  • setuid: running code with the permissions of the program owner (used when Apache drops privileges)
  • Privileged ports: network ports < 1024 (require root to bind to them)
  • TLS/SSL: encryption protocols that make HTTP into HTTPS
  • WAF: Web Application Firewall - extra security layer
  • HSTS: HTTP Strict Transport Security - forces browsers to use HTTPS

What I'm Taking Away

Learning Apache configuration isn't as intimidating as I thought it would be. The key insights I gained:

  1. Everything is about file mapping: Apache takes URLs and maps them to files on disk
  2. Security should be built-in from the start: Every directive has security implications
  3. Virtual hosts are incredibly powerful: One server can host many different websites
  4. Logs are crucial: Both for debugging and security monitoring
  5. The principle of least privilege applies everywhere: Only give access to what's needed

The OWASP security perspective makes this way more interesting than just "here's how to serve files." When you think about each configuration from an attacker's point of view, you make much better decisions.

I'm excited to apply this knowledge in real projects and continue learning about web security. Next up: diving deeper into application-level security!

Quick Reference Card

Essential directives:

APACHE
1DocumentRoot "/var/www/html" # Where files live 2ServerName mysite.example # Site identity 3Listen 443 # Port to listen on 4ErrorLog /path/to/error.log # Error logging

Security must-haves:

APACHE
1Options -Indexes # No directory listing 2ServerTokens Prod # Hide server info 3AllowOverride None # Disable .htaccess 4Require all denied # Default deny access

Virtual host template:

APACHE
1<VirtualHost *:80> 2 ServerName example.com 3 DocumentRoot /var/www/example 4 ErrorLog ${APACHE_LOG_DIR}/example-error.log 5 CustomLog ${APACHE_LOG_DIR}/example-access.log combined 6</VirtualHost>

This journey through Apache has been eye-opening, and I hope sharing my learning process helps others who are just starting out with web server configuration!

Understanding Web Servers: My Apache Learning Journey