Storage Azure

ZFile File Listing and Sharing Server on Ubuntu 24.04 on Azure User Guide

| Product: ZFile File Listing and Sharing Server on Ubuntu 24.04 LTS on Azure

Overview

ZFile is an open source file listing and sharing server for individuals and small teams. It mounts many storage backends side by side, from the VM's local disk to S3 compatible object storage, OneDrive, SharePoint, Google Drive, WebDAV, FTP and SFTP, and presents them all as one browsable web site with share links, direct links, short links and rich in browser previews (images with a gallery mode, audio, video, text and code, PDF, Office documents and more). The cloudimg image builds ZFile 4.5.0 entirely from the upstream MIT source, backend and web interface both, so the image contains only the open edition, with the MIT licence text shipped at /opt/zfile/LICENSE. ZFile runs as a systemd service bound to the loopback interface, nginx on port 80 is the only public surface, and a ready to use "Local Storage" source on a dedicated data disk is configured on first boot. Backed by 24/7 cloudimg support.

What is included:

  • ZFile 4.5.0 built from the upstream MIT source (Spring Boot backend under OpenJDK 21 + the Vue 3 web interface), running as the zfile systemd service
  • The ZFile web UI and REST API on port 80, fronted by nginx with ZFile bound to loopback only, tuned for large uploads (no request size cap)
  • No default credential of any kind: the image ships uninitialised, and a unique per VM admin password is generated on first boot to create the admin account
  • A pre configured "Local Storage" source rooted at /var/lib/zfile/files on a dedicated 32 GiB Azure data disk, which also holds the embedded SQLite database
  • Share links, direct links and short links per file or folder, with optional passwords and expiry
  • An unauthenticated /healthz endpoint on :80 for Azure Load Balancer health probes
  • zfile.service + nginx.service as systemd units, enabled and active
  • 24/7 cloudimg support

