Deployment guide

ZeroFS

Overview

ZeroFS is an open source, log-structured filesystem for object storage, written in Rust. It presents a bucket or container as a real POSIX filesystem and serves it over NFS, 9P and NBD, so ordinary tools, mounts and block devices work against object storage without modification. This SecureAnyCloud image runs ZeroFS on Ubuntu 24.04 on Azure, with a bundled backend so the filesystem works the moment the VM boots.

File contents are split into 32 KiB extents. Each extent is compressed, encrypted and packed into immutable segment objects. Metadata (inodes, directory entries and one pointer per extent) lives in an LSM tree on the same store. A local disk and memory cache keeps working-set access fast.

The image installs the official pinned ZeroFS 2.3.2 package from the project's own signed repository. It runs under systemd as the unprivileged zerofs system user. ZeroFS cannot do anything without a backend, so this appliance bundles one and wires it up for you. A single-node object store provides the S3 API, and Redis provides the conditional-write coordination that ZeroFS requires for fencing.

The result is a filesystem that works as soon as the VM boots. You can repoint it at Azure Blob Storage, Amazon S3, Google Cloud Storage or any S3-compatible store whenever you are ready.

Secure by default. This matters more for ZeroFS than for most software. The ZeroFS Web UI has no authentication on any route. Its WebSocket endpoint hands the browser a full read and write session on the filesystem, its administrative gRPC endpoint accepts requests from any origin, and it includes an in-browser terminal that boots a Linux virtual machine with the filesystem mounted inside it. NFS, 9P and NBD are likewise unauthenticated wire protocols.

This image therefore exposes none of them to the network. Every one of those listeners is bound to loopback. The only network-facing surface is nginx on port 443, which terminates TLS and enforces HTTP basic authentication before anything reaches ZeroFS, including the WebSocket. This matches what the ZeroFS project itself recommends.

Every secret is generated on your own VM at first boot, and none is baked into the image. That covers the filesystem encryption password, the web credential, the object store keys, the Redis password and the TLS certificate. Until first boot has produced them, ZeroFS and the object store cannot start, so the shipped image can never come up with a shared or empty encryption password.

What you get:

  • ZeroFS 2.3.2 installed unmodified from the project's official signed package repository, with the version pinned so an unattended upgrade cannot move you to an untested release.
  • NFS, 9P and NBD servers, the web file manager, a live dashboard with a file access tracer, and the in-browser terminal.
  • A bundled single-node object store and a Redis conditional-write coordinator, both bound to loopback, so the filesystem works out of the box.
  • The filesystem already mounted and ready to use on the VM at /mnt/zerofs.
  • A dedicated 40 GiB data volume at /srv/zerofs that holds the object store and the cache.
  • nginx terminating TLS on :443 and enforcing HTTP basic authentication on every request, including the WebSocket, with HSTS and sensible security headers. Port :80 redirects to HTTPS.
  • A unique credential and encryption password generated per VM on first boot. Only a one-way bcrypt hash of the web password is stored, and the plain values land in root-only files.
  • A built-in self test at /usr/local/bin/zerofs-selftest that proves the authentication gate and a real filesystem round trip end to end.
  • Ubuntu 24.04 LTS base with the latest security patches applied at build time and unattended security upgrades left enabled.
  • The Azure Linux Agent, for cloud integration and SSH key injection.
  • 24/7 SecureAnyCloud support with a guaranteed 24-hour response SLA.

SecureAnyCloud is not affiliated with the ZeroFS project. ZeroFS is licensed under the GNU Affero General Public License v3.0 and is shipped here unmodified.

Prerequisites

  • An Azure subscription with permission to deploy virtual machines.
  • An SSH key pair for administrative access to the VM as the azureuser account.
  • A Network Security Group (NSG) allowing inbound TCP 443 (HTTPS) and 80 (redirect) from the networks that should reach the service, and 22 (SSH) from your management network only.
  • A VM size of Standard_B2s or larger (recommended).
1

Deploy from the Azure Portal

  • Find the ZeroFS on Ubuntu 24.04 LTS image in the Azure Marketplace and select Create.
  • Choose your subscription, resource group and region.
  • Select a VM size (Standard_B2s or larger) and provide your SSH public key for the azureuser account.
  • On the Networking tab, allow inbound 443 and 80 from the networks that should reach the service, and 22 from your management network only.
  • Leave the data disk that ships with the image in place. It is mounted at /srv/zerofs and holds the object store and cache.
  • Choose Review + create. First boot takes about a minute while the VM generates its own secrets and initializes the filesystem.
2

Deploy from the Azure CLI

