Styling Apache directory listings

In this post you will find how to make stylish listing generated by the Apache server. This is not just another CSS solution. The trick is in configuring Apache to generate XML directory list and to use browser (IE, FF, Opera, Safari ...) to transform XML to the HTML. You will have full freedom to modify and style auto generated directory listings.

Contents
  1. Edit httpd.conf
  2. Create header.html file
  3. Set execute permission to the header.html
  4. Create stylesheet.xsl
  5. Conclusion



1. Edit httpd.conf
Open httpd.conf file and edit IndexOptions and HeaderName directive.

# create XHTML table
IndexOptions XHTML HTMLtable
#  avoid duplicated <html><body> and no column sorting
IndexOptions SuppressHTMLPreamble SuppressColumnSorting
# place folders first
IndexOptions FoldersFirst
# add text/xml HTTP header
IndexOptions Type=text/xml
# define absolute path to the header file
HeaderName /header.html

If you want to have current directory displayed as a page title, please add +Includes to the Options directive - this will enable SSI, but Apache will not parse files until you define SSI files. SSI files can be marked by extension like shtml or by execute bit. In this example, I marked SSI files with execution bit. Don't forget to set execute permission to the SSI file or it will not be processed.

# parse SSI directives in files with the execute bit set
XBitHack on

Check if directory listing is enabled by Indexes option in Options directive.

# The Options directive is both complicated and important. Please see
# http://httpd.apache.org/docs/2.2/mod/core.html#options
# for more information.
Options Indexes ...



2. Create header.html file
header.html contains beginning of the XML listing. The rest of XML will be generated by Apache. XML has defined stylesheet and defined nbsp entity because Apache writes nbsp in emtpy table cells. Last line is a SSI directive, and if you need any other server variable, just wrap it within XML tag.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#160;"> ]>
<?xml-stylesheet type="text/xsl" href="/stylesheet.xsl"?>
<html><body>
<request_uri><!--#echo var="REQUEST_URI" --></request_uri>



3. Set execute permission to the header.html
It is important to set execute permission to the header.html because Apache will process header file and execute line with REQUEST_URI. If you don't need "current directory" info or any other dynamics in header file, you can skip this step and omit +Includes / XBitHack in httpd.conf. On the other hand, if Apache "knows" PHP, and you aren't satisfied with static header.html, you can write PHP header file and you should name it header.php

<? print '<?xml version="1.0" encoding="utf-8"?>' ?>
<? print '<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#160;"> ]>' ?>
<? print '<?xml-stylesheet type="text/xsl" href="/stylesheet.xsl"?>' ?>
<html><body>
<request_uri><?= $_SERVER['REQUEST_URI'] ?></request_uri>

For PHP header file, you don't need +Includes / XBitHack in httpd.conf because Apache has defined PHP interpreter to handle files with a php extension.



4. Create stylesheet.xsl
Here is a simple stylesheet.xsl to process dynamically generated XML. Please save stylesheet.xsl to the document root or change path in the header file. After directory request, Apache will respond with XML. Browser will start to process XML and make request for stylesheet.xsl file. With requested XML and stylesheet.xsl, browser will render HTML page. If you click on View page source, you will not see finished HTML, but XML generated by Apache.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="utf-8"
            doctype-public="-//W3C//DTD HTML 4.01//EN"
            doctype-system="http://www.w3.org/TR/html4/strict.dtd" />

	<xsl:template match="/html/body">
	  <html>
	    <head>
	    	<title>Directory: <xsl:value-of select="request_uri"/></title>
				<style>
					body         {font-family: sans-serif; text-align: center;}
					table        {margin: 0px auto; border-collapse: collapse;}
					td           {border: 1px solid lightgrey;}
					a, a:visited {color: #ff6600; text-decoration: none;}
					a:hover      {text-decoration: underline;}
				</style>
			</head>
			<body>
				<h2>Directory: <xsl:value-of select="request_uri"/></h2>
				<table>
					<!-- define table column width -->
					<colgroup>
						<col width="50"/>  <!-- icon -->
						<col width="400"/> <!-- link -->
						<col width="180"/> <!-- last modified -->
						<col width="50"/>  <!-- size -->
					</colgroup>
					<!-- process 'tr' rows with td only (skip th rows) -->
					<xsl:apply-templates select="table/tr[td]"/>
				</table>
			</body>
	  </html>
	</xsl:template>

	<!-- print table rows -->
	<xsl:template match="tr">
		<tr>
			<td align="center"><xsl:copy-of select="td[position()=1]/*"/></td>
			<td align="left"><xsl:copy-of select="td[position()=2]/a"/></td>
			<td align="center"><xsl:value-of select="td[position()=3]"/></td>
			<td align="right"><xsl:value-of select="td[position()=4]"/></td>
		</tr>
	</xsl:template>
</xsl:stylesheet>



5. Conclusion
Described procedure may seem complicated, but it all boils down to the two files and a couple of lines in the httpd.conf file. First file is header file - static HTML or HTML with SSI or PHP (depends what you need). And the second file is XSL. Place files inside document root and make absolute reference to them in HeaderName directive and in header file. After files are created and Apache is configured, you should have a styled directory listing page.

I hope you might find this post useful.
Cheers!

Related posts

Bookmark and Share

8 Responses to “Styling Apache directory listings”

  1. dirch says:

    How do I get the "root-style" for directories within my root-files-directory, Did I miss something?
    And is it possible to have icons for mime-types? Thy are linked in the sites source, but do not appear on the site itself.

    Apart from that, very nice! And thanks in advance!

  2. dbunic says:

    @dirch - You have to set Indexes in Options directive, otherwise Apache will return "HTTP 403 - Forbidden" instead of directory list. More about Options can be read on Options Directive. Mime-type icons should be displayed by default after enabling directory listing. In Fedora distribution, icons are located in /var/www/icons and the icon mapping is defined in httpd.conf by AddIcon* directives.

  3. dirch says:

    Thanks for your reply!

    To be more precise, and maybe you find my mistake, here is the link to my files directory http://mjhp.net/files/ . As you can see there are no icons. In the source i saw that they are expected to be in /icons, so i've created that one and copied a set of icons there (of course they are readable by everyone).

    My .htaccess looks like that:

    Options +Indexes

    IndexOptions FancyIndexing
    IndexOptions XHTML
    IndexOptions HTMLtable
    IndexOptions SuppressHTMLPreamble
    IndexOptions SuppressColumnSorting
    IndexOptions FoldersFirst
    IndexOptions IconsAreLinks
    IndexOptions NameWidth=*
    IndexOptions Type=text/xml

    IndexIgnore ..
    HeaderName HEADER.html

    The other files (stylesheet an HEADER.html are copied from your site.

    ah, the server is running FreeBSD 7.1-STABLE

    Thanks!

  4. dbunic says:

    @dirch - Error was in stylesheet.xsl in "tr" template. Please look at the first xsl:copy-of line (responsible for the column with icons).

    Before todays update, line was looked like:

    <td align="center"><xsl:copy-of select="td[position()=1]/img"/></td>

    and that was wrong. So, if you need icon and link, you should please replace "img" with "*" (as I updated stylesheet.xsl in this post)

    <td align="center"><xsl:copy-of select="td[position()=1]/*"/></td>

    Or if you need only icon, then you can write "a/img".

    <td align="center"><xsl:copy-of select="td[position()=1]/a/img"/></td>

    Thank you for pointing to the icon problem.
    Bye!

  5. dirch says:

    It's me who has to thank you!

    My other "problem" looks like that http://mjhp.net/files/nostyle/. As you can see there is no style at all. Of course i could put my header and all that into every directory i create, but maybe there is another option to have the same style in the root directory and all subdirectories.

  6. dbunic says:

    @dirch - I think you have to set absolute path to the HEADER.html file. Instead of:

    HeaderName HEADER.html

    try with:

    HeaderName /files/HEADER.html

    Hope this will solve problem and all subdirectories will be styled as root dir.
    ;)

  7. dirch says:

    Thats it. Sometimes i wonder how dumb me can be... Thanks a lot!
    btw: really nice site, keep up the good work!

Leave a Reply