Skip to content

AWS VPC Network Setup Guide

Richard Salas edited this page Aug 7, 2025 · 3 revisions

Unlocked VPC Network Setup Guide

This document provides a step-by-step reference for building the Unlocked VPC network and supporting AWS resources.

Table of Contents


1. Create VPC

  1. Click 'Create VPC'
  2. Name tag: unlockedv2_<statename>-vpc
  3. IPv4 CIDR block: IPv4 CIDR manual input
  4. IPv4 CIDR: 10.0.0.0/16
  5. IPv6 CIDR: Amazon-provided IPv6 CIDR block
  6. Network border group: us-west-2
  7. Tenancy: Default
  8. Click Create VPC

2. Create Subnets

Create 4 subnets (2 private, 2 public).

private1 subnet

  1. Select VPC ID of the VPC created
  2. Subnet Name: unlockedv2_<statename>-subnet-private1-us-west-2a
  3. Availability Zone: us-<region>-2a
  4. IPv4 subnet CIDR block: 10.0.128.0/20
  5. IPv6 CIDR block: Manual input
  6. IPv6 subnet CIDR block: Select option and set as /64 (e.g., 2600:1f14:3228:f700::/64)
  7. Click Add new subnet

private2 subnet

  1. Select VPC ID of the VPC created
  2. Subnet Name: unlockedv2_<statename>-subnet-private2-us-west-2b
  3. Availability Zone: us-<region>-2b
  4. IPv4 subnet CIDR block: 10.0.144.0/20
  5. IPv6 CIDR block: Manual input
  6. IPv6 subnet CIDR block: Set as /64 (e.g., 2600:1f14:3228:f701::/64)
  7. Click Add new subnet

public1 subnet

  1. Select VPC ID of the VPC created
  2. Subnet Name: unlockedv2_<statename>-subnet-public1-us-west-2a
  3. Availability Zone: us-<region>-2a
  4. IPv4 subnet CIDR block: 10.0.0.0/20
  5. IPv6 CIDR block: Manual input
  6. IPv6 subnet CIDR block: Set as /64 (e.g., 2600:1f14:3228:f702::/64)
  7. Click Add new subnet

public2 subnet

  1. Select VPC ID of the VPC created
  2. Subnet Name: unlockedv2_<statename>-subnet-public2-us-west-2b
  3. Availability Zone: us-<region>-2b
  4. IPv4 subnet CIDR block: 10.0.16.0/20
  5. IPv6 CIDR block: Manual input
  6. IPv6 subnet CIDR block: Set as /64 (e.g., 2600:1f14:3228:f703::/64)
  7. Click Create subnet

3. Create Internet Gateway

  1. Name tag: unlockedv2_<statename>-igw
  2. Click Create internet gateway
  3. Click Actions > Attach to VPC
    • Available VPCs: select VPC created above
    • Click Attach internet gateway

4. Create Route Tables, NAT Gateway, PrivateLink and Lattice Endpoints

PUBLIC Route Tables

  1. Click 'Create route tables'
  2. Name: unlockedv2_<statename>-rtb-public
  3. VPC: select VPC created above
  4. Click Create route table
  5. Select Routes tab of the route table just created
    • Click Edit routes
    • Add route:
      • Destination: 0.0.0.0/0
      • Target: Internet Gateway - igw-<created>
    • Add route:
      • Destination: 0.0.0.0/16
      • Target: Internet Gateway - igw-<created>
    • Click Save changes
  6. Select Subnet associations tab
    • Click Edit subnet associations
    • Select both public subnets
    • Click Save associations

Create NAT Gateway

  1. Name: unlockedv2_<statename>-nat-public1-us-west-2a
  2. Subnet: select public1 subnet
  3. Connectivity type: Public
  4. Elastic IP allocation ID: Click allocate Elastic IP
  5. Additional Settings - Primary private IPv4 address: 10.0.14.231
  6. Click Create NAT gateway

PRIVATE Route Tables

