Skip to main content

NGINX

NGINX FancyIndex: Beautiful Directory Listings

by ,


We have by far the largest RPM repository with NGINX module packages and VMODs for Varnish. If you want to install NGINX, Varnish, and lots of useful performance/security software with smooth yum upgrades for production use, this is the repository for you.
Active subscription is required.

NGINX’s built-in autoindex module generates directory listings that look like they belong in the 1990s. Plain text, no styling, no sorting controls, and no way to customize the appearance. If you serve files for download — software packages, documentation, media archives, or shared project assets — you need NGINX FancyIndex.

The NGINX FancyIndex module (ngx_http_fancyindex_module) replaces autoindex with beautiful, fully customizable directory listings. It adds sortable columns, human-readable file sizes, custom headers and footers, CSS theming, and regex-based file filtering. In this comprehensive guide, you will learn how to install, configure, and customize NGINX FancyIndex to create professional directory listings on your server.

NGINX FancyIndex vs. Autoindex: Why Switch?

NGINX ships with the autoindex module for directory listings. However, it offers only four configuration directives: autoindex, autoindex_format, autoindex_localtime, and autoindex_exact_size. That is it — no custom styling, no clickable sort headers, and no file filtering.

In contrast, NGINX FancyIndex provides 15 directives that give you complete control over directory listing appearance and behavior:

Feature autoindex FancyIndex
Sortable columns No Yes (clickable headers)
Custom CSS styling No Yes (fancyindex_css_href)
Custom headers/footers No Yes (local files or subrequests)
Hide specific files No Yes (regex patterns)
Hide dotfiles No Yes (fancyindex_show_dotfiles)
Hide symlinks No Yes (fancyindex_hide_symlinks)
Directories-first sorting No Yes (fancyindex_directories_first)
Custom time format No Yes (fancyindex_time_format)
Hide parent directory link No Yes (fancyindex_hide_parent_dir)

If you need anything beyond a bare-bones file list, NGINX FancyIndex is the clear upgrade.

How NGINX FancyIndex Works

When a request arrives for a directory path (ending with /), NGINX FancyIndex intercepts it and generates an HTML table listing all files and subdirectories. The module reads the directory contents from the filesystem, then collects file metadata (name, size, modification time). After that, it sorts entries according to your configuration and renders a styled HTML response.

The generated HTML includes:

  • A <table> with clickable column headers for File Name, File Size, and Date
  • Proper HTML entity escaping for filenames (preventing XSS attacks)
  • URI-encoded links for files with special characters
  • Optional custom header and footer sections
  • An optional external CSS stylesheet link

Users can sort the listing interactively by clicking column headers, which appends URL parameters like ?C=S&O=D (sort by Size, Descending order).

Installing NGINX FancyIndex

The easiest way to install NGINX FancyIndex is through the GetPageSpeed repository, which provides pre-built packages for RHEL-based distributions.

RHEL, CentOS, AlmaLinux, Rocky Linux 8+, Fedora, Amazon Linux 2023+

sudo dnf install https://extras.getpagespeed.com/release-latest.rpm
sudo dnf install nginx-module-fancyindex

CentOS/RHEL 7 and Amazon Linux 2

sudo yum install https://extras.getpagespeed.com/release-latest.rpm
sudo yum install nginx-module-fancyindex

Loading the Module

After installation, add the load_module directive at the top of your /etc/nginx/nginx.conf file (before the events block):

load_module modules/ngx_http_fancyindex_module.so;

Verify the configuration is valid:

sudo nginx -t

You should see:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Then reload NGINX to activate the module:

sudo systemctl reload nginx

Ubuntu and Debian installation of FancyIndex NGINX module

Simply set up our APT repository and then run:

sudo apt-get update
sudo apt-get install nginx-module-fancyindex

The module is automatically enabled.

Basic NGINX FancyIndex Configuration

The simplest NGINX FancyIndex configuration enables directory listings with human-readable file sizes:

location /downloads/ {
    fancyindex on;
    fancyindex_exact_size off;
}

This replaces the autoindex on directive you may already have. The directory listing now displays a styled HTML table with sortable columns and file sizes shown as “5.0 MiB” instead of raw byte counts like “5242880”.

Complete NGINX FancyIndex Directive Reference

NGINX FancyIndex provides 15 directives, all available in http, server, and location contexts. Here is a detailed reference for every directive.

fancyindex

Syntax: fancyindex on | off;
Default: off

