AWS (bare metal)
AWS is *.metal only. Standard EC2 with Nitro nested virt does not surface
/dev/kvm to Firecracker — only true bare-metal SKUs do.
Status
Section titled “Status”Verified end-to-end 2026-05-06 on c5.metal in us-east-1. Cycle ≈ 35 min
wall, ≈ $2.50 in AWS charges.
Defaults
Section titled “Defaults”INSTANCE_TYPE=c5.metal(~$4.08/hr; rejected if it doesn’t match*.metal)REGION=us-east-1BOOT_DISK_SIZE=50(Ubuntu AMI default 8GB runs out mid-build)- Image: latest Canonical Ubuntu 24.04 LTS amd64 (resolved by AMI filter at call time so it doesn’t drift)
Prerequisites
Section titled “Prerequisites”awsCLI v2 authenticated:aws configure(access key + secret + default region)- A default VPC with subnets in the chosen region. If not, set
AWS_SUBNET_ID=<subnet-id>.
The adapter handles SG creation lazily — see “Bugs caught” below.
PROVIDER=aws bash ops/ephemeral/up.sh# ... 15–25 min (bare metal allocation is slow) ...PROVIDER=aws LABEL=<label> bash ops/ephemeral/down.shBare-metal SKUs that work: c5.metal, c5n.metal, c5d.metal, c6i.metal,
c7i.metal, m5.metal, m6i.metal, m7i.metal, i3.metal, etc.
Bugs caught during verification
Section titled “Bugs caught during verification”- Default-VPC default-SG blocks inbound SSH. Only intra-SG ingress is
allowed, so
ssh root@<ip>from the operator workstation never reaches the box. Adapter now lazily creates a per-region SG namedmvm-ephemeral-sshwith a 22/tcp ingress rule for the operator’s current public IP (looked up viahttps://checkip.amazonaws.com).AWS_SG_IDoverrides for an externally managed group. - 8GB Ubuntu AMI root volume runs out mid-build. After cloud-init’s apt
- rustup + Nix + cargo-tools install, ~5GB is used and ~1.7GB remains
free, far short of mvmd’s
target/. Adapter now sets--block-device-mappingsto a 50GB gp3 root.
- rustup + Nix + cargo-tools install, ~5GB is used and ~1.7GB remains
free, far short of mvmd’s
- Ubuntu AMIs ship
/root/.ssh/authorized_keyswith a forced “login as ubuntu” command.ssh root@<ip>connects but the forced command prints the message and disconnects. Adapter splices a cleanwrite_filesentry into cloud-init’s existingwrite_files:list (two top-levelwrite_fileskeys would last-wins, not merge).
Bash gotcha that bit us
Section titled “Bash gotcha that bit us”local sg_id=$(aws ec2 create-security-group ... --query 'GroupId') silently
masks the AWS API’s non-zero exit code — local’s own return is 0, so
set -euo pipefail doesn’t catch a failed RHS. When the SG-create call
failed (we’d put an em-dash in the description; AWS rejects non-ASCII),
$sg_id was quietly empty and the next four AWS calls all errored out on
malformed input.
Fix: explicit [ -z "$var" ] && return 1 after every API call that produces
an id we depend on.