Ba
Artificial Intelligence (AI) AWS

big-AGI 2.0.5 on AWS User Guide

| Product: big-AGI 2.0.5 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and verifying big-AGI 2.0.5 on Ubuntu 24.04 from cloudimg on Amazon EC2. It is one version of the cloudimg Hardened Ollama, LiteLLM & Self Hosted LLM Server AMIs listing on AWS Marketplace; you pick it as the software version when you subscribe and launch. The other LLM servers, gateways and chat interfaces in the listing are described on the listing's guide hub.

big-AGI is an open-source (MIT) AI chat and agent workspace. It gives you one web interface for the models you already use: OpenAI, Anthropic, Google Gemini, OpenRouter and more, or a self-hosted server such as Ollama, LocalAI or llama.cpp. It adds personas, side-by-side "Beam" answers from several models, voice calls, file and link attachments, diagram and code rendering, and chat import and export.

big-AGI is a chat client, not a model host: the models run at your providers or on your own inference server, so it needs no GPU. big-AGI has no server-side accounts and stores nothing on the server. Your provider keys, chats and personas live in your browser's local storage.

What is on the image:

  • big-AGI 2.0.5, the upstream container image ghcr.io/enricoros/big-agi:v2.0.5, pinned by digest sha256:539f8da1692222e35356e9499446405e99ad6c794ae264f5c989c038dbecfbc2, run by Docker CE (official Docker apt repository) with a restart policy
  • big-AGI bound to loopback only (127.0.0.1:3000), with nginx as the only network-facing service
  • HTTPS on port 443 with a self-signed certificate created on your instance's first boot; port 80 redirects to HTTPS
  • A per-instance login (HTTP Basic authentication, user admin) generated on first boot into a root-only file
  • big-agi-set-hostname, a helper that serves big-AGI under your own DNS name and re-issues the certificate for it

Default user: ubuntu · Architecture: x86_64 · Root volume: 12 GiB gp3

Security posture

  • No default credential. The login password is generated on each instance's first boot and stored only as a bcrypt hash (/etc/nginx/big-agi.htpasswd) and in a root-only file. It is never in the image, so no two instances share one.
  • Every page and API route needs the login. big-AGI itself has no authentication, so nginx enforces it in front of everything: the UI and every /api route, including the routes that call model providers. The only open path is nginx's own /healthz literal, which never reaches big-AGI.
  • Fails closed. nginx will not start until first boot has finished and the per-instance password file exists.
  • Only nginx faces the network. It answers only for the configured hostname (any other Host header gets its connection closed), uses TLS 1.2 or 1.3, refuses cross-origin POST requests and WebSocket upgrades (403), strips CORS headers, and replaces any client-supplied X-Forwarded-For, X-Real-IP or Forwarded header with the real peer address.
  • The hostname comes from configuration, never from a request. First boot reads it from EC2 instance metadata (IMDSv2), or from /etc/cloudimg/big-agi-hostname if you set one.
  • No instance metadata access for the app. big-AGI's server fetches whatever provider address a signed-in user enters, so the container is blocked from the instance metadata service (169.254.169.254 and fd00:ec2::254) by a Docker DOCKER-USER firewall rule, which is in place before the container starts. nginx is blocked from it by systemd IPAddressDeny. A provider address can never read the instance's role credentials.
  • IMDSv2 required. The AMI is registered with ImdsSupport v2.0, so instances launched from it refuse token-less (IMDSv1) metadata requests.
  • No third-party analytics. The upstream container image has its maintainer's Google Analytics ID built into the web app, so every browser session would report to a third party. This image removes that ID from the JavaScript nginx serves, so big-AGI never loads Google Analytics. Next.js telemetry is also off.
  • Per-instance identity. SSH host keys, the machine ID and Docker's engine 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
  3. An API key for at least one model provider (OpenAI, Anthropic, Gemini, OpenRouter and so on), or a self-hosted model server such as Ollama that the instance can reach

Recommended instance type: m5.large. big-AGI is a web client and holds no model, so 2 vCPUs and 8 GiB of memory are ample; the model work happens at your providers.

Connecting to your instance

Version Operating system SSH user
big-AGI 2.0.5 on Ubuntu 24.04 Ubuntu 24.04 LTS ubuntu