Good to know: the ZFile web interface is presented in Chinese (the upstream project's language). The layout is a conventional file manager, every workflow shown in this guide is reproducible from the screenshots alone, and browser page translation works well with it. A fresh VM is also private by default: anonymous visitors see an empty site until you either sign in or explicitly grant anonymous view permissions on a storage source (Step 9).

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a comfortable starting point for a personal or small team file server; size up for heavy concurrent transfer workloads. NSG inbound: allow 22/tcp from your management network, 80/tcp for the web UI, and 443/tcp if you add TLS. ZFile serves plain HTTP out of the box; for production use, front it with TLS on your own domain.

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for ZFile by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Review the dedicated data disk on the Disks tab, then Review + create -> Create.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name zfile \
  --image <marketplace-image-urn> \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard

az vm open-port --resource-group <your-rg> --name zfile --port 80 --priority 1010

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

systemctl is-active zfile.service nginx.service

Both report active. ZFile itself listens only on the loopback address 127.0.0.1:8080; nginx fronts port 80 as the only public surface. The embedded SQLite database (db/) and the Local Storage file root (files/) live on the dedicated data disk mounted at /var/lib/zfile:

findmnt -no SOURCE,SIZE,FSTYPE /var/lib/zfile
ls -l /var/lib/zfile

The zfile and nginx services active, and the dedicated data disk mounted at /var/lib/zfile holding the db and files directories

Step 5 - Retrieve your admin password

The image ships with no account at all. On the first boot of your VM, a unique admin password is generated, the admin account is created with it, and it is written to a root only file:

sudo cat /root/zfile-credentials.txt

This file contains ZFILE_URL, ZFILE_USERNAME (admin) and ZFILE_ADMIN_PASSWORD. Store the password somewhere safe. The MIT licence and full source provenance for the build ship in the image too:

head -2 /opt/zfile/NOTICE.txt

The OpenJDK 21 runtime, the MIT source provenance in NOTICE.txt, the root only per VM credentials file, and the healthz endpoint returning ok

Step 6 - Confirm the health endpoint

nginx serves an unauthenticated health endpoint for load balancers and probes:

curl -s http://localhost/healthz

It returns ok. This endpoint never requires authentication, so it is safe for an Azure Load Balancer health probe.

Step 7 - Confirm the authentication gate

The following reads the per VM password from the credentials file and proves the round trip - a wrong password is rejected and the correct password authenticates:

PW=$(sudo grep '^ZFILE_ADMIN_PASSWORD=' /root/zfile-credentials.txt | cut -d= -f2-)
curl -s -H 'Content-Type: application/json' \
  -d '{"username":"admin","password":"wrong-pw"}' http://127.0.0.1/user/login | jq -r '.code'
curl -s -H 'Content-Type: application/json' \
  -d "{\"username\":\"admin\",\"password\":\"$PW\"}" http://127.0.0.1/user/login | jq '{code, admin: .data.admin}'

The wrong password returns error code 42001; the per VM password returns code "0" with admin: true. Anonymous visitors cannot list files: a fresh VM is private until you sign in or grant anonymous permissions (Step 9).

The authentication round trip: a wrong password rejected with code 42001 and the per VM admin password authenticating with code 0

Step 8 - Sign in and browse your files

Browse to http://<vm-public-ip>/ and click through to the sign in page (or open http://<vm-public-ip>/login directly). Enter admin and the password from Step 5.

The ZFile sign in page

After signing in, the home page lists your storage sources - the pre configured Local Storage source is already there:

The ZFile home page listing the pre configured Local Storage source

Click Local Storage to enter the file browser. The welcome README.txt seeded by the image is listed with its timestamp and size. Use the toolbar icons to upload files, create folders, and switch to gallery view; right click a file for rename, copy, move, delete, direct link and share link actions.

The ZFile file browser listing the seeded README.txt inside the Local Storage source

Double click README.txt to preview it - text and code files open in an in browser editor, and images, audio, video, PDF and Office documents each get their own preview:

The in browser text preview rendering the content of README.txt

Step 9 - Manage storage sources and permissions

Open the settings icon (or browse to http://<vm-public-ip>/admin) to reach the admin area. Under the storage source settings you can edit the pre configured Local Storage source or add more sources - S3 compatible object storage, OneDrive, SharePoint, Google Drive, WebDAV, FTP, SFTP and others - each of which appears alongside Local Storage on the home page.

The admin storage source settings showing the enabled Local Storage source and the add source tile

A fresh VM is private by default: anonymous visitors see an empty storage list. To publish a source as a public file library, open the source's permission settings in the admin area and grant the anonymous role the view (and optionally download) permissions you want. The multi user system under user management lets you create additional accounts scoped to specific sources or directories.

Step 10 - Upload a file and share it by link

Everything in the UI is also scriptable through the same REST API, which is how the image proves itself on every boot. The following uploads a file through the API, generates a share link for it, and downloads it back through the share link:

PW=$(sudo grep '^ZFILE_ADMIN_PASSWORD=' /root/zfile-credentials.txt | cut -d= -f2-)
TOKEN=$(curl -s -H 'Content-Type: application/json' \
  -d "{\"username\":\"admin\",\"password\":\"$PW\"}" http://127.0.0.1/user/login | jq -r '.data.token')

echo 'hello from zfile on azure' > hello.txt
curl -s -X PUT -H "zfile-token: $TOKEN" -F 'file=@hello.txt' \
  http://127.0.0.1/file/upload/local/hello.txt | jq -r '.code + " " + .msg'

SHARE=$(curl -s -H 'Content-Type: application/json' -H "zfile-token: $TOKEN" \
  -d '{"storageKey":"local","sharePath":"/","shareEntries":[{"name":"hello.txt","type":"FILE"}],"shareType":"FILE"}' \
  http://127.0.0.1/api/share/create | jq -r '.data.shareKey')
curl -s -L "http://127.0.0.1/api/share/download/$SHARE?path=/hello.txt"

The upload returns 0 ok, and the share link download prints hello from zfile on azure - a byte identical round trip through nginx on port 80. In the web UI the same share action is on the file's right click menu, and the generated http://<vm-public-ip>/share/<key> page can be sent to anyone; share links support optional passwords and expiry dates.

The API upload, share link creation and share link download round trip, byte identical through nginx port 80

Server Components

Component Version Detail
ZFile 4.5.0 Built from the upstream MIT source (backend + web UI), /opt/zfile/app.jar + /opt/zfile/static/
OpenJDK 21 (headless JRE) Runtime for the Spring Boot backend
nginx Ubuntu 24.04 archive Port 80 reverse proxy, the only public surface
SQLite embedded ZFile's database at /var/lib/zfile/db/zfile on the data disk
Ubuntu 24.04 LTS Fully patched at image capture, unattended security upgrades enabled

Filesystem Layout

Mount Point Size Description
/ 30 GB Root filesystem
/boot/efi 1 GB UEFI boot partition (Gen2 Hyper V)
/var/lib/zfile 32 GB Dedicated data disk: db/ (SQLite database) + files/ (Local Storage root)
/mnt varies Azure temporary resource disk

Key directories:

Path Purpose
/opt/zfile/app.jar The ZFile server (built from MIT source)
/opt/zfile/static/ The web interface (built from MIT source)
/opt/zfile/LICENSE The MIT licence text
/opt/zfile/NOTICE.txt Source provenance (repos, tag, commit)
/var/lib/zfile/files/ Local Storage source root - uploaded files land here
/var/lib/zfile/db/ Embedded SQLite database
/var/log/zfile/ Application logs
/root/zfile-credentials.txt Per VM admin credentials (root only, 0600)

Managing the service

sudo systemctl status zfile.service     # status
sudo systemctl restart zfile.service    # restart ZFile
sudo systemctl restart nginx.service    # restart the reverse proxy
sudo journalctl -u zfile.service -e     # recent logs

Troubleshooting

The web UI shows an empty site or "please select a storage source" with nothing listed

You are browsing anonymously. A fresh VM is private by default - sign in as admin (Step 5) to see the pre configured Local Storage source, or grant anonymous view permissions on the source (Step 9) to publish it.

Sign in fails

Re-read the exact password: sudo cat /root/zfile-credentials.txt (the value after ZFILE_ADMIN_PASSWORD=). Repeated failed logins are rate limited (10 per minute); wait a minute and retry.

HTTP 502 from nginx

ZFile is starting or has stopped. Check systemctl status zfile.service and sudo journalctl -u zfile.service -e. The Java backend takes roughly 20 to 40 seconds to start on a B2s.

Uploads fail for large files

nginx on this image imposes no request size cap (client_max_body_size 0), so check free space on the data disk first: df -h /var/lib/zfile. To grow it, resize the Azure data disk and then the filesystem (sudo resize2fs /dev/disk/azure/scsi1/lun0).

I locked myself out / lost the admin password

The password is only stored hashed inside the database. Simplest recovery on a fresh appliance: sudo systemctl stop zfile nginx, sudo rm -rf /var/lib/zfile/db, sudo rm /var/lib/cloudimg/zfile-firstboot.done /var/lib/cloudimg/zfile-bootstrap-ready, then sudo reboot - first boot runs again, regenerates a fresh password into /root/zfile-credentials.txt and recreates the Local Storage source. (This resets ZFile's settings and accounts; files under /var/lib/zfile/files are untouched.)

On Startup

zfile-firstboot.service runs once on the first boot of the VM: it generates the unique admin password, initialises ZFile with it, creates the Local Storage source, proves a real upload round trip through the API, writes /root/zfile-credentials.txt, and only then allows nginx (the public surface) to start - so the site is never reachable in an uninitialised state. On every later boot the service exits immediately (sentinel file /var/lib/cloudimg/zfile-firstboot.done).

Security Recommendations

  • Add TLS for production: front the VM with your own domain and terminate TLS on :443 (for example with certbot), then restrict :80 in your NSG.
  • Keep anonymous access deliberate: only grant anonymous permissions on sources you intend to be public; use the per source password and the multi user system for anything else.
  • Restrict SSH: limit 22/tcp to your management IP range in the NSG.
  • Loopback binding: ZFile is bound to 127.0.0.1:8080 in /etc/systemd/system/zfile.service - keep it that way; nginx is the only intended public path.
  • Security patches: unattended-upgrades remains enabled so the OS continues to receive security updates automatically.

Support

cloudimg provides 24/7 expert support for this image. Contact support@cloudimg.co.uk.