Storage AWS

HFS (HTTP File Server) on AWS User Guide

| Product: HFS (HTTP File Server) on AWS

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.large or 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

  1. Open the product page in AWS Marketplace and choose Continue to Subscribe, then Continue to Configuration.
  2. Select the software version and your AWS Region, then choose Continue to Launch.
  3. Choose an instance type (m5.large or larger), your VPC subnet, the security group described above, and your EC2 key pair.
  4. 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:

HFS login prompt - no anonymous access

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:

HFS file listing after signing in

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:

Inside a shared folder in HFS, with upload and zip 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

The HFS admin panel

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/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 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_read to true on that folder only and leave the rest gated. Never 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.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.