AWSTemplateFormatVersion: '2010-09-09' Description: > ArchNest - Single-user self-hosted ops dashboard on AWS. Deploys a t4g.small EC2 instance with Docker Compose. Parameters: KeyPairName: Type: String Default: kiro-ide-key Description: SSH key pair name for EC2 access InstanceType: Type: String Default: t4g.small AllowedValues: - t4g.micro - t4g.small - t4g.medium Description: EC2 instance type (ARM/Graviton) VolumeSize: Type: Number Default: 30 Description: EBS volume size in GB Resources: # Security Group — allows SSH, HTTP, HTTPS, and the backend port ArchNestSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: ArchNest security group GroupName: archnest-sg SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 Description: SSH access - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 Description: HTTP (redirect to HTTPS) - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: 0.0.0.0/0 Description: HTTPS - IpProtocol: tcp FromPort: 8080 ToPort: 8080 CidrIp: 0.0.0.0/0 Description: Frontend (direct, before proxy) - IpProtocol: tcp FromPort: 4000 ToPort: 4000 CidrIp: 0.0.0.0/0 Description: Backend API SecurityGroupEgress: - IpProtocol: -1 CidrIp: 0.0.0.0/0 Description: All outbound (SSH to managed hosts, Docker pulls, etc.) Tags: - Key: Name Value: archnest-sg # Elastic IP — stable public IP across stop/start ArchNestEIP: Type: AWS::EC2::EIP Properties: Domain: vpc Tags: - Key: Name Value: archnest-eip # EC2 Instance ArchNestInstance: Type: AWS::EC2::Instance Properties: InstanceType: !Ref InstanceType KeyName: !Ref KeyPairName ImageId: !FindInMap [RegionAMI, !Ref 'AWS::Region', AMI] SecurityGroupIds: - !Ref ArchNestSecurityGroup BlockDeviceMappings: - DeviceName: /dev/sda1 Ebs: VolumeSize: !Ref VolumeSize VolumeType: gp3 Encrypted: true UserData: Fn::Base64: | #!/bin/bash set -e # Update system apt-get update -y apt-get upgrade -y # Install Docker apt-get install -y docker.io docker-compose-v2 git curl systemctl enable --now docker # Create deploy directory mkdir -p /opt/archnest chown ubuntu:ubuntu /opt/archnest # Signal ready echo "ArchNest instance ready" > /opt/archnest/READY Tags: - Key: Name Value: archnest # Associate Elastic IP with instance ArchNestEIPAssociation: Type: AWS::EC2::EIPAssociation Properties: InstanceId: !Ref ArchNestInstance EIP: !Ref ArchNestEIP # Budget alarm — $30/month ceiling ArchNestBudget: Type: AWS::Budgets::Budget Properties: Budget: BudgetName: archnest-monthly BudgetType: COST TimeUnit: MONTHLY BudgetLimit: Amount: 30 Unit: USD NotificationsWithSubscribers: - Notification: NotificationType: ACTUAL ComparisonOperator: GREATER_THAN Threshold: 80 Subscribers: - SubscriptionType: EMAIL Address: samueljamesinc@gmail.com - Notification: NotificationType: ACTUAL ComparisonOperator: GREATER_THAN Threshold: 100 Subscribers: - SubscriptionType: EMAIL Address: samueljamesinc@gmail.com Mappings: # Ubuntu 24.04 LTS ARM64 AMIs per region RegionAMI: us-east-1: AMI: ami-0a7a4e87939439934 us-east-2: AMI: ami-0ea3405d2d2522162 us-west-2: AMI: ami-05d38da78ce859165 Outputs: PublicIP: Description: ArchNest public IP address Value: !Ref ArchNestEIP SSHCommand: Description: SSH into the instance Value: !Sub 'ssh -i ~/.ssh/kiro_ide_key ubuntu@${ArchNestEIP}' InstanceId: Description: EC2 Instance ID Value: !Ref ArchNestInstance EstimatedMonthlyCost: Description: Estimated monthly cost Value: '~$15/month (t4g.small + 30GB gp3 + Elastic IP)'