Media & Entertainment AWS

Manyfold 0.154.1 on AWS User Guide

| Product: Manyfold 0.154.1 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and verifying Manyfold 0.154.1 on Ubuntu 24.04 from cloudimg on Amazon EC2. It is one version of the cloudimg Hardened SRS Streaming Media Server & Media Servers AMIs listing on AWS Marketplace; you pick it as the software version when you subscribe and launch. The other media and streaming products in the listing are described on the listing's guide hub.

Manyfold is a free, open source, self-hosted digital asset manager for 3D-print files (AGPL-3.0 licence). Point it at your STL, 3MF, OBJ and other model files and it organises them into a searchable web library: models, creators and collections, tags, rendered preview images and an in-browser 3D viewer, mesh analysis, and accounts with roles so a household, makerspace or team can share one collection on infrastructure they own.

What is on the image:

  • Manyfold 0.154.1, the official upstream image manyfold3d/manyfold, with PostgreSQL 17.11 (postgres:17.11-alpine3.24) and Valkey 8.1.11 (valkey/valkey:8.1.11-alpine3.24), all three pinned by their linux/amd64 manifest digests and pulled at build time (your instance never pulls an image)
  • Docker CE from Docker's official repository (its signing key pinned by fingerprint), configured so that no container can reach the instance metadata service
  • nginx serving HTTPS on port 443 with a certificate created on your instance; port 80 redirects to HTTPS
  • Multi-user mode with a per-instance administrator created on first boot, before the web server opens; public sign-up is closed
  • A dedicated 10 GiB data volume at /var/lib/manyfold for your model library, the database and the job queue
  • The complete Manyfold 0.154.1 source code on the instance, as the AGPL-3.0 requires (Step 10)
  • manyfold-set-hostname (serve Manyfold under your own DNS name) and manyfold-selftest (an end-to-end check)

Default user: ubuntu · Architecture: x86_64 · Root volume: 16 GiB gp3 · Data volume: 10 GiB gp3

Security posture

  • No default login and no open registration. First boot creates the admin account with a password made on your instance and switches Manyfold to multi-user mode with registration closed, all before nginx accepts a connection. Signed-out visitors are sent to the sign-in page, and the sign-up page redirects away. The admin password (24 characters) is written only to /root/manyfold-credentials.txt (mode 0600, root).
  • Per-instance secrets. The admin password, the PostgreSQL password, the Valkey password, Rails' SECRET_KEY_BASE, the TLS key and the database itself are all created on your instance. The image ships with an empty data volume.
  • The database and the job queue are private. PostgreSQL and Valkey have no host port and accept only password logins. They are reachable only from the Manyfold container on a private Docker network; another container on the instance cannot reach them, and nor can anything outside the instance. Manyfold's own port 3214 listens on the instance's loopback interface only, so nginx is the only way in.
  • The containers cannot read instance metadata. A rule in Docker's DOCKER-USER chain, applied before dockerd starts any container, drops traffic to 169.254.169.254 and fd00:ec2::254, so no container can fetch the instance's IAM role credentials, including through Manyfold's import-from-URL feature. Docker, the Manyfold unit and nginx also carry systemd IPAddressDeny for those addresses.
  • HTTPS from first boot. TLS 1.2 and 1.3 only (TLS 1.1 is refused), Strict-Transport-Security and Manyfold's HTTPS-only mode, so its session cookie is Secure and HttpOnly. The host name comes from configuration, never from a request: first boot reads the instance's public DNS name from EC2 instance metadata (IMDSv2) and pins nginx to it; requests for any other host name get their connection closed.
  • Cross-site requests are refused. nginx refuses state-changing requests and WebSocket upgrades whose Origin or Referer is another site (403). Forged X-Forwarded-For, X-Real-IP and Forwarded headers from a client never reach Manyfold. Request bodies are capped at 16 MB, except Manyfold's signed-in upload endpoint, which takes model files in small chunks.
  • Verified build. All three image digests were scanned for known vulnerabilities and their licences checked before the build. Usage reporting is off. SSH allows keys only, no root login and no X11 forwarding; the AMI requires IMDSv2; SSH host keys and the machine ID are generated fresh on every instance.