private1 route table

  1. Name: unlockedv2_<statename>-rtb-private1-us-west-2a
  2. VPC: select VPC created above
  3. Click Create route table

private2 route table

  1. Name: unlockedv2_<statename>-rtb-private2-us-west-2b
  2. VPC: select VPC created above
  3. Click Create route table

Create S3 Service Endpoint (PrivateLink and Lattice Endpoints)

  1. Name: unlockedv2_<statename>-vpce-s3
  2. Type: AWS services
  3. Services: com.amazonaws.us-west-2.s3 | Gateway
  4. VPC: select VPC created above
  5. Route tables: select both private route tables
  6. Policy: Full Access
  7. Click Create endpoint

private1 route table associations and routes

  1. Select Subnet associations tab of unlockedv2_<statename>-rtb-private1-us-west-2a
    • Click Edit subnet associations
    • Select private1 subnet
    • Click Save associations
  2. Select Routes tab
    • Click Edit routes
    • Add route:
      • Destination: 0.0.0.0/0
      • Target: NAT Gateway - nat-<created>
    • Click Save changes

private2 route table associations and routes

  1. Select Subnet associations tab of unlockedv2_<statename>-rtb-private2-us-west-2b
    • Click Edit subnet associations
    • Select private2 subnet
    • Click Save associations
  2. Select Routes tab
    • Click Edit routes
    • Add route:
      • Destination: 0.0.0.0/0
      • Target: NAT Gateway - nat-<created>
    • Click Save changes

5. Create Load Balancer

  1. From EC2 select Load Balancers from side nav
  2. Click Create load balancer
  3. Load Balancer type: Application Load Balancer
  4. Load Balancer Name: unlockedv2-<statename>
  5. Scheme: Internet-facing
  6. Load balancer IP address type: Dualstack
  7. VPC: select VPC created above
  8. Availability Zones: select both regions and both public subnets
  9. Security Groups: select default (should already be selected)
  10. Listeners and routing: Click Create target group
    • Target type: Instances
    • Target group name: unlockedv2-<statename>
    • Protocol: HTTP
    • Port: 80
    • IP address type: IPv4
    • VPC: select VPC created above
    • Protocol version: HTTP1
    • Health check protocol: HTTP
    • Health check path: /api/healthcheck
    • Click Next and Create target group
    • Note: You will need to add instance here later
  11. Click Create load balancer

Modify Listeners and Rules

  1. From the Load Balancer you just created Listeners and rules tab, click 1 rule link
  2. Place check in the checkbox of the Default rule, click Action > Edit rule
  3. Default action - Routing action: Redirect to URL
    • Protocol: HTTPS
    • Port: 443
    • Status Code: 301 Permanently moved
  4. Click Save Changes

6. Create Domain Name (Route 53)

Steps:

  1. From Route 53 select Hosted Zones from side nav
  2. Select the hosted zone you are going to add a new domain name to (production: unlockedlabs.org / test: unlockedlabs.xyz)
  3. Click Create Record
  4. Routing Policy: Simple Routing
  5. Configure Records: Click Define simple record
  6. Record Name: <statename>
  7. Record Type: A - Routes traffic to IPv4 address and some AWS resources
  8. Value/Route Traffic to: Alias to Application and Classic Load Balancer
  9. Choose Region: <region>
  10. Select load balancer created above
  11. Click Define simple record
  12. Repeat for *.<statename>
    • Record Name: *.<statename>
    • Repeat steps 7-11 above
  13. Click Create records

7. Create Security Group for SSM

Steps:

  1. From EC2 select Security Groups from side nav
  2. Click Create security group
  3. Security group name: unlockedv2_<statename>_deployment
  4. Description: allow SSM connection and load balancer traffic
  5. VPC: Select VPC created above
  6. Inbound rules:
    • Rule: HTTP
      • Add rule
      • Type: HTTP
      • Source: Custom (select default / sg for your VPC)
      • Description: ELB traffic - healthcheck
    • Rule: SSH (IPv4)
      • Add rule
      • Type: SSH
      • Source: Anywhere-IPv4
      • Description: SSM
    • Rule: SSH (IPv6)
      • Add rule
      • Type: SSH
      • Source: Anywhere-IPv6
      • Description: SSM
  7. Click Create security group

