Apache Basics
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.
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.
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 |
|---|---|---|
prefork | One process per request | Running non-thread-safe modules (e.g. mod_php with older PHP) |
event | Thread pool + async keep-alive | Modern 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
- Config test:
apachectl configtest - VirtualHost resolution:
apachectl -S - Module enabled:
a2enmod proxy proxy_http(Debian) or checkconf.d/forLoadModulelines (RHEL) - Permissions on
DocumentRoot— can Apache read the files? - SELinux context —
ls -lZon the document root - Cert path correct if using TLS
- Backend reachable if proxying