AWS Production-Grade Migration: Building the Target Cloud Environment (Part 2)

Learn how to build a production-grade target cloud environment in AWS for migration. This comprehensive guide covers Multi-AZ VPC setup, RDS PostgreSQL databases, VPC peering, and networking configuration for cloud migration.

AWS Production-Grade Migration: Building the Target Cloud Environment (Part 2)

Table of Contents

AWS Production-Grade Migration: Building the Target Cloud Environment (Part 2)

Overview

In this comprehensive guide, we’ll build the modern, production-grade AWS infrastructure that will serve as our migration destination. This includes a highly-available Multi-AZ architecture, VPC peering to connect the source and target environments, and all necessary networking configuration for seamless cloud migration.

Estimated Time: 50-70 minutes
Region: ap-south-1 (Mumbai)
Difficulty: Intermediate


Why This Matters for Cloud Migration

Building the target environment is crucial for successful cloud migration. This hands-on approach gives you:

  • Production-grade architecture with Multi-AZ high availability
  • Real-world networking with VPC peering and proper segmentation
  • Database migration readiness with Multi-AZ RDS configuration
  • Security best practices for enterprise-grade cloud infrastructure

Prerequisites Checklist

  • Phase 1 completed successfully
  • All Phase 1 resource IDs documented
  • Source environment (on-prem-vpc) is fully operational
  • Source database has sample data

Cost Warning

⚠️ Resources that will incur charges:

  • RDS Multi-AZ db.t3.micro: $0.034/hour ($24.82/month) - 2x single-AZ cost
  • NAT Gateway (if created): $0.045/hour ($32.85/month) + data transfer
  • Data transfer between AZs: ~$0.01/GB
  • VPC Peering: No charge, but data transfer applies

Estimated Phase 2 Cost: ~$1.00-1.50 per day while running


Architecture Diagram

┌──────────────────────────────────────────────────────────────────┐
│  aws-target-vpc (10.1.0.0/16)                                    │
│                                                                    │
│  ┌───────────────────────────────┬───────────────────────────┐  │
│  │ ap-south-1a                   │ ap-south-1b              │  │
│  │                                │                           │  │
│  │ ┌──────────────────────────┐  │ ┌──────────────────────┐ │  │
│  │ │ Public Subnet            │  │ │ Public Subnet        │ │  │
│  │ │ 10.1.1.0/24              │  │ │ 10.1.2.0/24          │ │  │
│  │ │                           │  │ │                       │ │  │
│  │ │ (Reserved for ALB/NAT)   │  │ │ (Reserved for ALB)   │ │  │
│  │ └──────────────────────────┘  │ └──────────────────────┘ │  │
│  │                                │                           │  │
│  │ ┌──────────────────────────┐  │ ┌──────────────────────┐ │  │
│  │ │ Private Subnet           │  │ │ Private Subnet       │ │  │
│  │ │ 10.1.11.0/24             │  │ │ 10.1.12.0/24         │ │  │
│  │ │                           │  │ │                       │ │  │
│  │ │ (Migrated EC2 servers)   │  │ │ (Future servers)     │ │  │
│  │ └──────────────────────────┘  │ └──────────────────────┘ │  │
│  │                                │                           │  │
│  │ ┌──────────────────────────┐  │ ┌──────────────────────┐ │  │
│  │ │ Database Subnet          │  │ │ Database Subnet      │ │  │
│  │ │ 10.1.21.0/24             │  │ │ 10.1.22.0/24         │ │  │
│  │ │                           │  │ │                       │ │  │
│  │ │  ┌──────────────────┐    │  │ │  ┌──────────────────┐│ │  │
│  │ │  │ RDS Primary      │◄───┼──┼─┼─►│ RDS Standby      ││ │  │
│  │ │  │ production-db    │    │  │ │  │ (Multi-AZ sync)  ││ │  │
│  │ │  └──────────────────┘    │  │ │  └──────────────────┘│ │  │
│  │ └──────────────────────────┘  │ └──────────────────────┘ │  │
│  └───────────────────────────────┴───────────────────────────┘  │
│                                                                    │
│  Internet Gateway ←→ Public Subnets                               │
└──────────────────────────────────────────────────────────────────┘
                                ▲
                                │ VPC Peering
                                ▼
