Directory Lister 5.8.1
Overview
This guide covers launching and using the Directory Lister 5.8.1 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud BookStack, CMS, Blogs and Wikis listing on AWS Marketplace. You pick it as the software version when you subscribe and launch.
Directory Lister is an open-source web application that turns a folder of files into a clean, styled listing in the browser. Visitors move through folders with breadcrumbs, search by file name, and read README files rendered on the page. They can check a file's MD5, SHA-1 and SHA-256 hashes, download single files, and download a whole folder as a zip archive. It needs no database, because it reads the files straight from the disk.
What you get:
- Private by default. Out of the box, Directory Lister has no sign-in, so every file you put in its folder is public at once. On this image, every visitor signs in as
adminwith a password generated on your instance's first boot. The password is stored on the instance only as a bcrypt hash for the web server and in/root/directory-lister-credentials.txt(readable by root only). Nothing from the image build ships in the image. Making the listing public is a deliberate step that you take yourself (Step 9). - A sign-in that resists guessing. A client that floods the sign-in with requests is answered
429 Too Many Requestsbefore a password is even checked. The limit is keyed on the connection's address, never on a header that a client sends. - HTTPS from the first boot. nginx serves the listing on port 443 with a certificate generated on your instance's first boot. Port 80 redirects to HTTPS.
- The served folder is locked down. Directory Lister relies on PHP's
open_basedirand its hidden-file rules to keep visitors inside the folder it serves. This image sets the folder as PHP's hard limit, keeps the application itself in a hidden folder inside it, and hides every dot file and dot folder. - Refused paths. Every listing, download, search, zip and file info request refuses these: paths that climb out of the folder (
../, encoded or absolute), symbolic links that point outside it, the application's code, configuration and cache, and any hidden file. - Nothing in the folder ever runs. nginx runs PHP only as Directory Lister's own front controller and serves only its compiled stylesheets, scripts, fonts and icons. A PHP file you put in the folder is offered as a download, never executed. Files opened from the listing carry a policy that stops an HTML or SVG file from running script in the site, and the listing page itself allows only its own scripts.
- Fail closed. nginx and PHP refuse to start until first boot has finished.
- Hardened defaults. The code and your files are owned by root. PHP runs as its own unprivileged user, can write only Directory Lister's cache, cannot run shell commands or open URLs, and never sees the sign-in password. nginx and PHP are blocked from the instance metadata service, the AMI requires IMDSv2, and requests for a host name that the instance does not serve are dropped.
- Fully patched Ubuntu 24.04 LTS at build time, including Ubuntu's PHP 8.3 fix for the PHP2Shell vulnerabilities (CVE-2026-109618 and CVE-2026-109619), with unattended security upgrades switched on.
- What is on the image: Directory Lister 5.8.1 (the official release archive, checksum verified), PHP 8.3 FPM, nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent. A small sample folder (a README,
documents,dataandimages) shows how the listing looks until you add your own files. - Default user:
ubuntu - Architecture: x86_64
- Recommended instance type: m5.large
Prerequisites
- An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet with a route to the internet (or a private route you use for management).
- A security group that allows TCP 22 (SSH), TCP 443 (the listing) and TCP 80 (redirects to HTTPS) from the networks that should reach them. Keep 22 to your own networks.
Launch the instance
In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Pick Directory Lister 5.8.1 on Ubuntu 24.04 as the software version, select your Region, and choose Launch through EC2.
Choose m5.large, your key pair and a security group as above. Directory Lister is very light, so a smaller instance is fine for a small listing. Give the instance enough disk for the files you will serve, or attach a separate EBS volume for them (Step 7).
With the AWS CLI (replace the values in angle brackets):
aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
--instance-type m5.large --key-name <your-key-pair> \
--security-group-ids <your-security-group> --subnet-id <your-subnet> \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=directory-lister}]'Connect to your instance
- Directory Lister 5.8.1 on Ubuntu 24.04: SSH user ubuntu
ssh -i <your-key.pem> ubuntu@<public-ip>Check the services
First boot takes a few seconds. After that, nginx, PHP and the first boot unit are active:
systemctl is-active nginx php8.3-fpm directory-lister-firstbootactive active activenginx serves ports 80 and 443. PHP listens on a local socket only, and there is no database, so the only open ports are 22, 80 and 443:
sudo ss -tlnp | awk 'NR==1 || /nginx|sshd|php/' | awk '{print $1, $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g'State Local Peer LISTEN 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx")) LISTEN 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx")) LISTEN 0.0.0.0:22 users:(("sshd"),("systemd")) LISTEN [::]:443 users:(("nginx"),("nginx"),("nginx")) LISTEN [::]:80 users:(("nginx"),("nginx"),("nginx")) LISTEN [::]:22 users:(("sshd"),("systemd"))grep -m1 -oE "'pretty_version' => '[0-9.]+'" /var/www/directory-lister/files/.directory-lister/app/vendor/composer/installed.php php -v | head -1'pretty_version' => '5.8.1' PHP 8.3.6 (cli) (built: Oct 19 2026 15:16:58) (NTS)Get your sign-in details
The credentials file holds the address the listing is served as (your instance's public DNS name by default), the user name and the password generated on this instance. Show the file with:
sudo cat /root/directory-lister-credentials.txtDIRECTORY_LISTER_URL=https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/ DIRECTORY_LISTER_USER=admin DIRECTORY_LISTER_PASSWORD=<24 letters and digits>Open the listing
Open DIRECTORY_LISTER_URL in your browser. The certificate is self-signed (generated on your instance), so accept the browser warning once, or install your own certificate (Step 11).
The browser asks for a user name and password. Sign in as admin with DIRECTORY_LISTER_PASSWORD. Your browser remembers the sign-in until you close it.
The home page lists the served folder, with its README rendered underneath:
Browse, search and download
Click a folder to open it. The breadcrumb at the top takes you back. Click a file to open or download it. Use the download arrow at the top right to download the folder you are in as a zip archive.
Type in the search box to find files by name anywhere in the served folder.
Hover over a file and click the information icon to see its MD5, SHA-1 and SHA-256 hashes. Whoever downloads the file can use them to check the copy they received.
The light bulb in the header switches between the light and dark themes.
Serve your own files
The served folder is /var/www/directory-lister/files. Copy your files into it over SSH and they appear in the listing at once. There is nothing to restart. Remove the sample files you do not want:
sudo rm -r /var/www/directory-lister/files/documents /var/www/directory-lister/files/data /var/www/directory-lister/files/images scp -i <your-key.pem> -r <your-folder> ubuntu@<public-ip>:/tmp/upload
sudo cp -r /tmp/upload/. /var/www/directory-lister/files/ && rm -rf /tmp/uploadFiles must be readable by everyone on the instance, because PHP reads them as its own unprivileged user. Use mode 644 for files and 755 for folders, which cp gives you by default.
Edit /var/www/directory-lister/files/README.md (or delete it) to change the text under the listing. Any folder can have its own README.md.
Three rules keep the folder safe:
- Keep the hidden
.directory-listerfolder. It holds the application and must stay inside the served folder. Do not delete it, and do not pointFILES_PATHanywhere else. PHP is confined to the served folder, which stops visitors climbing out of it. - Dot files are never shown. Any file or folder whose name starts with a dot is hidden from the listing, search, zips and downloads.
- Use a mount, not a symbolic link, to serve another disk. A symbolic link that points outside the served folder is refused, and the folder that contains it cannot be listed. To serve a separate EBS volume, mount it on a folder inside the served folder, for example
sudo mkdir /var/www/directory-lister/files/shared && sudo mount /dev/nvme1n1 /var/www/directory-lister/files/shared. Add it to/etc/fstabby UUID to keep it across reboots.
Listing settings
Directory Lister reads its settings from /var/www/directory-lister/files/.directory-lister/.env. You can change these:
- The page title (
SITE_TITLE). - The sort order (
SORT_ORDER,REVERSE_SORT). - Whether READMEs are shown (
DISPLAY_READMES,READMES_FIRST). - Whether folders can be downloaded as zips (
ZIP_DOWNLOADS).
Then restart PHP so that it reads the new values:
sudo nano /var/www/directory-lister/files/.directory-lister/.env
sudo systemctl restart php8.3-fpmLeave FILES_PATH, HIDDEN_FILES_LIST and APP_DEBUG=false as they are. Directory Lister's documentation at docs.directorylister.com lists every setting.
Private or public
The listing is private, so every visitor needs the admin password. To publish the folder to anyone who can reach port 443, make it public deliberately. Make it private again the same way:
sudo directory-lister-set-access public
sudo directory-lister-set-access private
sudo directory-lister-set-access statusOnly make it public for files you mean to publish to the world. Keeping it private and restricting port 443 in the security group to your own networks is safer still.
Security checks
Port 80 sends browsers to HTTPS, the listing asks for the password, and the health endpoint answers for load balancer checks. Requests for a host name that the instance does not serve are dropped:
H=$(sed -n 's/^set \$dl_host "\(.*\)";$/\1/p' /etc/nginx/directory-lister-host.conf)
curl -s -o /dev/null -w 'port 80: %{http_code} -> %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/"
curl -sk -o /dev/null -w 'no password: %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/"
curl -sk --resolve "$H:443:127.0.0.1" "https://$H/healthz"
curl -s -o /dev/null -w 'unknown host name: %{http_code}\n' -H 'Host: example.com' http://127.0.0.1/ || trueport 80: 301 -> https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/ no password: 401 ok unknown host name: 000000 means nginx closed the connection without an answer.
Signed in, a folder opens, while paths out of the folder, the application's own files and the hidden folder are refused. This block hands the password to curl from the credentials file without printing it:
H=$(sed -n 's/^set \$dl_host "\(.*\)";$/\1/p' /etc/nginx/directory-lister-host.conf) for q in "dir=documents" "file=../../../../etc/passwd" "file=..%2F..%2F..%2Fetc%2Fpasswd" "file=.directory-lister/.env" "dir=.directory-lister" "zip=.."; do curl -sk -K <(sudo sed -n 's/^DIRECTORY_LISTER_PASSWORD=\(.*\)/user = "admin:\1"/p' /root/directory-lister-credentials.txt) \
-o /dev/null -w "?$q: %{http_code}\n" --resolve "$H:443:127.0.0.1" "https://$H/?$q" done?dir=documents: 200 ?file=../../../../etc/passwd: 404 ?file=..%2F..%2F..%2Fetc%2Fpasswd: 404 ?file=.directory-lister/.env: 404 ?dir=.directory-lister: 404 ?zip=..: 404The credentials file is readable by root only, and the password hash file by root and nginx only. The served folder belongs to root, and PHP can write only the application's cache. The hash file holds one user, admin, with a bcrypt hash:
sudo stat -c '%a %U:%G %n' /root/directory-lister-credentials.txt /etc/nginx/directory-lister.htpasswd /var/www/directory-lister/files /var/www/directory-lister/files/.directory-lister/app/cache
sudo cut -c1-13 /etc/nginx/directory-lister.htpasswd grep auth_basic /etc/nginx/directory-lister-access.conf600 root:root /root/directory-lister-credentials.txt 640 root:www-data /etc/nginx/directory-lister.htpasswd 755 root:root /var/www/directory-lister/files 750 dirlister:dirlister /var/www/directory-lister/files/.directory-lister/app/cache admin:$2y$10$ auth_basic "Directory Lister"; auth_basic_user_file /etc/nginx/directory-lister.htpasswd;nginx and PHP cannot reach the instance metadata service, and PHP runs as dirlister, confined to the served folder, with no shell commands and no URL access:
systemctl show nginx -p IPAddressDeny
systemctl show php8.3-fpm -p IPAddressDeny grep -E '^(user|php_admin_value\[open_basedir\]|php_admin_value\[disable_functions\]|php_admin_flag\[allow_url_fopen\])' /etc/php/8.3/fpm/pool.d/dirlister.confIPAddressDeny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128 IPAddressDeny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128 user = dirlister php_admin_value[open_basedir] = /var/www/directory-lister/files php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen,pcntl_exec php_admin_flag[allow_url_fopen] = offThe certificate was generated on this instance and names its own addresses:
H=$(sed -n 's/^set \$dl_host "\(.*\)";$/\1/p' /etc/nginx/directory-lister-host.conf)
echo | openssl s_client -connect 127.0.0.1:443 -servername "$H" 2>/dev/null | openssl x509 -noout -subject -ext subjectAltNamesubject=CN = ec2-<public-ip-dashed>.<region>.compute.amazonaws.com, O = sac X509v3 Subject Alternative Name: DNS:ec2-<public-ip-dashed>.<region>.compute.amazonaws.com, IP Address:<public-ip>, IP Address:<private-ip>, IP Address:127.0.0.1, DNS:localhostYour own DNS name and certificate
Point a DNS record at the instance, then set the name that the listing is served as. This command mints a new self-signed certificate for the name, updates nginx and the URL in /root/directory-lister-credentials.txt, and keeps the name across reboots:
sudo directory-lister-set-hostname <your-domain>To use a certificate from your own certificate authority instead, copy it over the generated pair and reload nginx. Running directory-lister-set-hostname again replaces it with a self-signed one:
sudo install -m 0644 <your-domain>.crt /etc/nginx/ssl/directory-lister.crt
sudo install -m 0600 <your-domain>.key /etc/nginx/ssl/directory-lister.key
sudo nginx -t && sudo systemctl reload nginxOnce browsers trust the certificate, you can also add an HSTS header (add_header Strict-Transport-Security "max-age=31536000" always;) to /etc/nginx/snippets/sac-directory-lister-headers.conf. The image does not send one, because browsers ignore HSTS from a site whose certificate they do not trust.
Password and upgrades
directory-lister-set-password gives admin a new random password, writes its bcrypt hash for nginx and records it in /root/directory-lister-credentials.txt. Browsers that saved the old password are asked to sign in again.
Run it without arguments, or pass your own password (24 to 64 letters and digits) on stdin:
sudo directory-lister-set-password printf '%s\n' '<your-new-password>' | sudo directory-lister-set-password --stdinIf you lock yourself out with too many fast requests, wait a few seconds. The limit clears itself.
To upgrade to a later Directory Lister release, snapshot the instance and download the release archive from the Directory Lister releases page. Replace the contents of /var/www/directory-lister/files/.directory-lister with it. Keep .env and hidden-files.txt, empty app/cache, and leave the tree owned by root (with app/cache owned by dirlister).
Your files are untouched, because they live outside the application folder.
Server components
- Served folder (your files): /var/www/directory-lister/files
- Directory Lister (hidden, root-owned): /var/www/directory-lister/files/.directory-lister
- Settings: /var/www/directory-lister/files/.directory-lister/.env
- nginx site: /etc/nginx/sites-available/sac-directory-lister
- Sign-in switch and password hash: /etc/nginx/directory-lister-access.conf, /etc/nginx/directory-lister.htpasswd
- PHP pool: /etc/php/8.3/fpm/pool.d/dirlister.conf
- Certificate and key: /etc/nginx/ssl/
- First boot script: /usr/local/sbin/directory-lister-firstboot.sh
- Helpers: /usr/local/sbin/directory-lister-set-access, /usr/local/sbin/directory-lister-set-password, /usr/local/sbin/directory-lister-set-hostname
- License and release record: /usr/share/doc/directory-lister/
- Credentials: /root/directory-lister-credentials.txt (mode 0600)
Security recommendations
- Allow port 22 in the security group from your own networks only, and port 443 from the networks that should see the files.
- Keep the listing private unless you mean to publish every file in it, and keep the password secret. Rotate it with Step 12 if it may have been shared.
- Use your own DNS name and a certificate your browsers trust (Step 11).
- If you add a
.customizations.htmlfile (Directory Lister's way to add analytics or custom scripts), note that the listing page only runs its own scripts. Extend theContent-Security-Policyin/etc/nginx/sites-available/sac-directory-listerfor the sources you add. - Keep the operating system patched. Unattended security upgrades are on, and
sudo apt-get update && sudo apt-get upgradeapplies everything else. - PHP-FPM and the PHP zip extension (with its libzip library) come from Ubuntu's universe repository.
sudo pro security-status --esm-appsshows whether Ubuntu Pro (ESM Apps) has security updates for them. None were pending when the image was built. - Back up your files with EBS snapshots of the instance's volumes.
Support and licensing
Directory Lister is open source under the MIT license (a copy is at /usr/share/doc/directory-lister/LICENSE). There is no per-user or per-CPU license fee.
The application is the unmodified upstream release, and SecureAnyCloud's configuration surrounds it. The AMI price covers SecureAnyCloud's hardening, first boot setup and support.
- Email: sales@secureanycloud.com
- Website: https://secureanycloud.com
- Support: 24/7, with a 24 hour response SLA
Deploy on AWS
Launch Directory Lister 5.8.1 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com