Directory Lister on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of Directory Lister on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Directory Lister is a lightweight web application that turns a directory of files into a clean, styled listing in the browser, published at github.com/DirectoryLister/DirectoryLister. It needs no database: it reads files straight from the filesystem and renders a browsable listing with breadcrumb navigation, file search, inline README rendering, single-file downloads and on-the-fly zip downloads of whole folders.
The image installs Directory Lister 5.6.1 served by nginx and PHP 8.3 FPM, with the application running under a dedicated non-root service account. Unattended security upgrades are configured to keep the server patched on your running VM.
One appliance, one web application. nginx and php8.3-fpm serve the whole site on port 80. There is no database and no mail engine — port 80 is the only network-reachable service.
A safe served root, and hardened for a file browser. The appliance serves a dedicated, self-contained demo directory (/var/www/dirlister/files), never the server filesystem, the application's own source, or any sensitive path. Directory Lister protects file access through PHP open_basedir, so this image is arranged so that the served directory is the open_basedir ceiling: the application code lives in a hidden subdirectory inside the served root. As a result:
- Path traversal above the served root is refused. Relative paths (
../), URL-encoded sequences and symlinks that point outside the served directory all return404— no file outside the served directory can be read. - The application's own configuration, environment file and source are never listed or served. They are excluded from the listing, from search and from zip archives, and return
404over HTTP. - nginx never renders a raw directory index — only Directory Lister's own rendered listing of the served files is shown.
Public read-only by design — no credential ships in the image. The demo listing is public and read-only; there is no login and no secret anywhere in the image. If you want a private listing you can enable Directory Lister's built-in password protection yourself (see Step 13). On first boot a one-shot service prepares each instance (it resolves the VM's address and writes an information file), then a bootstrap marker lets nginx and php8.3-fpm start; until that marker exists systemd skips those units, so the site never serves a half-prepared instance. The units are enabled, so the appliance comes straight back after a reboot.
What is included:
- Directory Lister 5.6.1 served by nginx and PHP 8.3 FPM, running under a dedicated non-root service account, with a strict nginx allowlist that serves only the compiled front-end assets and the application's rendered listing
- A safe, self-contained demo directory as the served root, with the served root as the
open_basedirceiling so traversal above it is refused - A first-boot service that prepares each instance and a bootstrap gate that holds the web services until preparation is complete
Prerequisites
- An Azure subscription and either the Azure Portal or the Azure CLI (
az) signed in - An SSH key pair so you can administer the VM
- Inbound TCP port 80 open to the browsers that will reach the listing (and port 22 for administration)
Step 1: Deploy from the Azure Portal
- Open the cloudimg Directory Lister on Ubuntu 24.04 LTS offer in the Azure Marketplace and choose Create.
- Pick a resource group and region, keep the recommended Standard_B2s size (Directory Lister is tiny and runs comfortably on 2 vCPU / 4 GB), and provide your SSH public key for the
azureuseraccount. - On the Networking step allow inbound 80 (the web application) and 22 (SSH). Directory Lister serves over port 80; put it behind an Azure Application Gateway or a reverse proxy if you want TLS.
- Create the VM, then browse to its public IP address to see the demo directory listing.
Step 2: Deploy from the Azure CLI
# Replace <sub-id> and <version> with your subscription and the image version.
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/directory-lister-ubuntu-24-04/versions/<version>"
az group create --name directory-lister-rg --location eastus
az vm create \
--resource-group directory-lister-rg \
--name directory-lister \
--image "$GALLERY_IMAGE_ID" \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
az vm open-port --resource-group directory-lister-rg --name directory-lister --port 80
Step 3: First boot and the appliance information
On first boot a one-shot service resolves the VM's address and writes an information file. There is no credential — the listing is public and read-only by design. Read the information file over SSH:
sudo cat /root/directory-lister-info.txt
It records the listing URL and the served directory:
DIRECTORY_LISTER_URL=http://<your-service-ip>/
DIRECTORY_LISTER_SERVED_ROOT=/var/www/dirlister/files
Step 4: Confirm the appliance is running
Both web services are active, PHP 8.3 and nginx report their versions, the application runs as the dedicated non-root dirlister account, and port 80 is the only listener:
sudo systemctl is-active php8.3-fpm nginx
php -v | head -1
nginx -v
id dirlister
sudo ss -tulnp | grep ':80 '

Step 5: Browse the demo directory
Browse to the VM's address to see the demo directory rendered as a clean, styled listing: the data, documents and images folders, the README.md file (rendered inline), each entry with its size and modified date, a search box, and a download control.

Step 6: Open a folder and download files
Click a folder to browse into it. Each file shows its size and modified date, you can download an individual file, and you can download the whole folder as a zip archive from the download control in the breadcrumb bar.