┌──────────────────────────────────────────────────────────────────┐
│  on-prem-vpc (10.0.0.0/16)                                       │
│  (Source Environment from Phase 1)                                │
└──────────────────────────────────────────────────────────────────┘

Step 1: Create Target VPC with “VPC and more” Wizard

This wizard will automatically create the VPC, subnets, route tables, and Internet Gateway.

1.1 Navigate to VPC Console

  1. Go to ServicesVPC
  2. Ensure you’re in ap-south-1 region

1.2 Launch VPC Wizard

  1. Click Your VPCs in the left sidebar
  2. Click Create VPC (orange button)
  3. Select VPC and more (this is the wizard option)

1.3 Configure VPC Settings

VPC settings:

  • Name tag auto-generation: aws-target (it will auto-prefix resources)
  • IPv4 CIDR block: 10.1.0.0/16
  • IPv6 CIDR block: No IPv6 CIDR block
  • Tenancy: Default

Availability Zones:

  • Number of Availability Zones: 2
  • Customize AZs:
    • AZ 1: ap-south-1a
    • AZ 2: ap-south-1b

Number of public subnets: 2

  • Public subnet in ap-south-1a: 10.1.1.0/24
  • Public subnet in ap-south-1b: 10.1.2.0/24

Number of private subnets: 4

  • Private subnet in ap-south-1a: 10.1.11.0/24
  • Private subnet in ap-south-1b: 10.1.12.0/24
  • Private subnet in ap-south-1a: 10.1.21.0/24
  • Private subnet in ap-south-1b: 10.1.22.0/24

NAT gateways: None (to save costs - ~$32/month)

  • ⚠️ For production, you would select “1 per AZ”
  • For this migration demo, we’ll skip NAT Gateway to reduce costs

VPC endpoints: None

DNS options:

  • ☑ Enable DNS hostnames
  • ☑ Enable DNS resolution

1.4 Review Preview Panel

On the right side, you’ll see a preview of all resources that will be created. Verify:

  • 1 VPC
  • 6 subnets (2 public, 4 private)
  • 2 route tables
  • 1 Internet Gateway

1.5 Create VPC

  1. Click Create VPC
  2. Wait for creation to complete (30-60 seconds)
  3. You’ll see a success message with all created resource IDs

1.6 Document Resource IDs

📝 Note down these IDs:

ResourceNameIDCIDR
VPCaws-target-vpcvpc-xxxxxxxx10.1.0.0/16
Public Subnet 1aaws-target-subnet-public1-ap-south-1asubnet-xxxxxxxx10.1.1.0/24
Public Subnet 1baws-target-subnet-public2-ap-south-1bsubnet-xxxxxxxx10.1.2.0/24
Private Subnet 1aaws-target-subnet-private1-ap-south-1asubnet-xxxxxxxx10.1.11.0/24
Private Subnet 1baws-target-subnet-private2-ap-south-1bsubnet-xxxxxxxx10.1.12.0/24
Private Subnet 1a (DB)aws-target-subnet-private3-ap-south-1asubnet-xxxxxxxx10.1.21.0/24
Private Subnet 1b (DB)aws-target-subnet-private4-ap-south-1bsubnet-xxxxxxxx10.1.22.0/24
Internet Gatewayaws-target-igwigw-xxxxxxxxN/A

Step 2: Rename and Organize Subnets

The wizard creates generic names. Let’s rename them for clarity.

2.1 Rename Subnets

  1. Go to Subnets in the left sidebar
  2. For each subnet, click the Name column to edit:
Current NameNew NamePurpose
aws-target-subnet-private1-ap-south-1atarget-app-subnet-1aMigrated EC2 instances
aws-target-subnet-private2-ap-south-1btarget-app-subnet-1bMigrated EC2 instances
aws-target-subnet-private3-ap-south-1atarget-db-subnet-1aRDS databases
aws-target-subnet-private4-ap-south-1btarget-db-subnet-1bRDS databases

2.2 Tag Database Subnets

For the two database subnets, add an additional tag:

  1. Select target-db-subnet-1a
  2. Go to Tags tab
  3. Click Manage tags
  4. Add tag:
    • Key: Type
    • Value: Database
  5. Repeat for target-db-subnet-1b

Step 3: Create Security Groups for Target Environment