8. Create Certificate

Steps:

  1. From AWS Certificate Manager click Request
  2. Certificate type: Request a public certificate | click Next
  3. Fully qualified domain name: *.<statename>.unlockedlabs.org
  4. Click Add another name to this certificate and add: <statename>.unlockedlabs.org
  5. Validation method: DNS validation
  6. Key algorithm: RSA 2048
  7. Click Request
  8. From the Domains section in the Certificate you created, click Create records in Route 53
  9. Click Create records

9. Create Instance

  1. From EC2 select Instances

  2. Click Launch instances

  3. Name: production_unlockedv2_<statename>_node

  4. Application and OS images: Debian

  5. Architecture: 64-bit (x86)

  6. Instance Type: t3.large

  7. Key pair: Click Create new key pair

    • Key pair name: unlockedv2_<statename>-keys
    • Key pair type: RSA
    • Private key file format: .pem
    • Click Create ... (will download key file, keep this safe)
  8. From Network Settings section click Edit

  9. VPC: Select VPC created above

  10. Subnet: select private1 subnet

  11. Make sure Auto-assign public IP and IPv6 IP settings are set to Disable

  12. Firewall: Select existing security group

  13. Select the one created in Section 7 above (unlockedv2_<statename>_deployment)

  14. Configure storage: 50 GiB gp3

  15. From Advanced Details, IAM instance profile: select ec2_ssm_profile

  16. Metadata response hop limit: 3

  17. Upload file. Create a new file named setup.sh and paste this content:

    #!/bin/bash

mkdir s3 mkdir -p /tmp/ssm cd /tmp/ssm wget https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/debian_amd64/amazon-ssm-agent.deb sudo dpkg -i amazon-ssm-agent.deb sudo systemctl enable amazon-ssm-agent curl -sfL https://get.k3s.io | sh - wget https://s3.amazonaws.com/mountpoint-s3-release/latest/x86_64/mount-s3.deb sudo dpkg -i mount-s3.deb cat <<'EOF' > /usr/bin/mounts3.sh #!/bin/bash IS_MOUNTED=$(ls /s3 | wc -l) if [ $IS_MOUNTED -eq 0 ]; then mount-s3 unlockedv2 /s3 echo 'Mounted S3 bucket' exit 0 fi echo 'Bucket already mounted' EOF

chmod u+x /usr/bin/mounts3.sh

cat < /etc/systemd/system/mounts3.service [Unit] Description=Mount S3 bucket for videos + thumbnails Wants=network-online.target After=network-online.target

[Install] WantedBy=multi-user.target

[Service] RemainAfterExit=yes Type=oneshot ExecStart=/usr/bin/mounts3.sh EOF

