Apache directory listings: turn off Indexes or build a file area

Updated November 2026

When a URL points to a folder that has no index.html, Apache httpd can show an automatic "Index of /folder" page listing every file in it. That is handy for a download area and dangerous everywhere else, because it reveals backups, exports and forgotten files. This guide shows how to switch listings off, how to make a deliberate listing look decent, and how to make files download instead of opening in the browser.

When Apache shows a listing

Three things must all be true:

  1. The URL maps to a directory (Apache first redirects /files to /files/).
  2. None of the files named by DirectoryIndex (default index.html; often index.html index.php) exists there.
  3. Options Indexes is in effect for that directory, and mod_autoindex is loaded.

If the third condition fails, the visitor gets 403 Forbidden and the error log says:

AH01276: Cannot serve directory /var/www/html/files/: No matching DirectoryIndex (index.html) found, and server-generated directory index forbidden by Options directive

That message is normal, and it means the protection works.

Listings are on by default. Debian/Ubuntu's apache2.conf has Options Indexes FollowSymLinks for /var/www/, and RHEL/Alma/Rocky's httpd.conf has the same line for /var/www/html. Any folder there without an index file is listed unless you change it.

Turn listings off

Best: remove Indexes in the server configuration, for all sites at once. On Debian/Ubuntu edit /etc/apache2/apache2.conf; on RHEL-family systems /etc/httpd/conf/httpd.conf:

<Directory /var/www/>
    Options FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

Or, in a virtual host or a specific directory, switch off just this one option and keep the rest:

<Directory "/var/www/example.com/public">
    Options -Indexes
</Directory>

Then check and reload:

sudo apache2ctl configtest && sudo systemctl reload apache2   # Debian/Ubuntu
sudo apachectl configtest && sudo systemctl reload httpd      # RHEL family

On shared hosting, put Options -Indexes in .htaccess. That needs AllowOverride Options (or All) for the directory; if it is not allowed you get a 500 error (see .htaccess files).

Two rules about Options trip people up. Options with + or - are merged with the inherited ones, while a line without them replaces the whole set. And mixing the two forms on one line (Options -Indexes FollowSymLinks) is a syntax error that stops Apache from starting.

If no site on the server should ever list a directory, you can remove the module: sudo a2dismod -f autoindex on Debian/Ubuntu (it counts as an essential module, hence -f), or comment out the LoadModule autoindex_module line in /etc/httpd/conf.modules.d/00-base.conf on RHEL. Turning Indexes off is usually enough and survives package updates better.

Test from outside:

curl -s -o /dev/null -w '%{http_code}\n' https://www.example.com/images/
403

A deliberate download area

For a folder you want listed, turn listings on only there and give them a clean layout:

<Directory "/var/www/example.com/public/downloads">
    Options +Indexes
    IndexOptions FancyIndexing HTMLTable FoldersFirst VersionSort NameWidth=* Charset=UTF-8 SuppressDescription
    IndexOrderDefault Descending Date
    HeaderName HEADER.html
    ReadmeName README.html
    IndexIgnore HEADER.html README.html .??* *~ *#
    IndexStyleSheet "/css/listing.css"
</Directory>
FancyIndexing, HTMLTable
Columns for name, date and size with sortable headings, as an HTML table. The documentation says HTMLTable is needed on UTF-8 platforms and for file names that mix left-to-right and right-to-left text.
FoldersFirst, VersionSort
Subfolders on top; tool-1.7.zip sorted before tool-1.12.zip.
NameWidth=*, Charset=UTF-8
Do not cut long names (default is 20 bytes); declare the page encoding.
IndexOrderDefault Descending Date
Newest files first. Visitors can still re-sort with links such as ?C=M;O=D unless you add IgnoreClient.
HeaderName, ReadmeName
Files inserted above and below the list, relative to the folder (or to the document root if they start with /). They must be text/*, usually HTML. If HEADER.html contains its own <html> and <head>, add SuppressHTMLPreamble.
IndexStyleSheet
A CSS file for the listing; with HTMLTable the table has the id indexlist.

IndexOptions merges like Options: IndexOptions +SuppressSize adds to the inherited set, while a keyword without a sign resets it. Debian's /etc/apache2/mods-available/autoindex.conf already sets FancyIndexing VersionSort HTMLTable NameWidth=* DescriptionWidth=* Charset=UTF-8, so there you may only need the extras. In .htaccess, the autoindex directives need AllowOverride Indexes.

Hidden is not protected

IndexIgnore only removes names from the listing. The files can still be downloaded by anyone who knows or guesses the name. With IndexIgnore *.bak, a request for /downloads/db.sql.bak still returns 200. To really block files, deny them, and Apache will also leave them out of the listing:

<FilesMatch "(\.(bak|sql|old|swp)|~)$">
    Require all denied
</FilesMatch>

# version-control folders
RedirectMatch 404 /\.git(/|$)

Better still, keep backups, database dumps and .git folders outside the document root. More in Hardening checklist and Access control.

Also leave DirectorySlash at its default On. The mod_dir documentation warns that with it off and Indexes enabled, a request for a folder without the trailing slash can show the listing even where an index.html exists.

Make files download

Apache picks the Content-Type from the file extension using mime.types (mod_mime). PDFs, images and text open in the browser; a file with an unknown extension is sent without any Content-Type, and the browser has to guess. To change that:

# Add a type Apache does not know (do not edit mime.types itself)
AddType application/x-apple-diskimage .dmg

# Always offer these as downloads
<FilesMatch "\.(?i:pdf|zip|csv|iso)$">
    Header set Content-Disposition "attachment"
</FilesMatch>

# Serve a whole folder as raw bytes
<Directory "/var/www/example.com/public/downloads/raw">
    ForceType application/octet-stream
    Header set X-Content-Type-Options "nosniff"
</Directory>

Content-Disposition: attachment tells the browser to save the file instead of displaying it; you can suggest a name with "attachment; filename=\"report.pdf\"". The Header directive comes from mod_headers: run sudo a2enmod headers on Debian/Ubuntu (it is loaded by default on RHEL). ForceType overrides the type for every file in its scope. In .htaccess all of these need AllowOverride FileInfo. Check the result with:

curl -sI https://www.example.com/downloads/report.pdf | grep -iE 'content-(type|disposition)'
Content-Disposition: attachment
Content-Type: application/pdf

For large public files, a listing plus correct types is all you need. If the files are private, add password protection and serve them over HTTPS only.

Sources