HFS (HTTP File Server) on AWS User Guide
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 - browse, download, download a whole folder as an archive, drag and drop upload - with a modern responsive front end and a full admin panel for managing 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 HFS logs and permissions see it. Port 80 redirects to HTTPS, and an unauthenticated /healthz endpoint (served by nginx itself, never proxied) is available on both ports for load balancer health checks.
The image is secure by default, and this 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 - which, behind a reverse proxy, would hand the admin panel to every visitor on the internet. This image closes that: localhost_admin is disabled so an administrator login is always required, the shared folder is gated to logged in accounts only so there is no anonymous browsing, and 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, lets HFS store only a one way SRP hash of the password, 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, which 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 + health) and port 443 (HTTPS).
Self signed certificate. The per-instance TLS certificate is self signed, so your browser will show 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 allowing inbound TCP 22 (SSH) from your IP, and TCP 443 (HTTPS) - and optionally TCP 80 - from your users.
- 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 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, 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 fully supported.
Step 3 - Confirm the services are running
HFS and nginx both start automatically on boot. Check them:
systemctl is-active hfs.service nginx.service
active
active
Confirm the version that is installed and where it came from:
cat /opt/hfs/app/VERSION
hfs_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:53Z
The listener layout shows the design: HFS only on loopback, nginx on 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 it:
sudo cat /root/hfs-credentials.txt
You will see the generated HFS_USER, HFS_PASS and the HFS_URL for this instance. Keep this file secret - it is readable only by root (0600). HFS itself never stores the plain password: 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 will warn about the self signed certificate the first time - accept it to continue (or install a real certificate, Step 9). Because there is no anonymous access, an unauthenticated visitor is met with 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 really 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 401
curl -sk -o /dev/null -w 'healthz HTTP %{http_code}\n' https://127.0.0.1/healthz
healthz HTTP 200
curl -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 exposes the 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 you add on the server itself appear immediately - the shared folder is just a directory on disk:
ls -la /srv/hfs/files
Step 7 - Add your own shared folders
Open the admin panel from the front end menu, or go straight to it:
https://<instance-public-ip>/~/admin

Choose Shared files to edit the Virtual File System - 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, 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/hfsfor 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 can be set to specific accounts, to * (any logged in account - 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_readtotrueon that folder only and leave the rest gated. Never setcan_uploadtotrueon 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.yaml
Step 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 -t
sudo systemctl reload nginx
Alternatively, 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 - 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-selftest
OK 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 refused
Step 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/hfs
TARGET SOURCE FSTYPE SIZE USED
/srv/hfs /dev/nvme1n1 ext4 97.9G 2.4M
df -h /srv/hfs
Filesystem Size Used Avail Use% Mounted on
/dev/nvme1n1 98G 2.4M 93G 1% /srv/hfs
To grow the store, modify the EBS volume in the EC2 console (or with aws ec2 modify-volume), then extend the filesystem in place - no downtime and no rebuild:
sudo resize2fs /dev/nvme1n1
Back 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/cloudimg-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 cloudimg publishes refreshed images as upstream releases land.
Troubleshooting
The browser shows a certificate warning. Expected - the per-instance certificate is self signed. Accept it, or install a CA signed certificate (Step 9).
I get a login prompt and no files. That is the intended behaviour: 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, 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, or write a fresh configuration with sudo /usr/local/sbin/hfs-write-config <username> <new-password> and restart hfs.service; HFS re-hashes it and strips the plain text on startup.
Nothing answers on port 443. Check systemctl is-active nginx.service and sudo nginx -t. Confirm 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
cloudimg provides 24/7 technical support for this product by email and live chat.
- Email: support@cloudimg.co.uk
- Live chat: available 24/7
We help 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.