Prerequisites

  1. An AWS account and permission to launch EC2 instances
  2. An EC2 key pair in the Region you launch in

Recommended instance type: m5.large (2 vCPUs, 8 GiB). Manyfold's web server and its background workers use about 1.3 GiB at rest; rendering previews and analysing large meshes want the headroom.

Connecting to your instance

Version Operating system SSH user
Manyfold 0.154.1 on Ubuntu 24.04 Ubuntu 24.04 LTS ubuntu

Step 1: Launch the instance

Option A: AWS Marketplace console

  1. Open the cloudimg Hardened SRS Streaming Media Server & Media Servers AMIs listing on AWS Marketplace and choose View purchase options, then Subscribe. One subscription covers every version in the listing.
  2. Once the subscription is active, choose Launch your software.
  3. Choose One-click launch from AWS Marketplace (or Launch from EC2 Console for the full launch wizard). In Version, choose Manyfold 0.154.1 on Ubuntu 24.04, then choose your Region.
  4. Pick an instance type (m5.large recommended) and your key pair. The 10 GiB data volume is part of the image; make it larger in the storage settings if your model collection needs the room.
  5. Security group: the listing's default group opens SSH (22), HTTP (80) and HTTPS (443). Restrict SSH to your own IP address and restrict 80 and 443 to the networks your users work from. Never open 3214, 5432 or 6379.
  6. Choose your VPC and subnet, leave the metadata defaults (the image already requires IMDSv2), then choose Launch.

Option B: AWS CLI

Run this on your own workstation. Replace the AMI ID with the one shown for your Region on the Marketplace launch page, and the VPC, subnet, key pair and CIDRs with your own:

SG=$(aws ec2 create-security-group --group-name manyfold \
  --description "Manyfold" --vpc-id vpc-0123456789abcdef0 \
  --query GroupId --output text)
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 22 --cidr <your-mgmt-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 443 --cidr <your-mgmt-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 80 --cidr <your-mgmt-cidr>
aws ec2 run-instances \
  --image-id ami-0123456789abcdef0 \
  --instance-type m5.large \
  --key-name my-key-pair \
  --security-group-ids "$SG" \
  --subnet-id subnet-0123456789abcdef0 \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=manyfold}]'

You do not need --metadata-options: the AMI already makes IMDSv2 required. Associate an Elastic IP if you want the address to survive a stop and start.

Step 2: Connect and find your login

Connect as ubuntu with the key pair you chose:

ssh -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip>