az group create --name zerofs-rg --location eastus
az vm image terms accept --urn sac1647283583153:zerofs-ubuntu-24-04:default:latest
az vm create \
  --resource-group zerofs-rg \
  --name zerofs-vm \
  --image sac1647283583153:zerofs-ubuntu-24-04:default:latest \
  --size Standard_B2s \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard
az vm open-port --resource-group zerofs-rg --name zerofs-vm --port 443 --priority 1001
az vm open-port --resource-group zerofs-rg --name zerofs-vm --port 80 --priority 1002
3

Retrieve your per-instance credential

Every VM generates its own web credential on first boot. It is written to a root-only file:

sudo cat /root/zerofs-credentials.txt

The file lists the administrator username, the password and the URL to open:

ZEROFS_UI_USER=admin ZEROFS_UI_PASSWORD=<a unique 24 character password generated on this VM> ZEROFS_URL=https://<your VM address>/ ZEROFS_MOUNTPOINT=/mnt/zerofs

Back up the encryption password. ZEROFS_PASSWORD in /etc/zerofs/zerofs.env is the key that encrypts everything stored in the object store. Without it, the stored data cannot be decrypted, and SecureAnyCloud cannot recover it for you. Copy it somewhere safe before you put real data on this filesystem:

sudo grep '^ZEROFS_PASSWORD=' /etc/zerofs/zerofs.env
4

Sign in to the Web UI

Open https://<your VM address>/ in a browser. The certificate is self-signed and generated for this VM, so your browser warns you once. Accept it, or replace the certificate as described in Step 14. Sign in with the username and password from Step 3.

You land on the file manager, which shows the real contents of the ZeroFS filesystem.

5

Browse, open and edit files

Double-click a file to open it. Text files open in an editor, and Ctrl+S writes the buffer back through the filesystem. Drag-and-drop uploads work, including whole folders. Dragging entries onto another tab moves them instead of copying them.

Opening the seeded README.txt reads its bytes back out of the encrypted object store and displays them.

Ctrl+F searches the current directory, recursing up to ten levels. A plain query is a case-insensitive substring match. A query containing * or ? is a glob, and /pattern/ is a regular expression.

6

Watch the dashboard

The Monitor view streams live statistics: total operations, bytes read and written, storage used, inode count, throughput and IOPS. It also shows a file access tracer with recent operations.

7

Use the in-browser terminal

The Terminal view boots a small Linux VM inside your browser with the ZeroFS filesystem mounted at /mnt. It is useful for quick file operations without opening an SSH session. The guest has no network device, so files move in and out only through the mounted filesystem.

This terminal can read and write everything on the filesystem. That is one of the main reasons the Web UI is never exposed without authentication on this image.

8

Use the filesystem on the virtual machine

ZeroFS is already mounted at /mnt/zerofs over the in-kernel 9P client. Treat it like any other filesystem:

ls -la /mnt/zerofs/ mount | grep ' /mnt/zerofs '
echo "hello from the sac deployment guide" | sudo tee /mnt/zerofs/hello.txt sync cat /mnt/zerofs/hello.txt
sudo rm -f /mnt/zerofs/hello.txt

The mount reports no fixed size, because the capacity of a ZeroFS filesystem is whatever its object store provides. On this image the bundled store is bounded by the 40 GiB data volume. Check the real backing capacity with:

df -h /srv/zerofs
9

Create a block device over NBD

Files placed in the .nbd directory are exposed as raw block devices. You can put a conventional filesystem or a database on top of object storage:

sudo mkdir -p /mnt/zerofs/.nbd
sudo truncate -s 1G /mnt/zerofs/.nbd/volume1 ls -lh /mnt/zerofs/.nbd/
sudo rm -f /mnt/zerofs/.nbd/volume1

The NBD server listens on 127.0.0.1:10809. Attach the device from the same VM, or reach it from elsewhere over an SSH tunnel as in Step 10.

10

Reach the filesystem from another host

The NFS, 9P and NBD servers are unauthenticated protocols, so they are deliberately bound to loopback and are not reachable across the network. To mount the filesystem from another machine, forward the port over SSH from your client and mount through the tunnel. Run these commands on the client, not on the appliance:

$ ssh -i ~/.ssh/id_rsa -N -L 5564:127.0.0.1:5564 azureuser@<your VM address> $
sudo mount -t 9p -o trans=tcp,port=5564,version=9p2000.L,cache=mmap,access=user 127.0.0.1 /mnt/zerofs

If you would rather expose a protocol port directly on a private network, bind it to the VM's private address in /etc/zerofs/config.toml. Restrict it with a Network Security Group rule to the specific source range that needs it. Never expose these ports to the public internet, because they carry no authentication of their own.

