Skip to main content

Deploy Moyai on AWS with Lambda MicroVMs

Deploy Moyai on a private EC2 host and run agent tools in AWS Lambda MicroVMs. Use the bundled Temporal service for durable execution and LiteLLM gateway for Bedrock inference. Authenticate Bedrock requests with the EC2 IAM role.

Source: Moyai's native Pydantic AI and Temporal implementation at b73f74d. See the upstream AWS quickstart for operations and the MicroVM guide for manual configuration.

Deployment scope

Use this quickstart for a new, single-instance installation. You get one application/Temporal host and one NAT gateway, with no automatic application failover. Allow outbound access for AWS APIs, images, and Slack if enabled. For EKS, follow the Helm integration instructions.

Infrastructure​

Moyai AWS deployment with Lambda MicroVMsSend browser or Slack requests through an HTTPS load balancer to one private EC2 host running Moyai, Temporal, and LiteLLM. Use RDS for application records, S3 for artifacts and checkpoints, and encrypted EBS for installation keys and Temporal's PostgreSQL data. Run guest tools in Lambda MicroVMs and call Bedrock through LiteLLM with the host IAM role. Keep runtime credentials in Secrets Manager on the trusted side. Give guests scoped S3 checkpoint URLs without application credentials.MOYAI / AWS DEPLOYMENTBrowser / SlackRoute 53 DNS + ACM certificateSingle-host Terraform quickstartYOUR AWS VPCAWS MANAGED SERVICESHTTPS load balancerALB · public subnetsHTTPSPRIVATE SUBNETSONE EC2 HOST · DOCKER SPLIT DEPLOYMENTMoyai applicationAPI · coordinator · broker · Pydantic AI workerTemporalDurable executionLiteLLM gatewayPrivate HTTPSEncrypted EBSTemporal PostgreSQL · installation keysRDS PostgreSQLMoyai users · sessions · application recordsNo public IP · maintenance through SSMPrivate S3Artifacts + filesystemcheckpointsObjectsLambda MicroVMsShell · files · browserNo application credentialsToolsScoped URLsAmazon BedrockHost IAM roleModelsConnect to MicroVMs throughAWS-authenticated endpointsoutside the application VPC.Route host outbound trafficthrough the NAT gateway.Secrets ManagerRuntime credentials

Open the full-size diagram, or scroll it left and right on smaller screens.

Use Route 53 DNS and an ACM certificate for HTTPS access through the ALB. Access the private EC2 host through Systems Manager; it has no public IP or SSH ingress. Route outbound traffic through the NAT gateway and connect to MicroVMs through AWS-authenticated endpoints outside the application VPC.

With the Terraform module, provision a private ECR repository, scoped IAM roles, Secrets Manager, CloudWatch logs, and daily AWS Backup recovery points for the EBS state volume.

BoundaryWhat runs there
Trusted EC2 servicesPydantic AI agent execution, model requests, connection credentials, API, coordinator, broker, and worker
Lambda MicroVM guestWorkspace tools and command/checkpoint transport; no model, database, or Slack credentials and no guest execution role in this quickstart
Persistent stateRDS for application records; EBS for installation keys and Temporal's database; separate S3 prefixes for product objects and guest checkpoints

Before you start​

Install Git, uv, the AWS CLI, Terraform 1.9 or newer but below 2.0, and Docker with an AMD64 Buildx builder. For local uv sync, install Python 3.13, Node.js 22 or newer, and Rust 1.88 or newer to build the UI and AgentChat SDK.

Build the application for AMD64. The guest packager uses ARM64 with at least 8 GiB of memory.

Confirm Lambda MicroVM access in your AWS region and capacity to build images and launch VMs. Lambda function access alone is insufficient. You need an existing public Route 53 hosted zone, an unused hostname, and permission to provision the resources, pass scoped roles, and use SSM Run Command.

Enable a Bedrock model or inference profile and verify that your account can invoke it. For a cross-region inference profile, allow both the profile ARN and every destination model ARN. Inspect the profile with:

aws bedrock get-inference-profile \
--region YOUR_REGION \
--inference-profile-identifier YOUR_PROFILE_ID