First boot takes one to two minutes after the instance starts (a little longer on the very first start, while EC2 reads the container images from their snapshot). It sets the name Manyfold is served as (the instance's public DNS name when it has one), creates the TLS certificate and this instance's secrets, starts PostgreSQL, Valkey and Manyfold, creates the administrator and then opens nginx. The login is in a root-only file; this shows the address, the user names and the field names without printing any password:

sudo grep -E '^manyfold\.(url|admin\.user|admin\.email|db\.name|db\.user)=' /root/manyfold-credentials.txt
sudo grep -oE '^[a-z.]+=' /root/manyfold-credentials.txt
sudo stat -c '%a %U:%G %n' /root/manyfold-credentials.txt
manyfold.url=https://ec2-54-174-222-146.compute-1.amazonaws.com/
manyfold.admin.email=admin@localhost.localdomain
manyfold.admin.user=admin
manyfold.db.name=manyfold
manyfold.db.user=manyfold
manyfold.url=
manyfold.admin.email=
manyfold.admin.pass=
manyfold.admin.user=
manyfold.db.name=
manyfold.db.user=
manyfold.db.pass=
manyfold.valkey.pass=
600 root:root /root/manyfold-credentials.txt
Value What it is for
manyfold.url The address of this instance's Manyfold web interface
manyfold.admin.email / manyfold.admin.pass The administrator's sign-in. Manyfold signs in by e-mail address, so use admin@localhost.localdomain until you change it
manyfold.admin.user The administrator's account name (admin)
manyfold.db.user / manyfold.db.pass Manyfold's PostgreSQL account (manyfold), for backups and database administration
manyfold.valkey.pass The password of the Valkey job queue, used by Manyfold's background workers

To read the passwords, run sudo cat /root/manyfold-credentials.txt in your own session and store them in your password manager.

Step 3: Confirm Manyfold is running

The first-boot unit has finished; Docker, the metadata block, the Manyfold stack and nginx are active; exactly three containers run, from the pinned images. The only public listening sockets are sshd and nginx on 22, 80 and 443; Manyfold's 3214 is on 127.0.0.1 only and PostgreSQL and Valkey have no host port at all:

systemctl is-active manyfold-firstboot docker cloudimg-docker-imds-deny manyfold nginx
sudo ss -Htlnp | awk '{print $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort -u
sudo docker ps --format '{{.Names}} {{.Image}} {{.Ports}}'
sudo docker image ls --digests --format '{{.Repository}}:{{.Tag}} {{.Digest}}'
active
active
active
active
active
0.0.0.0:22 users:(("sshd"),("systemd"))
0.0.0.0:443 users:(("nginx"),("nginx"),("nginx"))
0.0.0.0:80 users:(("nginx"),("nginx"),("nginx"))
127.0.0.1:3214 users:(("docker-proxy"))
127.0.0.53%lo:53 users:(("systemd-resolve"))
127.0.0.54:53 users:(("systemd-resolve"))
[::]:22 users:(("sshd"),("systemd"))
[::]:443 users:(("nginx"),("nginx"),("nginx"))
[::]:80 users:(("nginx"),("nginx"),("nginx"))
manyfold manyfold3d/manyfold 127.0.0.1:3214->3214/tcp
manyfold-valkey valkey/valkey 6379/tcp
manyfold-postgres postgres 5432/tcp
postgres:17.11-alpine3.24 sha256:4717f90960a225c2d1c5dac50508c401230f693ff626e06e84e6db0a68ded508
manyfold3d/manyfold:0.154.1 sha256:050e8dde3f59fe0aca5e294b5f3697550c6344d12e2a1bcd8219b7134c97286b
valkey/valkey:8.1.11-alpine3.24 sha256:ac81eb0a7b37e054000af8fdd5e6c3eb17249caa71eba79c003a145e518415e5

Step 4: Prove the login and the web defaults

Signed-out requests for the library, settings, account, import and job-queue pages are all sent to the sign-in page, the sign-up page redirects away, the health check answers, plain HTTP redirects to HTTPS, an unknown Host header gets no answer and TLS 1.1 is not offered. The last command is the image's own round-trip check: it signs in with this instance's administrator over https://<your-name>/ and proves that a wrong password is refused and that the database and job-queue passwords work:

H=$(sudo sed -nE 's#^manyfold\.url=https://([^/]+)/?.*#\1#p' /root/manyfold-credentials.txt)
for p in / /settings /users/edit /imports/new /admin/sidekiq; do
  printf '%-16s %s\n' "$p" "$(curl -sk -o /dev/null -w '%{http_code}' --connect-to ::127.0.0.1: "https://$H$p")"
done
curl -sk -D - -o /dev/null --connect-to ::127.0.0.1: "https://$H/settings" | grep -i '^location'
printf 'sign-up page     %s\n' "$(curl -sk -o /dev/null -w '%{http_code}' --connect-to ::127.0.0.1: "https://$H/users/sign_up")"
printf '/health          %s\n' "$(curl -sk -o /dev/null -w '%{http_code}' --connect-to ::127.0.0.1: "https://$H/health")"
curl -s -D - -o /dev/null --connect-to ::127.0.0.1: "http://$H/" | grep -iE '^(HTTP|location)'
curl -sk -o /dev/null -w 'unknown Host     %{http_code}\n' -H 'Host: evil.example' https://127.0.0.1/ || true
curl -sk -o /dev/null -w 'TLS 1.1          %{http_code}\n' --tls-max 1.1 --connect-to ::127.0.0.1: "https://$H/" || true
sudo manyfold-selftest
/                302
/settings        302
/users/edit      302
/imports/new     302
/admin/sidekiq   302
location: https://ec2-54-174-222-146.compute-1.amazonaws.com/users/sign_in
sign-up page     302
/health          200
HTTP/1.1 301 Moved Permanently
Location: https://ec2-54-174-222-146.compute-1.amazonaws.com/
unknown Host     000
TLS 1.1          000
round-trip OK https://ec2-54-174-222-146.compute-1.amazonaws.com/: 5 protected routes redirect anonymous visitors to sign-in; sign-up closed; wrong admin password 422; admin signed in over 443 (303), /settings 200, account page shows admin@localhost.localdomain; PostgreSQL password authenticates, a wrong one refused; Valkey password PONG, anonymous NOAUTH

--connect-to ::127.0.0.1: sends each request to this instance while keeping the real host name in the request, exactly as a browser would send it. 000 means the server closed the connection without an answer.

Step 5: Sign in to Manyfold

Browse to manyfold.url (https://<public-dns-name>/). The certificate is self-signed, so your browser warns once; accept it for this host, or install your own certificate (Step 8). Sign in with the e-mail address admin@localhost.localdomain and the manyfold.admin.pass value from the credentials file:

The Manyfold 0.154.1 sign-in page served over HTTPS

Manyfold offers a short tour of its main features on the first visit; close it or step through it. Then open the gear icon (Site Settings) and choose Manage Accounts. The image creates one account, admin, with the member and administrator roles. Open it with View to change its e-mail address to your own, and use New account to add an account for each person who should see the library. Because registration is closed, nobody can create an account for themselves:

Manyfold's Manage Accounts page with the single admin account

Step 6: Add your models

The image creates one library, Models, at /libraries inside the container, which is /var/lib/manyfold/libraries on the data volume. There are two ways to fill it:

  • In the browser: choose Add content, then Upload models, and drop your model files (or a zip of them) on the page. Large files upload in small chunks, so the 16 MB request limit does not apply to them.
  • From the instance: copy a folder per model into the library and give it to the manyfold user, then choose Scan, then Scan for new files in the web interface (replace the source path with your own):
sudo cp -r ~/my-models/* /var/lib/manyfold/libraries/
sudo chown -R manyfold:manyfold /var/lib/manyfold/libraries

Manyfold turns each folder into a model, then its background workers render a preview of every file and analyse the meshes. The Models page shows the collection with its previews:

The Manyfold model library with two models and their rendered previews

Open a model to see its files, load any of them into the 3D viewer, download them, tag the model and file it under a creator or a collection. New models are shared with your signed-in local users by default; the padlock icon on each model changes who can see it:

A Manyfold model page with the rendered file, model details and download button

The home page searches the whole library and lists recent activity:

The Manyfold home page with search and recent activity

Importing a model from a web page (Add content, then Import URL) needs outbound internet access from the instance and, for most sites, that site's API key, which you add under Site Settings, then Integrations. Imports can never reach the instance metadata service.

Step 7: The data volume

Your model library, the PostgreSQL database and the Valkey job queue live on the 10 GiB data volume, mounted by its filesystem UUID:

findmnt -n -o SOURCE,FSTYPE,SIZE,TARGET /var/lib/manyfold
sudo ls /var/lib/manyfold
grep ' /var/lib/manyfold ' /etc/fstab | sed -E 's/UUID=[0-9a-f-]+/UUID=<uuid>/'
/dev/nvme1n1 ext4    9.7G /var/lib/manyfold
libraries
lost+found
postgres
valkey
UUID=<uuid> /var/lib/manyfold ext4 defaults,nofail 0 2

To grow the library's space, enlarge the volume in the EC2 console (Volumes, Modify volume), then run sudo resize2fs on the device that findmnt shows. Snapshot the volume to back the library up (Maintenance, below).

Step 8: Serve Manyfold under your own DNS name

Point a DNS record (for example models.example.com) at the instance's public or Elastic IP address, then tell the image to serve that name. It creates a new self-signed certificate for the name, pins nginx, the cross-site guard and Manyfold to it, updates manyfold.url in the credentials file and keeps the name across reboots:

sudo manyfold-set-hostname models.example.com

For a trusted certificate, obtain one for that name (for example with certbot's certonly mode using its own temporary web server, or from your organisation's CA), copy the certificate chain and key over /etc/ssl/manyfold/manyfold.crt and /etc/ssl/manyfold/manyfold.key (key mode 0600, root), and run sudo systemctl reload nginx.

Step 9: Check the security controls

The DOCKER-USER rules drop the metadata addresses (IPv4 and IPv6) and keep other containers off the Manyfold network; no container gets an answer from instance metadata, while the Manyfold container still reaches the internet (the 200 is that positive control); the PostgreSQL and Valkey ports answer nothing on the host; the services carry IPAddressDeny; and SSH runs with the cloudimg pins:

sudo iptables -S DOCKER-USER
sudo ip6tables -S DOCKER-USER
sudo docker exec manyfold ruby -rnet/http -e 'puts "manyfold -> internet: " + Net::HTTP.get_response(URI("http://checkip.amazonaws.com/")).code'
for c in manyfold manyfold-postgres manyfold-valkey; do
  sudo docker exec "$c" sh -c 'wget -q -T 5 -O /dev/null http://169.254.169.254/latest/meta-data/ 2>/dev/null && echo answered || echo blocked' | sed "s/^/$c -> IMDS: /"
done
for p in 5432 6379; do
  curl -s -m 5 -o /dev/null -w "host -> 127.0.0.1:$p: %{http_code}\n" "telnet://127.0.0.1:$p" || true
done
systemctl show -p IPAddressDeny docker manyfold nginx
sudo sshd -T | grep -E '^(passwordauthentication|permitrootlogin|kbdinteractiveauthentication|x11forwarding) '
-N DOCKER-USER
-A DOCKER-USER ! -i br-manyfold -o br-manyfold -m conntrack --ctstate NEW -j DROP
-A DOCKER-USER -d 168.63.129.16/32 -j DROP
-A DOCKER-USER -d 169.254.169.254/32 -j DROP
-N DOCKER-USER
-A DOCKER-USER -o br-manyfold -j DROP
-A DOCKER-USER -d fd00:ec2::254/128 -j DROP
manyfold -> internet: 200
manyfold -> IMDS: blocked
manyfold-postgres -> IMDS: blocked
manyfold-valkey -> IMDS: blocked
host -> 127.0.0.1:5432: 000
host -> 127.0.0.1:6379: 000
IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32

IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32

IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32
permitrootlogin no
passwordauthentication no
kbdinteractiveauthentication no
x11forwarding no

Step 10: The AGPL-3.0 source offer

Manyfold is licensed under the GNU Affero General Public License version 3. Section 13 requires that anyone using the program over a network is offered the corresponding source of the running version. The instance carries it, so no network access is needed:

head -12 /usr/share/doc/manyfold/SOURCE-OFFER.txt
cd /usr/share/manyfold/source && sha256sum -c manyfold-0.154.1-source.tar.gz.sha256
Manyfold 0.154.1 - AGPL-3.0 offer of corresponding source
================================================================

This appliance runs Manyfold 0.154.1 from the official upstream container image, unmodified:

    manyfold3d/manyfold@sha256:050e8dde3f59fe0aca5e294b5f3697550c6344d12e2a1bcd8219b7134c97286b
    (multi-arch index sha256:32308a8370452af6bc93f749fc4fa037de8d77075b9c3f0e423efe5dfef1d192, tag 0.154.1)

Manyfold is free software licensed under the GNU Affero General Public License, version 3 (AGPL-3.0).
Under section 13, every user who interacts with this program over a network is offered the complete
corresponding source of the version that is running.

manyfold-0.154.1-source.tar.gz: OK

cloudimg makes no changes to Manyfold itself. The image adds only the Docker Compose project, the systemd units, the nginx configuration and the first-boot setup.

Maintenance

  • Change the admin password: in Manyfold, open the account menu (the person icon, top right), change the password on your account page (/users/edit); then replace the old one in /root/manyfold-credentials.txt once you have stored the new one.
  • Operating system updates: unattended security upgrades are on. Reboot when /var/run/reboot-required exists; the metadata block, the Manyfold stack and nginx start again by themselves.
  • Manyfold updates: the stack runs the pinned images and never pulls one. To move to a newer release, launch the newer version of this image when the listing offers it and move the data volume (or a snapshot of it) across with Manyfold stopped. Do not run docker image prune -a: manyfold.service starts the pinned images only.
  • Backups: snapshot the data volume, or dump the database with this instance's own password passed through the environment: sudo bash -c 'PGPASSWORD=$(sed -n "s/^manyfold\.db\.pass=//p" /root/manyfold-credentials.txt) docker exec -e PGPASSWORD manyfold-postgres pg_dump -U manyfold manyfold' > manyfold.sql. The model files themselves are in /var/lib/manyfold/libraries.
  • Logs: sudo docker logs manyfold for the web server and workers, sudo docker logs manyfold-postgres and sudo docker logs manyfold-valkey for the database and queue; /var/log/nginx/ for web requests; sudo journalctl -u manyfold-firstboot for first boot.

Troubleshooting

  • The page does not load right after launch: first boot is still running. sudo journalctl -u manyfold-firstboot -f shows its progress.
  • Browser shows "connection closed": nginx answers only the configured name and closes the connection for any other name. Use manyfold.url, or run sudo manyfold-set-hostname <name> for a new name. Use the name rather than an IP address in the browser too: the cross-site guard accepts changes only from the configured name.
  • Sign-in keeps failing: Manyfold signs in by e-mail address, not account name, and locks an account for a while after repeated wrong passwords. Use the manyfold.admin.email value and the password from the credentials file, and wait a few minutes after several failures.
  • A model shows "Path does not match template": Manyfold compares each model's folder with its preferred folder layout (Site Settings, then Libraries). It is advice, not an error; the model works either way.
  • 502 Bad Gateway: Manyfold is starting (it applies its database migrations at start) or has stopped. sudo systemctl status manyfold and sudo docker logs --tail 50 manyfold show why.
  • The end-to-end check: sudo manyfold-selftest signs in with this instance's administrator and prints round-trip OK when everything works.

Licensing

Manyfold is licensed under the GNU Affero General Public License version 3 (AGPL-3.0); the licence text is on the instance in /usr/share/doc/manyfold/LICENSE, and its source is in /usr/share/manyfold/source/ (Step 10). PostgreSQL is licensed under the PostgreSQL Licence. Valkey is licensed under the BSD 3-Clause licence; its licence text is in /usr/share/doc/manyfold/third-party/. Manyfold is a name of the Manyfold project; cloudimg is not affiliated with, sponsored by or endorsed by the Manyfold project, and the name identifies the software this image contains.

Support

cloudimg provides 24/7 technical support for this image by email and live chat: deployment, first login, HTTPS and DNS setup, libraries, uploads and imports, storage, upgrades and troubleshooting. Contact support@cloudimg.co.uk.