11

Point ZeroFS at your own storage

The bundled object store makes the appliance work immediately, but the reason to run ZeroFS is usually your own object storage. Repointing is a configuration change and a restart. Doing so starts a brand-new, empty filesystem. The data already in the bundled store is not migrated, so copy anything you want to keep off /mnt/zerofs first.

Azure Blob Storage

Edit the [storage] section of /etc/zerofs/config.toml and replace the [aws] block with an [azure] block:

[storage] url = "azure://<your-container>/zerofs-data" encryption_password = "${ZEROFS_PASSWORD}" [azure] storage_account_name = "${AZURE_STORAGE_ACCOUNT_NAME}" storage_account_key = "${AZURE_STORAGE_ACCOUNT_KEY}"

Then add the account credentials to /etc/zerofs/zerofs.env. Keep the existing ZEROFS_PASSWORD line unchanged. Then restart the services:

$
sudo tee -a /etc/zerofs/zerofs.env <<'EOF' AZURE_STORAGE_ACCOUNT_NAME=<your-storage-account> AZURE_STORAGE_ACCOUNT_KEY=<your-storage-account-key> EOF $
sudo systemctl restart zerofs zerofs-mount $
sudo systemctl status zerofs --no-pager

Consider granting the VM a managed identity and using it in place of a stored account key.

Amazon S3 or any S3-compatible store

[storage] url = "s3://<your-bucket>/zerofs-data" encryption_password = "${ZEROFS_PASSWORD}" [aws] access_key_id = "${AWS_ACCESS_KEY_ID}" secret_access_key = "${AWS_SECRET_ACCESS_KEY}" default_region = "us-east-1"

Amazon S3 implements conditional writes natively, which is what ZeroFS needs for fencing. On real S3 you can therefore remove the conditional_put line from the [aws] block and stop the local coordinator:

$
sudo systemctl disable --now redis-server

Keep conditional_put pointing at Redis for any S3-compatible store that does not correctly implement conditional writes. ZeroFS checks this at startup and refuses to run against a store that would silently lose the guarantee. If it starts, the guarantee holds.

Choose a hot storage class

Whatever backend you use, keep it on a hot, standard access tier. Archive tiers make the filesystem unusable. Infrequent-access tiers charge retrieval on the constant reads ZeroFS performs, which usually costs more rather than less.

12

Verify the deployment

Confirm that every service is running:

systemctl is-active zerofs.service zerofs-mount.service garage.service redis-server.service nginx.service

Expected output:

active active active active active

Confirm the network exposure. Only 22, 80 and 443 face the network. Everything else is on loopback:

ss -tlnH | awk '{print $4}' | sort -u

Expected output:

0.0.0.0:22 0.0.0.0:443 0.0.0.0:80 127.0.0.1:10809 127.0.0.1:2049 127.0.0.1:3901 127.0.0.1:3910 127.0.0.1:3913 127.0.0.1:5564 127.0.0.1:6379 127.0.0.1:7000 127.0.0.1:8080 127.0.0.53%lo:53 127.0.0.54:53 [::1]:6379 [::]:22 [::]:443 [::]:80

Only 22, 80 and 443 are bound to a routable address. Everything ZeroFS serves is on loopback: the Web UI on 8080, 9P on 5564, NFS on 2049, NBD on 10809 and the admin RPC on 7000. So are the bundled object store (3901, 3910, 3913), Redis (6379) and the local DNS stub (53).

Run the built-in self test, which proves the whole appliance end to end:

sudo /usr/local/bin/zerofs-selftest

Expected output:

OK zerofs self-test passed: healthz 200, unauth / and /ws/9p 401, authed / 200 (ZeroFS Web UI), authed /ws/9p 101, ZeroFS + object store + Redis all loopback-only, Redis requires auth, filesystem write/read/delete round-trip OK

Prove a real round trip through the filesystem by writing a megabyte and reading it back:

sudo bash -c 'head -c 1048576 /dev/urandom > /tmp/rt.bin; cp /tmp/rt.bin /mnt/zerofs/rt.bin; sync; \
  A=$(sha256sum /tmp/rt.bin | cut -d" " -f1); B=$(sha256sum /mnt/zerofs/rt.bin | cut -d" " -f1); \
  [ "$A" = "$B" ] && echo "ROUND-TRIP OK $A" || echo "MISMATCH"; rm -f /mnt/zerofs/rt.bin /tmp/rt.bin'
13

TLS, redirect and the authentication gate

The health endpoint is deliberately unauthenticated so that load balancer probes work:

curl -sk -o /dev/null -w '%{http_code}\n' https://127.0.0.1/healthz

Expected output:

200

Port 80 redirects to HTTPS:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/

Expected output:

301

Everything else is refused without the per-instance credential, including the WebSocket that backs the file manager and the in-browser terminal:

curl -sk -o /dev/null -w 'web ui: %{http_code}\n' https://127.0.0.1/
curl -sk -o /dev/null -w '9p websocket: %{http_code}\n' https://127.0.0.1/ws/9p

Expected output:

web ui: 401 9p websocket: 401

With the credential, the same request succeeds:

sudo bash -c 'U=$(grep -m1 "^ZEROFS_UI_USER=" /root/zerofs-credentials.txt | cut -d= -f2-); \
  P=$(grep -m1 "^ZEROFS_UI_PASSWORD=" /root/zerofs-credentials.txt | cut -d= -f2-); \
  curl -sk -o /dev/null -w "authenticated: %{http_code}\n" -u "$U:$P" https://127.0.0.1/'

Expected output:

authenticated: 200
14

Replace the TLS certificate

The image generates a self-signed certificate for this VM on first boot, with the VM address in its Subject Alternative Names. To use your own certificate, put it in place and reload nginx:

$
sudo cp /path/to/fullchain.pem /etc/nginx/tls/zerofs.crt $
sudo cp /path/to/privkey.pem /etc/nginx/tls/zerofs.key $
sudo chmod 0600 /etc/nginx/tls/zerofs.key $
sudo nginx -t && sudo systemctl reload nginx

To change the web password, rewrite the basic-authentication file with the bundled helper. Only the bcrypt hash is stored:

$
sudo /usr/local/sbin/zerofs-write-htpasswd admin '<a strong new password>' $
sudo systemctl reload nginx

Then update /root/zerofs-credentials.txt so that the recorded value stays accurate.

15

Check the version and key paths

Print the installed ZeroFS version:

zerofs --version dpkg-query -W -f='zerofs deb version: ${Version}\n' zerofs

Expected output:

zerofs 2.3.2 zerofs deb version: 2.3.2

Key paths on the appliance:

  • /etc/zerofs/config.toml: ZeroFS configuration (storage backend, cache and server ports).
  • /etc/zerofs/zerofs.env: per-VM secrets, root only (encryption password, object store key, Redis password).
  • /root/zerofs-credentials.txt: per-VM web credential and URL, root only.
  • /mnt/zerofs: the ZeroFS filesystem, mounted on the VM.
  • /srv/zerofs: the dedicated data volume that holds the object store and the cache.
  • /etc/nginx/sites-available/sac-zerofs: the TLS and authentication front.
  • /usr/local/bin/zerofs-selftest: the end-to-end appliance self test.

The image ships ZeroFS 2.3.2 from the project's own repository. Ubuntu's unattended upgrades act only on Ubuntu's own security origins, so ZeroFS is never upgraded automatically underneath you. Take a newer release deliberately when you are ready:

$
sudo apt-get update && sudo apt-get install --only-upgrade zerofs $
sudo systemctl restart zerofs zerofs-mount

Security notes

  • The Web UI has no authentication of its own. Access is controlled entirely by the nginx basic-authentication credential over TLS. Its WebSocket endpoint is a full read and write session on the filesystem, its gRPC endpoint exposes administrative methods and accepts any origin, and its terminal boots a Linux VM with the filesystem mounted. Never bind ZeroFS to a non-loopback address, and never remove the auth_basic directives.
  • NFS, 9P and NBD carry no authentication. They are bound to loopback on this image. If you expose one on a private network, restrict it with a Network Security Group rule to the exact source range that needs it.
  • Every secret is per VM. The encryption password, web password, object store keys, Redis password and TLS certificate are all generated on first boot. Nothing usable is baked into the image, and ZeroFS and the object store cannot start until first boot has produced them.
  • The encryption password is not recoverable. It lives only on your VM in /etc/zerofs/zerofs.env. Back it up before storing anything important.
  • Restrict SSH. Allow port 22 only from your management network, and keep key-based authentication.
  • The base image is patched at build time and ships with unattended security upgrades enabled.

Support

SecureAnyCloud provides 24/7 support with a guaranteed 24-hour response SLA for this image. For questions about the image, its configuration or its security posture, contact SecureAnyCloud support at sales@secureanycloud.com.

ZeroFS itself is open source under the GNU Affero General Public License v3.0 and is shipped unmodified. SecureAnyCloud is not affiliated with the ZeroFS project.

Deploy on Azure

Launch ZeroFS 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