Apache or Nginx?

Chapter 2 — Web Server

The web server is the front door of your stack — it listens for incoming HTTP requests and decides what to do with them. This chapter covers both Apache and Nginx in full: installation, directory structure, configuration, virtual hosts, and essential management commands. You only need to install one; both are documented here so the chapter serves as a complete reference regardless of which you choose.

Which should I pick? For Philip's Learning Blog — Apache. The existing site uses .htaccess files and was built around Apache conventions. For a new high-traffic site or a reverse proxy in front of another service — Nginx. The rest of this chapter documents both equally.

Apache

⬡ Apache HTTP Server

Installation

Terminal
$ sudo apt update $ sudo apt install -y apache2 Reading package lists... Done Setting up apache2 (2.4.57-2) ... # Apache starts automatically after install. Verify: $ sudo systemctl status apache2 ● apache2.service - The Apache HTTP Server Loaded: loaded (/lib/systemd/system/apache2.service; enabled) Active: active (running) since Tue 2026-06-17 10:00:00 BST # Test from the server itself $ curl -s http://localhost | grep -o "<title>.*</title>" <title>Apache2 Debian Default Page: It works</title>

Open http://YOUR_SERVER_IP in a browser — you should see the Apache2 Debian Default Page. That page lives at /var/www/html/index.html and confirms Apache is serving files.

Directory Structure

/etc/apache2/ ├── apache2.conf # Main config — global settings ├── ports.conf # Which ports Apache listens on (80, 443) ├── sites-available/ # All virtual host config files live here │ ├── 000-default.conf # Default site (port 80) │ └── default-ssl.conf # Default HTTPS site (disabled by default) ├── sites-enabled/ # Symlinks to active sites in sites-available │ └── 000-default.conf # → ../sites-available/000-default.conf ├── mods-available/ # All available modules (.load + .conf pairs) ├── mods-enabled/ # Symlinks to active modules └── conf-available/ # Additional config snippets /var/www/html/ # Default document root /var/log/apache2/ ├── access.log # Every request logged here └── error.log # Errors and warnings
sites-available vs sites-enabled: Apache uses a symlink pattern — config files live in sites-available/ and a symlink in sites-enabled/ activates them. Never edit files in sites-enabled/ directly. Use a2ensite / a2dissite to manage the symlinks automatically.

Useful Modules to Enable

Terminal — enable essential modules
# mod_rewrite — required for clean URLs and .htaccess rewrites $ sudo a2enmod rewrite # mod_headers — send custom HTTP headers (security headers, CORS) $ sudo a2enmod headers # mod_ssl — HTTPS support (needed for Chapter 5) $ sudo a2enmod ssl # mod_deflate — gzip compression for faster page loads $ sudo a2enmod deflate # Apply all module changes $ sudo systemctl restart apache2 # Verify a module is enabled $ apache2ctl -M | grep rewrite rewrite_module (shared)

Configuring the Default Site

The default virtual host config controls what Apache serves when no other virtual host matches. Edit it to point to your actual site files:

Terminal
$ sudo vi /etc/apache2/sites-available/000-default.conf
# /etc/apache2/sites-available/000-default.conf <VirtualHost *:80> ServerAdmin webmaster@osztromok.com ServerName osztromok.com ServerAlias www.osztromok.com DocumentRoot /var/www/html <Directory /var/www/html> Options -Indexes +FollowSymLinks AllowOverride All # Allows .htaccess to work Require all granted </Directory> ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>
Terminal — test config and reload
# Always test config syntax before reloading — catches typos $ sudo apache2ctl configtest Syntax OK $ sudo systemctl reload apache2

Creating a Named Virtual Host

If you want to host multiple sites on one machine, or simply keep your config tidy, create a dedicated virtual host file for each site:

Terminal
# Create the document root for the new site $ sudo mkdir -p /var/www/osztromok.com $ sudo chown -R $USER:$USER /var/www/osztromok.com # Create the virtual host config $ sudo vi /etc/apache2/sites-available/osztromok.com.conf
# /etc/apache2/sites-available/osztromok.com.conf <VirtualHost *:80> ServerName osztromok.com ServerAlias www.osztromok.com DocumentRoot /var/www/osztromok.com <Directory /var/www/osztromok.com> Options -Indexes +FollowSymLinks AllowOverride All Require all granted </Directory> ErrorLog ${APACHE_LOG_DIR}/osztromok.com-error.log CustomLog ${APACHE_LOG_DIR}/osztromok.com-access.log combined </VirtualHost>
Terminal — enable the new site
# Enable the new site (creates the symlink in sites-enabled/) $ sudo a2ensite osztromok.com.conf Enabling site osztromok.com. To activate the new configuration, you need to run: systemctl reload apache2 # Disable the default site if this is your only site $ sudo a2dissite 000-default.conf $ sudo apache2ctl configtest && sudo systemctl reload apache2 Syntax OK

Apache Management Commands

