Directory listing lets anyone browse filenames and subdirectories when a request lands on a folder that does not contain a default index file. That can expose backups, exported data, temporary uploads, or source trees that were never meant to be reachable from the web.
Apache serves directory requests in two stages. mod_dir checks whether the requested directory contains a configured DirectoryIndex file such as index.html or index.php, and if no index file exists a generated listing appears only when the effective Options set still includes Indexes and mod_autoindex is loaded.
Examples below use the Debian and Ubuntu layout with /etc/apache2/, apache2ctl, and the apache2 service. The normal hardening path is to remove Indexes in server configuration for the specific directory or vhost, while disabling mod_autoindex is a server-wide choice and .htaccess should be kept for cases where you cannot edit the main Apache config directly.
Related: How to disable access to a directory in Apache
Related: How to deny access to sensitive files in Apache
Related: How to disable Apache directory listing in cPanel
Adding more filenames to DirectoryIndex can reduce accidental exposure, but it does not disable listing when a directory still has no matching index file and Indexes remains enabled.
Methods to disable directory listing in Apache:
Prefer Options -Indexes in a VirtualHost, <Directory> block, or dedicated conf snippet. Disable mod_autoindex only when no site on the server should ever expose an auto-generated directory index.
Disabling mod_autoindex removes Apache's generated directory index handler for the whole server. Use this method when directory browsing is unwanted everywhere, not when one site still needs auto-generated listings.
$ sudo a2dismod --force autoindex Module autoindex disabled. To activate the new configuration, you need to run: service apache2 restart
On platforms without a2dismod, disable the autoindex_module load line in the active Apache module configuration, then restart the service.
$ sudo apache2ctl configtest Syntax OK
The common AH00558 warning about a missing global ServerName is not a syntax failure.
Related: How to test Apache configuration
$ sudo systemctl restart apache2
On current Debian and Ubuntu systems, systemctl restart apache2 is the normal equivalent of the service apache2 restart hint printed by a2dismod.
$ curl -I -sS -H 'Host: host.example.net' http://127.0.0.1/downloads/ HTTP/1.1 404 Not Found Date: Wed, 08 Apr 2026 04:42:39 GMT Server: Apache/2.4.58 (Ubuntu) Content-Type: text/html; charset=iso-8859-1
Use a path that genuinely has no DirectoryIndex match such as index.html or index.php. In current Debian or Ubuntu package verification, removing mod_autoindex changed the same directory request from a 200 OK listing to 404 Not Found.
Removing Indexes from the effective Options set is the normal per-site hardening approach. It blocks directory browsing for the chosen path while leaving mod_autoindex available for other sites or directories that still need it.
$ sudo vi /etc/apache2/sites-available/000-default.conf
The same change can live in a vhost file or a dedicated include under /etc/apache2/conf-available/ when you prefer to keep hardening rules separate from the site definition.
<Directory /var/www/html/downloads> Options Indexes FollowSymLinks </Directory>
<Directory /var/www/html/downloads> Options -Indexes </Directory>
Because every option in the second example uses a + or - modifier, Apache merges it with the inherited options instead of replacing the entire set. If the block already uses relative syntax, add -Indexes there instead of rewriting unrelated flags.
$ sudo apache2ctl configtest Syntax OK
Related: How to test Apache configuration
$ sudo systemctl reload apache2
$ curl -I -sS -H 'Host: host.example.net' http://127.0.0.1/downloads/ HTTP/1.1 403 Forbidden Date: Wed, 08 Apr 2026 04:42:39 GMT Server: Apache/2.4.58 (Ubuntu) Content-Type: text/html; charset=iso-8859-1
A 403 Forbidden response is the normal result when Apache reaches the directory but is no longer allowed to generate an index. If you still see 200 OK, the request is likely hitting a different vhost or a different <Directory> rule than the one you edited.
A .htaccess file is useful when shared hosting or delegated site management prevents you from editing the main Apache configuration directly. It works only when the matching <Directory> block allows Options overrides, and it adds per-request filesystem checks that are better avoided on servers where you can edit the vhost normally.
<Directory /var/www/html/downloads> AllowOverride Options </Directory>
If AllowOverride None remains in effect, Apache ignores the directory's .htaccess file completely and the directory listing stays available.
Keep the override scoped to the real site path rather than the global <Directory "/"> block.
$ sudo apache2ctl configtest Syntax OK $ sudo systemctl reload apache2
Related: How to test Apache configuration
$ sudo vi /var/www/html/downloads/.htaccess
Options -Indexes
Apache 2.4 reads this file on the next request once AllowOverride Options is active, so a second reload is not required for the .htaccess file itself.
Use the relative form -Indexes. Mixing + or - modifiers with plain Options values is invalid syntax.
$ curl -I -sS -H 'Host: host.example.net' http://127.0.0.1/downloads/ HTTP/1.1 403 Forbidden Date: Wed, 08 Apr 2026 04:42:39 GMT Server: Apache/2.4.58 (Ubuntu) Content-Type: text/html; charset=iso-8859-1
If the request still returns 200 OK with a directory index, the usual cause is that the wrong path was matched in <Directory> or AllowOverride is still effectively None higher in the config tree.