Deployment guide

Uguu 1.9.9

Overview

This guide shows you how to launch and use the Uguu 1.9.9 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud File Browser and File Sharing listing on AWS Marketplace. You pick it as the software version when you subscribe and launch.

Uguu is a simple, lightweight temporary file host (the maintained successor to Pomf). You upload a file by drag and drop, paste or a small HTTP API, and you get back a short link to share. Files expire automatically after a retention window (8 hours by default) and are then deleted from disk and from the database. Uguu runs on PHP 8.3 behind nginx, with a local SQLite database for file metadata.

Upstream Uguu lets anyone upload, which makes an open instance easy to abuse for hosting malware or pirated content. The SecureAnyCloud image closes that gap.

What you get:

  • Uploads need a key unique to your instance. The uploader page and the upload endpoint require HTTP Basic authentication (user uguu) with a key generated on your instance's first boot and written to /root/uguu-credentials.txt. nginx refuses an upload without the key before it reaches PHP. Downloads stay public, so a recipient only needs the link. A browser upload posted from another web site is refused even when your browser has the key cached.
  • Uploaded files are never run or rendered as active content. They are served as static files from their own directory, which PHP never executes. Every download is sent with X-Content-Type-Options: nosniff and a sandboxing Content Security Policy. XML, XHTML and script types are sent as downloads instead of being shown in the browser. HTML, SVG, PHP and executable uploads are refused outright.
  • HTTPS from the first boot. nginx serves Uguu on port 443 with a certificate generated on your instance. Port 80 redirects to HTTPS. Requests for a host name the instance does not serve get no answer.
  • Fail closed. No key, password hash or certificate is baked into the image, and nginx refuses to start until first boot has created them.
  • Hardened defaults. nginx, PHP-FPM and the expiry job are blocked from the instance metadata service, and the AMI requires IMDSv2. The client address Uguu sees (it rate-limits uploads per client) comes from the connection, never from a header a client can forge. Uploads are capped at 128 MB, and no client IP addresses are stored.
  • Your files on their own volume. Uploaded files live on a separate 32 GiB EBS volume mounted at /data, which you can resize 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: Uguu 1.9.9 (/var/www/uguu/dist, built from the upstream release with its checksum verified), nginx, PHP 8.3 (php8.3-fpm), SQLite, 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 (or a private route you use for management).
  • A security group that allows TCP 443 (uploads and downloads) and TCP 80 (redirects to HTTPS) from the people who will use the service, and TCP 22 (SSH) from your own networks only.
1

Launch the instance

In the AWS Marketplace listing, click Continue to Subscribe, then Continue to Configuration. Pick Uguu 1.9.9 on Ubuntu 24.04 as the software version, choose your Region, then click Launch through EC2.

Choose m5.large. Uguu is light, so a smaller type works for a small team. Select your key pair and a security group as described in Prerequisites. Keep the second EBS volume, because it stores uploaded files.

To launch with the AWS CLI instead, 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=uguu}]'
2

Connect to your instance

Version SSH user

Uguu 1.9.9 on Ubuntu 24.04 ubuntu

ssh -i <your-key.pem> ubuntu@<public-ip>
3

Check the services and the data volume

First boot takes a few seconds. Afterwards, nginx, PHP-FPM and the first-boot unit are active:

systemctl is-active nginx php8.3-fpm uguu-firstboot
active active active

nginx is the only web listener. PHP-FPM uses a local socket, not a port:

sudo ss -tlnp | awk 'NR==1 || /nginx|sshd|php/' | 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:22 users:(("sshd"),("systemd")) LISTEN 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx")) LISTEN [::]:443 users:(("nginx"),("nginx"),("nginx")) LISTEN [::]:22 users:(("sshd"),("systemd")) LISTEN [::]:80 users:(("nginx"),("nginx"),("nginx"))

Uploaded files are stored on the separate data volume:

findmnt -no SOURCE,TARGET,FSTYPE /data df -h --output=size,avail,target /data
/dev/nvme1n1 /data ext4 Size Avail Mounted on 32G 30G /data
4

Get your URL and upload key

sudo cat /root/uguu-credentials.txt