Step 7: Search the listing
Type in the search box to filter the listing by file name. Directory Lister searches the served directory and shows the matching files with their paths.

Step 8: Light and dark themes
Directory Lister ships light and dark themes; use the theme toggle in the top bar to switch. The listing renders the same content in either theme.

Step 9: Serve your own directory
To publish your own files, set FILES_PATH in the application environment file to your directory, then restart the web services:
# Point Directory Lister at your own directory of files:
# 1. Edit the environment file and set FILES_PATH to your directory:
sudo nano /var/www/dirlister/files/.dirlister-app/.env # set FILES_PATH=/path/to/your/files
# 2. Restart the web services:
sudo systemctl restart php8.3-fpm nginx
Keep your served directory self-contained and free of sensitive files, exactly as the shipped demo directory is. The traversal and configuration-exposure protections shown in the next two steps apply to whatever directory you serve.
Step 10: Path traversal above the served root is refused
The served root is a dedicated directory, and any attempt to read a file above it — with relative paths, URL-encoded sequences or symlinks — returns 404. Nothing outside the served directory can be read:
# relative-path traversal
curl -s -o /dev/null -w '?dir=../../../../etc -> HTTP %{http_code}\n' 'http://127.0.0.1/?dir=../../../../etc'
curl -s -o /dev/null -w '?file=../../../../etc/passwd -> HTTP %{http_code}\n' 'http://127.0.0.1/?file=../../../../etc/passwd'
# URL-encoded traversal
curl -s -o /dev/null -w 'url-encoded traversal -> HTTP %{http_code}\n' 'http://127.0.0.1/?file=..%2f..%2f..%2f..%2fetc%2fpasswd'
# and nothing from /etc/passwd is ever returned:
echo "leaked /etc/passwd lines: $(curl -s 'http://127.0.0.1/?file=../../../../etc/passwd' | grep -c 'root:.*:0:0' || true)"

Step 11: The application's own config and source are never served
The application's environment file, configuration and source live in a hidden subdirectory inside the served root. They are excluded from the listing and return 404 over HTTP, while the compiled front-end assets are served normally:
curl -s -o /dev/null -w 'GET /.env -> HTTP %{http_code}\n' 'http://127.0.0.1/.env'
curl -s -o /dev/null -w 'GET /app/config/app.php -> HTTP %{http_code}\n' 'http://127.0.0.1/app/config/app.php'
curl -s -o /dev/null -w '?file=.dirlister-app/.env -> HTTP %{http_code}\n' 'http://127.0.0.1/?file=.dirlister-app/.env'
# the app directory never appears in the rendered listing:
echo "app dir in listing: $(curl -s 'http://127.0.0.1/' | grep -c 'dirlister-app' || true) (0 = hidden)"

Step 12: How the first-boot gate works
nginx and php8.3-fpm are each gated on a bootstrap marker that the first-boot service writes only after it has prepared the instance. Until the marker exists systemd skips those units; the units are enabled so they survive a reboot:
grep -h ConditionPathExists /etc/systemd/system/nginx.service.d/*.conf /etc/systemd/system/php8.3-fpm.service.d/*.conf
sudo ls -l /var/lib/cloudimg/
sudo systemctl is-enabled php8.3-fpm nginx directory-lister-firstboot

Step 13: Security recommendations
- Keep the served directory self-contained. Serve a dedicated directory of the files you want to publish; do not point
FILES_PATHat a home directory, a system path, or anywhere holding secrets. The traversal protection stops reads above the served root, but everything inside the served directory is, by design, browsable. - Enable password protection for a private listing. Directory Lister supports built-in password/hash directory protection; enable it if the listing should not be public. See the Directory Lister configuration documentation.
- Put TLS in front. Serve over HTTPS with an Azure Application Gateway, a load balancer or a reverse proxy such as Caddy or nginx with a certificate.
- Restrict inbound access. Use an Azure Network Security Group to limit who can reach ports 80 and 22.
- Keep the OS patched. Unattended security upgrades are enabled; reboot periodically to apply kernel updates.
Step 14: Support and licensing
Directory Lister is open-source software distributed under the MIT License; the licence text ships in the image at /var/www/dirlister/files/.dirlister-app/LICENSE. This cloudimg image bundles Directory Lister with nginx and PHP on Ubuntu 24.04 and adds the security hardening, first-boot preparation and deployment tooling described above.
cloudimg provides 24/7 support for this image by email (support@cloudimg.co.uk) and live chat, covering deployment, pointing the listing at your own directory, sort and hidden-file rules, themes and titles, enabling password protection, zip and download behaviour, serving over HTTPS, and Directory Lister version upgrades. All product and company names are trademarks or registered trademarks of their respective holders.