Erugo 0.2.15 on AWS User Guide
Overview
This guide covers launching and using the Erugo 0.2.15 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg file sharing and sync listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.
Erugo is a self-hosted file sharing and file transfer platform. You upload files or whole folders in the browser, and Erugo hands you a short link to send to the recipient, who downloads everything in one go without an account. Shares expire on a date you choose, can be password protected or limited to a number of downloads, and can be e-mailed to recipients directly. Large uploads are resumable, so a dropped connection picks up where it left off. You can also send a "reverse share" request so someone outside your organisation can upload files to you. Version 0.2.15 is the release that fixes the critical upload flaw GHSA-336w-hgpq-6369 (remote code execution, versions 0.2.14 and earlier).
A stock Erugo install creates its first administrator through a web setup page that is open until somebody uses it, so the first visitor to a new server becomes its administrator. The cloudimg image adds:
- No setup page, no default login. The image ships with the administrator account already in place and its setup page sealed. On first boot the instance generates its own administrator password, Laravel application key and token signing secret and writes the password to
/root/erugo-credentials.txt, readable by root only. Nothing secret is baked into the image. - HTTPS from the first boot. nginx serves Erugo on port 443 with a certificate generated on your instance. Port 80 only redirects to HTTPS, and a request for a host name the instance does not serve gets no answer.
- Share links that name your server, not the visitor's request. The address in share links, e-mails and password reset links comes from the instance's own configuration (its public address, or the DNS name you set), never from a header a client sends.
- Uploads that cannot run. Shared files are only ever served as downloads (with
Content-Disposition: attachmentandnosniff), uploads never execute as code, only Erugo's own entry point runs PHP, and the application code is read only to the web server. - Bounded uploads. A share can hold up to 2 GB (Erugo's own default, enforced again by the upload service), and the upload service never serves files back without going through Erugo's share checks.
- Brute force throttled. Sign-in, token refresh and password reset are rate limited per client address, and a wrong password gets a plain "Invalid credentials" answer.
- Hardened defaults. The services cannot reach the instance metadata service and the AMI requires IMDSv2. The upload service and its internal callback listen on
127.0.0.1only, the application trusts forwarded headers from the local proxy only, and the PHP dependencies are updated to their latest security releases. - Your files on their own volume. The application, its database and every upload live on a separate 32 GiB EBS volume mounted at
/var/www, which you can grow and snapshot on its own. - Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
What is on the image: Erugo 0.2.15 (from the checksum verified release), the resumable upload service tusd 2.10.1, nginx 1.24, PHP 8.3 with PHP-FPM, SQLite, ffmpeg (for background video thumbnails), Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent.
Default user: ubuntu · Architecture: x86_64 · Recommended instance type: m5.large
Prerequisites
- An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet with a route to the internet.
- A security group that allows TCP 443 (Erugo) and TCP 80 (redirects to HTTPS) from the people who will upload and download, and TCP 22 (SSH) from your own networks only.
Step 1: Launch the instance
In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick Erugo 0.2.15 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large, your key pair and a security group as above. Keep the second EBS volume: it holds Erugo and every file you share. Grow it at launch if you plan to share a lot.
With the AWS CLI (replace the values in angle brackets):
aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
--instance-type m5.large --key-name <your-key-pair> \
--security-group-ids <your-security-group> --subnet-id <your-subnet> \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=erugo}]'
Step 2: Connect to your instance
| Version | SSH user |
|---|---|
| Erugo 0.2.15 on Ubuntu 24.04 | ubuntu |
ssh -i <your-key.pem> ubuntu@<public-ip>
Step 3: Check the services, ports and data volume
First boot takes a few seconds. Then nginx, PHP-FPM, the upload service (erugo-tusd), the queue worker that packages shares and sends mail (erugo-queue), the first boot unit and the scheduler are active:
systemctl is-active nginx php8.3-fpm erugo-tusd erugo-queue erugo-firstboot erugo-scheduler.timer
active
active
active
active
active
active
nginx is the only public listener. The upload service (8080) and Erugo's internal upload callback (8081) listen on loopback only:
sudo ss -tlnp | awk 'NR==1 || /nginx|sshd|tusd/' | awk '{print $1, $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g'
State Local Peer
LISTEN 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx"))
LISTEN 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx"))
LISTEN 0.0.0.0:22 users:(("sshd"),("systemd"))
LISTEN 127.0.0.1:8081 users:(("nginx"),("nginx"),("nginx"))
LISTEN 127.0.0.1:8080 users:(("tusd"))
LISTEN [::]:443 users:(("nginx"),("nginx"),("nginx"))
LISTEN [::]:80 users:(("nginx"),("nginx"),("nginx"))
LISTEN [::]:22 users:(("sshd"),("systemd"))
Erugo, its database and your files are on the separate data volume:
findmnt -no SOURCE,TARGET,FSTYPE /var/www
df -h --output=size,avail,target /var/www
/dev/nvme1n1 /var/www ext4
Size Avail Mounted on
32G 30G /var/www
Step 4: Get your URL and password
The address and the administrator password generated on this instance are in a root only file:
sudo cat /root/erugo-credentials.txt
# Erugo 0.2.15 - generated on first boot by erugo-firstboot.service
# These credentials are unique to this instance; none was baked into the image. Keep this file secret.
ERUGO_URL=https://<public-ip>/
erugo.url=https://<public-ip>/
erugo.admin.user=admin@erugo.local
erugo.admin.pass=<24 letters and digits>
# Sign in at the URL above with the e-mail address and password. The certificate is self signed (minted on this
# instance), so the browser warns once. Port 80 redirects to https.
# Change the name Erugo is served as (share links use it): sudo erugo-set-hostname <your-dns-name>
# Largest upload: 2 GB per share (Erugo setting "Max share size" + tusd -max-size; see the user guide).
# User guide: https://www.cloudimg.co.uk/guides/erugo-0-2-15-on-ubuntu-24-04-aws/
To see just the address and the sign-in e-mail without printing the password:
sudo grep -E '^(erugo\.url|erugo\.admin\.user)=' /root/erugo-credentials.txt
erugo.url=https://<public-ip>/
erugo.admin.user=admin@erugo.local
Step 5: Sign in
Open erugo.url in your browser. The certificate is self signed (generated on your instance), so accept the browser warning once, or use your own name and certificate (Step 10). Sign in with admin@erugo.local and erugo.admin.pass:

After signing in, open My Account from the settings (gear) button and change the e-mail address to your own, so password reset and notification e-mails reach you.
Step 6: Share files
Click Add Files or Add Folders and pick what you want to send. Give the share a name and, if you like, a message for the recipients. Add Recipient e-mails the link for you (once SMTP is set up, Step 9); without recipients Erugo simply gives you the link. The line under the buttons shows the size so far against the 2 GB limit and when the share expires; click (change) to pick another expiry. The padlock button sets a password on the share:

Click Upload. The files go up in resumable chunks, and when they are done Erugo shows the share link to copy:

The recipient opens the link, sees the files, your message and when the share expires, and downloads everything with one click (several files arrive as one ZIP, packaged by the queue worker):

Under the gear button, My Shares lists your shares with their download counts and dates, where you can expire a share at once or extend it:

Step 7: Check the appliance
The image ships a self test that proves the whole path over HTTPS: the administrator signs in, uploads a random file through the resumable upload service, shares it, waits for the queue worker to package it and downloads it through the public link byte for byte, then expires and removes the test share. It also proves that wrong and blank passwords, a second administrator through the setup page, and anonymous shares or uploads are refused:
sudo /usr/local/sbin/erugo-cred-roundtrip.sh
OK per-instance admin signs in (JWT) and round-trips a 177064-byte payload through tus, a share and the queue worker (test share expired and pruned); weak/blank passwords, a second admin, anonymous shares and anonymous uploads refused
Step 8: Security checks
Plain HTTP redirects to HTTPS on the configured name, a request for a host name the instance does not serve gets no answer, Erugo's internal upload callback cannot be reached from the network, a wrong password is refused, the first-run setup page refuses a second administrator, and an upload bigger than the limit is refused before any data is sent:
H=$(sudo sed -nE 's#^erugo\.url=https://([^/]+)/$#\1#p' /root/erugo-credentials.txt)
curl -s -o /dev/null -w 'plain HTTP: %{http_code} -> %{redirect_url}\n' --connect-to "$H:80:127.0.0.1:80" "http://$H/"
curl -s -o /dev/null -w 'unknown host name: %{http_code}\n' -H 'Host: evil.example' http://127.0.0.1/ || true
curl -sk -o /dev/null -w 'upload callback from the network: %{http_code}\n' --connect-to "$H:443:127.0.0.1:443" -X POST "https://$H/api/tusd-hooks"
curl -sk -w ' %{http_code}\n' --connect-to "$H:443:127.0.0.1:443" -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"email":"admin@erugo.local","password":"password"}' "https://$H/api/auth/login"
curl -sk -w ' %{http_code}\n' --connect-to "$H:443:127.0.0.1:443" -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"name":"x","email":"x@example.com","password":"Intruder12345","password_confirmation":"Intruder12345"}' "https://$H/api/setup"
curl -sk -o /dev/null -w 'a 3 GiB upload: %{http_code}\n' --connect-to "$H:443:127.0.0.1:443" -X POST -H 'Tus-Resumable: 1.0.0' -H 'Upload-Length: 3221225472' "https://$H/files/"
plain HTTP: 301 -> https://<public-ip>/
unknown host name: 000
upload callback from the network: 404
{"status":"error","message":"Invalid credentials"} 401
{"status":"error","message":"First user already created"} 404
a 3 GiB upload: 413
The web server, PHP, the upload service and the queue worker cannot reach the instance metadata service (so a URL that Erugo is asked to fetch, such as a sign-in provider's address, cannot be pointed at it), and the secrets are readable by root (and the web server group for the application settings) only:
systemctl show nginx php8.3-fpm erugo-tusd erugo-queue -p Id -p IPAddressDeny
sudo stat -c '%a %U:%G %n' /root/erugo-credentials.txt /var/www/erugo/.env /etc/ssl/erugo/erugo.key
IPAddressDeny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128
Id=nginx.service
IPAddressDeny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128
Id=php8.3-fpm.service
IPAddressDeny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128
Id=erugo-tusd.service
IPAddressDeny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128
Id=erugo-queue.service
600 root:root /root/erugo-credentials.txt
640 root:www-data /var/www/erugo/.env
600 root:root /etc/ssl/erugo/erugo.key
The certificate was generated on this instance and names its own addresses:
H=$(sudo sed -nE 's#^erugo\.url=https://([^/]+)/$#\1#p' /root/erugo-credentials.txt)
echo | openssl s_client -connect 127.0.0.1:443 -servername "$H" 2>/dev/null | openssl x509 -noout -subject -ext subjectAltName
subject=CN = <public-ip>, O = cloudimg
X509v3 Subject Alternative Name:
IP Address:<public-ip>, DNS:ec2-<public-ip-dashed>.compute-1.amazonaws.com, IP Address:<private-ip>, DNS:ip-<private-ip-dashed>.ec2.internal, IP Address:127.0.0.1, DNS:localhost
Step 9: Settings, e-mail and the upload limit
Everything else is configured in the browser under the gear button. System settings holds the application name, the Application URL used in e-mails (the image keeps it equal to the configured name; erugo-set-hostname in Step 10 updates it), share defaults, notifications, SMTP (fill this in to e-mail share links and password resets), Auth (sign-in with an OpenID Connect provider such as Authentik or Microsoft Entra ID) and daily Database Backups. Users adds accounts for your colleagues, and Branding & UI sets your logo, colours and backgrounds:

Self registration is off, so only accounts an administrator creates can upload.
Upload limit. A share can hold up to 2 GB: Erugo's Max Share Size setting (System settings > Shares) and the upload service's own cap agree on it. The values on this instance:
grep -o -- '-max-size [0-9]*' /etc/systemd/system/erugo-tusd.service
echo "SELECT key||'='||value FROM settings WHERE key IN ('max_share_size','max_share_size_unit');" | sudo -u www-data sqlite3 /var/www/erugo/storage/database/database.sqlite
-max-size 2147483648
max_share_size=2
max_share_size_unit=GB
To allow bigger shares, raise Max Share Size in the browser, then raise the upload service's cap to match (in bytes; for example 10 GiB) and make sure the data volume has room (Step 11):
sudo sed -i 's/-max-size [0-9]*/-max-size 10737418240/' /etc/systemd/system/erugo-tusd.service
sudo systemctl daemon-reload && sudo systemctl restart erugo-tusd
Step 10: Your own DNS name and certificate
Point a DNS record at the instance, then set the name Erugo is served as. This mints a new self signed certificate for the name, updates nginx, the address in share links and e-mails, and the URL in /root/erugo-credentials.txt, and keeps the name across reboots:
sudo erugo-set-hostname <your-domain>
To use a certificate from your own certificate authority instead, copy it over the generated pair and reload nginx (running erugo-set-hostname again replaces it with a self signed one):
sudo install -m 0644 <your-domain>.crt /etc/ssl/erugo/erugo.crt
sudo install -m 0600 <your-domain>.key /etc/ssl/erugo/erugo.key
sudo nginx -t && sudo systemctl reload nginx
Step 11: Grow the data volume
Erugo, its SQLite database and every shared file live on the EBS volume mounted at /var/www. To make room, grow that volume in the EC2 console (Volumes > Modify volume), then grow the file system online, with no restart:
sudo resize2fs "$(findmnt -no SOURCE /var/www)"
Snapshot the volume to back up Erugo and its files together. Erugo also writes a daily copy of its database to /var/www/erugo/storage/app/backups (kept for 7 days).
Step 12: Server components
| Component | Path |
|---|---|
| Erugo 0.2.15 | /var/www/erugo (on the /var/www volume; code read only to the web server) |
| Database (SQLite) | /var/www/erugo/storage/database/database.sqlite |
| Uploads in progress and shared files | /var/www/erugo/storage/app/uploads, /var/www/erugo/storage/app/shares |
| Application settings and keys | /var/www/erugo/.env (root:www-data, 0640) |
| PHP dependencies shipped | /etc/cloudimg/erugo-php-dependencies.txt |
| Services | nginx.service, php8.3-fpm.service, erugo-tusd.service, erugo-queue.service, erugo-scheduler.timer |
| nginx site | /etc/nginx/sites-available/cloudimg-erugo |
| Certificate and key | /etc/ssl/erugo/ |
| First boot script | /usr/local/sbin/erugo-firstboot.sh |
| Host name helper | /usr/local/sbin/erugo-set-hostname |
| Self test | /usr/local/sbin/erugo-cred-roundtrip.sh |
| Credentials | /root/erugo-credentials.txt (mode 0600) |
| Licence | /var/www/erugo/LICENSE |
Step 13: Security recommendations
- Allow port 22 in the security group from your own networks only. Ports 80 and 443 need to be open to everyone who uploads or downloads.
- Change the administrator e-mail to your own (Step 5) and keep the password private; change it under My Account if it may have leaked.
- Use your own DNS name and a certificate your browsers trust (Step 10), so recipients are not taught to click through certificate warnings.
- Set an expiry on every share and a password on sensitive ones; expire shares you no longer need from My Shares.
- Keep the operating system patched; unattended security upgrades are on, and
sudo apt-get update && sudo apt-get upgradeapplies everything else.
Support and licensing
Erugo is free software under the MIT licence (Copyright (c) 2025 Dean Ward); a copy is at /var/www/erugo/LICENSE. tusd is also MIT licensed. There is no per user or per CPU licence fee. The AMI price covers cloudimg's hardening, first boot setup and support.
- Email: support@cloudimg.co.uk
- Website: https://www.cloudimg.co.uk
- Support: 24/7, with a 24 hour response SLA