TaskCommand
Start Apachesudo systemctl start apache2
Stop Apachesudo systemctl stop apache2
Restart (full restart)sudo systemctl restart apache2
Reload (no downtime)sudo systemctl reload apache2
Enable at bootsudo systemctl enable apache2
Test config syntaxsudo apache2ctl configtest
Enable a sitesudo a2ensite sitename.conf
Disable a sitesudo a2dissite sitename.conf
Enable a modulesudo a2enmod modulename
Disable a modulesudo a2dismod modulename
List enabled modulesapache2ctl -M
View error log (live)sudo tail -f /var/log/apache2/error.log
View access log (live)sudo tail -f /var/log/apache2/access.log
Check Apache versionapache2 -v

Nginx

⬡ Nginx
Important: Apache and Nginx both listen on port 80 by default. You cannot run both at the same time unless you change one of them to a different port. Stop Apache first if it is running: sudo systemctl stop apache2 && sudo systemctl disable apache2

Installation

Terminal
$ sudo apt update $ sudo apt install -y nginx Setting up nginx (1.22.1-9) ... # Nginx starts automatically. Verify: $ sudo systemctl status nginx ● nginx.service - A high performance web server Active: active (running) $ curl -s http://localhost | grep -o "<title>.*</title>" <title>Welcome to nginx!</title>

Directory Structure

/etc/nginx/ ├── nginx.conf # Main config — worker processes, logging, includes ├── sites-available/ # All server block configs live here │ └── default # Default server block ├── sites-enabled/ # Symlinks to active configs │ └── default # → ../sites-available/default ├── conf.d/ # Additional config snippets (auto-loaded) ├── modules-available/ └── modules-enabled/ /var/www/html/ # Default document root (same as Apache) /var/log/nginx/ ├── access.log └── error.log
No .htaccess in Nginx. Nginx does not read .htaccess files at all — all configuration lives in the server block files under /etc/nginx/sites-available/. Rewrite rules that live in .htaccess for Apache need to be translated into Nginx rewrite or try_files directives.

Configuring the Default Server Block

Terminal
$ sudo vi /etc/nginx/sites-available/default
# /etc/nginx/sites-available/default server { listen 80; listen [::]:80; server_name osztromok.com www.osztromok.com; root /var/www/html; index index.php index.html index.htm; # Try the request URI, then as a directory, then fall back to index.php location / { try_files $uri $uri/ /index.php?$query_string; } # Pass PHP requests to PHP-FPM (configured in Chapter 4) location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php8.2-fpm.sock; } # Deny access to .htaccess files (they do nothing in Nginx # but shouldn't be publicly readable) location ~ /\.ht { deny all; } error_log /var/log/nginx/osztromok.com-error.log; access_log /var/log/nginx/osztromok.com-access.log; }

Creating a Named Server Block

Terminal
# Create a dedicated config file for the site $ sudo vi /etc/nginx/sites-available/osztromok.com # Enable it with a symlink $ sudo ln -s /etc/nginx/sites-available/osztromok.com /etc/nginx/sites-enabled/ # Disable the default block if this is your only site $ sudo rm /etc/nginx/sites-enabled/default # Test config syntax — always do this before reloading $ sudo nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful $ sudo systemctl reload nginx

Nginx Management Commands

TaskCommand
Start Nginxsudo systemctl start nginx
Stop Nginxsudo systemctl stop nginx
Restart (full restart)sudo systemctl restart nginx
Reload (no downtime)sudo systemctl reload nginx
Enable at bootsudo systemctl enable nginx
Test config syntaxsudo nginx -t
Enable a sitesudo ln -s /etc/nginx/sites-available/name /etc/nginx/sites-enabled/
Disable a sitesudo rm /etc/nginx/sites-enabled/name
View error log (live)sudo tail -f /var/log/nginx/error.log
View access log (live)sudo tail -f /var/log/nginx/access.log
Check Nginx versionnginx -v

Side-by-Side Quick Reference

TaskApacheNginx
Test configapache2ctl configtestnginx -t
Reload configsystemctl reload apache2systemctl reload nginx
Enable a sitea2ensite name.confln -s sites-available/name sites-enabled/
Disable a sitea2dissite name.confrm sites-enabled/name
Enable a modulea2enmod modulename(edit nginx.conf / install package)
Config location/etc/apache2//etc/nginx/
Default doc root/var/www/html//var/www/html/
Error log/var/log/apache2/error.log/var/log/nginx/error.log
.htaccess supportYes (AllowOverride All)No
PHP integrationmod_php or PHP-FPMPHP-FPM only
Placing your site files: Both web servers default to /var/www/html/ as the document root. For a real site, either copy or symlink your files there, or update the DocumentRoot / root directive in the virtual host config to point to wherever your files actually live. Ensure the web server user (www-data on Debian) can read the files: sudo chown -R www-data:www-data /var/www/html
Next: Chapter 3 — Database
Chapter 3 covers MySQL, MariaDB, and PostgreSQL — installation on Debian 12, running the security hardening script, creating databases and users, and connecting from PHP. All three are documented; for Philip's Learning Blog the existing setup_database.sql script is ready to run straight after installation.