Boot on AWS
This guide walks through booting your first Kheeper-managed host on Amazon Web Services.
Prerequisites
- Install the Kheeper CLI and log in
- An AWS account with EC2 access
awsCLI authenticated to your account
Set the variables in your shell needed for the remaining steps.
ORG=$(kheeper orgs list | grep 'user-[0-9a-f]' | awk '{ print $1 }')
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
AWS_REGION=us-east-2
Note the us-east-2 region is currently the only region that has the Kheeper API so instances must be launched in that region.
Step 1 — Create an IAM role for EC2
The instance needs an IAM role so it can call STS GetCallerIdentity during auto-registration. Create a minimal role:
aws iam create-role \
--role-name kheeper-autoregister \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "ec2.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}'
aws iam create-instance-profile \
--instance-profile-name kheeper-autoregister
aws iam add-role-to-instance-profile \
--instance-profile-name kheeper-autoregister \
--role-name kheeper-autoregister
Or, equivalently, with Terraform:
resource "aws_iam_role" "kheeper_autoregister" {
name = "kheeper-autoregister"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "ec2.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
}
resource "aws_iam_instance_profile" "kheeper_autoregister" {
name = "kheeper-autoregister"
role = aws_iam_role.kheeper_autoregister.name
}
No additional permissions are needed — GetCallerIdentity requires no IAM permissions.
Step 2 — Connect your AWS account
Link your AWS account to your Kheeper org so that AWS instances can auto-register as Kheeper hosts.
kheeper clouds create ${ORG}/my-aws --provider aws --account-id ${ACCOUNT_ID}
This will allow new instances created from Kheeper AMIs to register as new hosts in the region shown by kheeper status.
Kheeper accounts are region-scoped.
If the same AWS account is linked to multiple Kheeper regions, instances will fail to register unless a region is configured with metadata:
aws ec2 run-instances --user-data 'kheeper-region=us.kheeper.com'
Step 3 — Create an EC2 instance
Since this guide uses the postgres image, create a security group that will allow your instance to get a TLS certificate from Lets Encrypt (port 80) and listen for incoming connections to postgres (port 5432). Additionally ssh (port 22) allows for accessing the instance for sysadmin work.
VPC_ID=$(aws ec2 describe-vpcs --filters "Name=isDefault,Values=true" \
--query 'Vpcs[0].VpcId' --output text --region ${AWS_REGION})
SG_ID=$(aws ec2 create-security-group \
--group-name kheeper-http-postgres \
--description "Allow HTTP and Postgres" \
--vpc-id ${VPC_ID} \
--region ${AWS_REGION} \
--query 'GroupId' --output text)
aws ec2 authorize-security-group-ingress \
--group-id ${SG_ID} \
--protocol tcp --port 80 --cidr 0.0.0.0/0 \
--region ${AWS_REGION}
aws ec2 authorize-security-group-ingress \
--group-id ${SG_ID} \
--protocol tcp --port 5432 --cidr 0.0.0.0/0 \
--region ${AWS_REGION}
aws ec2 authorize-security-group-ingress \
--group-id ${SG_ID} \
--protocol tcp --port 22 --cidr 0.0.0.0/0 \
--region ${AWS_REGION}
Then launch an instance using the public Kheeper AMI. This is a Fedora bootc image that automatically connects to the Kheeper registry on first boot.
AMI_ID=$(aws ec2 describe-images \
--owners 223249276674 \
--filters "Name=name,Values=kheeper-aws-*" "Name=state,Values=available" \
--query 'sort_by(Images, &CreationDate)[-1].ImageId' \
--output text --region ${AWS_REGION})
INSTANCE_ID=$(aws ec2 run-instances \
--image-id ${AMI_ID} \
--instance-type m7i.large \
--block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":40}}]' \
--iam-instance-profile Name=kheeper-autoregister \
--security-group-ids ${SG_ID} \
--user-data 'kheeper-region=us.kheeper.com' \
--region ${AWS_REGION} \
--query 'Instances[0].InstanceId' --output text)
echo "Launched ${INSTANCE_ID}"
Or, equivalently, with Terraform (the region comes from your aws provider block):
data "aws_vpc" "default" {
default = true
}
resource "aws_security_group" "kheeper_http_postgres" {
name = "kheeper-http-postgres"
description = "Allow HTTP and Postgres"
vpc_id = data.aws_vpc.default.id
}
resource "aws_vpc_security_group_ingress_rule" "http" {
security_group_id = aws_security_group.kheeper_http_postgres.id
ip_protocol = "tcp"
from_port = 80
to_port = 80
cidr_ipv4 = "0.0.0.0/0"
}
resource "aws_vpc_security_group_ingress_rule" "postgres" {
security_group_id = aws_security_group.kheeper_http_postgres.id
ip_protocol = "tcp"
from_port = 5432
to_port = 5432
cidr_ipv4 = "0.0.0.0/0"
}
resource "aws_vpc_security_group_ingress_rule" "ssh" {
security_group_id = aws_security_group.kheeper_http_postgres.id
ip_protocol = "tcp"
from_port = 22
to_port = 22
cidr_ipv4 = "0.0.0.0/0"
}
data "aws_ami" "kheeper" {
owners = ["223249276674"]
most_recent = true
filter {
name = "name"
values = ["kheeper-aws-*"]
}
filter {
name = "state"
values = ["available"]
}
}
resource "aws_instance" "kheeper" {
ami = data.aws_ami.kheeper.id
instance_type = "m7i.large"
iam_instance_profile = aws_iam_instance_profile.kheeper_autoregister.name
vpc_security_group_ids = [aws_security_group.kheeper_http_postgres.id]
user_data = "kheeper-region=us.kheeper.com"
root_block_device {
volume_size = 40
}
}
Step 4 — Verify Host Registration
The instance will boot and auto-register within a few minutes. Check that the host appeared:
kheeper hosts list --org ${ORG}
You should see a host whose instance name matches the instance ID you launched.
Step 5 — Author the config
Generate a starter config from the image's schema and edit it to fit your host.
Here we are using the public postgres image:
You can use the DNS name from kheeper hosts list where the config requests a domain.
kheeper releases start config.json --image us.kheeper.com/public/postgres:v0.2.0
Here's an example for a config with a single ssh public key that creates a database named kheeper and a database user named kheeper.
{
"base": {
"admin_authorized_keys": "ssh-ed25519 AAAAC3NzaC1lZDI1NET5AAAAINFEt8Q1O8VSKe+GVOsHMqjXdyukUkM38VI/edNs0ur8"
},
"database": {
"name": "kheeper",
"users": [{"name": "kheeper", "password": "changeme1234567890"}]
},
"postgres": {
"domain_name": "i-0a35818c9f09bada3.user-12345678.us.kheeper.app"
}
}
Step 6 — Create a release
Create and activate a release that pairs the image with your config:
kheeper releases create ${ORG}/${INSTANCE_ID}:v1 \
--image us.kheeper.com/public/postgres:v0.2.0 \
--config-file config.json \
--activate
Step 7 — Verify Postgres
The host will pick up the release within a minute, pull and reboot.
You can now connect to your Postgres server with psql.
HOST_DNS=$INSTANCE_ID.user-12345678.us.kheeper.app
USER=kheeper
export PGPASSWORD=changeme1234567890
psql "host=$HOST_DNS user=$USER sslmode=verify-full sslrootcert=system"
Troubleshooting
If an instance fails to autoregister as a new host or fails to reboot into a release after you activate it, you should inspect the console output:
aws ec2 get-console-output --instance-id ${INSTANCE_ID} --region ${AWS_REGION} --output text
Clean up
Terminate the EC2 instance and delete the Kheeper host when you're done:
aws ec2 terminate-instances --instance-ids ${INSTANCE_ID} --region ${AWS_REGION}
kheeper hosts delete ${ORG}/${INSTANCE_ID}