Step 1: Launch the instance

Option A: AWS Marketplace console

  1. Open the cloudimg Hardened Ollama, LiteLLM & Self Hosted LLM Server 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 big-AGI 2.0.5 on Ubuntu 24.04, then choose your Region.
  4. Pick an instance type (m5.large recommended; the software charge is $0.04 per vCPU per hour) and your key pair.
  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 browse from.
  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. It creates a security group that allows SSH from your management address and HTTPS from your users' network, then launches the instance. Replace the AMI ID with the one shown for your Region on the Marketplace launch page, and the VPC, subnet, key pair and CIDR ranges with your own:

SG=$(aws ec2 create-security-group --group-name big-agi \
  --description "big-AGI chat" --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 203.0.113.0/24
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 80 --cidr 203.0.113.0/24
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=big-agi}]'

You do not need --metadata-options: the AMI already makes IMDSv2 required.

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 finishes within a minute of launch. It sets the hostname big-AGI is served as (the instance's public DNS name when it has one), creates the TLS certificate for it, starts the big-AGI container on loopback, generates the login password, and writes /root/big-agi-credentials.txt (mode 0600, root). Then it starts nginx. These are the entries in that file (the password is not shown here):

sudo grep -E '^BIG_AGI_(URL|USERNAME)=' /root/big-agi-credentials.txt
sudo grep -oE '^[A-Z_]+=' /root/big-agi-credentials.txt
sudo stat -c '%a %U:%G' /root/big-agi-credentials.txt
BIG_AGI_URL=https://ec2-3-86-100-237.compute-1.amazonaws.com/
BIG_AGI_USERNAME=admin
BIG_AGI_URL=
BIG_AGI_USERNAME=
BIG_AGI_PASSWORD=
600 root:root
Value What it is for
BIG_AGI_URL The address of this instance's big-AGI
BIG_AGI_USERNAME Login username (always admin)
BIG_AGI_PASSWORD Login password, generated on this instance

To read the password, run sudo cat /root/big-agi-credentials.txt in your own session and store it in your password manager.

Step 3: Confirm big-AGI is running

The first-boot unit, Docker, the metadata firewall rule and nginx are active. Only sshd and nginx listen beyond loopback; big-AGI itself is on 127.0.0.1:3000, so the nginx login is the only way in.

systemctl is-active big-agi-firstboot.service docker.service cloudimg-docker-imds-deny.service nginx.service
sudo docker ps --format '{{.Names}} {{.Ports}}'
sudo ss -Htlnp | awk '{print $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort -u
curl -sk https://127.0.0.1/healthz
active
active
active
active
big-agi 127.0.0.1:3000->3000/tcp
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:3000 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"))
ok

/healthz is answered by nginx itself and reveals nothing, so it is safe to use as a load balancer health check.

Step 4: Prove the login and the web defaults

Anonymous requests to the UI and to the API are refused, and so is a password that is wrong by one character. This instance's own password is accepted. A cross-origin POST is refused even with the right password, an unknown Host header gets no answer, and plain HTTP redirects to the configured HTTPS name:

H=$(sudo sed -n 's/^set \$app_host "\(.*\)";$/\1/p' /etc/nginx/big-agi-host.conf)
P=$(sudo grep '^BIG_AGI_PASSWORD=' /root/big-agi-credentials.txt | cut -d= -f2-)
curl -sk -o /dev/null -w 'no password -> %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/"
curl -sk -o /dev/null -w 'no password, API -> %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/api/edge/llmOllama.listModels"
curl -sk -o /dev/null -w 'wrong password -> %{http_code}\n' -K <(printf 'user = "admin:%sX"\n' "$P") --resolve "$H:443:127.0.0.1" "https://$H/"
curl -sk -o /dev/null -w 'this instance password -> %{http_code}\n' -K <(printf 'user = "admin:%s"\n' "$P") --resolve "$H:443:127.0.0.1" "https://$H/"
curl -sk -o /dev/null -w 'cross-origin POST -> %{http_code}\n' -K <(printf 'user = "admin:%s"\n' "$P") --resolve "$H:443:127.0.0.1" \
  -X POST -H 'Origin: https://evil.example' -H 'Content-Type: application/json' -d '{}' "https://$H/api/edge/x"
curl -sk -o /dev/null -w 'unknown Host -> %{http_code}\n' -H 'Host: evil.example' https://127.0.0.1/ || true
curl -s -o /dev/null -w 'http -> %{http_code} %{redirect_url}\n' -H "Host: $H" http://127.0.0.1/
no password -> 401
no password, API -> 401
wrong password -> 401
this instance password -> 200
cross-origin POST -> 403
unknown Host -> 000
http -> 301 https://ec2-3-86-100-237.compute-1.amazonaws.com/

The password is passed to curl through a config file on a file descriptor, so it never appears on a command line or in your shell history.

Step 5: Sign in to big-AGI

Browse to BIG_AGI_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). The browser then asks for a username and password: use admin and BIG_AGI_PASSWORD.

