--- title: "Setting Up Your Cluster" seoTitle: "Set Up Your First Spinifex Cluster — Spinifex Docs" description: "Import an AMI and the RDS, ECS and EKS base images, create an SSH key pair and a VPC with a public subnet, then launch your first EC2 instance on a fresh Spinifex cluster." category: "Admin" tags: - setup - vpc - ec2 - quickstart resources: - title: "Spinifex Repository" url: "https://github.com/mulgadc/spinifex" - title: "AWS EC2 CLI Reference" url: "https://docs.aws.amazon.com/cli/latest/reference/ec2/" --- # Setting Up Your Cluster > Import an AMI and the system base images, create a VPC with a public subnet, and launch your first instance. ## Table of Contents - [1. Import an AMI](#1-import-an-ami) - [Option C: Import the system base images](#option-c-import-the-system-base-images) - [2. Create an SSH Key](#2-create-an-ssh-key) - [3. Create a VPC and Public Subnet](#3-create-a-vpc-and-public-subnet) - [4. Launch an Instance](#4-launch-an-instance) - [5. Connect via SSH](#5-connect-via-ssh) - [6. Managing Instances](#6-managing-instances) - [7. Launching the Web UI](#7-launching-the-web-ui) - [8. Secure the Install](#8-secure-the-install) - [Troubleshooting](#troubleshooting) --- ## Overview This guide walks through the first steps on a freshly installed cluster: importing an AMI and the system base images RDS, ECS and EKS need, creating an SSH key and a VPC with a public subnet, launching an instance, and connecting to it. ## Instructions ## Prerequisites - Spinifex installed and running — see [Single-Node Install](/docs/install), [Multi-Node Install](/docs/install-multi-node), or [Source Install](/docs/install-source) - AWS CLI configured with the `spinifex` profile: ```bash export AWS_PROFILE=spinifex ``` ## 1. Import an AMI ### Option A: Import a bundled image List the bundled images and import one matching your architecture: ```bash spx admin images list ``` ``` NAME | DISTRO | VERSION | ARCH | BOOT debian-13-arm64 | debian | 13 | arm64 | uefi debian-13-x86_64 | debian | 13 | x86_64 | uefi ubuntu-26.04-arm64 | ubuntu | 26.04 | arm64 | uefi ubuntu-26.04-x86_64 | ubuntu | 26.04 | x86_64 | uefi ``` ```bash spx admin images import --name ubuntu-26.04-x86_64 ``` Verify the import and note the AMI ID: ```bash AMI_ID=$(aws ec2 describe-images --query 'Images[0].ImageId' --output text) ``` ### Option B: Import a local image file ```bash spx admin images import --file ~/images/ubuntu-26.04-server-cloudimg-amd64.img --checksum ~/images/SHA256SUMS --distro ubuntu --version 26.04 --arch x86_64 --boot-mode uefi ``` Verify the import and note the AMI ID: ```bash AMI_ID=$(aws ec2 describe-images --query 'Images[0].ImageId' --output text) ``` ### Option C: Import the system base images **RDS, ECS and EKS each launch from an image of their own, and none of them is imported for you.** Until these are in the catalog, `CreateDBInstance`, `CreateCluster` and `CreateNodegroup` all fail at the point they go looking for a node image — so a cluster without them has those three services present in the API and unusable in practice. Import them once, now, and the install is functional from the start. Run these one at a time rather than in parallel, so predastore is not taking four concurrent uploads: ```bash for img in spinifex-rds-postgres spinifex-rds-mariadb spinifex-ecs-node spinifex-eks-node; do sudo spx admin images import --name "$img" --config /etc/spinifex/spinifex.toml done ``` | Image | Serves | Contents | | ----------------------- | -------------------------------- | ----------------------------------------------- | | `spinifex-rds-postgres` | RDS, `--engine postgres` | Alpine 3.24.1 + PostgreSQL 18 + `rds-init` | | `spinifex-rds-mariadb` | RDS, `--engine mariadb` | Alpine 3.24.1 + MariaDB 11.8 + `rds-init` | | `spinifex-ecs-node` | ECS container instances | Alpine 3.21.7 + containerd + ecs-agent | | `spinifex-eks-node` | EKS control plane and nodegroups | Alpine 3.21.7 + K3s v1.32.5 + eks-token-webhook | All four boot **BIOS**, unlike the distro images, which boot UEFI. That is a property of how they are built and nothing you need to pass. If you run GPU workloads, add `spinifex-ecs-node-gpu` and `spinifex-eks-node-gpu` as well — Ubuntu 26.04 with the NVIDIA driver, selected automatically for a GPU instance type. They boot UEFI and they are large, so import them only if you have GPUs. > [!IMPORTANT] > **These register under generic names, and that is correct.** `describe-images` shows `spinifex-eks-node` and `spinifex-ecs-node` both as `ami-alpine-3.21.7-x86_64`, and the two RDS images both as `ami-alpine-3.24.1-x86_64`. Nothing resolves them by name: ECS and EKS find theirs by the `spinifex:managed-by=ecs|eks` tag, and RDS by `spinifex:managed-by=rds` plus the `engine` and `engine-version` tags. **Verify the tags, not the names** — four rows with duplicate-looking names is what success looks like: > > ```bash > aws ec2 describe-images \ > --filters 'Name=tag-key,Values=spinifex:managed-by' \ > --query 'Images[].[ImageId,State,Tags[?Key==`spinifex:managed-by`].Value|[0],Tags[?Key==`engine`].Value|[0]]' \ > --output text > ``` `spx admin images list --config /etc/spinifex/spinifex.toml` on a node shows the whole catalog, including the images not imported here. ## 2. Create an SSH Key ### Option A: Import an existing key ```bash aws ec2 import-key-pair \ --key-name "spinifex-key" \ --public-key-material fileb://~/.ssh/id_rsa.pub ``` ### Option B: Create a new key pair ```bash aws ec2 create-key-pair --key-name spinifex-key \ | jq -r '.KeyMaterial | rtrimstr("\n")' > ~/.ssh/spinifex-key chmod 600 ~/.ssh/spinifex-key ssh-keygen -y -f ~/.ssh/spinifex-key > ~/.ssh/spinifex-key.pub ``` Verify: ```bash aws ec2 describe-key-pairs ``` ## 3. Create a VPC and Public Subnet ### Create a VPC ```bash VPC_ID=$(aws ec2 create-vpc --cidr-block 10.200.0.0/16 \ --query 'Vpc.VpcId' --output text) ``` ### Create an Internet Gateway An Internet Gateway enables instances in public subnets to reach the internet and be reachable from the LAN/WAN. ```bash IGW_ID=$(aws ec2 create-internet-gateway \ --query 'InternetGateway.InternetGatewayId' --output text) aws ec2 attach-internet-gateway \ --internet-gateway-id $IGW_ID \ --vpc-id $VPC_ID ``` ### Create a Subnet Create the subnet your instances will launch into. The routing and public-IP steps below are what make it a _public_ subnet. ```bash SUBNET_ID=$(aws ec2 create-subnet \ --vpc-id $VPC_ID \ --cidr-block 10.200.1.0/24 \ --query 'Subnet.SubnetId' --output text) ``` ### Create a Route Table A subnet is only **public** if its route table has a default route to the Internet Gateway. Spinifex does **not** add this route automatically — a new VPC's route table only routes traffic within the VPC (matching AWS). Without a `0.0.0.0/0` route to the IGW, instances in the subnet cannot reach the internet (and inbound connections cannot complete) even with a public IP assigned. ```bash RT_ID=$(aws ec2 create-route-table \ --vpc-id $VPC_ID \ --query 'RouteTable.RouteTableId' --output text) # Default route to the internet via the IGW aws ec2 create-route \ --route-table-id $RT_ID \ --destination-cidr-block 0.0.0.0/0 \ --gateway-id $IGW_ID # Associate the route table with the subnet aws ec2 associate-route-table \ --route-table-id $RT_ID \ --subnet-id $SUBNET_ID ``` ### Enable Auto-Assign Public IP Give every instance launched into the subnet a routable public IP, making it directly reachable from your network. ```bash aws ec2 modify-subnet-attribute \ --subnet-id $SUBNET_ID \ --map-public-ip-on-launch ``` ### Allow SSH and ICMP Every VPC gets a default security group that **blocks inbound traffic from outside the group** (matching AWS). Instances launched without an explicit security group use this default, so you must authorize ingress before you can SSH or ping the instance. ```bash SG_ID=$(aws ec2 describe-security-groups \ --filters Name=vpc-id,Values=$VPC_ID \ --query 'SecurityGroups[0].GroupId' --output text) # Allow SSH from anywhere aws ec2 authorize-security-group-ingress \ --group-id $SG_ID \ --protocol tcp --port 22 --cidr 0.0.0.0/0 # Allow ICMP (ping) from anywhere aws ec2 authorize-security-group-ingress \ --group-id $SG_ID \ --protocol icmp --port -1 --cidr 0.0.0.0/0 ``` **Note:** `0.0.0.0/0` opens these ports to every source. For anything beyond a quick evaluation, scope the `--cidr` to a trusted range. Rule changes apply immediately — no instance restart needed. ### Verify ```bash aws ec2 describe-vpcs --vpc-ids $VPC_ID aws ec2 describe-subnets --subnet-ids $SUBNET_ID aws ec2 describe-route-tables --route-table-ids $RT_ID aws ec2 describe-security-groups --group-ids $SG_ID ``` ## 4. Launch an Instance Launch an instance in the public subnet on a `t3.micro` (2 vCPU / 1 GiB). > **Note:** On an **arm64** host, use `t4g.micro` instead of `t3.micro`. ```bash INSTANCE_ID=$(aws ec2 run-instances \ --image-id $AMI_ID \ --instance-type t3.micro \ --key-name spinifex-key \ --subnet-id $SUBNET_ID \ --count 1 \ --query 'Instances[0].InstanceId' --output text) ``` Wait for the instance to reach `running` state: ```bash aws ec2 describe-instances --instance-ids $INSTANCE_ID \ --query 'Reservations[0].Instances[0].[State.Name, PrivateIpAddress, PublicIpAddress]' \ --output text ``` Expected output: ``` running 10.200.1.4 192.168.1.155 ``` The instance has both a private IP (VPC overlay) and a public IP (from your external pool, routable on your network). ## 5. Connect via SSH SSH directly to the instance's public IP: ```bash PUBLIC_IP=$(aws ec2 describe-instances --instance-ids $INSTANCE_ID \ --query 'Reservations[0].Instances[0].PublicIpAddress' --output text) ssh -i ~/.ssh/spinifex-key ubuntu@$PUBLIC_IP ``` > **Note:** cloud-init takes 30-60 seconds to configure the instance. If SSH is refused, wait and retry. Once connected, verify the instance has internet access: ```bash curl -s http://ifconfig.me ``` This should return the instance's public IP or the gateway's SNAT address. ## 6. Managing Instances ### Stop ```bash aws ec2 stop-instances --instance-ids $INSTANCE_ID ``` ### Start ```bash aws ec2 start-instances --instance-ids $INSTANCE_ID ``` ### Terminate ```bash aws ec2 terminate-instances --instance-ids $INSTANCE_ID ``` ### Console Output View the instance's serial console log (useful for debugging boot issues): ```bash aws ec2 get-console-output --instance-id $INSTANCE_ID \ --query 'Output' --output text ``` ### Multi-Node: Check Instance Placement On a multi-node cluster, instances are distributed across nodes: ```bash spx get vms ``` ## 7. Launching the Web UI Spinifex ships with a built-in web console — an alternative to the AWS CLI, SDKs, and Terraform, analogous to the AWS Management Console. Every action in the UI is a standard AWS SigV4 API call, so the same IAM policies and audit behaviour apply.