Apache Basics

Page 16 — Web server. VirtualHosts, config testing, and useful apachectl commands.

What Apache is

Apache is a web server. Like Nginx, it can serve websites, handle TLS, and reverse proxy to backend applications. Available as httpd on RHEL-like systems and apache2 on Debian-like systems.

What a VirtualHost is

A VirtualHost is Apache's way of defining site-specific behaviour. Each VirtualHost block applies to requests for a specific hostname and port.

Common files

RHEL-like

/etc/httpd/conf/httpd.conf
/etc/httpd/conf.d/

Debian-like

/etc/apache2/apache2.conf
/etc/apache2/sites-enabled/

Debian: enabling sites and modules

Debian/Ubuntu Apache manages sites and modules with helper commands that create symlinks in sites-enabled/ and mods-enabled/. You write config in sites-available/, then enable it — rather than editing one big config file.

# Create a site config
vim /etc/apache2/sites-available/mysite.conf

# Enable the site (creates symlink in sites-enabled/)
a2ensite mysite.conf
# Disable the site
a2dissite mysite.conf

# Enable a module (e.g. proxy for reverse proxying)
a2enmod proxy proxy_http
# Disable a module
a2dismod proxy

# Reload Apache to pick up changes
systemctl reload apache2

On RHEL-like systems there is no a2ensite — drop .conf files directly into /etc/httpd/conf.d/ and they are loaded automatically. Use LoadModule lines in httpd.conf or conf.d to enable modules.

Workflow on Debian: always use a2ensite / a2dissite rather than creating symlinks manually. These tools also run basic checks and display the correct reload command.

VirtualHost example — static site

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/html
</VirtualHost>

Responds on port 80 for example.com and serves files from /var/www/html.

VirtualHost example — reverse proxy

<VirtualHost *:80>
    ServerName app.example.com
    ProxyPreserveHost On
    ProxyPass        / http://127.0.0.1:8080/
    ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>

Forwards all requests to a backend on localhost port 8080. Requires mod_proxy and mod_proxy_http to be enabled.

Useful commands

apachectl configtest

apachectl configtest

Checks config syntax. Always run this before restarting. Reports Syntax OK if valid.

VirtualHost — SSL/TLS

# RHEL: /etc/httpd/conf.d/mysite-ssl.conf
# Debian: /etc/apache2/sites-available/mysite-ssl.conf
<VirtualHost *:443>
    ServerName example.com

    SSLEngine on
    SSLCertificateFile      /etc/pki/tls/certs/example.com.crt
    SSLCertificateKeyFile   /etc/pki/tls/private/example.com.key
    SSLCertificateChainFile /etc/pki/tls/certs/example.com-chain.crt

    # Recommended: disable old TLS and weak ciphers
    SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1
    SSLCipherSuite          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
    SSLHonorCipherOrder     off
    Header always set Strict-Transport-Security "max-age=63072000"

    DocumentRoot /var/www/html/example.com
    <Directory /var/www/html/example.com>
        Options -Indexes
        AllowOverride None
        Require all granted
    </Directory>

    ErrorLog  /var/log/httpd/example.com-error.log
    CustomLog /var/log/httpd/example.com-access.log combined
</VirtualHost>

# HTTP → HTTPS redirect (separate VirtualHost)
<VirtualHost *:80>
    ServerName example.com
    Redirect permanent / https://example.com/
</VirtualHost>

On Debian: a2enmod ssl headers then a2ensite mysite-ssl then systemctl reload apache2. On RHEL: drop the file in /etc/httpd/conf.d/ and systemctl reload httpd. The headers module is required for Header always set.

mod_rewrite basics

mod_rewrite rewrites incoming URLs before Apache processes or proxies them. Enable it on RHEL with LoadModule rewrite_module modules/mod_rewrite.so (usually already loaded) or on Debian with a2enmod rewrite.

<VirtualHost *:443>
    ServerName example.com
    RewriteEngine On

    # Remove trailing slash from paths (except root)
    RewriteCond %{REQUEST_URI} ^/(.+)/$
    RewriteRule ^/(.+)/$ /$1 [R=301,L]

    # Redirect /old-path to /new-path
    RewriteRule ^/old-path/?$ /new-path [R=301,L]

    # Redirect /api/ requests to a different backend
    RewriteRule ^/api/(.*)$ http://127.0.0.1:9000/$1 [P,L]
    # [P] = proxy (needs mod_proxy); [R] = redirect; [L] = last rule
</VirtualHost>

Flags: R=301 sends a permanent redirect to the client. P proxies transparently (client never sees the new URL). L stops processing further rules. Always test rewrites with apachectl configtest and check with curl -I.

Tip: Use RewriteLog (Apache 2.2) or LogLevel alert rewrite:trace3 (Apache 2.4) to trace exactly how rules match during debugging.

MPM — process model

Apache's Multi-Processing Module determines how it handles concurrent connections. The two that matter in practice:

MPM Model Use when
preforkOne process per requestRunning non-thread-safe modules (e.g. mod_php with older PHP)
eventThread pool + async keep-aliveModern installs; far lower memory under load
# Check which MPM is active
httpd -V | grep MPM      # RHEL
apache2 -V | grep MPM    # Debian

# Switch MPM on Debian (disables prefork, enables event)
a2dismod mpm_prefork
a2enmod  mpm_event
systemctl restart apache2

On RHEL the MPM is set via LoadModule lines in /etc/httpd/conf.modules.d/00-mpm.conf. Comment out one and uncomment the other, then restart. If you are proxying to PHP-FPM (recommended for modern PHP) you should be on event MPM.

apachectl -S

apachectl -S

Shows how Apache resolved VirtualHosts — which config applies to which hostname. Very useful when the wrong site is being served or a VirtualHost is not being picked up.

Service checks

systemctl status httpd         # RHEL
systemctl status apache2       # Debian
journalctl -u httpd -n 50      # RHEL
journalctl -u apache2 -n 50   # Debian

Troubleshooting