3.1 Create Migrated Web Server Security Group

  1. Go to Security Groups in the left sidebar

  2. Click Create security group

  3. Configure:

    • Security group name: target-web-sg
    • Description: Security group for migrated web servers in target VPC
    • VPC: Select aws-target-vpc
  4. Inbound rules - Add these rules:

    Rule 1 (HTTP from anywhere):

    • Type: HTTP
    • Protocol: TCP
    • Port range: 80
    • Source: 0.0.0.0/0
    • Description: HTTP from anywhere

    Rule 2 (HTTPS from anywhere):

    • Type: HTTPS
    • Protocol: TCP
    • Port range: 443
    • Source: 0.0.0.0/0
    • Description: HTTPS from anywhere

    Rule 3 (SSH for management):

    • Type: SSH
    • Protocol: TCP
    • Port range: 22
    • Source: My IP
    • Description: SSH for administration

    Rule 4 (Allow from source VPC for testing):

    • Type: All traffic
    • Protocol: All
    • Port range: All
    • Source: Custom → 10.0.0.0/16
    • Description: Allow traffic from source VPC during migration
  5. Outbound rules: Leave default (All traffic)

  6. Click Create security group

  7. 📝 Note the Security Group ID: sg-xxxxxxxxweb

3.2 Create Database Security Group

  1. Click Create security group again

  2. Configure:

    • Security group name: target-db-sg
    • Description: Security group for production Multi-AZ database
    • VPC: Select aws-target-vpc
  3. Inbound rules - Add these rules:

    Rule 1 (PostgreSQL from web servers):

    • Type: PostgreSQL
    • Protocol: TCP
    • Port range: 5432
    • Source: Custom → Select target-web-sg (the security group we just created)
    • Description: PostgreSQL from target web servers

    Rule 2 (PostgreSQL from source VPC for DMS):

    • Type: PostgreSQL
    • Protocol: TCP
    • Port range: 5432
    • Source: Custom → 10.0.0.0/16
    • Description: PostgreSQL from source VPC for DMS migration
  4. Outbound rules: Leave default

  5. Click Create security group

  6. 📝 Note the Security Group ID: sg-xxxxxxxxdb

3.3 Create DMS Security Group

  1. Click Create security group again

  2. Configure:

    • Security group name: target-dms-sg
    • Description: Security group for DMS replication instance
    • VPC: Select aws-target-vpc
  3. Inbound rules: None needed

  4. Outbound rules: Leave default (All traffic)

  5. Click Create security group

  6. 📝 Note the Security Group ID: sg-xxxxxxxxdms


Step 4: Update Source VPC Security Groups for Peering

Before setting up peering, we need to prepare the source security groups.

4.1 Update Source Database Security Group

  1. Go to Security Groups
  2. Find and select on-prem-db-sg (from Phase 1)
  3. Go to Inbound rules tab
  4. Click Edit inbound rules
  5. Click Add rule:
    • Type: PostgreSQL
    • Protocol: TCP
    • Port range: 5432
    • Source: Custom → 10.1.0.0/16 (target VPC CIDR)
    • Description: Allow DMS from target VPC
  6. Click Save rules

Step 5: Set Up VPC Peering Connection

VPC Peering allows private communication between the two VPCs without going through the internet.

5.1 Create Peering Connection

  1. In the VPC console, click Peering connections in the left sidebar
  2. Click Create peering connection
  3. Configure:
    • Name: on-prem-to-target-peering
    • VPC (Requester): Select on-prem-vpc (10.0.0.0/16)
    • Account: My account
    • Region: This region (ap-south-1)
    • VPC (Accepter): Select aws-target-vpc (10.1.0.0/16)
  4. Click Create peering connection
  5. You’ll see the status as “Pending Acceptance”

5.2 Accept Peering Connection

  1. Select the peering connection you just created
  2. Click ActionsAccept request
  3. Confirm by clicking Accept request in the dialog
  4. Status will change to “Active”
  5. 📝 Note the Peering Connection ID: pcx-xxxxxxxx

Step 6: Update Route Tables for VPC Peering

Now we need to add routes in both VPCs to route traffic through the peering connection.

6.1 Update Source VPC Route Tables

