Deployment guide

ZFile

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 local disk of the VM to S3-compatible object storage, OneDrive, SharePoint, Google Drive, WebDAV, FTP and SFTP. It presents them all as one browsable website with share links, direct links, short links and rich in-browser previews, including images with a gallery mode, audio, video, text and code, PDF, Office documents and more.

The SecureAnyCloud 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. The MIT licence text ships at /opt/zfile/LICENSE. ZFile runs as a systemd service bound to the loopback interface, and nginx on port 80 is the only public surface. First boot configures a ready-to-use "Local Storage" source on a dedicated data disk. 24/7 SecureAnyCloud support backs the image.

What you get:

  • 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, and tuned for large uploads (no request size cap)
  • No default credential of any kind: the image ships uninitialised, and first boot generates a unique per-VM admin password to create the admin account
  • A preconfigured "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 SecureAnyCloud support

Good to know: The ZFile web interface is presented in Chinese, the language of the upstream project. The layout is a conventional file manager, you can reproduce every workflow in this guide 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 and 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 rules that 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 SecureAnyCloud, and select Create.
  • On the Basics tab, 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).
  • On the Disks tab, review the dedicated data disk.
  • Select Review + create, then Create.

Step 2 - Deploy from the Azure CLI

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:zfile:default:latest
az vm create \
  --resource-group <your-rg> \
  --name zfile \
  --image sac1647283583153:zfile:default:latest \
  --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 services report active. ZFile itself listens only on the loopback address 127.0.0.1:8080, and 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

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 the password is written to a root-only file. Read the file with:

sudo cat /root/zfile-credentials.txt

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

head -2 /opt/zfile/NOTICE.txt

Step 6 - Confirm the health endpoint

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

curl -s http://localhost/healthz

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

Step 7 - Confirm the authentication gate

The following commands read the per-VM password from the credentials file and prove 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, because a fresh VM is private until you sign in or grant anonymous permissions (Step 9).

Step 8 - Sign in and browse your files

In a browser, go to http://<vm-public-ip>/ and click through to the sign-in page. You can also open http://<vm-public-ip>/login directly. Enter admin and the password from Step 5.

After you sign in, the home page lists your storage sources. The preconfigured Local Storage source is already there.

Click Local Storage to enter the file browser. The welcome README.txt that the image seeds 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 the rename, copy, move, delete, direct link and share link actions.

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.

Step 9 - Manage storage sources and permissions

Click 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 preconfigured Local Storage source or add more sources: S3-compatible object storage, OneDrive, SharePoint, Google Drive, WebDAV, FTP, SFTP and others. Each source appears alongside Local Storage on the home page.

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 permission settings of the source in the admin area and grant the anonymous role the view permission, and optionally the download permission. 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 commands upload a file through the API, generate a share link for it, and download 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. This is a byte-identical round trip through nginx on port 80.

In the web UI, the same share action is on the right-click menu of the file. You can send the generated http://<vm-public-ip>/share/<key> page to anyone. Share links support optional passwords and expiry dates.

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 preconfigured Local Storage source, or grant anonymous view permissions on the source (Step 9) to publish it.

Sign in fails

Re-read the exact password with sudo cat /root/zfile-credentials.txt (the value after ZFILE_ADMIN_PASSWORD=). Repeated failed logins are rate-limited to 10 per minute, so 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 VM.

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 with df -h /var/lib/zfile. To grow the disk, resize the Azure data disk and then the filesystem (sudo resize2fs /dev/disk/azure/scsi1/lun0).

I locked myself out / lost the admin password

ZFile stores the password only as a hash inside the database. The simplest recovery on a fresh appliance is to run sudo systemctl stop zfile nginx, sudo rm -rf /var/lib/zfile/db, sudo rm /var/lib/sac/data/zfile-firstboot.done /var/lib/sac/data/zfile-bootstrap-ready, and then sudo reboot. First boot runs again, regenerates a fresh password into /root/zfile-credentials.txt and recreates the Local Storage source. This resets the ZFile 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 and writes /root/zfile-credentials.txt. Only then does it allow 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/sac/data/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: Grant anonymous permissions only on sources that 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, because nginx is the only intended public path.
  • Security patches: unattended-upgrades remains enabled, so the OS continues to receive security updates automatically.

Support

SecureAnyCloud provides 24/7 expert support for this image. Contact sales@secureanycloud.com.

Deploy on Azure

Launch ZFile File Listing and Sharing Server on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure