# How to Easily Migrate from EC2-Classic to VPC

Key Takeaways

  • EC2-Classic is AWS's legacy, pre-VPC networking platform and has been fully retired — any remaining EC2-Classic resources must migrate to VPC.
  • Since EC2-Classic instances cannot be moved directly into a VPC, migration means re-launching workloads inside VPC-based infrastructure.
  • A VPC migration is a good opportunity to also modernize security groups, subnetting, and network segmentation.
  • Plan the cutover around DNS, load balancer re-pointing, and a rollback window to avoid downtime.

Why EC2-Classic Still Comes Up

EC2-Classic was Amazon's original EC2 networking model, predating Amazon VPC. Every instance shared a single, flat network per AWS region with no concept of custom subnets, route tables, or network ACLs the way VPC provides. AWS has fully retired EC2-Classic — new accounts have never supported it, and all remaining EC2-Classic resources have been migrated by AWS or require migration by the account owner.

If you're reading this because you inherited an old AWS account, found legacy documentation referencing EC2-Classic, or are auditing old infrastructure-as-code templates, the practical task is the same: get everything running inside a properly structured VPC.

Why You Can't Just "Move" an Instance

A critical fact: you cannot directly move an EC2-Classic instance into a VPC. The underlying network attachment model is fundamentally different — EC2-Classic instances don't have an Elastic Network Interface (ENI) the way VPC instances do. Migration means:

  1. Launching new, equivalent instances inside a VPC.
  2. Migrating data and configuration to those new instances.
  3. Cutting over traffic (DNS, load balancers) to the new VPC-based infrastructure.
  4. Decommissioning the old EC2-Classic resources.

This is effectively a lift-and-shift migration, not an in-place conversion.

Step-by-Step Migration Plan

1. Inventory What You Have

Start by cataloging every EC2-Classic resource — instances, security groups, Elastic IPs, and any ClassicLink associations to existing VPCs.

# List instances and check which ones are NOT in a VPC
aws ec2 describe-instances \
  --query 'Reservations[].Instances[?VpcId==null].[InstanceId,InstanceType,State.Name]' \
  --output table

2. Design the Target VPC

Design your VPC with proper subnetting (public/private split across Availability Zones), route tables, and NAT Gateways for private subnet internet egress. Don't just replicate the old flat network — this is your opportunity to apply least-privilege security groups and network segmentation.

# Terraform: minimal VPC with public and private subnets
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true
  tags = { Name = "migrated-vpc" }
}

resource "aws_subnet" "private_a" {
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "us-east-1a"
  tags = { Name = "private-a" }
}

resource "aws_subnet" "public_a" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.101.0/24"
  availability_zone       = "us-east-1a"
  map_public_ip_on_launch = true
  tags = { Name = "public-a" }
}

3. Recreate Security Groups Inside the VPC

EC2-Classic security groups don't transfer automatically. Rebuild equivalent rules as VPC security groups, and use this step to tighten overly broad legacy rules (e.g., replace 0.0.0.0/0 SSH access with bastion-only or Session Manager access).

aws ec2 create-security-group \
  --group-name app-sg-vpc \
  --description "Migrated application security group" \
  --vpc-id vpc-0abc12345def67890

aws ec2 authorize-security-group-ingress \
  --group-id sg-0123456789abcdef0 \
  --protocol tcp --port 443 --cidr 10.0.0.0/16

4. Launch and Validate New Instances

Launch replacement instances inside the new VPC subnets, matching instance type, AMI, and application configuration. Validate functionality fully before touching production traffic — including internal service-to-service connectivity, which changes once security groups replace the old flat-network model.

5. Migrate Data

For stateful workloads, use the appropriate data migration path: EBS snapshot copy-and-attach for block storage, database-native replication or AWS DMS for databases, and S3 sync for object data. Avoid long-running manual copy jobs where a managed migration service exists.

6. Cut Over Traffic

Repoint DNS (Route 53) and any load balancers to the new VPC-based instances. If using an Elastic Load Balancer, register new targets and deregister old ones with health checks gating the transition, so traffic shifts only once new instances are confirmed healthy.

aws elbv2 register-targets \
  --target-group-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/app-tg-vpc/abc123 \
  --targets Id=i-0newvpcinstance01

7. Decommission the Old Resources

Once the new environment has run cleanly through a full business cycle (including batch jobs, backups, and peak load), terminate the old EC2-Classic instances and release any associated Elastic IPs.

Diagram: EC2-Classic to VPC Migration Flow

<svg viewBox="0 0 700 260" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="EC2-Classic to VPC migration flow diagram">
  <style>
    text { font-family: -apple-system, Segoe UI, Roboto, sans-serif; font-size: 13px; fill: currentColor; }
    .box { fill: none; stroke: currentColor; stroke-width: 1.5; rx: 8; }
    .label { font-size: 11px; opacity: 0.75; }
    .arrow { stroke: currentColor; stroke-width: 1.5; fill: none; marker-end: url(#arrowhead); }
  </style>
  <defs>
    <marker id="arrowhead" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto">
      <path d="M0,0 L8,3 L0,6 Z" fill="currentColor" />
    </marker>
  </defs>

  <rect x="20" y="90" width="150" height="70" class="box" />
  <text x="35" y="120" font-weight="600">EC2-Classic</text>
  <text x="35" y="140" class="label">Flat network</text>

  <path class="arrow" d="M170,125 L230,125" />
  <text x="175" y="110" class="label">Inventory</text>

  <rect x="240" y="90" width="150" height="70" class="box" />
  <text x="255" y="120" font-weight="600">New VPC</text>
  <text x="255" y="140" class="label">Subnets + SGs</text>

  <path class="arrow" d="M390,125 L450,125" />
  <text x="395" y="110" class="label">Launch + migrate data</text>

  <rect x="460" y="90" width="150" height="70" class="box" />
  <text x="475" y="120" font-weight="600">New Instances</text>
  <text x="475" y="140" class="label">Validated, running</text>

  <path class="arrow" d="M535,160 L535,200" />
  <text x="440" y="220" class="label">DNS / LB cutover, then decommission old instances</text>
</svg>

FAQ

What is EC2-Classic? EC2-Classic was AWS's original, pre-VPC EC2 networking platform, where all instances shared one flat network per region with no custom subnetting. It has been fully retired by AWS.

Can I convert an EC2-Classic instance into a VPC instance directly? No. EC2-Classic instances don't have the network interface model VPC requires. Migration means launching new VPC-based instances and migrating data and traffic to them.

Does ClassicLink still work? ClassicLink allowed EC2-Classic instances to communicate with instances in a linked VPC, but it was a bridging tool for the transition period, not a long-term architecture — all workloads should now run natively in VPC.

What's the safest way to cut over traffic during migration? Use health-check-gated load balancer target registration and Route 53 traffic shifting, keeping old infrastructure running until new infrastructure is fully validated under real traffic.

Need Help With a Legacy AWS Network Migration?

F9infotech's AWS engineers handle legacy network migrations regularly, including EC2-Classic cleanups, VPC redesigns, and security group hardening. Reach out to plan a safe, zero-surprise cutover.