Apache Cheatsheet
Apache HTTP Server at a glance: service commands, file layout on Ubuntu and RHEL, virtual hosts, modules, .htaccess, redirects, TLS, reverse proxy, and log formats.
Apache is packaged as apache2 on Ubuntu and Debian and as httpd on Fedora and RHEL, with different file layouts and helper tools. This cheatsheet covers service and apachectl commands, configuration paths on both families, virtual hosts, modules, directory access and .htaccess, redirects, TLS, reverse proxy settings, access control, caching, logging, and common startup errors.
Service and CLI Commands
Use apache2 on Ubuntu and Debian, httpd on Fedora and RHEL.
| Command | Description |
|---|---|
sudo systemctl reload apache2 | Apply a new configuration with a graceful restart |
sudo systemctl restart apache2 | Stop and start the service |
sudo systemctl start apache2 | Start the service |
sudo systemctl stop apache2 | Stop the service |
sudo systemctl status apache2 | Show the service state and recent log lines |
sudo systemctl enable --now httpd | Start now and at every boot on Fedora and RHEL |
sudo apachectl configtest | Test the configuration for syntax errors |
sudo apachectl -t -D DUMP_INCLUDES | List every configuration file that is loaded |
sudo apachectl graceful | Restart workers after current requests finish |
sudo apachectl graceful-stop | Stop after current requests finish |
apachectl -v | Print the version |
apachectl -V | Print the version, MPM, and build settings |
Run configtest before every reload. On Ubuntu and Debian, call apache2ctl or apachectl rather than the apache2 binary, which needs the variables from /etc/apache2/envvars. On Fedora and RHEL, use sudo httpd -t -D DUMP_INCLUDES, httpd -v, and httpd -V for these diagnostic options; the packaged apachectl does not forward arbitrary arguments to httpd.
Configuration Layout
The two package families lay out the configuration differently.
| Path | Description |
|---|---|
/etc/apache2/apache2.conf | Main file on Ubuntu and Debian |
/etc/apache2/ports.conf | Listen directives on Ubuntu and Debian |
/etc/apache2/sites-available/ | Virtual host files on Ubuntu and Debian |
/etc/apache2/mods-available/ | Module load and config snippets |
/etc/apache2/conf-available/ | Global config snippets |
/etc/httpd/conf/httpd.conf | Main file on Fedora and RHEL |
/etc/httpd/conf.d/*.conf | Virtual hosts and snippets on Fedora and RHEL |
/etc/httpd/conf.modules.d/ | Module loading on Fedora and RHEL |
/var/www/html | Default document root on both |
/var/log/apache2/ | Logs on Ubuntu and Debian |
/var/log/httpd/ | Logs on Fedora and RHEL |
Apache runs as www-data on Ubuntu and Debian and as apache on Fedora and RHEL. Give that user read access to the document root.
Sites, Modules, and Config Snippets
Ubuntu and Debian helpers that manage the *-enabled symlinks. Before switching MPMs, migrate to PHP-FPM and disable mod_php if it is enabled.
| Command | Description |
|---|---|
sudo a2ensite example.com | Enable example.com.conf |
sudo a2dissite 000-default | Disable the default site |
sudo a2enmod rewrite | Enable a module |
sudo a2dismod autoindex | Disable a module |
sudo a2enconf servername | Enable servername.conf |
sudo a2disconf serve-cgi-bin | Disable a config snippet |
sudo apachectl -M | List loaded modules |
sudo apachectl -S | List virtual hosts and which one is the default |
sudo a2dismod mpm_prefork && sudo a2enmod mpm_event | Switch to event; test and restart afterward |
Site files must end in .conf. After an MPM change, run configtest and restart the service. Fedora and RHEL use conf.d/ for snippets and LoadModule lines in conf.modules.d/. Inspect modules with sudo httpd -M and virtual hosts with sudo httpd -S.
Virtual Hosts
Directives that decide which site answers a request.
| Directive | Description |
|---|---|
<VirtualHost *:80> ... </VirtualHost> | Define a site on port 80 |
ServerName example.com | Primary host name for the site |
ServerAlias www.example.com *.example.com | Additional host names |
DocumentRoot /var/www/example.com/public_html | Directory served for the site |
DirectoryIndex index.html index.php | File served when a directory is requested |
ServerAdmin webmaster@example.com | Address shown on some error pages |
ErrorLog ${APACHE_LOG_DIR}/example.com-error.log | Per-site error log on Ubuntu and Debian |
CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined | Per-site access log |
Listen 8080 | Accept connections on another port |
When no ServerName or ServerAlias matches, Apache serves the first virtual host defined for that address and port. On Ubuntu and Debian that is usually 000-default.conf, because files load in alphabetical order.
Directory Access and .htaccess
Control what Apache may serve from a directory and what .htaccess may change.
| Directive | Description |
|---|---|
<Directory /var/www/example.com> ... </Directory> | Apply settings to a directory tree |
Require all granted | Allow access |
Require all denied | Deny access |
Options -Indexes | Turn off directory listings |
Options +FollowSymLinks | Follow symbolic links |
AllowOverride None | Ignore .htaccess files |
AllowOverride All | Let .htaccess override any directive |
AllowOverride FileInfo AuthConfig | Allow rewrites and auth only |
<FilesMatch "\.(env|ini|log)$">Require all denied</FilesMatch> | Block sensitive file types |
.htaccess is read on every request in every parent directory, which costs performance. Put rules in the virtual host when you control the server, and keep AllowOverride None where .htaccess is not needed.
Redirects and Rewrites
Redirect comes from mod_alias. The Rewrite* directives need a2enmod rewrite.
| Directive | Description |
|---|---|
Redirect permanent / https://example.com/ | 301 redirect that keeps the path |
Redirect 302 /old /new | Temporary redirect for one path |
RedirectMatch 301 ^/blog/(.*)$ /news/$1 | Regex redirect that keeps the tail |
RewriteEngine On | Enable the rewrite engine for this context |
RewriteCond %{HTTPS} off | Match only plain HTTP requests |
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] | Redirect to HTTPS |
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] | Match the www host, case-insensitive |
RewriteRule ^ https://%1%{REQUEST_URI} [L,R=301] | Redirect to the bare domain |
RewriteCond %{REQUEST_FILENAME} !-f | Continue only when no file exists |
RewriteRule ^ index.php [L] | Front controller in .htaccess or <Directory> |
Prefer Redirect for plain redirects. In .htaccess, patterns omit the leading slash: ^old/ instead of ^/old/. Use the final two rows together only in .htaccess or <Directory> context, where REQUEST_FILENAME is a filesystem path.
HTTPS and TLS
Terminate TLS on port 443. Enable mod_ssl with sudo a2enmod ssl on Ubuntu and Debian, or install the mod_ssl package on Fedora and RHEL.
| Directive | Description |
|---|---|
<VirtualHost *:443> ... </VirtualHost> | Define the TLS site |
SSLEngine on | Turn on TLS for the virtual host |
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem | Certificate and intermediate chain |
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem | Private key |
SSLProtocol -all +TLSv1.2 +TLSv1.3 | Allow only modern protocol versions |
Protocols h2 http/1.1 | Enable HTTP/2, needs mod_http2 |
Header always set Strict-Transport-Security "max-age=63072000" | Send HSTS, needs mod_headers |
sudo certbot --apache -d example.com -d www.example.com | Issue and install a certificate |
sudo a2ensite default-ssl | Enable the bundled self-signed TLS site |
The prefork MPM severely restricts HTTP/2 concurrency. Prefer mpm_event; if mod_php is enabled, migrate PHP to PHP-FPM and disable mod_php before switching MPMs.
Reverse Proxy
Forward requests to an application. Enable the modules with sudo a2enmod proxy proxy_http headers.
| Directive | Description |
|---|---|
ProxyPass / http://127.0.0.1:3000/ | Forward requests to a local application |
ProxyPassReverse / http://127.0.0.1:3000/ | Rewrite Location headers in redirects |
ProxyPreserveHost On | Pass the original Host header |
RequestHeader set X-Forwarded-Proto "https" | Tell the application TLS was used |
ProxyPass /ws ws://127.0.0.1:3000/ws | Proxy WebSockets, needs mod_proxy_wstunnel |
ProxyPass / http://127.0.0.1:3000/ upgrade=websocket | WebSocket upgrade in mod_proxy_http on 2.4.47+ |
ProxyPass /static ! | Exclude a path from proxying, list it first |
ProxyTimeout 300 | Wait longer for a slow backend |
ProxyRequests Off | Keep forward proxying disabled |
mod_proxy adds X-Forwarded-For, X-Forwarded-Host, and X-Forwarded-Server automatically. Order matters: Apache uses the first ProxyPass that matches, so put specific paths before /.
Access Control and Hardening
Limit who reaches a path and what the server reveals. Use htpasswd -c only for a new file, because it overwrites an existing one.
| Directive | Description |
|---|---|
Require ip 10.0.0.0/8 | Allow a network |
Require not ip 203.0.113.5 | Block an address inside <RequireAll> |
AuthType Basic | Turn on HTTP basic authentication |
AuthName "Restricted" | Realm shown in the login prompt |
AuthUserFile /etc/apache2/.htpasswd | Point to the password file |
Require valid-user | Accept any user in the file |
sudo htpasswd -c /etc/apache2/.htpasswd admin | Create a new password file |
sudo htpasswd /etc/apache2/.htpasswd editor | Add or update a user |
LimitRequestBody 67108864 | Cap request bodies at 64 MB |
ServerTokens Prod | Send only Apache in the Server header |
ServerSignature Off | Remove the version footer from error pages |
TraceEnable Off | Disable the TRACE method |
On Ubuntu and Debian, ServerTokens, ServerSignature, and TraceEnable live in /etc/apache2/conf-available/security.conf.
Compression and Caching
Cut response size with mod_deflate and set browser caching with mod_expires and mod_headers.
| Directive | Description |
|---|---|
sudo a2enmod deflate expires headers | Enable the modules on Ubuntu and Debian |
AddOutputFilterByType DEFLATE text/html text/css application/javascript | Compress these types |
AddOutputFilterByType DEFLATE application/json image/svg+xml | Compress JSON and SVG |
ExpiresActive On | Turn on expiry headers |
ExpiresByType image/webp "access plus 1 month" | Cache images for a month |
ExpiresByType text/css "access plus 1 year" | Cache CSS for a year inside the asset block below |
<Directory /var/www/assets>Header set Cache-Control "public, max-age=31536000, immutable"</Directory> | Cache fingerprinted public assets in this directory |
Header unset ETag | Drop ETags when a CDN or long expiry handles caching |
FileETag None | Stop generating ETags |
The directory must contain only fingerprinted public assets. Keep the one-year CSS expiry and ETag settings in this block, away from HTML and application responses. Do not compress images, archives, or video that are already compressed.
Logging
Choose what gets recorded and where to watch it.
| Directive | Description |
|---|---|
ErrorLog ${APACHE_LOG_DIR}/error.log | Set the error log file |
LogLevel warn | Set the error log level |
LogLevel info ssl:warn rewrite:trace3 | Set levels per module |
CustomLog ${APACHE_LOG_DIR}/access.log combined | Write access logs in the combined format |
LogFormat "%h %t \"%r\" %>s %b %D" timed | Define a custom format named timed |
SetEnvIf Request_URI "^/health$" nolog | Mark health checks |
CustomLog ${APACHE_LOG_DIR}/access.log combined env=!nolog | Skip marked requests |
sudo tail -f /var/log/apache2/error.log | Follow errors live |
sudo journalctl -u apache2 -f | Follow service-level messages |
Error log levels run emerg, alert, crit, error, warn, notice, info, debug, and trace1 to trace8. Use rewrite:trace3 to debug rewrite rules, and turn it off afterward because it logs every request.
Log Format Strings
Placeholders for LogFormat, the Apache counterpart to nginx variables.
| Format | Description |
|---|---|
%h | Client address |
%a | Client IP, after mod_remoteip when it is enabled |
%u | Authenticated user |
%t | Time the request was received |
%r | First line of the request |
%>s | Final status code |
%b | Response size in bytes, - for zero |
%D | Time to serve the request in microseconds |
%T | Time to serve the request in seconds |
%v | Canonical ServerName of the virtual host |
%{Referer}i | Referer request header |
%{User-Agent}i | User-Agent request header |
%{X-Forwarded-For}i | Forwarding chain from a proxy |
The combined format is %h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i".
Common Errors
Startup and request errors you will see in the error log or systemctl status.
| Error | Fix |
|---|---|
AH00558: Could not reliably determine the server's fully qualified domain name | Add ServerName localhost in a config snippet |
AH00072: make_sock: could not bind to address [::]:80 | Another process holds the port; find it with sudo ss -tlnp 'sport = :80' |
Invalid command 'RewriteEngine' | Enable the module with sudo a2enmod rewrite |
Invalid command 'ProxyPass' | Enable proxy and proxy_http |
AH01630: client denied by server configuration | Add Require all granted to the <Directory> block |
403 Forbidden with correct Require | Fix filesystem permissions; Apache needs execute on every parent directory |
.htaccess rules ignored | Set AllowOverride All for that directory |
500 after editing .htaccess | Check the error log for the bad directive |
AH00558 is only a warning. Apache still starts, but the message appears on every reload until ServerName is set.
Firewall
Open HTTP and HTTPS after installing Apache.
| Command | Description |
|---|---|
sudo ufw allow 'Apache Full' | Open ports 80 and 443 with UFW |
sudo ufw allow 'Apache' | Open port 80 only |
sudo ufw allow 'Apache Secure' | Open port 443 only |
sudo ufw app info 'Apache Full' | Show the ports in a profile |
sudo firewall-cmd --permanent --add-service={http,https} | Open both ports with firewalld |
sudo firewall-cmd --reload | Apply the firewalld change |
Related Guides
Use these guides for the longer explanations behind these commands.
| Guide | Description |
|---|---|
Apache Commands: Manage and Troubleshoot Your Web Server | Service, module, and diagnostic commands in detail |
How to Start, Stop, and Restart Apache on Linux | Reload versus restart on each distribution |
How to Install Apache on Ubuntu 26.04 | Installation, firewall rules, and first steps |
How to Set Up Apache Virtual Hosts on Ubuntu | Hosting several sites on one server |
Redirect HTTP to HTTPS in Apache | Redirect and rewrite patterns |
How to Force HTTPS using .htaccess | HTTPS redirects when you cannot edit the virtual host |
Secure Apache with Let's Encrypt | Certbot setup and renewal |
Configuring the Apache Error and Access Logs | Log formats, levels, and rotation |
Nginx Cheatsheet | The same reference for nginx |