Update Private Route Table (for database connectivity):

  1. Go to Route Tables
  2. Find and select on-prem-private-rt (from Phase 1)
  3. Go to Routes tab
  4. Click Edit routes
  5. Click Add route:
    • Destination: 10.1.0.0/16 (target VPC CIDR)
    • Target: Peering Connection → Select on-prem-to-target-peering
  6. Click Save changes

Update Public Route Table (for web server connectivity):

  1. Find and select on-prem-public-rt
  2. Go to Routes tab
  3. Click Edit routes
  4. Click Add route:
    • Destination: 10.1.0.0/16
    • Target: Peering Connection → Select on-prem-to-target-peering
  5. Click Save changes

6.2 Update Target VPC Route Tables

Update Public Route Table:

  1. Find the route table for aws-target-vpc that’s associated with public subnets
    • It should be named something like aws-target-rtb-public
  2. Select it
  3. Go to Routes tab
  4. Click Edit routes
  5. Click Add route:
    • Destination: 10.0.0.0/16 (source VPC CIDR)
    • Target: Peering Connection → Select on-prem-to-target-peering
  6. Click Save changes

Update Private Route Table:

  1. Find the route table for aws-target-vpc that’s associated with private subnets
    • It should be named something like aws-target-rtb-private1-ap-south-1a
  2. Select it
  3. Go to Routes tab
  4. Click Edit routes
  5. Click Add route:
    • Destination: 10.0.0.0/16
    • Target: Peering Connection → Select on-prem-to-target-peering
  6. Click Save changes
  7. Repeat for the second private route table (aws-target-rtb-private2-ap-south-1b)
  8. Repeat for the third private route table (aws-target-rtb-private3-ap-south-1a)
  9. Repeat for the fourth private route table (aws-target-rtb-private4-ap-south-1b)

Step 7: Test VPC Peering Connectivity

7.1 SSH into Source Web Server

ssh -i on-prem-web-key.pem ec2-user@SOURCE_PUBLIC_IP

7.2 Test Connectivity to Target VPC

We’ll test if we can reach the target VPC’s IP range:

# Ping is typically blocked, but we can test with telnet or nc
# Since there's nothing running in target VPC yet, we'll verify routing
ip route get 10.1.1.1

# Expected output should show the route exists
# Output: 10.1.1.1 via <peering-connection> dev eth0 src 10.0.1.x

7.3 Verify Source Database Connectivity

Ensure you can still connect to your source database:

psql --host=YOUR_SOURCE_RDS_ENDPOINT --port=5432 --username=postgres --dbname=legacydb -c "SELECT COUNT(*) FROM users;"

Expected output: 4


Step 8: Create RDS Database Subnet Group

8.1 Navigate to RDS Console

  1. Go to ServicesRDS
  2. Ensure you’re in ap-south-1 region

8.2 Create Subnet Group

  1. Click Subnet groups in the left sidebar

  2. Click Create DB subnet group

  3. Configure:

    • Name: target-production-db-subnet-group
    • Description: Subnet group for production Multi-AZ database
    • VPC: Select aws-target-vpc
  4. Add subnets:

    • Availability Zones: Select both:
      • ap-south-1a
      • ap-south-1b
    • Subnets: Select the two database subnets:
      • 10.1.21.0/24 (target-db-subnet-1a)
      • 10.1.22.0/24 (target-db-subnet-1b)
  5. Click Create

  6. 📝 Note the Subnet Group Name: target-production-db-subnet-group


Step 9: Launch Multi-AZ RDS PostgreSQL Database

This is the production-grade database that will receive the migrated data.

9.1 Create Database

  1. In RDS console, click Databases in the left sidebar
  2. Click Create database

9.2 Engine Configuration

  • Choose a database creation method: Standard create
  • Engine type: PostgreSQL
  • Engine Version: PostgreSQL 16.x (same version as source)
  • Templates: Production (this enables Multi-AZ by default)

9.3 Settings

  • DB instance identifier: production-db
  • Master username: postgres
  • Credentials management: Self managed
  • Master password: Create a strong password (e.g., ProductionDB2024!)
  • Confirm password: Re-enter the password
  • 📝 Note down this password securely!

9.4 Instance Configuration

  • DB instance class: Burstable classes
    • Select: db.t3.micro (2 vCPUs, 1 GB RAM)
    • ⚠️ For real production, you’d use db.t3.small or larger