sudo systemctl enable mounts3 ```

  1. Click Launch instance

  2. Connect to the instance and do the following:

    sudo su
    systemctl restart mounts3
    systemctl status mounts3
    ls s3 # You should see folders/files
    sudo apt update
    sudo apt install cron
    crontab -e
    # (Add the following cron job at the bottom)
    02 * * * * /usr/local/bin/kubectl delete secret --ignore-not-found ecr-secret && /usr/local/bin/kubectl create secret docker-registry ecr-secret --docker-username=AWS --docker-email=none --docker-password=$(/usr/bin/aws ecr get-login-password --region us-west-2) --docker-server 239442854891.dkr.ecr.us-west-2.amazonaws.com >> /var/log/ecr-secret-refresh.log 2>&1
    systemctl enable cron
    systemctl start cron
    systemctl status cron
    apt install postgresql-client

10. Create RDS (Database)

Steps:

  1. From Aurora and RDS select Databases from the side nav
  2. Click Create database
  3. Select Standard create
  4. Engine type: Postgresql
  5. Engine version: PostgreSQL 17.4-R1
  6. Templates: Production
  7. Deployment options: Multi-AZ DB instance deployment (2 instances)
  8. DB instance identifier: unlockedv2-<statename>-encrypted-backup
  9. Master username: <addusernamehere> (remember this value)
  10. Credentials Management: Self managed
  11. Master password: <addpasswordhere> (remember this value)
  12. DB instance class: Burstable classes
  13. Select db.t3.micro
  14. Storage type: General Purpose SSD (gp3)
  15. Allocated storage: 200
  16. Additional storage configuration: Uncheck Enable storage autoscaling
  17. Compute resource: Connect to an EC2 compute resource
  18. EC2 instance: Select the EC2 instance created above
  19. Network type: IPv4
  20. DB subnet group: Automatic setup
  21. Public access: No
  22. VPC security group (firewall): Create new
  23. Certificate authority (optional): rds-ca-rsa2048-g1
  24. Database port: 5432
  25. Database authentication: Password authentication
  26. Monitoring: Database Insights - Advanced
  27. Additional monitoring settings:
    • Enable Enhanced monitoring
    • OS metrics granularity: 60 seconds
    • Monitoring role for OS metrics: rds-monitoring-role
    • Log exports: PostgreSQL log
    • Uncheck DevOps Guru
  28. Initial database name: (leave blank)
  29. DB parameter group: (default.postgres17)
  30. Enable automated backups: Yes
  31. Backup retention period: 7 days
  32. Backup window:
    • Start time: 10:17 UTC
    • Duration: 0.5 hours
  33. Copy tags to snapshots: Yes
  34. Enable replication in another AWS Region: Uncheck
  35. Enable encryption: Yes
  36. Maintenance window: No preference
  37. Enable deletion protection: Yes
  38. Click Create database

11. Verify Database Connection

  1. Log on to the EC2 instance created above

  2. Run:

    sudo su
    psql -h <hostname> -U <username> -d postgres
  3. Verify that psql prompt appears

  4. To close connection:

    \q
    

12. Add Listeners to Load Balancers

  1. From EC2 select Load Balancers from side nav
  2. Select the load balancer created above and click its link name
  3. From Listeners and rules tab, click Add listener
  4. Protocol: HTTPS
  5. Port: 443
  6. Routing action: Forward to target groups
  7. Target group: unlockedv2-<statename>
  8. Target group stickiness: keep off
  9. Security category: All security policies
  10. Policy name: ELBSecurityPolicy-TLS...
  11. Certificate source: from ACM
  12. Certificate (from ACM): select the certificate created above
  13. Mutual authentication (mTLS): Uncheck
  14. Click Add

Add Rule <statename>-www

  1. Click the listener just created HTTPS:443 (link)
  2. Click Add Rule
  3. Name: <statename>-www
  4. Click Add condition, select Host header
  5. Host header value: www.<statename>.unlockedlabs.org
  6. Routing action: Redirect to URL
  7. Check 'Custom host, path, query'
  8. Redirect to URL:
    • Protocol: HTTPS
    • Port: 443
    • Host: <statename>.unlockedlabs.org
    • Path: /#{path}
    • Query: #{query}
    • Status code: 301
  9. Priority: 1
  10. Click Create

Add Rule <statename>

  1. As above, but for host header: <statename>.unlockedlabs.org
  2. Routing action: Forward to target groups
  3. Target group: unlockedv2-<statename>
  4. Priority: 2
  5. Click Create

Add Rule glob-<statename>

  1. As above, for host header: *.<statename>.unlockedlabs.org
  2. Routing action: Forward to target groups
  3. Target group: unlockedv2-<statename>
  4. Priority: 3
  5. Click Create

13. Register Instance with Target Group

  1. From EC2 select Target Groups from side nav
  2. Select the target group created above and click its link name in the table
  3. Click Register targets
  4. From available instances, select the instance created above
  5. Click Include as pending below
  6. Click Register pending targets

Clone this wiki locally