parlel/ec2

A zero-dependency, in-process fake of AWS EC2. Speaks the AWS Query (XML) wire protocol, so the real @aws-sdk/client-ec2 works against it unchanged.

Port4700
ProtocolAWS Query / XML (API version 2016-11-15)
HealthGET /_parlel/health
ResetPOST /_parlel/reset

Default connection

AWS_ENDPOINT_URL=http://127.0.0.1:4700
AWS_ACCESS_KEY_ID=parlel
AWS_SECRET_ACCESS_KEY=parlel
AWS_REGION=us-east-1

Any SigV4 credentials are accepted (auth is not verified).

Supported operations

CategoryOperations
InstancesRunInstances, DescribeInstances, StartInstances, StopInstances, TerminateInstances
Security groupsCreateSecurityGroup, DescribeSecurityGroups, AuthorizeSecurityGroupIngress
VPC / SubnetsCreateVpc, DescribeVpcs, CreateSubnet, DescribeSubnets
ImagesDescribeImages (one AMI is seeded: ami-0abcdef1234567890)
TagsCreateTags, DescribeTags
Key pairsCreateKeyPair

Generated ids look like real EC2: i-…, sg-…, vpc-…, subnet-…, ami-….

SDK usage example

import { EC2Client, RunInstancesCommand, DescribeInstancesCommand } from "@aws-sdk/client-ec2";

const ec2 = new EC2Client({
  endpoint: "http://127.0.0.1:4700",
  region: "us-east-1",
  credentials: { accessKeyId: "parlel", secretAccessKey: "parlel" },
});

const run = await ec2.send(new RunInstancesCommand({
  ImageId: "ami-0abcdef1234567890",
  MinCount: 1,
  MaxCount: 1,
  InstanceType: "t3.small",
}));
const id = run.Instances[0].InstanceId;

const desc = await ec2.send(new DescribeInstancesCommand({ InstanceIds: [id] }));
console.log(desc.Reservations[0].Instances[0].State.Name); // "running"

Access via MCP / preview URL

When running inside a Daytona sandbox, this HTTP service is exposed at an automatically-provisioned preview URL. Point the SDK endpoint at that URL and add the preview token header:

const ec2 = new EC2Client({
  endpoint: "https://<sandbox-id>-4700.preview.daytona.io",
  region: "us-east-1",
  credentials: { accessKeyId: "parlel", secretAccessKey: "parlel" },
  requestHandler: { httpOptions: { headers: { "x-daytona-preview-token": process.env.DAYTONA_PREVIEW_TOKEN } } },
});

Surface coverage

This emulator faithfully replicates the API surface most application code and agents exercise. Anything below the supported lines is either an intentional design choice for a fast, zero-cost local emulator (✓ By design) or a candidate for a future release (⟳ Roadmap) — never a silent inaccuracy.

Legend: ✅ fully supported · ◐ accepted (stored, not strictly enforced) · ✓ by design · ⟳ on the roadmap.

AreaLimitation
LifecycleState transitions are instantaneous; there is no pending/stopping interim state.
NetworkingNo real network connectivity; IPs are synthetic placeholders.
FiltersDescribe* filters (Filters param) are not applied — id selection only.
AMIsOnly one AMI is seeded; RegisterImage/CopyImage are not implemented.
AuthSigV4 is accepted but never validated.
PersistenceState is in-memory and lost on restart/reset.
PaginationResults are returned in a single page.
<!-- parlel:testenv:start -->

Configuration — test.env

Copy these into your test.env (used by the bridge sidecar flow). Tokens are Parlel's seeded test credentials — any non-empty value is accepted by the emulator, so you rarely need to change them. Swap in real credentials only when pointing at the live service in prod.env.

AWS_ACCESS_KEY_ID=parlel
AWS_SECRET_ACCESS_KEY=parlel
AWS_REGION=us-east-1
AWS_ENDPOINT_URL=http://parlel-bridge:4700
<!-- parlel:testenv:end -->