Apache httpd configuration basics: files, directives, sections

Updated November 2026

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.

Main file and include folders
SystemMain filePulled in from
Upstream / source build/usr/local/apache2/conf/httpd.confconf/extra/*.conf (commented-out Include lines)
Debian, Ubuntu/etc/apache2/apache2.confmods-enabled/, ports.conf, conf-enabled/, sites-enabled/
RHEL, Fedora/etc/httpd/conf/httpd.confconf.modules.d/*.conf first, conf.d/*.conf at the end
openSUSE/etc/apache2/httpd.confconf.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

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 443 for 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.html becomes /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-data on Debian, apache on 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:

SectionMatchesTypical use
<Directory "/var/www/html">a folder on disk and everything below itaccess rules, Options, AllowOverride
<Files "secret.txt">, <FilesMatch>file names, in any folderblocking backups or dot-files
<Location "/server-status">a URL path, whether or not a file existshandlers, proxying
<If "expression">a condition checked on every requestrules based on headers, host name, method
<VirtualHost *:80>one website (see Virtual hosts)per-site settings
<IfModule>, <IfDefine>, <IfVersion>checked once at startupoptional 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:

1. Directory+ .htaccess 2. DirectoryMatch (regex) 3. FilesFilesMatch 4. LocationLocationMatch 5. Ifwins last later steps override earlier ones · VirtualHost sections merge after the main server
The order in which httpd 2.4 merges configuration sections for a request.

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

  1. Copy the file first (sudo cp example.com.conf example.com.conf.bak), or keep /etc/apache2 or /etc/httpd in git.
  2. Make one change at a time.
  3. Run sudo apachectl configtest.
  4. Reload, not restart: sudo systemctl reload apache2 (or httpd). A graceful reload lets running requests finish.
  5. Test with curl -I and watch the error log (sudo tail -f /var/log/apache2/error.log or /var/log/httpd/error_log).

Common mistakes

Sources