> ## Documentation Index
> Fetch the complete documentation index at: https://b5bfb29-opencomputer.manicule.dev/llms.txt
> Use this file to discover all available pages before exploring further.
> For every page in one file, fetch https://b5bfb29-opencomputer.manicule.dev/llms-full.txt (large).
> To search and read these docs as tools, connect the MCP server at https://b5bfb29-opencomputer.manicule.dev/api/mcp.
> Every agent surface: https://b5bfb29-opencomputer.manicule.dev/.well-known/llms-manifest.json

# On AWS (/self-hosting/aws)

<!-- agent-signals: reading_time_min: 4 · est_tokens: 1652 · updated: 2026-11-13 -->
Related: [Start here](/self-hosting/overview.md), [On Azure](/self-hosting/azure.md), [On Google Cloud](/self-hosting/gcp.md)

> Deploy the app and gateway Workers on Cloudflare, and create each organization's Computer VM on EC2 yourself

On AWS the gateway runs with `COMPUTER_VMS` set to `self-managed`: it creates no VMs. You create one EC2 instance per organization, and the instance connects out to the gateway with that organization's host token.

| The gateway                                                                                                              | You                                         |
| ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------- |
| Shows the Computer as `Online` while its VM is connected and `Offline` otherwise                                         | Create, size, stop, start and delete the VM |
| Holds a Slack message that arrives while the VM is offline, says so once in the thread, and runs it when the VM connects | Start the VM again                          |

The examples use `app.example.com` and `gateway.example.com`, as in [On Azure](/self-hosting/azure).

## 1. Get the code

```bash
git clone https://github.com/diggerhq/opencomputer.git
cd opencomputer
(cd services/managed-agents && npm ci)
(cd cloudflare-workers/api-edge && npm ci)
(cd web && npm ci)
```

## 2. Create the Cloudflare resources and the apps

Follow two steps of the Azure guide unchanged:

* [Create the Cloudflare resources](/self-hosting/azure#2-create-the-cloudflare-resources)
* [Create the WorkOS, Slack and GitHub apps](/self-hosting/azure#3-create-the-workos-slack-and-github-apps)

## 3. Deploy the gateway Worker

Follow [Deploy the gateway Worker](/self-hosting/azure#4-deploy-the-gateway-worker) unchanged. Keep the value of `COMPUTER_HOST_TOKEN_KEY` at hand: step 6 derives each organization's host token from it.

## 4. Deploy the app Worker

Follow [Deploy the app Worker](/self-hosting/azure#5-deploy-the-app-worker) unchanged.

## 5. Build and upload the Computer release

From the repository root:

```bash
computer/deploy/bundle.sh /tmp/calvin.bundle

export AWS_REGION=us-east-1
export BUCKET=<globally unique>
aws s3 mb "s3://$BUCKET" --region "$AWS_REGION"
aws s3 cp /tmp/calvin.bundle "s3://$BUCKET/calvin.bundle"
```

The bundle holds the Computer source and the model proxy built for Linux amd64. The bucket stays private; step 7 gives the VM a URL that is valid for one hour.

## 6. Get the organization ID and make the host token

1. Open `https://app.example.com` and sign in.
2. Open **Settings** and copy the **Organization ID**.
3. Derive the organization's host token from `COMPUTER_HOST_TOKEN_KEY`:

```bash
export ORG_ID='<ORGANIZATION_ID>'
export COMPUTER_HOST_TOKEN_KEY='<the gateway secret>'

export TOKEN="sph_$(printf 'calvin-host:%s' "$ORG_ID" \
  | openssl dgst -sha256 -hmac "$COMPUTER_HOST_TOKEN_KEY" -binary \
  | base64 | tr '+/' '-_' | tr -d '=')"
```

The token is valid for that organization only, and for as long as the key does not change.

## 7. Create the VM

The VM is Ubuntu 24.04 on amd64 with a second, blank EBS volume for `/data`. It needs outbound internet access and no inbound access: a new security group has no inbound rules.

Make a download URL for the release, then write the VM's first-boot script with `self-managed-user-data.sh`. The script it prints stores the gateway URL and the token in a root-only file on the VM, downloads the release and runs its boot script:

```bash
export BUNDLE_URL="$(aws s3 presign "s3://$BUCKET/calvin.bundle" --expires-in 3600 --region "$AWS_REGION")"

(umask 077; GATEWAY_HOST=gateway.example.com \
  computer/deploy/vm/self-managed-user-data.sh > computer-user-data.sh)
```

Create the security group and the instance in the default VPC:

```bash
AMI="$(aws ssm get-parameter --region "$AWS_REGION" --query Parameter.Value --output text \
  --name /aws/service/canonical/ubuntu/server/24.04/stable/current/amd64/hvm/ebs-gp3/ami-id)"

SG="$(aws ec2 create-security-group --region "$AWS_REGION" --group-name computer \
  --description 'Computer VMs: no inbound' --query GroupId --output text)"

aws ec2 run-instances --region "$AWS_REGION" \
  --image-id "$AMI" --instance-type m7i.large \
  --security-group-ids "$SG" \
  --block-device-mappings \
    'DeviceName=/dev/sda1,Ebs={VolumeSize=64,VolumeType=gp3}' \
    'DeviceName=/dev/sdf,Ebs={VolumeSize=128,VolumeType=gp3,DeleteOnTermination=false}' \
  --metadata-options HttpTokens=required \
  --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=computer},{Key=organization,Value=$ORG_ID}]" \
  --user-data file://computer-user-data.sh \
  --query 'Instances[0].InstanceId' --output text
```

The first boot installs the toolchains, formats the blank volume, mounts it at `/data` and starts the host. It takes about five minutes. The boot script formats a volume only when it is blank.

The token stays in the instance's user data. On the VM only root can read it; in AWS, anyone allowed to call `ec2:DescribeInstanceAttribute` can.

## 8. Add the Slack app and connect GitHub

1. Open `https://app.example.com`. The Computer shows `Online` once the VM has connected.
2. Click **Add to Slack** and approve.
3. Connect GitHub and choose the repositories.
4. Mention `@computer` in a channel.

Repeat steps 6 and 7 for each further organization.

## Stop, start and resize

Stop the instance with `aws ec2 stop-instances`; the Computer shows `Offline` and Slack messages wait. Start it with `aws ec2 start-instances`; the host reconnects and the workspace is still on `/data`. To resize, stop the instance, change its type with `aws ec2 modify-instance-attribute`, and start it.

Terminating the instance does not delete the data volume.

## Check a VM

The VM has no SSH access. The boot log is `/var/log/calvin-boot.log`, and the two services are `slack-presence-host` and `oc-modelproxy`. From a root shell on the VM, for example through AWS Systems Manager Session Manager (the instance then needs an instance profile with the `AmazonSSMManagedInstanceCore` policy):

```bash
systemctl is-active slack-presence-host.service oc-modelproxy.service
tail -50 /var/log/calvin-boot.log
```

## Update a VM

A self-managed VM does not update itself. Build and upload a new bundle (step 5), download it to `/opt/bootstrap/calvin.bundle` on the VM, and run as root:

```bash
git -C /opt/bootstrap/calvin-src fetch -q /opt/bootstrap/calvin.bundle main
git -C /opt/bootstrap/calvin-src checkout -q -f --detach FETCH_HEAD
CODE_ONLY=1 BOOTSTRAP_FETCH=0 bash /opt/bootstrap/calvin-src/deploy/vm/azure-computer-boot.sh
```