9.5 Storage

  • Storage type: General Purpose SSD (gp3)
  • Allocated storage: 20 GB
  • Storage autoscaling:
    • ☑ Enable storage autoscaling
    • Maximum storage threshold: 100 GB

9.6 Availability & Durability

  • Multi-AZ deployment: ☑ Create a standby instance (This is automatically checked with Production template)
    • This creates a synchronous replica in ap-south-1b

9.7 Connectivity

  • Compute resource: Don’t connect to an EC2 compute resource
  • Network type: IPv4
  • VPC: Select aws-target-vpc
  • DB subnet group: Select target-production-db-subnet-group
  • Public access: No
  • VPC security group: Choose existing
    • Remove the default security group
    • Select target-db-sg
  • Availability Zone: No preference (let AWS choose)
  • Database port: 5432

9.8 Database Authentication

  • Database authentication: Password authentication
  • For production, you could also enable IAM authentication

9.9 Monitoring

  • Enable Enhanced monitoring: Yes
    • Granularity: 60 seconds (to keep costs low)
    • Monitoring Role: Default

9.10 Additional Configuration

Click Additional configuration to expand:

  • Initial database name: productiondb ⚠️ Important!
  • DB parameter group: default.postgres16
  • Option group: default:postgres-16

Backup:

  • ☑ Enable automated backups
  • Backup retention period: 7 days
  • Backup window: No preference
  • Copy tags to snapshots: Yes

Encryption:

  • ☑ Enable encryption
  • AWS KMS key: (default) aws/rds

Log exports: (optional, but recommended)

  • ☑ PostgreSQL log
  • ☑ Upgrade log

Maintenance:

  • ☑ Enable auto minor version upgrade
  • Maintenance window: No preference

Deletion protection:

  • Uncheck (so we can delete during cleanup)
  • For real production, you would check this

9.11 Review and Create

  1. Review the Estimated monthly costs (should show ~$25-30 for Multi-AZ)
  2. Click Create database
  3. Wait for status to change to “Available” (takes 10-15 minutes for Multi-AZ)
  4. ☕ Perfect time for a break!

9.12 Verify Multi-AZ Configuration

Once available:

  1. Click on the database name production-db
  2. In the Configuration tab, verify:
    • Multi-AZ: Yes
    • Secondary AZ: ap-south-1b
  3. Scroll down to Connectivity & security
  4. 📝 Note down:
    • Endpoint: production-db.xxxxxxxx.ap-south-1.rds.amazonaws.com
    • Port: 5432

Step 10: Test Cross-VPC Database Connectivity

Now let’s verify that DMS will be able to connect to both databases through VPC peering.

10.1 SSH into Source Web Server

ssh -i on-prem-web-key.pem ec2-user@SOURCE_PUBLIC_IP

10.2 Test Connection to Target Database

Try connecting to the production database from the source web server:

psql --host=YOUR_TARGET_RDS_ENDPOINT --port=5432 --username=postgres --dbname=productiondb

Enter the production database password when prompted.

Expected result: You should successfully connect and see:

psql (16.x)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

productiondb=>

10.3 Verify Empty Database

-- List all tables (should be empty)
\dt

-- Exit
\q

Expected output: Did not find any relations. (database is empty, ready for migration)

✅ If you can connect, VPC peering is working correctly!


Step 11: Create DMS Subnet Group

DMS requires its own subnet group to deploy the replication instance.

11.1 Navigate to DMS Console

  1. Go to ServicesDatabase Migration Service (or search “DMS”)
  2. Ensure you’re in ap-south-1 region
  3. If this is your first time, you may see a welcome screen - click Get started or go to the navigation menu

11.2 Create Subnet Group

  1. Click Subnet groups in the left sidebar

  2. Click Create subnet group

  3. Configure:

    • Name: dms-target-subnet-group
    • Description: DMS subnet group for replication instance
    • VPC: Select aws-target-vpc
  4. Add subnets:

    • Click Add subnets
    • Select the two public subnets:
      • 10.1.1.0/24 (aws-target-subnet-public1-ap-south-1a)
      • 10.1.2.0/24 (aws-target-subnet-public2-ap-south-1b)
    • ⚠️ We use public subnets so DMS can reach both VPCs through peering
  5. Click Create subnet group


