Apache httpd configuration basics: files, directives, sections
Apache httpd reads plain text files full of directives when it starts, and only then: change a file and nothing happens until you reload. Each directive sets one thing. Sections such as <Directory> limit a directive to part of the site, and a fixed merge order decides which setting wins. Learn those three ideas and the files on any system make sense.
Where the files are
Every installation has one main file. The others are pulled in with Include lines, so the server sees them as one long file. An included file counts as if its text were pasted where the Include line is.
| System | Main file | Pulled in from |
|---|---|---|
| Upstream / source build | /usr/local/apache2/conf/httpd.conf | conf/extra/*.conf (commented-out Include lines) |
| Debian, Ubuntu | /etc/apache2/apache2.conf | mods-enabled/, ports.conf, conf-enabled/, sites-enabled/ |
| RHEL, Fedora | /etc/httpd/conf/httpd.conf | conf.modules.d/*.conf first, conf.d/*.conf at the end |
| openSUSE | /etc/apache2/httpd.conf | conf.d/, vhosts.d/*.conf and others |
Include fails with an error if a wildcard such as conf.d/*.conf matches no file; IncludeOptional silently skips it. Wildcard matches are read in alphabetical order, which is why file names often start with numbers such as 00-. Relative paths are relative to ServerRoot (/etc/apache2 on Debian, /etc/httpd on RHEL).
The Debian and Ubuntu layout
Debian’s apache2.conf is meant to stay untouched. It includes, in this order:
IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf
Include ports.conf
IncludeOptional conf-enabled/*.conf
IncludeOptional sites-enabled/*.conf
The *-enabled folders contain only symbolic links to files in the matching *-available folders. You never make the links by hand; the helper commands do it:
sudo a2enmod headers # module: mods-available/headers.load
sudo a2dismod autoindex
sudo a2enconf local-servername # conf-available/local-servername.conf
sudo a2ensite example.com # sites-available/example.com.conf
sudo a2dissite 000-default
Only files ending in .conf are included. Debian suggests starting your own snippets in conf-available/ with local- so they never clash with files from packages. ports.conf holds the Listen lines, and envvars sets the variables used in the config (${APACHE_LOG_DIR} is /var/log/apache2, the run user is www-data). Because of those variables, start and test Apache through apache2ctl (or systemctl), never by running /usr/sbin/apache2 directly.
On RHEL and Fedora there are no helper commands: drop a .conf file into /etc/httpd/conf.d/ to add configuration, and comment out a LoadModule line in /etc/httpd/conf.modules.d/ to remove a module. The run user there is apache.
Directive syntax
- One directive per line: the name, a space, then its arguments, for example
KeepAliveTimeout 5. Directive names are not case-sensitive, but their arguments often are. - Put an argument in quotes if it contains spaces:
DocumentRoot "/srv/my site". - A line starting with
#is a comment. A comment may not follow a directive on the same line. - A backslash as the very last character continues the directive on the next line. A space after it breaks this.
- Use forward slashes in paths, even on Windows:
"C:/Apache24/htdocs". - Each directive’s documentation page lists its Context (server config, virtual host, directory, .htaccess). A directive used in the wrong place stops the server from starting.
The directives you set first
Listen 80- The port, and optionally the IP address, to accept connections on. It is required; without any
Listen, httpd will not start. Use several lines for several ports (Listen 443for HTTPS). ServerName www.example.com- The name the server uses for itself, including in redirects it builds. If it is not set globally, httpd guesses from the system host name and logs “AH00558: Could not reliably determine the server's fully qualified domain name … Set the 'ServerName' directive globally to suppress this message”.
DocumentRoot "/var/www/html"- The folder that the URL path is added to:
http://www.example.com/a/b.htmlbecomes/var/www/html/a/b.html. DirectoryIndex index.html- The file served when the URL names a folder (mod_dir). With PHP you would add
index.php. ErrorLog,CustomLog,LogLevel- Where errors and requests are written, and how much detail you get. See Logging.
User/Group- The unprivileged account the worker processes run as (
www-dataon Debian,apacheon RHEL). The parent process starts as root only to open ports 80 and 443.
To silence AH00558 on Debian or Ubuntu, create /etc/apache2/conf-available/local-servername.conf with one line, using your server’s real name:
ServerName www.example.com
then enable it and test:
sudo a2enconf local-servername
sudo apache2ctl configtest
sudo systemctl reload apache2
On RHEL, put the same line in /etc/httpd/conf.d/servername.conf.
Sections: where a directive applies
Directives outside any section apply to the whole server. Sections narrow them down:
| Section | Matches | Typical use |
|---|---|---|
<Directory "/var/www/html"> | a folder on disk and everything below it | access rules, Options, AllowOverride |
<Files "secret.txt">, <FilesMatch> | file names, in any folder | blocking backups or dot-files |
<Location "/server-status"> | a URL path, whether or not a file exists | handlers, proxying |
<If "expression"> | a condition checked on every request | rules based on headers, host name, method |
<VirtualHost *:80> | one website (see Virtual hosts) | per-site settings |
<IfModule>, <IfDefine>, <IfVersion> | checked once at startup | optional parts of a config |
Both default configurations use the same safe pattern, and it is worth keeping: deny the whole disk, then grant only the web folder.
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>
<Directory "/var/www/">
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
If you later move a site to /srv/example.com, you must add a matching <Directory "/srv/example.com"> with Require all granted, or every request gets 403 Forbidden. In old 2.2 configs you may still see Order allow,deny and Allow from all in that place. That is the old syntax; 2.4 uses Require (see Access control).
Use <Directory> and <Files>, not <Location>, to protect files on disk. Several URLs can lead to the same file, and a <Location> rule only covers the one URL you wrote. Keep <IfModule> for configs that really must work with or without a module: wrapped around everything, it hides the error you would want to see when a module is missing.
Merge order: which setting wins
For each request, httpd merges the matching sections in five rounds; a later round overrides an earlier one:
- Plain
<Directory>sections go from the shortest path to the longest, wherever they appear in the files, so/var/www/html/privateoverrides/var/www/html. - Within the other rounds, and for several sections on the same path, the order in the files decides.
- Sections inside a
<VirtualHost>are applied after the same kind of section in the main server, so a site can override global settings. - Because
<Location>comes late, a rule there beats a<Directory>rule for the same request. Remember this when an access rule “does nothing”.
Tools to check your work
sudo apachectl configtest # same as: apachectl -t
sudo apachectl -S # virtual hosts and main paths as parsed
sudo apachectl -M # loaded modules
apachectl -V # version, MPM, compiled-in paths
(Use apache2ctl on Debian and Ubuntu.) A good test prints Syntax OK and exits with code 0. A bad one names the file and line:
AH00526: Syntax error on line 12 of /etc/apache2/sites-enabled/example.com.conf:
Invalid command 'Header', perhaps misspelled or defined by a module not included in the server configuration
That particular message means the module is not loaded: sudo a2enmod headers fixes it on Debian, where mod_headers and mod_rewrite are off by default. RHEL loads both by default. apachectl -M prints one module per line, such as rewrite_module (shared) or core_module (static). apachectl -S ends with the global paths (ServerRoot, Main DocumentRoot, Main ErrorLog), which is a quick way to find the config a server is really using.
A safe routine for every change
- Copy the file first (
sudo cp example.com.conf example.com.conf.bak), or keep/etc/apache2or/etc/httpdin git. - Make one change at a time.
- Run
sudo apachectl configtest. - Reload, not restart:
sudo systemctl reload apache2(orhttpd). A graceful reload lets running requests finish. - Test with
curl -Iand watch the error log (sudo tail -f /var/log/apache2/error.logor/var/log/httpd/error_log).
Common mistakes
- Editing a file that is never read, such as a file in
sites-availablethat was never enabled, or one whose name does not end in.conf.apachectl -Sshows which files the virtual hosts came from. - Two definitions of the same thing. A second
Listen 80line in another file makes the config test fail with “Cannot define multiple Listeners on the same IP:port”. A second program on port 80 gives “Address already in use” at startup instead. - Using .htaccess for everything. When you control the server, put rules in the main config; see .htaccess files.
- Copying 2.2-era snippets.
NameVirtualHostno longer does anything, andOrder/Allow/Denyneed mod_access_compat. See Upgrade 2.2 to 2.4.
Sources
- Configuration Files, Apache httpd 2.4 documentation
- Configuration Sections, Apache httpd 2.4 documentation
- Apache Core Features (Include, IncludeOptional, ServerName, DocumentRoot, Options, AllowOverride), Apache httpd 2.4 documentation
- Apache MPM Common Directives (Listen), Apache httpd 2.4 documentation
- mod_dir, Apache httpd 2.4 documentation
- apachectl, Apache httpd 2.4 documentation
- httpd command-line options, Apache httpd 2.4 documentation
- Stopping and Restarting Apache HTTP Server, Apache httpd 2.4 documentation
- Getting Started, Apache httpd 2.4 documentation
- README.Debian for apache2, Debian Sources
- Debian default apache2.conf, Debian Sources
- apache2 postinst (default modules), Debian Sources
- Fedora default httpd.conf, Fedora Package Sources
- Fedora 00-base.conf (default modules), Fedora Package Sources
- Setting up the Apache HTTP web server, RHEL 10 documentation, Red Hat
- server/util.c (AH00558 message), Apache httpd 2.4.x source
- server/listen.c (duplicate Listen check), Apache httpd 2.4.x source
- Default httpd.conf template, Apache httpd 2.4.x source