The file holds the address Uguu is served on (your instance's public IP address by default) and the upload key generated on this instance:

# Uguu - generated on first boot by uguu-firstboot.service. Unique to this instance; keep it safe. uguu.url=https://<public-ip>/ uguu.upload.endpoint=https://<public-ip>/upload.php uguu.upload.user=uguu uguu.upload.key=<32 letters and digits>

The configuration keeps file metadata in SQLite and stores files on /data. It expires files after 8 hours, caps uploads at 128 MB, keeps the type filter and rate limiting on, and stores no client IP addresses:

jq '{DOMAIN,FILE_DOMAIN,DB_MODE,FILES_ROOT,expireTime,expireTimeUnit,max_upload_size,FILTER_MODE,RATE_LIMIT,LOG_IP}' /var/www/uguu/dist/config.json
{ "DOMAIN": "<public-ip>", "FILE_DOMAIN": "<public-ip>", "DB_MODE": "sqlite", "FILES_ROOT": "/data/uguu/files/", "expireTime": 8, "expireTimeUnit": "hours", "max_upload_size": 128, "FILTER_MODE": true, "RATE_LIMIT": true, "LOG_IP": false }
5

Upload from your browser

Open the uguu.url address 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). The browser then asks for a user name and password. Enter uguu and the upload key from Step 4. The uploader shows the size limit and the expiry window.

Drag a file onto Drop or paste file(s), paste from the clipboard, or click to choose a file. Uguu uploads the file and shows its share link with a copy button:

6

Share a link

Anyone with the link can open the file. No key is needed to download. The link stops working when the file expires:

7

Upload from the API or a screenshot tool

Uguu has a small HTTP API for scripts and screenshot tools. POST one or more files as files[] to /upload (or /upload.php). You get JSON back by default, or csv, text, html or gyazo with ?output=. Uploads need the key with HTTP Basic authentication (user uguu). The API page on your instance shows its own endpoint:

On the instance, run the following to upload a file and download it back through its share link. The key is read from the credentials file and handed to curl on standard input (-K -), so it never appears on a command line or in the process list:

H=$(sudo sed -nE 's#^uguu.url=https://([^/]+)/.*#\1#p' /root/uguu-credentials.txt)
echo "hello from sac" > /tmp/uguu-demo.txt
URL=$(sudo sed -nE 's/^uguu.upload.key=(.*)$/user = "uguu:\1"/p' /root/uguu-credentials.txt \
  | curl -sk -K - --resolve "$H:443:127.0.0.1" -F "files[]=@/tmp/uguu-demo.txt" "https://$H/upload?output=json" | jq -r '.files[0].url')
echo "share link: $URL" curl -sk --resolve "$H:443:127.0.0.1" "$URL" rm -f /tmp/uguu-demo.txt
share link: https://<public-ip>/<8 random letters>.txt hello from sac

From your own computer, let curl prompt for the key instead of typing it on the command line:

curl -k -u uguu -F "files[]=@photo.jpg" "https://<public-ip>/upload?output=text"

For a screenshot tool such as ShareX, set the request URL to https://<public-ip>/upload, the method to POST and the file form name to files[]. Then add HTTP Basic authentication with user uguu and your key.

8

Check the upload gate

The image ships a self-test that checks the security model end to end over HTTPS. It confirms that an upload without the key is refused and that an upload with the key returns a share link on your configured host. It also confirms that the file lands on the /data volume and downloads back without a key, with the safe download headers:

sudo /opt/uguu/uguu-selftest.sh
OK: upload without key refused (401); keyed upload -> https://<public-ip>/<8 random letters>.txt; blob on /data; public download matches with nosniff + CSP sandbox
9

Security checks

These checks confirm four things. Plain HTTP redirects to HTTPS. The uploader and the upload endpoint refuse you without the key. An upload posted from another web site is refused even with the key. A request for a host name the instance does not serve gets no answer:

H=$(sudo sed -nE 's#^uguu.url=https://([^/]+)/.*#\1#p' /root/uguu-credentials.txt)
echo test > /tmp/uguu-check.txt curl -s -o /dev/null -w 'plain HTTP: %{http_code} -> %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/" curl -sk -o /dev/null -w 'uploader page without the key: %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/" curl -sk -o /dev/null -w 'upload without the key: %{http_code}\n' --resolve "$H:443:127.0.0.1" -F "files[]=@/tmp/uguu-check.txt" "https://$H/upload"
sudo sed -nE 's/^uguu.upload.key=(.*)$/user = "uguu:\1"/p' /root/uguu-credentials.txt \
  | curl -sk -K - -o /dev/null -w 'upload posted from another web site: %{http_code}\n' --resolve "$H:443:127.0.0.1" \
  -H 'Origin: https://evil.example' -F "files[]=@/tmp/uguu-check.txt" "https://$H/upload" curl -s -o /dev/null -w 'unknown host name: %{http_code}\n' -H 'Host: evil.example' http://127.0.0.1/ || true rm -f /tmp/uguu-check.txt
plain HTTP: 301 -> https://<public-ip>/ uploader page without the key: 401 upload without the key: 401 upload posted from another web site: 403 unknown host name: 000

An HTML page is refused at upload. An XML file is sent as a download, with nosniff and a sandboxing Content Security Policy, so nothing an uploader sends can run in your browser:

H=$(sudo sed -nE 's#^uguu.url=https://([^/]+)/.*#\1#p' /root/uguu-credentials.txt) printf '<html><script>alert(1)</script></html>\n' > /tmp/page.html printf '<?xml version="1.0"?><note>hi</note>\n' > /tmp/note.xml auth() {
sudo sed -nE 's/^uguu.upload.key=(.*)$/user = "uguu:\1"/p' /root/uguu-credentials.txt; } auth | curl -sk -K - --resolve "$H:443:127.0.0.1" -F "files[]=@/tmp/page.html" "https://$H/upload" | jq -c '{success, description}'
URL=$(auth | curl -sk -K - --resolve "$H:443:127.0.0.1" -F "files[]=@/tmp/note.xml" "https://$H/upload" | jq -r '.files[0].url')
curl -sk --resolve "$H:443:127.0.0.1" -o /dev/null -D - "$URL" | grep -iE '^(content-type|content-disposition|x-content-type-options|content-security-policy):' rm -f /tmp/page.html /tmp/note.xml
{"success":false,"description":"Filetype not allowed"} content-type: text/xml; charset=utf-8 x-content-type-options: nosniff content-security-policy: default-src 'none'; img-src 'self'; media-src 'self'; style-src 'unsafe-inline'; frame-ancestors 'none'; sandbox content-disposition: attachment

nginx, PHP-FPM and the expiry job cannot reach the instance metadata service. nginx hands PHP the client address from the connection and discards forwarding headers a client could forge. The secrets are readable by root only (and, for the key hash, nginx):

systemctl show nginx php8.3-fpm uguu-expire -p Id -p IPAddressDeny grep -E 'fastcgi_param HTTP_(CF_CONNECTING_IP|X_REAL_IP|X_FORWARDED_FOR)' /etc/nginx/uguu-fastcgi.conf
sudo stat -c '%a %U:%G %n' /root/uguu-credentials.txt /etc/nginx/uguu.htpasswd /etc/nginx/ssl/uguu.key
IPAddressDeny=fd00:ec2::254/128 168.63.129.16/32 169.254.169.254/32 Id=nginx.service IPAddressDeny=fd00:ec2::254/128 168.63.129.16/32 169.254.169.254/32 Id=php8.3-fpm.service IPAddressDeny=fd00:ec2::254/128 168.63.129.16/32 169.254.169.254/32 Id=uguu-expire.service fastcgi_param HTTP_CF_CONNECTING_IP $remote_addr; fastcgi_param HTTP_X_REAL_IP $remote_addr; fastcgi_param HTTP_X_FORWARDED_FOR ""; 600 root:root /root/uguu-credentials.txt 640 root:www-data /etc/nginx/uguu.htpasswd 600 root:root /etc/nginx/ssl/uguu.key

The certificate is generated on this instance and names its own addresses:

H=$(sudo sed -nE 's#^uguu.url=https://([^/]+)/.*#\1#p' /root/uguu-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 = sac X509v3 Subject Alternative Name: IP Address:<public-ip>, DNS:ec2-<public-ip-dashed>.compute-1.amazonaws.com, IP Address:<private-ip>, IP Address:127.0.0.1, DNS:localhost
10

Your own DNS name and certificate

Point a DNS record at the instance, then set the name Uguu is served on. The command below creates a new self-signed certificate for the name. It updates nginx, the host in every new share link, the API and FAQ pages, and the URL in /root/uguu-credentials.txt. The name persists across reboots:

sudo uguu-set-host <your-domain>

To use a certificate from your own certificate authority instead, copy it over the generated pair and reload nginx. Running uguu-set-host again replaces it with a self-signed certificate:

sudo install -m 0644 <your-domain>.crt /etc/nginx/ssl/uguu.crt
sudo install -m 0600 <your-domain>.key /etc/nginx/ssl/uguu.key
sudo nginx -t && sudo systemctl reload nginx
11

Rotate the upload key

The key is the only thing between your instance and an open file drop. To change it, set a new key for the uguu user. htpasswd prompts for the key, so it never appears on a command line. Then update uguu.upload.key in /root/uguu-credentials.txt and in your API clients. nginx uses the new key at once, and share links are unaffected:

sudo htpasswd -B /etc/nginx/uguu.htpasswd uguu
12

Expiry, limits and data

Files expire automatically. uguu-expire.timer runs checkExpire.php every 15 minutes. It deletes files past their retention window from disk and from the database:

systemctl is-enabled uguu-expire.timer
enabled

The retention window is expireTime and expireTimeUnit in /var/www/uguu/dist/config.json. The same file holds these settings:

  • max_upload_size (in MB). Also raise client_max_body_size in /etc/nginx/sites-available/sac-uguu, and upload_max_filesize and post_max_size in /etc/php/8.3/fpm/conf.d/99-uguu.ini, to match.
  • The FILTER_EXTENSIONS and FILTER_MIME block lists.
  • The RATE_LIMIT settings.

PHP caches the configuration, so after a change run sudo systemctl restart php8.3-fpm.

Uploaded files are under /data/uguu/files/ on the separate EBS volume. The metadata database is /var/lib/uguu/db/uguu.sq3. To back up, snapshot the /data volume. To grow the volume, resize it in EC2, then run sudo resize2fs on its device.

13

Server components

Component Path

Uguu application (web root dist/public) /var/www/uguu/dist

Configuration /var/www/uguu/dist/config.json

Uploaded files /data/uguu/files/ (on the /data volume)

Metadata database /var/lib/uguu/db/uguu.sq3

nginx site /etc/nginx/sites-available/sac-uguu

Upload key hash /etc/nginx/uguu.htpasswd (root:www-data, 0640)

Certificate and key /etc/nginx/ssl/

First boot script /usr/local/sbin/uguu-firstboot.sh

Host name helper /usr/local/sbin/uguu-set-host

Self test /opt/uguu/uguu-selftest.sh

Expiry job uguu-expire.service / uguu-expire.timer

Credentials /root/uguu-credentials.txt (mode 0600)

License /usr/share/doc/uguu/LICENSE

14

Security notes

  • Allow port 22 in the security group from your own networks only. Open 80 and 443 only to the people who should upload or download.
  • Keep the upload key private and rotate it if it may have leaked (Step 11).
  • Use your own DNS name and a certificate your clients trust (Step 10), so nobody learns to click through certificate warnings.
  • Keep the retention window as short as your workflow allows.
  • Keep the operating system patched. Unattended security upgrades are on, and sudo apt-get update && sudo apt-get upgrade applies everything else.

Support and licensing

Uguu is free software under the GNU General Public License, version 3 or (at your option) any later version; a copy is at /usr/share/doc/uguu/LICENSE. There is no per user or per CPU licence fee. The AMI price covers SecureAnyCloud's hardening, first boot setup and support.

  • Email: sales@secureanycloud.com
  • Website: https://secureanycloud.com
  • Support: 24/7, with a 24 hour response SLA

Deploy on AWS

Launch Uguu 1.9.9 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.

View on Marketplace

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on AWS