A bastion host allows you to securely access private resources for testing and troubleshooting.

12.1 Create Bastion Security Group

  1. Go to VPCSecurity Groups

  2. Click Create security group

  3. Configure:

    • Security group name: target-bastion-sg
    • Description: Security group for bastion host
    • VPC: Select aws-target-vpc
  4. Inbound rules:

    • Type: SSH
    • Protocol: TCP
    • Port: 22
    • Source: My IP
    • Description: SSH from my IP
  5. Outbound rules: Leave default

  6. Click Create security group

12.2 Update Target Database Security Group

  1. Find and select target-db-sg
  2. Go to Inbound rules tab
  3. Click Edit inbound rules
  4. Click Add rule:
    • Type: PostgreSQL
    • Protocol: TCP
    • Port: 5432
    • Source: Custom → Select target-bastion-sg
    • Description: PostgreSQL from bastion host
  5. Click Save rules

12.3 Launch Bastion Host (Optional)

  1. Go to EC2Instances
  2. Click Launch Instance
  3. Configure:
    • Name: target-bastion-host
    • AMI: Amazon Linux 2023
    • Instance type: t2.micro
    • Key pair: Use the same key from Phase 1 (on-prem-web-key)
    • Network settings:
      • VPC: aws-target-vpc
      • Subnet: Select a public subnet (10.1.1.0/24)
      • Auto-assign public IP: Enable
      • Security group: Select target-bastion-sg
    • Install: PostgreSQL 16 client
  4. Click Launch instance
  5. 📝 Note the public IP for future use

Step 13: Final Verification Checklist

Before proceeding to Phase 3 and 4, verify everything:

VPC Configuration

  • Target VPC aws-target-vpc created with CIDR 10.1.0.0/16
  • 2 public subnets in different AZs (1a and 1b)
  • 4 private subnets in different AZs (2 for apps, 2 for DB)
  • Internet Gateway attached
  • Route tables properly configured

Security Groups

  • target-web-sg created and configured
  • target-db-sg created and configured
  • target-dms-sg created
  • Source on-prem-db-sg updated for peering
  • target-bastion-sg created (if using bastion)

VPC Peering

  • Peering connection created and accepted
  • All route tables updated (source and target, public and private)
  • Can connect from source web server to target database

Database

  • RDS production-db is available
  • Multi-AZ configuration verified (standby in different AZ)
  • Database subnet group configured
  • Can connect to production-db from source VPC
  • Database is empty (ready for migration)

DMS Preparation

  • DMS subnet group created

Resource Inventory for Migration Phases

📝 Save these values for Phase 3 (MGN) and Phase 4 (DMS):

Target VPC Resources

ResourceValueNotes
VPC IDvpc-xxxxxxxxaws-target-vpc
Public Subnet 1asubnet-xxxxxxxx10.1.1.0/24
Public Subnet 1bsubnet-xxxxxxxx10.1.2.0/24
App Private Subnet 1asubnet-xxxxxxxx10.1.11.0/24 - For MGN
App Private Subnet 1bsubnet-xxxxxxxx10.1.12.0/24
DB Private Subnet 1asubnet-xxxxxxxx10.1.21.0/24
DB Private Subnet 1bsubnet-xxxxxxxx10.1.22.0/24
Web SG IDsg-xxxxxxxxtarget-web-sg
DB SG IDsg-xxxxxxxxtarget-db-sg
DMS SG IDsg-xxxxxxxxtarget-dms-sg
Peering Connection IDpcx-xxxxxxxxon-prem-to-target

Target Database

ResourceValueNotes
RDS Endpointproduction-db.xxx.ap-south-1.rds.amazonaws.comTarget for DMS
DB NameproductiondbEmpty database
UsernamepostgresMaster username
Password******Keep secure!
Multi-AZYesPrimary: 1a, Standby: 1b
Port5432PostgreSQL port

DMS Resources

ResourceValueNotes
DMS Subnet Groupdms-target-subnet-groupFor replication instance

Troubleshooting

Issue: Cannot connect to target database from source VPC

Solution:

  • Verify VPC peering status is “Active”
  • Check route tables in both VPCs have peering routes
  • Verify target-db-sg allows PostgreSQL from 10.0.0.0/16
  • Verify on-prem-db-sg allows PostgreSQL from 10.1.0.0/16
  • Test with telnet: telnet TARGET_ENDPOINT 5432