Enables or disables the FancyIndex directory listing for the current context. When enabled, it replaces NGINX’s built-in autoindex module.

fancyindex_default_sort

Syntax: fancyindex_default_sort name | size | date | name_desc | size_desc | date_desc;
Default: name

Sets the default sort criterion for directory listings. The _desc variants sort in descending order. Users can override this by clicking column headers in the browser, which appends ?C=N&O=A (Name, Ascending) or similar parameters to the URL.

fancyindex_directories_first

Syntax: fancyindex_directories_first on | off;
Default: on

When enabled, directories are grouped together and listed before files, regardless of the sort criterion. This is the default behavior and matches what most users expect from a file manager.

fancyindex_exact_size

Syntax: fancyindex_exact_size on | off;
Default: on

Controls file size display format. When on, sizes are displayed in exact bytes (e.g., 5242880). When off, sizes are shown in human-readable format (e.g., 5.0 MiB). For most use cases, setting this to off produces a cleaner listing.

fancyindex_localtime

Syntax: fancyindex_localtime on | off;
Default: off

When off, file modification times are displayed in GMT/UTC. When on, times use the server’s local timezone. Enable this if your users are primarily in the same timezone as the server.

fancyindex_time_format

Syntax: fancyindex_time_format string;
Default: "%Y-%b-%d %H:%M"

Custom format string for file timestamps. Supports standard strftime specifiers, but uses locale-independent English month and day names. Common format specifiers include:

Specifier Output Example
%Y Four-digit year 2026
%m Two-digit month 02
%b Abbreviated month Feb
%B Full month name February
%d Day of month (01-31) 06
%H Hour (00-23) 14
%M Minute (00-59) 30
%S Second (00-59) 45

Example using ISO-style dates:

fancyindex_time_format "%Y-%m-%d %H:%M";

fancyindex_show_path

Syntax: fancyindex_show_path on | off;
Default: on

Controls whether the directory path is displayed as an <h1> heading above the file listing. Disable this when using a custom header that already shows the path.

fancyindex_show_dotfiles

Syntax: fancyindex_show_dotfiles on | off;
Default: off

Controls whether files and directories starting with a dot (.) are visible in the listing. Hidden files like .htaccess, .git, and .env are excluded by default for security reasons. Only enable this if you specifically need to expose hidden files.

fancyindex_hide_parent_dir

Syntax: fancyindex_hide_parent_dir on | off;
Default: off

When enabled, the “Parent directory/” link at the top of the listing is hidden. This is useful for root-level download directories where navigating to the parent is unnecessary or undesirable.

Syntax: fancyindex_hide_symlinks on | off;
Default: off

When enabled, symbolic links are hidden from directory listings. This can improve security by preventing users from discovering filesystem structure through symlink targets.

fancyindex_ignore

Syntax: fancyindex_ignore pattern ...;
Default: none

Specifies one or more patterns for files to exclude from the listing. When NGINX is compiled with PCRE (which is the standard for GetPageSpeed packages), patterns are treated as regular expressions.

Without PCRE, patterns are matched as exact filenames instead.

# Hide version control directories and backup files
fancyindex_ignore "\.git" "\.svn" "~$" "\.bak$";

Important: Since patterns are regular expressions when PCRE is available, use proper regex syntax. For example, \.bin$ matches files ending in .bin, while *.bin would cause a configuration error because * is not valid at the start of a regex.

fancyindex_css_href

Syntax: fancyindex_css_href uri;
Default: ""

Specifies a URI for a custom CSS stylesheet that is added as a <link> tag in the page header. The default built-in styles remain in place, so your custom CSS can selectively override them.

fancyindex_css_href "/assets/fancyindex.css";

The default styles use these CSS selectors that you can customize:

  • #list — the main table element
  • thead th — table header cells
  • .link — filename column cells
  • .size — file size column cells
  • .date — date column cells
  • tr:nth-child(even) — alternating row colors

fancyindex_header

Syntax: fancyindex_header path [local];
Default: ""

Inserts custom HTML content before the directory listing. The path argument specifies either a URI (for subrequest mode) or a filesystem path (for local mode).

Subrequest mode (default): The path is treated as a URI, and NGINX fetches it via an internal subrequest. This allows dynamic content generation through other NGINX modules or backend services:

fancyindex_header /includes/header.html;

Local mode: The file is read at configuration time and embedded directly. Use an absolute filesystem path:

fancyindex_header /etc/nginx/fancyindex/header.html local;

Syntax: fancyindex_footer path [local];
Default: ""

Inserts custom HTML content after the directory listing. Works identically to fancyindex_header with both subrequest and local modes.

fancyindex_footer /includes/footer.html;

fancyindex_name_length

Syntax: fancyindex_name_length number;
Default: 50

Sets the maximum display length for filenames in the listing. Files with names longer than this value are truncated with an ellipsis in the display. The full filename remains accessible as a link title attribute.

Practical NGINX FancyIndex Configuration Examples

File Download Server

This NGINX FancyIndex configuration is ideal for a public file download server with clean organization:

server {
    listen 80;
    server_name files.example.com;
    root /var/www/files;

    location / {
        fancyindex on;
        fancyindex_exact_size off;
        fancyindex_localtime on;
        fancyindex_default_sort name;
        fancyindex_directories_first on;
        fancyindex_hide_symlinks on;
        fancyindex_time_format "%Y-%m-%d %H:%M";
        fancyindex_ignore "\.git" "\.svn" "\.DS_Store" "Thumbs\.db";
    }
}

RPM/Package Repository

For hosting software packages, sort by date to show the latest versions first:

location /packages/ {
    fancyindex on;
    fancyindex_exact_size on;
    fancyindex_default_sort date_desc;
    fancyindex_directories_first on;
    fancyindex_hide_parent_dir on;
    fancyindex_ignore "repodata" "\.sqlite" "\.xml\.gz";
}

Custom-Themed Directory Listing

For a branded download page with custom header, footer, and CSS:

location /downloads/ {
    fancyindex on;
    fancyindex_exact_size off;
    fancyindex_localtime on;
    fancyindex_show_path off;
    fancyindex_header /includes/download-header.html;
    fancyindex_footer /includes/download-footer.html;
    fancyindex_css_href "/assets/fancyindex-theme.css";
    fancyindex_ignore "\.git" "\.svn";
}

The header file (/includes/download-header.html) could contain:

<div style="max-width: 960px; margin: 0 auto; padding: 20px;">
  <h1>Download Center</h1>
  <p>Browse and download files from our repository.</p>
</div>

Creating a Custom CSS Theme for NGINX FancyIndex

The default NGINX FancyIndex theme is functional but plain. However, you can create a modern-looking directory listing with a custom CSS file. Here is a starting point:

body {
    max-width: 960px;
    margin: 0 auto;
    padding: 20px;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    background: #fafafa;
}

h1 {
    color: #333;
    border-bottom: 2px solid #e0e0e0;
    padding-bottom: 10px;
}

#list {
    border: none;
    border-collapse: collapse;
    width: 100%;
}

#list thead th {
    background: #f5f5f5;
    padding: 12px 16px;
    border-bottom: 2px solid #ddd;
    font-size: 14px;
}

#list tbody td {
    padding: 10px 16px;
    border-bottom: 1px solid #eee;
}

#list tbody tr:hover {
    background: #f0f7ff;
}

#list a {
    color: #0366d6;
    text-decoration: none;
}

#list a:hover {
    text-decoration: underline;
}

Save this as a static file within your web root (e.g., /assets/fancyindex-theme.css) and reference it with fancyindex_css_href.

Here are three example themes to inspire your own NGINX FancyIndex customization. Each theme uses only fancyindex_css_href — no custom headers or footers required.

Modern Light Theme — Clean typography with uppercase headers and subtle hover effects:

NGINX FancyIndex directory listing with a clean modern CSS theme

Dark Theme (Tokyo Night) — A developer-friendly dark color scheme with monospace fonts:

NGINX FancyIndex directory listing with a dark Tokyo Night CSS theme

GitHub-Style Theme — Mimics the familiar GitHub repository file browser:

NGINX FancyIndex directory listing styled like GitHub repository file browser

All three themes above use the exact same NGINX FancyIndex configuration — the only difference is the CSS file referenced by fancyindex_css_href. This demonstrates how a single directive can completely transform the look of your directory listings.

NGINX FancyIndex Security Considerations

Directory listings expose your server’s file structure to visitors. Therefore, follow these security best practices when using NGINX FancyIndex:

Keep dotfiles hidden. The default fancyindex_show_dotfiles off setting prevents exposure of configuration files like .env, .htaccess, and .git directories. Do not enable this directive unless you have a specific reason.

