Deployment guide

miniserve

Overview

miniserve is a small, fast, self-hosted HTTP file server. Point it at a directory and it serves a clean web interface to browse folders, download files or whole folders as tar.gz or zip archives, and upload files or create directories from the browser. It is a single static Rust binary with no database and no accounts system.

Upstream miniserve is public and has no authentication. This SecureAnyCloud image requires HTTP basic authentication, binds miniserve to loopback behind an nginx reverse proxy, and serves only a dedicated directory at /srv/miniserve rather than the whole filesystem.

There is no default password. miniserve-firstboot.service generates a unique password on each VM's first boot. Only its sha256 hash is stored in the service configuration, and the plaintext is written to a root-only file at /root/miniserve-info.txt. The password is never baked into the image.

What you get:

  • miniserve 0.35.0 as a single static Rust binary (/usr/local/bin/miniserve)
  • A dedicated served directory at /srv/miniserve with file upload and directory creation enabled
  • miniserve.service running as miniserve, bound to loopback 127.0.0.1:8080, with HTTP basic auth required
  • nginx.service reverse proxy on TCP 80, ready for TLS and sized for large uploads
  • miniserve-firstboot.service, which generates a per-VM basic auth password on first boot (username SecureAnyCloud)
  • Folder downloads as tar.gz or zip, light and dark themes, and browser uploads
  • An Ubuntu 24.04 LTS base with the latest patches and unattended security upgrades enabled
  • 24/7 SecureAnyCloud support, 24h response SLA

Prerequisites

You need an active Azure subscription, an SSH key, and a VNet with a subnet.

The recommended VM size is Standard_B2s. miniserve is very light, so 4 GB of RAM is plenty.

1

Deploy from the Azure Portal

Search the Azure Marketplace for miniserve, choose the plan, and create the VM.

In the networking step, attach a network security group (NSG) that allows inbound TCP 22 (SSH) and TCP 80 (the web UI) from your client networks only. For production, put a TLS reverse proxy in front of port 80.

2

Deploy from the Azure CLI

RG="miniserve-prod"; LOCATION="eastus"; VM_NAME="miniserve-01" IMAGE_URN="sac1647283583153:miniserve-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION" az network vnet create -g "$RG" --name ms-vnet --address-prefix 10.104.0.0/16 --subnet-name ms-subnet --subnet-prefix 10.104.1.0/24 az network nsg create -g "$RG" --name ms-nsg az network nsg rule create -g "$RG" --nsg-name ms-nsg --name allow-ssh --priority 100 \
  --source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp az network nsg rule create -g "$RG" --nsg-name ms-nsg --name allow-web --priority 110 \
  --source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 80 --access Allow --protocol Tcp
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:miniserve-ubuntu-24-04:default:latest
az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" \
  --size Standard_B2s --storage-sku StandardSSD_LRS \
  --admin-username azureuser --ssh-key-values "$SSH_KEY" \
  --vnet-name ms-vnet --subnet ms-subnet --nsg ms-nsg --public-ip-sku Standard
3

Connect via SSH

Connect to the VM as azureuser:

ssh azureuser@<vm-ip>

miniserve.service, nginx.service and miniserve-firstboot.service all start automatically on first boot.

4

Verify the Service

Run these commands to check the services, the first-boot sentinel and the listening ports:

sudo systemctl is-active miniserve nginx miniserve-firstboot
sudo test -f /var/lib/sac/data/miniserve-firstboot.done && echo FIRSTBOOT_DONE
sudo ss -tlnp | grep -E ':80 |:8080 '

All three services report active. nginx is bound to the public port 80, and miniserve is bound to loopback 127.0.0.1:8080 only:

active active active FIRSTBOOT_DONE LISTEN 0 1024 127.0.0.1:8080 0.0.0.0:* users:(("miniserve",...)) LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",...))
5

Retrieve the Per-VM Login

There is no default password. On first boot the image generates a per-VM password for the SecureAnyCloud user. Only its sha256 hash is stored in the service configuration, and the plaintext is written to a root-only note. Read the note with sudo:

sudo cat /root/miniserve-info.txt

The note contains the username, the per-VM password and the resolved URL. The password is unique to this machine and never baked into the image:

MINISERVE_USERNAME=sac MINISERVE_PASSWORD=<MINISERVE_PASSWORD> MINISERVE_URL=http://<vm-ip>/ NOTE=Open MINISERVE_URL in a browser and log in with MINISERVE_USERNAME / MINISERVE_PASSWORD to browse, download and upload files under /srv/miniserve.
6

Secure by Default

miniserve binds only to loopback and is fronted by nginx. miniserve itself enforces basic auth, and the service configuration stores only the sha256 hash of the password, never the plaintext. Check the configuration:

grep '^MINISERVE_AUTH=' /etc/miniserve/miniserve.env
sudo ss -tlnp | grep 8080
grep -E 'client_max_body_size|proxy_pass' /etc/nginx/sites-available/sac-miniserve

The auth line carries the username and a sha256 hash. miniserve listens on loopback only, and nginx forwards requests to it:

MINISERVE_AUTH=sac:sha256:<sha256 hash of the per VM password> LISTEN 0 1024 127.0.0.1:8080 0.0.0.0:* users:(("miniserve",...)) client_max_body_size 5g; proxy_pass http://miniserve_backend;
7

Prove Auth Is Enforced and a File Round Trips

Without a login, the listing is refused with HTTP 401. The unauthenticated healthcheck stays open so a load balancer can probe it:

curl -s -o /dev/null -w 'no login: HTTP %{http_code}\n' http://127.0.0.1/
curl -s -o /dev/null -w 'healthcheck: HTTP %{http_code}\n' http://127.0.0.1/__miniserve_internal/healthcheck

Log in with the per-VM password to list the directory. Then upload a file through the /upload endpoint and download it back:

sudo bash -c ' P=$(grep "^MINISERVE_PASSWORD=" /root/miniserve-info.txt | cut -d= -f2-) curl -s -o /dev/null -w "listing (with login): HTTP %{http_code}\n" -u sac:$P http://127.0.0.1/ echo "hello from sac" > /tmp/report.txt curl -s -o /dev/null -w "upload: HTTP %{http_code}\n" -u sac:$P -F "file=@/tmp/report.txt;filename=report.txt" "http://127.0.0.1/upload?path=." echo "download: $(curl -s -u sac:$P http://127.0.0.1/report.txt)" rm -f /srv/miniserve/report.txt /tmp/report.txt '

The listing returns 200 with the login, the upload returns 303, and the file downloads back unchanged:

no login: HTTP 401 healthcheck: HTTP 200 listing (with login): HTTP 200 upload: HTTP 303 download: hello from sac

From your own machine, use the public URL and the per-VM password instead of loopback:

curl -u sac:<MINISERVE_PASSWORD> http://<vm-ip>/
curl -u sac:<MINISERVE_PASSWORD> -F 'file=@./photo.jpg' 'http://<vm-ip>/upload?path=.'
8

Browse in the Web UI

Open the URL in a browser and log in as SecureAnyCloud with the per-VM password:

open http://<vm-ip>/

The directory listing shows every file and folder with sizes and timestamps. It also provides buttons to download the whole directory as tar.gz or zip, a theme picker and a search box. Open any directory to browse deeper.

9

Upload Files and Create Directories

The upload form sits above the listing. Choose one or more files, or drag them anywhere into the window, then select Upload file. Uploads land directly in the served directory.

To create a folder, enter a name in the directory name field next to the upload form. Open a subfolder to browse into it, and use the breadcrumb at the top or the Parent directory row to navigate back up.

10

Themes

miniserve ships light and dark colour schemes. Use the Change theme control, or let miniserve follow your browser's light or dark preference automatically.

11

Server Components

These are the files that make up the installation:

Component Path

miniserve binary /usr/local/bin/miniserve

Served directory /srv/miniserve

Config (EnvironmentFile) /etc/miniserve/miniserve.env

Systemd unit /etc/systemd/system/miniserve.service

First-boot script /usr/local/sbin/miniserve-firstboot.sh

Per-VM info note /root/miniserve-info.txt (mode 0600)

Sentinel /var/lib/sac/data/miniserve-firstboot.done

/usr/local/bin/miniserve --version ls /usr/local/bin/miniserve /etc/miniserve/miniserve.env /etc/systemd/system/miniserve.service
12

Managing the Service

Restart the service and read its recent log lines with:

sudo systemctl restart miniserve.service
sudo journalctl -u miniserve.service --no-pager -n 20

miniserve refuses to start unless a valid MINISERVE_AUTH credential is present. It therefore never serves files without a login, even if first boot has not run.

13

Configuration

miniserve is configured entirely through environment variables in /etc/miniserve/miniserve.env. The image already sets these keys:

Variable Meaning Image default

MINISERVE_PATH Directory served /srv/miniserve

MINISERVE_INTERFACE Bind address 127.0.0.1 (loopback)

MINISERVE_PORT Bind port 8080

MINISERVE_AUTH Basic auth credential sac:sha256:... (per VM, at first boot)

MINISERVE_ALLOWED_UPLOAD_DIR Upload target within the served dir / (uploads land in the served directory)

MINISERVE_MKDIR_ENABLED Allow creating directories true

MINISERVE_ENABLE_TAR_GZ / MINISERVE_ENABLE_ZIP Folder archive downloads true

MINISERVE_TITLE Page title SecureAnyCloud file server

After you edit the file, apply the changes with sudo systemctl restart miniserve.service.

To rotate the password, set a new MINISERVE_AUTH line to sac:sha256:<hash>, where the hash is printf '%s' 'newpassword' | sha256sum. Then restart the service.

14

Add TLS (Optional)

For production, terminate TLS at nginx. Point a DNS record at the VM, then use the packaged nginx with a certificate from Let's Encrypt. Run:

sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <your-domain>

certbot installs the certificate, rewrites the nginx server block to listen on 443, and sets up automatic renewal.

15

Security Recommendations

  • Restrict the NSG so that ports 80 and 22 only reach trusted networks.
  • Terminate TLS at nginx (Step 14) so that file transfers and the login travel encrypted.
  • Keep basic auth on. The per-VM password protects the listing, uploads and downloads. Rotate it from /etc/miniserve/miniserve.env (Step 13).
  • Serve only /srv/miniserve. The image deliberately serves one dedicated directory, never the whole filesystem.
  • Patch the OS monthly with sudo apt-get update && sudo apt-get upgrade. Unattended security upgrades are already enabled.
16

Support and Licensing

miniserve is MIT licensed, with no per-CPU or per-user fee. SecureAnyCloud provides commercial support separately.

  • Email: sales@secureanycloud.com
  • Website: secureanycloud.com
  • Support hours: 24/7, 24h response SLA

Deploy on Azure

Deploy on Azure

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