Issue: Multi-AZ database creation failed

Solution:

  • Ensure subnet group has subnets in at least 2 different AZs
  • Check if you have enough resources in your AWS account
  • Verify the database subnet group is in the correct VPC
  • Try with a smaller instance class first (db.t3.micro)

Issue: Peering connection won’t accept

Solution:

  • Verify both VPCs are in the same region
  • Check if CIDR blocks don’t overlap
  • Ensure you have permissions to accept peering connections
  • Try deleting and recreating the peering connection

Issue: Route table updates not working

Solution:

  • Verify you’re updating the correct route table
  • Check if the peering connection is active before adding routes
  • Ensure you’re adding routes in both VPCs (bidirectional)
  • Verify CIDR blocks are correct (10.0.0.0/16 ↔ 10.1.0.0/16)

Architecture Validation

Verify Network Topology

Run these commands from the source web server to validate the setup:

# Test DNS resolution of target database
nslookup YOUR_TARGET_RDS_ENDPOINT

# Test connectivity to target database
telnet YOUR_TARGET_RDS_ENDPOINT 5432

# Test connectivity to target VPC
ping -c 3 10.1.1.1

# Verify routing
ip route | grep 10.1.0.0

# Test actual database connection
psql --host=YOUR_TARGET_RDS_ENDPOINT --port=5432 --username=postgres --dbname=productiondb -c "\l"

Cost Optimization Tips

💰 To minimize costs while building this phase:

  1. Stop RDS instances when not actively testing

    • Both legacy-db and production-db can be stopped temporarily
    • Saves ~$37/month when both are stopped
  2. Skip the bastion host if using Systems Manager

    • Systems Manager Session Manager provides console access without SSH
    • No need for a bastion instance
  3. Don’t create NAT Gateway unless absolutely needed

    • We skipped this to save ~$33/month
    • Only needed if private instances need internet access

Next Steps

Phase 2 Complete!

You now have a production-grade target environment with:

  • Multi-AZ VPC with proper subnet segmentation
  • High-availability Multi-AZ RDS database
  • VPC peering between source and target
  • All security groups and networking configured
  • DMS subnet group ready for replication

Ready for migration!

Proceed to:

  • Phase 3: Migrate the web server using AWS Application Migration Service (MGN)
  • Phase 4: Migrate the database using AWS Database Migration Service (DMS)

Quick Reference Commands

# SSH to source web server
ssh -i on-prem-web-key.pem ec2-user@SOURCE_PUBLIC_IP

# Connect to source database
psql --host=SOURCE_RDS_ENDPOINT --port=5432 --username=postgres --dbname=legacydb

# Connect to target database
psql --host=TARGET_RDS_ENDPOINT --port=5432 --username=postgres --dbname=productiondb

# Test cross-VPC connectivity
telnet TARGET_RDS_ENDPOINT 5432

# Verify routing
ip route get 10.1.1.1

Conclusion

In this comprehensive guide, we’ve successfully built a production-grade target cloud environment that perfectly prepares us for seamless cloud migration. This foundation is essential for understanding modern cloud architecture patterns and provides the perfect destination for AWS Application Migration Service (MGN) and Database Migration Service (DMS).

What we’ve accomplished:

  • Multi-AZ VPC Architecture: Created a highly-available network with proper subnet segmentation across multiple availability zones
  • Production Database: Set up a Multi-AZ RDS PostgreSQL instance with automated backups and encryption
  • VPC Peering: Established secure connectivity between source and target environments
  • Security: Implemented comprehensive security groups and network isolation
  • Migration Readiness: Prepared all infrastructure for seamless application and database migration

Key Learning Outcomes:

  • Understanding of Multi-AZ architecture and high availability patterns
  • Hands-on experience with VPC peering and cross-VPC connectivity
  • Database migration preparation with Multi-AZ RDS configuration
  • Security best practices for enterprise cloud infrastructure
  • Cost optimization strategies for production environments

This environment is now ready for the next phase of our migration journey, where we’ll perform the actual migration using AWS MGN and DMS services.


This is Part 2 of a comprehensive AWS migration series. Here is the Part 3, where we’ll migrate the web server using AWS Application Migration Service (MGN).

Table of Contents