> ## Documentation Index
> Fetch the complete documentation index at: https://docs.siderolabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Register an AWS EC2 Instance

> Launch AWS EC2 instances and register them with Omni.

export const release = 'v1.13.7';

This guide explains how to launch AWS EC2 instances and register them with Omni.

There are two ways to get started:

* **Option A: Use the official Talos AMI** — the fastest and recommended approach. Choose this unless you need to customize the image.
* **Option B: Build a custom Talos AMI** — use this only if you need system extensions or other image-level customizations.

Both options begin with the same AWS setup. First, complete the steps in [Set up your AWS environment](#set-up-your-aws-environment), then continue with either Option A or Option B.

## Set up your AWS environment

Before launching your instances, configure the AWS networking required for your deployment.

### Step 1: Set your AWS region

Define the AWS region where you want to create your Omni machines.

```bash theme={null}
REGION=<your-aws-region> # e.g. us-east-1
```

### Step 2: Identify the VPC

Your EC2 instances must run inside a VPC. Most AWS accounts have a default VPC available.

First list the VPCs in your region:

```bash theme={null}
aws ec2 describe-vpcs --region $REGION
```

Then capture the default VPC:

```bash theme={null}
VPC_ID=$(aws ec2 describe-vpcs \
  --region $REGION \
  --query "Vpcs[?IsDefault].VpcId" \
  --output text)

echo $VPC_ID
```

This command stores the VPC ID in the `VPC_ID` variable.

### Step 3: Create a subnet

Next, create a subnet within the VPC.

The subnet CIDR must fall within the VPC CIDR range. For example, if the VPC uses `172.31.0.0/16`, you can create a subnet such as `172.31.128.0/20`.

```bash theme={null}
SUBNET_ID=$(aws ec2 create-subnet \
  --region $REGION \
  --vpc-id $VPC_ID \
  --cidr-block 172.31.128.0/20 \
  --query "Subnet.SubnetId" \
  --output text)

echo $SUBNET_ID
```

The subnet ID will be used later when launching EC2 instances.

### Step 4: Create a security group

First, create a security group that will be attached to the EC2 instances.

```bash theme={null}
SECURITY_GROUP=$(aws ec2 create-security-group \
  --region $REGION \
  --group-name omni-aws-sg \
  --description "Security group for Omni EC2 instances" \
  --query "GroupId" \
  --output text)

echo $SECURITY_GROUP
```

Next, update the security group to allow all internal traffic within the same group. This allows Kubernetes applications running on different machines to communicate with each other:

```bash theme={null}
aws ec2 authorize-security-group-ingress \
  --region $REGION \
  --group-id $SECURITY_GROUP \
  --protocol all \
  --port -1 \
  --source-group $SECURITY_GROUP
```

## Option A: Use the official Talos AMI

Talos provides an official AWS AMI that you can use directly, with no image build required.

<Note>The official Talos AWS AMI includes the `ecr-credential-provider` system extension by default.</Note>

To register an instance, you add a [join config](./join-machines-to-omni) to the EC2 instance user data and boot the instance with the official Talos AMI. The machine then joins your Omni account automatically when it starts.

1. Define environment variables that specify the machines you want to register.

   These are example values. Adjust them to match your machine specifications.

   <CodeBlock lang="sh">
     {`
       AWS_REGION=$(aws configure get region)\nTALOS_VERSION=${release}\nARCH=amd64\nINSTANCE_TYPE=t3.small\nCOUNT=1
       `}
   </CodeBlock>

2. Retrieve the official Talos AWS AMI:

   ```bash theme={null}
   AMI=$(curl -sL https://github.com/siderolabs/talos/releases/download/${TALOS_VERSION}/cloud-images.json \
     | jq -r '.[] | select(.region == "'"$AWS_REGION"'") | select(.arch == "'"$ARCH"'") | .id')

   echo "Using AMI: $AMI"
   ```

3. Generate the join configuration. This allows the Talos machines to register with Omni when they boot:

   ```bash theme={null}
   USER_DATA=$(omnictl jointoken machine-config)
   ```

4. Launch the EC2 instances. Omni surfaces an instance's EC2 tags as machine labels when the machine first joins. Choose the option that fits your needs:

   <Tabs>
     <Tab title="Without labels">
       Launch the instances with the official AMI and your join configuration. The machine registers with Omni automatically when it boots:

       ```bash theme={null}
       aws ec2 run-instances \
         --region $AWS_REGION \
         --image-id $AMI \
         --instance-type $INSTANCE_TYPE \
         --count $COUNT \
         --user-data "$USER_DATA"
       ```
     </Tab>

     <Tab title="With machine labels">
       To attach labels, the instance must allow tags in instance metadata, which is **not** enabled by default. The `--metadata-options` flag enables it, and each tag becomes a machine label. In this example, the tag with key `cp-candidate` and value `true` becomes a machine label named `cp-candidate` with the value `true`:

       ```bash theme={null}
       aws ec2 run-instances \
         --region $AWS_REGION \
         --image-id $AMI \
         --instance-type $INSTANCE_TYPE \
         --count $COUNT \
         --user-data "$USER_DATA" \
         --metadata-options "InstanceMetadataTags=enabled" \
         --tag-specifications 'ResourceType=instance,Tags=[{Key=cp-candidate,Value=true}]'
       ```
     </Tab>
   </Tabs>

Your machine is now registered with Omni and will appear on the **Machines** page once it joins. To use it, continue to [Create a cluster](../../getting-started/getting-started#step-3-create-cluster).

When you are finished and no longer need these resources, see [Cleanup](#cleanup).

## Option B: Build a custom Talos AMI

If you need system extensions or other customizations baked into the image, build a custom Talos AMI.

In this option, you will:

1. Download the Talos AWS disk image from Omni
2. Upload it to Amazon S3
3. Import it into EC2 as a snapshot
4. Register the snapshot as an AMI
5. Launch instances from your custom AMI

### Step 1: Download the Talos AWS image

You can download the Talos AWS image from the CLI or the UI:

<Tabs>
  <Tab title="CLI">
    Run the following command to download the Talos AWS image:

    ```bash theme={null}
    omnictl download aws
    ```

    To see available options for adding system extensions:

    ```bash theme={null}
    omnictl download aws --help
    ```
  </Tab>

  <Tab title="UI">
    To download the Talos AWS image from the UI:

    1. Log into your Omni account.
    2. Go to the **Overview** page.
    3. Click **Download Installation Media**.
    4. Select **AWS AMI (amd64)** or **AWS AMI (arm64)** depending on your instance architecture.
    5. Add any required system extensions.
    6. Click **Download**.
  </Tab>
</Tabs>

The downloaded Talos AWS image will contain a compressed archive similar to:

```bash theme={null}
aws-amd64.tar.gz
```

Extract the archive:

```bash theme={null}
tar -xzf aws-amd64.tar.gz
```

This command will produce a disk image similar to `disk.raw`.

### Step 2: Create an S3 bucket

The disk image must be uploaded to an S3 bucket before it can be imported into EC2.

Bucket names must be globally unique. The following command creates a bucket with a globally unique name using a timestamp.

```bash theme={null}
BUCKET="omni-aws-$(date +%s)"

aws s3api create-bucket \
  --bucket $BUCKET \
  --region $REGION \
  --create-bucket-configuration LocationConstraint=$REGION
```

### Step 3: Upload the disk image to S3

Upload the extracted disk image to the S3 bucket:

```bash theme={null}
aws s3 cp disk.raw s3://$BUCKET/omni-aws.raw
```

### Step 4: Import the disk image as an EC2 snapshot

Next, import the uploaded disk image into EC2 as a snapshot.

```bash theme={null}
IMPORT_TASK=$(aws ec2 import-snapshot \
  --region $REGION \
  --description "Omni AWS" \
  --disk-container "Format=raw,UserBucket={S3Bucket=$BUCKET,S3Key=omni-aws.raw}" \
  --query "ImportTaskId" \
  --output text)

echo $IMPORT_TASK
```

### Step 5: Monitor the snapshot import

You can check the status of the import task using:

```bash theme={null}
aws ec2 describe-import-snapshot-tasks \
  --region $REGION \
  --import-task-ids $IMPORT_TASK
```

Once the import completes, retrieve the snapshot ID:

```bash theme={null}
SNAPSHOT=$(aws ec2 describe-import-snapshot-tasks \
  --region $REGION \
  --import-task-ids $IMPORT_TASK \
  --query "ImportSnapshotTasks[0].SnapshotTaskDetail.SnapshotId" \
  --output text)

echo $SNAPSHOT
```

You will use this snapshot in the next step to register the AMI.

### Step 6: Register the AMI

Create an AMI from the snapshot.

```bash theme={null}
AMI_ID=$(aws ec2 register-image \
  --region $REGION \
  --block-device-mappings "DeviceName=/dev/xvda,Ebs={DeleteOnTermination=true,SnapshotId=$SNAPSHOT,VolumeSize=14,VolumeType=gp2}" \
  --root-device-name /dev/xvda \
  --virtualization-type hvm \
  --architecture x86_64 \
  --ena-support \
  --name omni-aws-ami \
  --query "ImageId" \
  --output text)

echo $AMI_ID
```

### Step 7: Launch EC2 instances

Finally, create EC2 instances using your custom AMI.

```bash theme={null}
aws ec2 run-instances \
  --region $REGION \
  --image-id $AMI_ID \
  --count 1 \
  --instance-type t3.small \
  --subnet-id $SUBNET_ID \
  --security-group-ids $SECURITY_GROUP \
  --associate-public-ip-address \
  --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=omni-aws-ami}]"
```

Your machine is now registered with Omni and will appear on the **Machines** page once it joins. To use it, continue to [Create a cluster](../../getting-started/getting-started#step-3-create-cluster).

## Cleanup

If you no longer need the resources created in this guide, remove them to avoid unnecessary AWS charges.

### Terminate the EC2 instances

Terminate the instances you launched, using their instance IDs:

```bash theme={null}
aws ec2 terminate-instances \
  --region $REGION \
  --instance-ids <instance-id> [<instance-id> ...]
```

You can find your instance IDs in the EC2 console, or in the output of the `run-instances` command you ran earlier.

### Deregister the AMI (Option B only)

If you created a custom AMI, deregister it:

```bash theme={null}
aws ec2 deregister-image \
  --region $REGION \
  --image-id $AMI_ID
```

### Delete the snapshot (Option B only)

After deregistering the AMI, delete the snapshot used to create it:

```bash theme={null}
aws ec2 delete-snapshot \
  --region $REGION \
  --snapshot-id $SNAPSHOT
```

### Remove the disk image from S3 (Option B only)

Delete the uploaded disk image:

```bash theme={null}
aws s3 rm s3://$BUCKET/omni-aws.raw
```

### Delete the S3 bucket (Option B only)

After removing the object, delete the bucket:

```bash theme={null}
aws s3 rb s3://$BUCKET
```

### Delete the security group

Remove the security group created for the EC2 instances:

```bash theme={null}
aws ec2 delete-security-group \
  --region $REGION \
  --group-id $SECURITY_GROUP
```

### Delete the subnet

Finally, delete the subnet created earlier:

```bash theme={null}
aws ec2 delete-subnet \
  --region $REGION \
  --subnet-id $SUBNET_ID
```