Hide symbolic links when possible. Symlinks can reveal filesystem paths and internal server structure. Use fancyindex_hide_symlinks on unless your directory listing specifically requires symlink visibility.

Filter sensitive files. Use fancyindex_ignore to exclude files that should not be visible:

fancyindex_ignore "\.env" "\.htpasswd" "\.key$" "\.pem$" "\.log$";

Restrict access. Combine FancyIndex with NGINX access control directives to limit who can browse directories:

location /internal-files/ {
    fancyindex on;
    fancyindex_exact_size off;
    allow 10.0.0.0/8;
    deny all;
}

Add security headers. Consider using the NGINX security headers module to add Content-Security-Policy and X-Frame-Options headers to your directory listings. This prevents clickjacking and injection attacks.

You can always validate your NGINX configuration for security issues using the free NGINX config checker.

Troubleshooting NGINX FancyIndex

“unknown directive fancyindex”

This error means the module is not loaded. Verify that you have the load_module directive at the top of your nginx.conf:

load_module modules/ngx_http_fancyindex_module.so;

The load_module directive must appear before the events block.

403 Forbidden Instead of Directory Listing

If you get a 403 error, check:

  1. File permissions: NGINX worker process (typically running as nginx user) must have read and execute permissions on the directory:
sudo chmod 755 /path/to/directory
sudo chmod 644 /path/to/directory/*
  1. No conflicting index directive: If an index directive points to a nonexistent file, NGINX returns 403 before FancyIndex can handle the request. Either create the index file or remove the index directive for that location.

  • SELinux context: On RHEL-based systems, files must have the correct SELinux context:

  • sudo restorecon -Rv /path/to/directory
    

    fancyindex_ignore Pattern Errors

    If you see pcre2_compile() failed: quantifier does not follow a repeatable item, you are using glob syntax instead of regular expressions. FancyIndex patterns use PCRE regex:

    # Wrong - glob syntax
    fancyindex_ignore "*.log";
    
    # Correct - regex syntax
    fancyindex_ignore "\.log$";
    

    When using subrequest mode (the default), the header/footer path must be accessible as a URI within NGINX. Ensure the file exists within the web root and is served by a location block. For filesystem paths, use local mode with an absolute path:

    fancyindex_header /etc/nginx/fancyindex/header.html local;
    

    NGINX FancyIndex Performance Impact

    NGINX FancyIndex has minimal performance overhead. The module reads directory contents at request time (just like autoindex), sorts entries in memory, and generates HTML output. For directories with thousands of files, sorting adds negligible latency compared to the filesystem I/O of reading directory entries.

    For extremely large directories (10,000+ files), consider these optimizations:

    • Splitting files into subdirectories to reduce listing size
    • Using fancyindex_ignore to filter unnecessary files
    • Enabling fancyindex_hide_symlinks to skip lstat() calls on symlinks

    Version Notes

    The GetPageSpeed repository packages NGINX FancyIndex v0.5.2, which is the latest stable release. This version includes all directives documented above, including fancyindex_name_length.

    The upstream master branch on GitHub has diverged from v0.5.2 with two notable changes that have not yet been included in any official release:

    • Added fancyindex_case_sensitive (January 2021) — allows case-insensitive filename sorting. This directive is available only in unreleased development builds.
    • Removed fancyindex_name_length (October 2021) — replaced by CSS-based truncation using text-overflow: ellipsis. The packaged v0.5.2 still includes this directive.

    If you need case-insensitive sorting, you would need to build the module from the master branch. For most users, the stable v0.5.2 package provides everything needed.

    Conclusion

    The NGINX FancyIndex module transforms bare-bones directory listings into professional, user-friendly file browsers. With 15 configuration directives covering sorting, filtering, theming, and custom content injection, it provides everything you need for a polished download page — without requiring any backend application.

    Moreover, NGINX FancyIndex integrates seamlessly with existing NGINX configurations. You can combine it with access control, security headers, and custom themes to create a complete file serving solution.

    Install NGINX FancyIndex from the GetPageSpeed repository and start creating beautiful directory listings on your server today. The module source code is available on GitHub.

    D

    Danila Vershinin

    Founder & Lead Engineer

    NGINX configuration and optimizationLinux system administrationWeb performance engineering

    10+ years NGINX experience • Maintainer of GetPageSpeed RPM repository • Contributor to open-source NGINX modules

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    You may use these HTML tags and attributes:

    <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

    This site uses Akismet to reduce spam. Learn how your comment data is processed.