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/miniservewith file upload and directory creation enabled miniserve.servicerunning asminiserve, bound to loopback127.0.0.1:8080, with HTTP basic auth requirednginx.servicereverse 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.
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.
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 StandardConnect 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.
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",...))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.txtThe 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.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-miniserveThe 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;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/healthcheckLog 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 sacFrom 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=.'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.
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.
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.
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.serviceManaging 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 20miniserve 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.
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.
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.
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.
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