Budget for compute, storage, image builds, and inference. You continue paying for application services while guests are suspended.

1. Prepare the checkout and AWS configuration​

git clone https://github.com/BerriAI/moyai.git
cd moyai
uv sync --frozen
export AWS_PROFILE=your-aws-profile
aws sts get-caller-identity
cp deploy/aws/terraform.tfvars.example deploy/aws/terraform.tfvars

Continue from the Moyai checkout. Use the same revision for the application image and deployment bundle. Edit deploy/aws/terraform.tfvars:

SettingValue to supply
nameA unique resource prefix for this installation
regionAn AWS region where your account has MicroVM access
hostname, route53_zone_idAn unused hostname and its existing public hosted zone
bedrock_model_idYour enabled model or inference profile ID, without the bedrock/ prefix
bedrock_invoke_resourcesExact allowed profile/model ARNs, including cross-region destinations
computer_lifetime, computer_idle_timeoutVM lifetime and idle suspension window in seconds; the template uses 28800 and 600

Leave moyai_image unset for the first apply. Keep AWS keys and secrets out of .tfvars. For an installation you plan to keep, configure encrypted remote Terraform state with locking before terraform init.

2. Provision AWS infrastructure​

Review the plan, then apply it to create the infrastructure, empty ECR repository, and Secrets Manager secret:

terraform -chdir=deploy/aws init
terraform -chdir=deploy/aws plan -out=installation.tfplan
terraform -chdir=deploy/aws apply installation.tfplan

3. Build and pin the application image​

Build the current checkout and push it to the ECR repository:

MOYAI_REPOSITORY=$(terraform -chdir=deploy/aws output -raw application_repository)
MOYAI_REVISION=$(git rev-parse HEAD)
MOYAI_REGION=$(terraform -chdir=deploy/aws output -json quickstart | python3 -c 'import json,sys; print(json.load(sys.stdin)["region"])')

aws ecr get-login-password --region "$MOYAI_REGION" |
docker login --username AWS --password-stdin "${MOYAI_REPOSITORY%%/*}"
docker buildx build --platform linux/amd64 \
--build-arg MOYAI_BUILD_SHA="$MOYAI_REVISION" \
--tag "$MOYAI_REPOSITORY:$MOYAI_REVISION" --push .
docker logout "${MOYAI_REPOSITORY%%/*}"

aws ecr describe-images --region "$MOYAI_REGION" \
--repository-name "${MOYAI_REPOSITORY#*/}" \
--image-ids "imageTag=$MOYAI_REVISION" \
--query 'imageDetails[0].imageDigest' --output text

Pin moyai_image in terraform.tfvars to the repository URL followed by @ and the returned sha256: digest.

terraform -chdir=deploy/aws plan -out=application.tfplan
terraform -chdir=deploy/aws apply application.tfplan

Keep the quickstart's pinned LiteLLM image unless you have tested a replacement. Use its bedrock/<model ID> alias for Moyai; the gateway authenticates with the host IAM role.

4. Initialize credentials​

Create a JSON file outside the checkout with file mode 0600. Use {} to start without Slack. To enable Slack, supply all six fields:

{
"SLACK_CLIENT_ID": "your-client-id",
"SLACK_CLIENT_SECRET": "your-client-secret",
"SLACK_SIGNING_SECRET": "your-signing-secret",
"SLACK_TEAM_ID": "T_YOUR_WORKSPACE",
"SLACK_SESSION_USERS": "U_YOUR_TEST_USER",
"GOOGLE_ALLOWED_DOMAINS": "example.com"
}

Set GOOGLE_ALLOWED_DOMAINS to your Slack users' email domains. An empty policy rejects them. You do not need to enable Google OAuth.

uv run python deploy/aws/quickstart.py secrets \
--secret-file /secure/path/moyai.json

Run secrets to generate database, gateway, and administrator passwords in Secrets Manager. Reuse the same input on retries to retain existing credentials. To choose the administrator password, set WORKSPACE_PASSWORD in the JSON to at least 24 characters.

5. Build the MicroVM image and install Moyai​