On your first visit big-AGI shows a short notice that you bring your own API credentials. Choose I understand and it opens Setup AI Models.

Step 6: Connect your model providers

big-AGI has no provider configured, and no key ships with the image. In Setup AI Models, paste the API key for any of the popular providers (OpenAI, Anthropic, Gemini, OpenRouter), or choose More Services for the full list. Everything you enter is saved in your browser's local storage, not on the instance:

The big-AGI Setup AI Models dialog with key fields for OpenAI, Anthropic, Gemini and OpenRouter

To use a self-hosted model server, switch to Local and enter the server's address, for example the private address of an instance running the Ollama version of this listing (http://<private-ip>:11434). The address must be reachable from the instance, because big-AGI's server makes the call. Inside the big-AGI container, 127.0.0.1 is the container itself, not the instance. Make sure the model server's security group allows port 11434 from this instance.

The Local tab of Setup AI Models with LocalAI and Ollama server address fields

Step 7: Start chatting

Choose skip (or Done once a key is entered) to reach the chat home. Pick a persona, type in the composer and press Chat, or Beam to ask several models at once and merge their answers:

The big-AGI chat home with the AI persona tiles and the message composer

The Apps & Tools button in the left rail opens Create Personas, Compare Text, News, the AI Inspector and Clipboard History:

The big-AGI Apps and Tools menu showing Create Personas, Compare Text, News, AI Inspector and Clipboard History

Your chats are kept in the browser you use. Use Export in the chat drawer to back them up, and Import to move them to another browser.

Step 8: Serve big-AGI under your own DNS name

Point a DNS record at the instance (an Elastic IP keeps the address stable), then tell big-AGI the name. The helper re-issues the self-signed certificate for it, updates nginx's accepted names and the cross-origin guard, records the name in /etc/cloudimg/big-agi-hostname (kept across reboots) and updates BIG_AGI_URL:

sudo big-agi-set-hostname chat.example.com
big-agi-set-hostname: big-AGI is served at https://chat.example.com/

To use a certificate from your own CA or from Let's Encrypt instead, replace /etc/ssl/big-agi/big-agi.crt and /etc/ssl/big-agi/big-agi.key (keep the key mode 0600, owner root) and run sudo systemctl reload nginx.

Step 9: Check the security controls

The certificate was made for this instance on first boot, the container's traffic to the instance metadata service is dropped, and nginx is denied it too. The last line runs a request to the metadata service from inside the big-AGI container:

H=$(sudo sed -n 's/^set \$app_host "\(.*\)";$/\1/p' /etc/nginx/big-agi-host.conf)
openssl s_client -connect 127.0.0.1:443 -servername "$H" </dev/null 2>/dev/null | openssl x509 -noout -subject -enddate
sudo iptables -S DOCKER-USER | grep DROP
systemctl show -p IPAddressDeny --value nginx.service
sudo docker exec big-agi node -e 'fetch("http://169.254.169.254/latest/api/token",{method:"PUT",headers:{"X-aws-ec2-metadata-token-ttl-seconds":"60"},signal:AbortSignal.timeout(5000)}).then(r=>console.log("reached: HTTP "+r.status)).catch(e=>console.log("blocked: "+((e.cause&&e.cause.code)||e.name)))'
subject=CN = ec2-3-86-100-237.compute-1.amazonaws.com, O = cloudimg
notAfter=Jan 21 23:04:10 2029 GMT
-A DOCKER-USER -d 169.254.169.254/32 -j DROP
-A DOCKER-USER -d 168.63.129.16/32 -j DROP
169.254.169.254/32 168.63.129.16/32
blocked: TimeoutError

