HFS
Overview
This guide covers the deployment and configuration of HFS HTTP File Server on Ubuntu 24.04 on Azure, using SecureAnyCloud Azure Marketplace images. HFS (HTTP File Server) is an open source, self-hosted web file server. It lets you browse folders, upload with drag and drop, download files and whole folders as archives, and share content straight from a web browser. A full admin panel manages accounts, virtual folders and granular per-folder permissions.
The image installs the pinned stable HFS 3.2.1 release from the official prebuilt self-contained binary (recorded in /opt/hfs/app/VERSION). It runs HFS under systemd as the unprivileged hfs system user, bound to loopback only (127.0.0.1:8080). nginx is the sole network-facing surface. It terminates TLS on port 443 and reverse-proxies to HFS, and port 80 redirects to HTTPS.
Secure by default. Out of the box, HFS ships with no account and grants admin access to anyone connecting from localhost. Behind a reverse proxy, that behaviour would expose the admin panel to every visitor. This image disables it (localhost_admin: false), so an administrator login is always required.
The image also gates the shared folder to logged-in accounts only, so there is no anonymous access, and it generates a unique administrator credential on each virtual machine's first boot. HFS stores only a one-way SRP hash of the password, and the plain password is placed in a root-only file for the administrator to read. There are no shared or default credentials, and nothing usable is baked into the image.
What you get:
- HFS 3.2.1 from the official prebuilt self-contained binary, run under systemd as the unprivileged
hfssystem user - HFS bound to loopback only (
127.0.0.1:8080), so it is never exposed directly to the network - nginx terminating TLS on :443 and reverse-proxying to HFS, with HSTS, sensible security headers and unlimited upload body size for large files
- Port
:80returns a301redirect to HTTPS for every path except an unauthenticated/healthzendpoint (HTTP 200) for load balancer probes - A unique admin credential generated per VM on first boot. Only the one-way SRP hash is stored, and the plain password lands in a root-only file
- Admin panel access hardened (
localhost_admin: false) and one trusted reverse proxy configured (proxies: 1), so that real client IPs are logged - The shared folder
/srv/hfs-filesgated to logged-in accounts, so there is no anonymous access baked in - A self-signed TLS certificate regenerated per VM on first boot (its Subject Alternative Names include the VM public IP, hostname and
127.0.0.1). Replace it with your own CA-signed certificate for production - A built-in self test at
/usr/local/bin/hfs-selftestthat proves the authenticated file listing and admin API end to end over TLS - Ubuntu 24.04 LTS base with the latest security patches applied at build time
- Azure Linux Agent for cloud integration and SSH key injection
- 24/7 SecureAnyCloud support with a guaranteed 24 hour response SLA
Prerequisites
- An Azure subscription with permission to deploy virtual machines
- An SSH key pair for administrative access to the VM as the
azureuseraccount - A Network Security Group that allows inbound TCP
443(HTTPS) and80(redirect) from the networks that should reach the service, and22(SSH) from your management network only - A recommended size of Standard_B2s or larger
Deploy from the Azure Portal
Find the HFS HTTP File Server 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 your users, and restrict 22 to your management network.
Review and create the VM. When the VM is running, browse to https://<your-public-ip>/.
Deploy from the Azure CLI
Deploy the image from the command line and restrict SSH to your management network. Replace the example values with your own, and then run the commands:
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:hfs-ubuntu-24-04:default:latest
az vm create \
--resource-group my-resource-group \
--name hfs \
--image sac1647283583153:hfs-ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pub \
--public-ip-sku Standard
# Allow the web UI from your users and SSH from your management network only
az vm open-port --resource-group my-resource-group --name hfs --port 443 --priority 1001
az network nsg rule create --resource-group my-resource-group --nsg-name hfsNSG \
--name allow-ssh --priority 1002 --destination-port-ranges 22 \
--source-address-prefixes <your-mgmt-cidr> --access Allow --protocol TcpWhen the VM is running, browse to https://<public-ip>/.
Retrieve your per-instance admin credential
Access requires an HFS account login. Each VM generates its own admin username and password on first boot and writes them to a root-only file. Read the file over SSH:
ssh azureuser@<vm-ip> 'sudo cat /root/hfs-credentials.txt'The file contains the HFS_USER, HFS_PASS and HFS_URL for this specific VM. Keep the file secret. The server stores only a one-way SRP hash of the password, never the plain text.
Sign in to your file server
Browse to https://<vm-ip>/. The certificate is self-signed per VM, so your browser shows a certificate warning the first time. Accept the warning to proceed, or install the per-VM certificate, or place a CA-signed certificate in front, as covered in Step 10.
HFS then shows its login form. Sign in with the username and password from Step 3.
The shared folder is gated to logged-in accounts, so there is no anonymous access and an unauthenticated request is refused. After you sign in, you land on the file browser. It shows the shared files folder along with a toolbar for Select, Search, Options and Zip.
Browse, download and upload files
Open the files folder to see its contents. The image ships a WELCOME.txt starter file so that the folder is not empty. From here you can download individual files, or select several and download them as a single zip archive. As the admin account, you can upload new files with the Upload button or by dragging them onto the page.
Your files live on the VM at /srv/hfs-files. You can also add files to that folder directly over SSH, and they appear in the browser immediately.
Open the admin panel
Open the admin panel at https://<vm-ip>/~/admin. It opens on the Home page, which confirms that the server is working. The sidebar lists Shared files, Accounts, Options, Internet, Monitoring, Logs, Plugins and more. You manage everything about the server from here.
Add shared folders, accounts and permissions
Select Shared files in the admin sidebar to manage the Virtual File System. The tree shows your Home folder with the files folder inside it. Use the toolbar to add more folders from disk, and then set who can read, see, upload or delete on each one.
The available values are anyone, any logged-in account, admins only, or a named list of accounts. You can therefore mix public download folders with private ones.
Create additional users under Accounts, give each user their own home folder or set of permissions, and share links publicly or privately as needed. The single admin credential from Step 3 is only the starting point.
Verify the deployment
SSH to the VM as azureuser and confirm the services are running and HFS is bound to loopback only:
systemctl is-active hfs nginx
sudo ss -tlnp | grep 8080All services report active, and HFS listens on 127.0.0.1:8080 only. nginx is the only component exposed on :80 and :443.
Run the built-in self test. It reads this VM's credential and proves the full path over TLS. The health probe answers, an unauthenticated request is refused, and an unauthenticated file listing is refused. An authenticated request lists the shared folder and reaches the admin API:
sudo /usr/local/bin/hfs-selftestTLS, redirect and the authentication gate
nginx terminates TLS on port 443 and redirects plain HTTP on port 80 to HTTPS. Confirm the redirect, the unauthenticated health probe, and that both the file server and its listing API require the per-VM credential:
curl -s -o /dev/null -w 'port 80 -> HTTP %{http_code}\n' http://127.0.0.1/
curl -sk -o /dev/null -w 'healthz -> HTTP %{http_code}\n' https://127.0.0.1/healthz
curl -sk -o /dev/null -w 'no creds -> HTTP %{http_code}\n' https://127.0.0.1/
curl -sk -o /dev/null -w 'listing no creds -> HTTP %{http_code}\n' 'https://127.0.0.1/~/api/get_file_list?uri=/'Port 80 returns 301 and the health endpoint returns 200. An unauthenticated request to the file server, and to the file listing API, is refused with 401, while a request carrying this VM's credential succeeds with 200. The self-signed certificate is regenerated per VM on first boot, with the VM IP and hostname in its Subject Alternative Names:
Replace the certificate for production
The per-VM certificate is self-signed, so browsers warn on first use. For a public deployment, put a real certificate in front. The simplest approach is to point a DNS name at the VM and obtain a free certificate with Certbot:
# Point https://<your-domain> at this VM first, then:
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <your-domain>Alternatively, terminate TLS at an Azure Application Gateway or a load balancer in front of the VM and forward to port 443. HFS is already configured to trust one reverse proxy (proxies: 1), so it logs the real client IP behind nginx.
Baked version and per-instance credential
The baked HFS version is recorded on the VM, alongside this instance's credential summary. The password line is redacted below. Read the full value from the root-only file in Step 3. The config.yaml file stores only a one-way SRP hash, never a plain text password:
cat /opt/hfs/app/VERSION
sudo cat /root/hfs-credentials.txtSecurity notes
- No default login. HFS enforces its own account login, and a unique admin credential is generated on each VM's first boot. Only a one-way SRP hash is stored. The plain password lives in the root-only
/root/hfs-credentials.txt. - No anonymous access, hardened admin. The shared folder is gated to logged-in accounts, and
localhost_adminis disabled, so the admin panel behind the reverse proxy still requires an admin login. Nothing is exposed anonymously. - Loopback-only application. HFS binds to
127.0.0.1:8080and is reachable only through the nginx TLS reverse proxy on:443. Keep it that way, and let nginx (or a load balancer) be the sole network-facing surface. - Restrict access. Allow
443only from the networks that need it, keep22restricted to your management network, and replace the self-signed certificate with a CA-signed one for production. - Manage credentials in the admin panel. Change the admin password, create additional accounts and set per-folder permissions under Accounts and Shared files in the admin panel. Sign in only over HTTPS.
Support
This image is backed by 24/7 SecureAnyCloud support with a guaranteed 24 hour response SLA. Contact sales@secureanycloud.com for assistance.
HFS is open source software distributed under the GNU General Public License v3.0, and it is free. The SecureAnyCloud charge covers packaging, hardening, security patching, image maintenance and support.
Deploy on Azure
Launch HFS HTTP File 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
Overview
This image runs HFS (HTTP File Server) 3.2.2, the open source, self-hosted web file server by rejetto, on Ubuntu 24.04 LTS. HFS lets you share files and folders straight from a web browser. You can browse, download, download a whole folder as an archive, and upload with drag and drop. A modern, responsive front end and a full admin panel manage shared folders, accounts and granular per-folder permissions.
HFS ships as a self-contained prebuilt binary that bundles its own Node runtime, so there is no system Node.js to install or maintain. It runs as an unprivileged hfs system account under a systemd service that starts it on boot and restarts it on failure.
HFS listens on the loopback address 127.0.0.1:8080 by design and is never exposed directly. nginx terminates TLS on port 443 and reverse-proxies to the loopback listener, forwarding the real client address so that HFS logs and permissions see it. Port 80 redirects to HTTPS. An unauthenticated /healthz endpoint, served by nginx itself and never proxied, is available on both ports for load balancer health checks.
The image is secure by default, which matters more than usual for HFS. Out of the box, HFS ships with no account at all and grants admin panel access to anyone connecting from localhost. Behind a reverse proxy, that behaviour would hand the admin panel to every visitor on the internet. This image closes that gap in three ways:
localhost_adminis disabled, so an administrator login is always required.- The shared folder is gated to logged-in accounts only, so there is no anonymous browsing.
- Upload and delete are admin only, so there is no anonymous upload.
On the first boot of every deployed instance, a one-shot service generates a fresh per-instance admin credential and lets HFS store only a one-way SRP hash of the password. It also regenerates a per-instance self-signed TLS certificate and writes the plain credential to /root/hfs-credentials.txt (mode 0600, readable only by root). Two instances launched from the same AMI never share a credential, and no usable credential ships inside the image.
HFS also applies a progressive delay to failed logins. Each additional wrong password from the same client waits longer, which blunts password guessing without any extra configuration.
The shared file store is /srv/hfs/files. It lives on its own independently resizable EBS data volume mounted at /srv/hfs, kept separate from the operating system disk. HFS's own configuration lives on the OS disk at /opt/hfs.
The default security group for this listing opens port 22 (SSH), port 80 (HTTP, redirect and health) and port 443 (HTTPS).
Self-signed certificate. The per-instance TLS certificate is self-signed, so your browser shows a warning the first time you connect. This is expected. For production, install a CA-signed certificate for a real domain (see Step 9) or terminate TLS at an AWS load balancer.
HFS is licensed GPL-3.0. The licence text ships in the image at /opt/hfs/app/LICENSE.
Prerequisites
- An AWS account subscribed to this product in AWS Marketplace.
- An EC2 key pair in your target region for SSH access.
- A security group that allows inbound TCP 22 (SSH) from your IP, and TCP 443 (HTTPS) from your users. TCP 80 is optional.
- Recommended instance type:
m5.largeor larger.
Connecting to your instance
SSH in as the default login user for your operating system variant, using the key pair that you launched with.
OS variant Login user Example
Ubuntu 24.04 ubuntu ssh -i your-key.pem ubuntu@<instance-public-ip>
Step 1 - Launch from the AWS Marketplace console
- Open the product page in AWS Marketplace, and choose Continue to Subscribe, then Continue to Configuration.
- Select the software version and your AWS Region, and then choose Continue to Launch.
- Choose an instance type (
m5.largeor larger), your VPC subnet, the security group described above, and your EC2 key pair. - Launch the instance and wait for it to reach the running state with status checks passed.
Step 2 - Launch from the AWS CLI (alternative)
Replace the AMI ID, key name, security group and subnet with your own values:
aws ec2 run-instances \
--image-id ami-xxxxxxxxxxxxxxxxx \
--instance-type m5.large \
--key-name your-key \
--security-group-ids sg-xxxxxxxx \
--subnet-id subnet-xxxxxxxx \
--metadata-options "HttpTokens=required" \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=hfs-file-server}]'First boot resolves the instance's public IPv4 through IMDSv2, so launching with HttpTokens=required is supported.
Step 3 - Confirm the services are running
HFS and nginx both start automatically on boot. Check that they are running:
systemctl is-active hfs.service nginx.serviceactive activeConfirm the installed version and where it came from:
cat /opt/hfs/app/VERSIONhfs_version=3.2.2 hfs_binary=/opt/hfs/app/hfs source=https://github.com/rejetto/hfs/releases/download/v3.2.2/hfs-linux-x64-3.2.2.zip licence=GPL-3.0 baked_at=2026-07-26T05:01:53ZThe listener layout shows the design: HFS listens only on loopback, and nginx listens on ports 80 and 443.
sudo ss -tlnp | grep -E ':(80|443|8080)\b'LISTEN 0 511 127.0.0.1:8080 0.0.0.0:* users:(("HFS 3.2.2",pid=3785,fd=31)) LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=3798,fd=5),("nginx",pid=3797,fd=5),("nginx",pid=3794,fd=5)) LISTEN 0 511 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=3798,fd=7),("nginx",pid=3797,fd=7),("nginx",pid=3794,fd=7))Step 4 - Retrieve the per-instance admin credential
Each instance generates its own admin username and password on first boot and stores them in a root-only file. SSH in and read the file:
sudo cat /root/hfs-credentials.txtThe file shows the generated HFS_USER, HFS_PASS and HFS_URL for this instance. Keep this file secret. It is readable only by root (0600). HFS itself never stores the plain password, and its configuration holds only a one-way SRP hash.
Step 5 - Sign in to the file server
Browse to your instance over HTTPS:
https://<instance-public-ip>/Your browser warns about the self-signed certificate the first time. Accept the warning to continue, or install a real certificate (Step 9).
Because there is no anonymous access, an unauthenticated visitor sees a login prompt rather than your files:
Enter the HFS_USER and HFS_PASS from Step 4 and choose Continue. You are then signed in and see the shared folder at the root of the file server:
You can confirm from the command line that anonymous visitors are refused and that the health probe stays open for load balancers:
curl -sk -o /dev/null -w 'unauthenticated / HTTP %{http_code}\n' https://127.0.0.1/unauthenticated / HTTP 401curl -sk -o /dev/null -w 'healthz HTTP %{http_code}\n' https://127.0.0.1/healthzhealthz HTTP 200curl -s -o /dev/null -w 'port 80 HTTP %{http_code} -> %{redirect_url}\n' http://127.0.0.1/port 80 HTTP 301 -> https://127.0.0.1/Step 6 - Browse, download and upload files
Click a folder to open it. Each entry shows its size and timestamp, and the toolbar offers these actions:
- Download: click a file name.
- Download a whole folder: use Zip to stream the folder as an archive.
- Upload: drag files onto the listing, or use Upload. In the shipped configuration, upload and delete are admin only. Grant them to other accounts in Step 8.
- Search: find files by name beneath the current folder.
- Select: tick multiple entries to zip or delete them together.
Files that you add on the server itself appear immediately, because the shared folder is just a directory on disk:
ls -la /srv/hfs/filesStep 7 - Add your own shared folders
Open the admin panel from the front-end menu, or go straight to it:
https://<instance-public-ip>/~/adminChoose Shared files to edit the Virtual File System, which is the tree of what your users see. The shipped tree has one entry, files, pointing at /srv/hfs/files on the dedicated data volume.
To add another folder, select the Home folder node, use the + button to add a folder from disk, pick the path, and then save. Nothing on disk is modified. The virtual file system only decides what is exposed and to whom.
Keep customer data on the data volume. Prefer paths under /srv/hfs for anything you expect to grow. That volume is independently resizable and separate from the OS disk, so you can grow storage without rebuilding the instance.
Step 8 - Create accounts and per-folder permissions
In the admin panel, choose Accounts to add users and Shared files to set permissions on any folder in the tree. Each folder carries its own settings:
Permission What it controls
can_read Who may download from the folder
can_see Who may see the folder exists in a listing
can_archive Who may download the folder as a zip
can_upload Who may upload into the folder
can_delete Who may delete from the folder
Each permission can be set to specific accounts, to * (any logged-in account, which is the shipped default for reading), or to true (anyone, including anonymous visitors).
Anonymous access is opt-in, and it is your decision. The image deliberately ships with no anonymous read and no anonymous upload. If you want a public download folder, set can_read to true on that folder only and leave the rest gated. Do not set can_upload to true on a folder that anonymous visitors can reach, unless you intend to run an open drop box.
You can inspect the live configuration on the server. The values below are the shipped defaults:
sudo grep -E 'localhost_admin|can_read|can_upload|can_delete|listen_interface' /opt/hfs/data/config.yamlStep 9 - Install a CA-signed certificate for a real domain
The per-instance certificate is self-signed. For production, point a DNS name at the instance and replace the certificate that nginx serves.
Certificate and key paths used by nginx:
File Purpose
/etc/nginx/tls/hfs.crt Certificate chain served on port 443
/etc/nginx/tls/hfs.key Private key (mode 0600, root-only)
Install certbot and issue a certificate for your domain, or copy your own certificate and key over those two paths. Then test and reload nginx:
sudo nginx -tsudo systemctl reload nginxAlternatively, terminate TLS at an AWS Application Load Balancer with an ACM certificate and forward to port 443 on the instance.
Step 10 - Verify the whole appliance at any time
The image ships a self test that exercises the running server end to end over TLS. It checks the health probe, the refusal of anonymous browsing and anonymous upload, the rejection of a blank password, the authenticated file listing, and the admin API:
sudo /usr/local/bin/hfs-selftestOK hfs self-test passed: healthz 200, unauth / 401, unauth list 401, authed list 200 (files shared), authed / 200, admin API 200, blank credential rejected, anonymous upload refusedStep 11 - The dedicated file store volume
The shared folder lives on its own EBS volume, mounted by filesystem UUID so it survives reboots and re-launches:
findmnt -o TARGET,SOURCE,FSTYPE,SIZE,USED /srv/hfsTARGET SOURCE FSTYPE SIZE USED /srv/hfs /dev/nvme1n1 ext4 97.9G 2.4Mdf -h /srv/hfsFilesystem Size Used Avail Use% Mounted on /dev/nvme1n1 98G 2.4M 93G 1% /srv/hfsTo grow the store, modify the EBS volume in the EC2 console (or with aws ec2 modify-volume), and then extend the filesystem in place. This needs no downtime and no rebuild:
sudo resize2fs /dev/nvme1n1Back the store up with EBS snapshots of that volume, or with your own copy of /srv/hfs/files.
Maintenance
Task Command
Service state systemctl status hfs.service
Restart HFS sudo systemctl restart hfs.service
HFS logs sudo journalctl -u hfs.service -n 100
nginx logs sudo journalctl -u nginx.service -n 100
First boot log sudo cat /var/log/sac/sac-firstboot.log
Configuration /opt/hfs/data/config.yaml
Shared folder /srv/hfs/files
Credential note /root/hfs-credentials.txt (mode 0600)
Self test sudo /usr/local/bin/hfs-selftest
Operating system security updates are applied automatically by unattended-upgrades. HFS itself is version pinned in the image. The admin panel's Home page can check for newer HFS releases, and SecureAnyCloud publishes refreshed images as upstream releases land.
Troubleshooting
The browser shows a certificate warning. This is expected, because the per-instance certificate is self-signed. Accept the warning, or install a CA-signed certificate (Step 9).
I get a login prompt and no files. This is the intended behaviour, because there is no anonymous access. Sign in with the credential from Step 4.
A wrong password seems to hang. HFS deliberately delays repeated failed logins, and the delay grows with each failure from the same client. Wait, and then use the correct credential.
I lost the admin password. Read it again from /root/hfs-credentials.txt. If the file has been removed, set a new password from the admin panel's Accounts page while signed in. Alternatively, write a fresh configuration with sudo /usr/local/sbin/hfs-write-config <username> <new-password> and restart hfs.service. HFS re-hashes the password and strips the plain text on startup.
Nothing answers on port 443. Check systemctl is-active nginx.service and sudo nginx -t. Confirm that your security group allows inbound TCP 443.
Uploads fail for a non-admin account. Upload is admin only in the shipped configuration. Grant can_upload to that account on the target folder (Step 8).
Support
SecureAnyCloud provides 24/7 technical support for this product by email and live chat.
- Email: sales@secureanycloud.com
- Live chat: available 24/7
The support team helps with deployment, signing in, adding shared folders, creating accounts and per-folder permissions, installing a CA-signed certificate for a real domain, sizing and growing the file store volume, and scaling.
HFS is a trademark of its respective owner. All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.
Deploy on AWS
Launch HFS (HTTP File Server) on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com