uv run python deploy/aws/quickstart.py image
uv run python deploy/aws/quickstart.py install
uv run python deploy/aws/quickstart.py status
terraform -chdir=deploy/aws output -raw app_url

Use image to build and pin the guest with its tools and suspend/resume hooks. Use install to start the Docker split bundle on EC2 through SSM. The host reads credentials from Secrets Manager and keeps installation keys on encrypted EBS.

The installer sets SANDBOX_PROVIDER=lambda, LAMBDA_REGION, LAMBDA_IMAGE, LAMBDA_IMAGE_VERSION, and LAMBDA_CHECKPOINT_BUCKET from the provisioned resources. For an existing deployment, use the manual Lambda configuration.

Find the runtime secret ARN with terraform -chdir=deploy/aws output -raw runtime_secret_arn, then read WORKSPACE_PASSWORD in Secrets Manager. Open app_url and sign in as admin.

Check status for installer completion, then test model execution and recovery in the app.

6. Verify a task and workspace recovery​

Ask Moyai to create a file with a unique name under /workspace, read it, and save it for download. Check the tool output, download the file, and confirm the checkpoint. Send a follow-up in the same conversation asking Moyai to read the saved file.

TestExpected result
Let a completed session become SUSPENDED, then send a follow-upThe same VM resumes with its files, memory, and background processes
Keep a task active beyond the idle windowMoyai's health probes keep the VM active during the turn and checkpoint save
Let a test VM reach its lifetime limit, then send a follow-upA new VM restores the last accepted S3 filesystem checkpoint; RAM and running processes are gone
Restart the application while retaining RDS, S3, and EBSYou can sign in, read session history, and complete a follow-up

In a disposable test installation, set computer_lifetime=600 and computer_idle_timeout=60 before installation to test expiry with a ten-minute VM lifetime. Check file checksums, installed packages, permissions, symlinks, and deletions that your workload depends on. Record VM IDs and checkpoint results with the upstream acceptance checks.

Connect Slack​

Register these URLs under your app_url in a dedicated Slack app:

Slack settingPath
OAuth redirect/oauth/slack/callback
Events/hooks/slack/events
Interactions/hooks/slack/interactions

Complete OAuth through Connections → Slack with the requested scopes and event subscriptions. Keep the signed webhook reachable over HTTPS. Repeat the task and recovery checks in one Slack thread, including artifact delivery. Check that Moyai denies unsigned Slack events and anonymous application API requests.

Limits and operations​

Use Lambda MicroVMs for shell, file, and browser tools, plus authenticated desktop screenshots and actions. For interactive desktop streaming, choose Modal. Build a separate Lambda image for prepared environments; you cannot reuse a Modal environment image.

Set a VM lifetime of at most eight hours, including suspended time. During idle suspension, you retain memory and processes until that deadline. After expiry, Moyai restores files and installed packages into a new VM from the pinned image and S3 checkpoint. Moyai does not replay unfinished turns that lack an accepted checkpoint.

Use SSE-S3 (AES256) for checkpoints; SSE-KMS-only buckets are unsupported. Keep the guest image versions referenced by retained checkpoints.

Back up installation keys with the application database and S3 references. Test restoring them before production use; daily EBS backups are crash-consistent. Follow the maintenance procedure for app upgrades and configuration changes. terraform apply alone does not perform them.

For teardown, follow the AWS cleanup steps for guest images, retained S3 objects, ECR images, backups, and deletion protection. Delete guest images through the MicroVM API; Terraform does not manage them.

Troubleshooting​

SymptomCheck
MicroVM image build or launch deniedRegion-specific MicroVM access, image/VM capacity, scoped IAM permissions, and the pinned image's SUCCESSFUL state
Installation refuses the imagemoyai_image must contain the ECR digest and match the checkout used for the deployment bundle
Bedrock invocation deniedModel access and every ARN required by the inference profile, including destination regions
Installer completes but tasks failModel/tool output in the app, SSM invocation details, and the service's CloudWatch logs
Slack user cannot sign in or send a taskOAuth installation, team/user allowlist, and GOOGLE_ALLOWED_DOMAINS
Workspace cannot restoreAccepted checkpoint, original pinned image/version, S3 prefix permissions, and SSE-S3 encryption