The running container is the pinned release, telemetry is off, and the Google Analytics ID built into the upstream image is not served to browsers (the count is 0):

sudo docker image inspect --format '{{range .RepoDigests}}{{println .}}{{end}}' "$(sudo docker inspect --format '{{.Image}}' big-agi)"
sudo docker inspect --format '{{range .Config.Env}}{{println .}}{{end}}' big-agi | grep TELEMETRY
H=$(sudo sed -n 's/^set \$app_host "\(.*\)";$/\1/p' /etc/nginx/big-agi-host.conf)
P=$(sudo grep '^BIG_AGI_PASSWORD=' /root/big-agi-credentials.txt | cut -d= -f2-)
APP=$(curl -sk -K <(printf 'user = "admin:%s"\n' "$P") --resolve "$H:443:127.0.0.1" "https://$H/" | grep -oE '/_next/static/chunks/pages/_app-[A-Za-z0-9_-]+\.js' | head -1)
curl -sk --compressed -K <(printf 'user = "admin:%s"\n' "$P") --resolve "$H:443:127.0.0.1" "https://$H$APP" | grep -c 'G-D4J355ELL1' || true
ghcr.io/enricoros/big-agi@sha256:539f8da1692222e35356e9499446405e99ad6c794ae264f5c989c038dbecfbc2

NEXT_TELEMETRY_DISABLED=1
0

Step 10: Change the login password

The password is read from standard input, so it never appears on a command line, in your shell history or in the system logs. Enter the new password when prompted, then reload nginx:

sudo htpasswd -i -B /etc/nginx/big-agi.htpasswd admin
sudo systemctl reload nginx

Then put the new value in /root/big-agi-credentials.txt (or delete that file) so it does not hold a stale password.

Maintenance

  • Logs: sudo docker logs big-agi for big-AGI, /var/log/nginx/ for HTTPS access, sudo journalctl -u big-agi-firstboot.service for first boot.
  • Restart: sudo docker restart big-agi, or sudo systemctl restart nginx.
  • Operating system updates: Ubuntu's unattended security upgrades stay on, so nginx, Docker and the rest of the OS keep receiving patches. Apply the rest with sudo apt update && sudo apt upgrade in a maintenance window.
  • Upgrading big-AGI: the container image is pinned by digest and first boot never pulls. To upgrade deliberately, pull a newer release by digest, remove the big-agi container, and run the new image with the same options the first-boot script uses (/usr/local/sbin/big-agi-firstboot.sh): --restart unless-stopped, -e NEXT_TELEMETRY_DISABLED=1 and -p 127.0.0.1:3000:3000. Never publish the port on all interfaces, and never use host networking: that would bypass both the login and the metadata firewall rule. A newer release may build in a different analytics ID; check it with the last command of Step 9.
  • Your data: nothing is stored on the server. Chats, personas and provider keys are in your browser; export them from the chat drawer to back them up.

Troubleshooting

The browser keeps asking for a password. Use admin and BIG_AGI_PASSWORD from /root/big-agi-credentials.txt exactly, over https://.

nginx will not start. It waits for first boot to finish and for the password file to exist, by design. Check first boot with sudo journalctl -u big-agi-firstboot.service --no-pager | tail -20.

A model server is "not reachable". The address is called from the instance, not from your browser. Use an address the instance can reach (a private IP in the same VPC, or a public endpoint), and allow the port in that server's security group. Instance metadata addresses are blocked on purpose.

Support

cloudimg provides 24/7 support for this image by email and live chat: launching and connecting, provider setup, TLS and hostnames, and upgrades.

big-AGI is developed by Enrico Ros and contributors and is released under the MIT licence. Ubuntu is a registered trademark of Canonical Ltd. Docker is a trademark of Docker, Inc. All other product and company names are trademarks or registered trademarks of their respective holders. cloudimg is not affiliated with or endorsed by them.