Deploy HailBytes ASM on AWS via CLI

Programmatic deployment in one shell session. No console clicks. Works on commercial AWS and AWS GovCloud (US).

What you’ll do

  1. Accept the marketplace terms (one-time, per AWS account).
  2. Resolve the latest HailBytes ASM AMI for your region and architecture.
  3. Launch a hardened EC2 instance via aws ec2 run-instances — or use the CloudFormation path if your shop standardizes on IaC.
  4. Bootstrap admin credentials and generate an API key for REST + MCP access.
  5. Connect an MCP-aware client (Claude, Cursor, Windsurf) to the new instance.

Estimated time: 5–8 minutes including AMI resolution and the cloud-init bootstrap. Estimated infrastructure cost: ~$161/month for the recommended t3.xlarge in us-east-1 (your mileage will vary by region and instance type).

Prerequisites

  • AWS CLI v2, configured with credentials that can run EC2, IAM, and (optionally) CloudFormation.
  • An EC2 key pair in your target region. The CLI examples below assume $KEY_NAME.
  • A VPC with at least one public subnet (default VPC is fine for a quick start). The CLI examples assume $SUBNET_ID.
  • An office IP or VPN CIDR to lock the security group down to. The CLI examples assume $ALLOW_CIDR.
  • jq, for parsing the AMI lookup response.
export AWS_REGION=us-east-1
export KEY_NAME=my-keypair
export SUBNET_ID=subnet-0123456789abcdef0
export ALLOW_CIDR=203.0.113.4/32        # your office or VPN
export ARCH=x86_64                       # or arm64

Step 1 — Accept marketplace terms

AWS Marketplace requires per-account acceptance of EULA and pricing for each AMI. This is a one-time action; if you’ve already subscribed in the console you can skip it.

# Look up the marketplace product and its current offer
aws marketplace-catalog list-entities \
  --catalog AWSMarketplace \
  --entity-type SaaSProduct \
  --filter-list 'Name=ProductTitle,ValueList=HailBytes ASM' \
  --region "$AWS_REGION"

# Once you have the offer ARN, accept the agreement.
# (Most teams do this once in the console; it persists per-account.)

If your account has never subscribed before, AWS may require you to confirm pricing in the marketplace console at least once. After that, every region in the account can launch via CLI without re-confirmation.

Step 2 — Resolve the latest AMI

The HailBytes ASM AMI is published with a stable name pattern. Pin to the latest by sorting on creation date.

AMI_ID=$(aws ec2 describe-images \
  --region "$AWS_REGION" \
  --owners aws-marketplace \
  --filters \
    "Name=name,Values=hailbytes-asm-*" \
    "Name=architecture,Values=$ARCH" \
    "Name=virtualization-type,Values=hvm" \
    "Name=state,Values=available" \
  --query 'sort_by(Images, &CreationDate)[-1].ImageId' \
  --output text)

echo "Resolved AMI: $AMI_ID"

The AMI is published for both x86_64 and arm64. Graviton instances (t4g, m7g) work and are a little cheaper.

Step 3 — Launch via aws ec2 run-instances

Create a security group locked to your $ALLOW_CIDR, then launch.

# Security group: 22 (SSH) + 443 (HTTPS, web UI + MCP) from your CIDR only
SG_ID=$(aws ec2 create-security-group \
  --region "$AWS_REGION" \
  --group-name hailbytes-asm-sg \
  --description "HailBytes ASM web + SSH" \
  --vpc-id $(aws ec2 describe-subnets \
              --subnet-ids "$SUBNET_ID" \
              --query 'Subnets[0].VpcId' --output text) \
  --query 'GroupId' --output text)

aws ec2 authorize-security-group-ingress --region "$AWS_REGION" \
  --group-id "$SG_ID" \
  --ip-permissions \
    "IpProtocol=tcp,FromPort=22,ToPort=22,IpRanges=[{CidrIp=$ALLOW_CIDR}]" \
    "IpProtocol=tcp,FromPort=443,ToPort=443,IpRanges=[{CidrIp=$ALLOW_CIDR}]"

# Launch a t3.xlarge with 100 GB gp3 root volume.
INSTANCE_ID=$(aws ec2 run-instances \
  --region "$AWS_REGION" \
  --image-id "$AMI_ID" \
  --instance-type t3.xlarge \
  --key-name "$KEY_NAME" \
  --subnet-id "$SUBNET_ID" \
  --security-group-ids "$SG_ID" \
  --associate-public-ip-address \
  --block-device-mappings 'DeviceName=/dev/sda1,Ebs={VolumeSize=100,VolumeType=gp3,Encrypted=true}' \
  --metadata-options 'HttpTokens=required,HttpEndpoint=enabled' \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=hailbytes-asm}]' \
  --query 'Instances[0].InstanceId' --output text)

aws ec2 wait instance-running --region "$AWS_REGION" --instance-ids "$INSTANCE_ID"

PUBLIC_DNS=$(aws ec2 describe-instances --region "$AWS_REGION" \
  --instance-ids "$INSTANCE_ID" \
  --query 'Reservations[0].Instances[0].PublicDnsName' --output text)

echo "ASM is bootstrapping at https://$PUBLIC_DNS/"

Cloud-init runs the docker-compose stack; first boot takes 3–5 minutes. The instance is reachable on port 443 with a self-signed cert until you point a domain at it and run the included certbot helper.

Alternative — CloudFormation

Same outcome via IaC, parameterized for repeat deployments.

aws cloudformation deploy \
  --region "$AWS_REGION" \
  --stack-name hailbytes-asm \
  --template-url https://hailbytes-marketplace.s3.amazonaws.com/asm/cfn.yaml \
  --capabilities CAPABILITY_IAM \
  --parameter-overrides \
      AmiId="$AMI_ID" \
      KeyName="$KEY_NAME" \
      SubnetId="$SUBNET_ID" \
      AllowedCidr="$ALLOW_CIDR" \
      InstanceType=t3.xlarge

aws cloudformation describe-stacks \
  --region "$AWS_REGION" \
  --stack-name hailbytes-asm \
  --query 'Stacks[0].Outputs'

The published template uses the same Packer-built AMI; pinning AmiId to a known good build keeps redeploys deterministic. For multi-region rollouts, parameterize on AWS_REGION and let your CI loop the call.

Step 4 — Bootstrap credentials

SSH in, set an admin password, generate an API key.

ssh -i ~/.ssh/$KEY_NAME.pem ubuntu@$PUBLIC_DNS

# Inside the instance:
sudo /opt/hailbytes/bin/hailbytes-asm reset-admin --email admin@example.com
# → prints a one-time login URL

sudo /opt/hailbytes/bin/hailbytes-asm api-key create \
  --name "ci-bootstrap" \
  --description "First key for REST + MCP"
# → prints HAILBYTES_ASM_KEY=...   (save it; shown only once)

The API key works for both the REST API (X-API-Key header) and the MCP server. Keys are SHA-256 hashed at rest; the plaintext is never stored.

Step 5 — Connect MCP

Drop the new instance into your MCP-aware client.

{
  "mcpServers": {
    "hailbytes-asm": {
      "type": "streamable-http",
      "url":  "https://<your-asm-host>/mcp/",
      "headers": { "X-API-Key": "<HAILBYTES_ASM_KEY>" }
    }
  }
}

Confirm the agent can see HailBytes by asking it to “list targets in HailBytes ASM”. Full tool reference: /mcp/.

AWS GovCloud (US)

Same flow, different region prefix. Set AWS_REGION=us-gov-west-1 or us-gov-east-1 and use credentials in the partition aws-us-gov.

aws ec2 describe-images \
  --region us-gov-west-1 \
  --owners aws-marketplace \
  --filters "Name=name,Values=hailbytes-asm-*" \
  --query 'sort_by(Images, &CreationDate)[-1].ImageId' \
  --output text

FedRAMP-Moderate-aligned controls are configured by default on GovCloud AMIs. Check the security overview for the full posture statement.

Smoke test

# REST
curl -k https://$PUBLIC_DNS/api/listTargets/ \
  -H "X-API-Key: $HAILBYTES_ASM_KEY" | jq '.recordsTotal'

# MCP (any MCP-aware client; here we just confirm the route is up)
curl -k -I https://$PUBLIC_DNS/mcp/ \
  -H "X-API-Key: $HAILBYTES_ASM_KEY"

Tear-down

# run-instances path
aws ec2 terminate-instances --region "$AWS_REGION" --instance-ids "$INSTANCE_ID"
aws ec2 wait instance-terminated --region "$AWS_REGION" --instance-ids "$INSTANCE_ID"
aws ec2 delete-security-group --region "$AWS_REGION" --group-id "$SG_ID"

# CloudFormation path
aws cloudformation delete-stack --region "$AWS_REGION" --stack-name hailbytes-asm

Get the Free HailBytes ASM Getting Started Guide

A 7-part email series covering everything from your first deployment to advanced configuration and real-world workflows. One email per day, no spam.