How to Migrate Linux Server to AWS Cloud: Step-by-Step 2026






How to Migrate Linux Server to AWS Cloud: Step-by-Step 2026 | LinuxTeck



Distro-specific walkthrough for Ubuntu 22.04/24.04, Rocky Linux 9, and RHEL 9 using AWS Application Migration Service (MGN). Includes CLI commands, troubleshooting, and post-migration validation scripts.


Avg. Breach Cost 2024
$4.9M
Avg. Recovery Without Clean Backup
22 days
Attacks via Exposed SSH / RDP
68%

Note: AWS MGN is a critical component for Business Continuity and Disaster Recovery (BCDR), ensuring Linux workloads remain resilient against ransomware and local data center failures.

What This Guide Covers:

  • Choosing between AWS MGN, AWS DataSync, and AWS DMS
  • Pre-migration system readiness checks (with Bash commands)
  • Distro-specific AWS Replication Agent installation: Ubuntu 22.04/24.04, Rocky Linux 9, RHEL 9
  • Full MGN console walkthrough: replication, test instance, cutover
  • 6 real troubleshooting scenarios with exact fix commands
  • Post-migration validation script
  • Security hardening and IAM lockdown after migration
  • FAQ: 8 questions Linux sysadmins actually ask

Migrating a Linux server to an Amazon Web Services (AWS) environment seems as simple as it is complex, most people encounter their first kernel panic when they are trying to cut over to the new instance. Or they may experience a silent stall of their replication agent at 0%, with no idea why this is happening; after all, no one mentioned port 1500. This guide was written to provide guidance for Linux system administrators and DevOps Engineers who want to migrate a production server into an AWS -EC2 Environment with little surprise.

We take a deeper dive into the replication agent installation process specific to Rocky Linux 9 and RHEL 9. Additionally, we explain how SELinux can silently block the AWS Application Migration Service (MGN) agent process without obvious errors. This guide also covers the post-cutover Bash validation checks that should be performed before directing production traffic to the migrated environment through DNS.

We use AWS Application Migration Service (AWS MGN) as the primary migration tool throughout this guide, as it is currently AWS’s recommended service for lift-and-shift server migrations. All examples in this article are based on AWS MGN workflows. The screenshots referenced were captured from the AWS Management Console in early 2026. Although your console layout may have minor differences, the service names and overall workflows should remain consistent.

Which AWS Migration Tool Do You Actually Need?

This is the question every sysadmin asks first. Here is the complete decision table.

Tool Use Case Linux Compatible Cost (2026) Best For
AWS MGN Full server / VM migration Yes (Ubuntu, Rocky, RHEL, CentOS, SUSE) Free 90 days/server Lift-and-shift entire OS + apps to EC2
AWS DataSync Data / file transfer only Yes (NFS, SMB, EFS, S3) $0.0125 per GB transferred Moving files/data to S3, EFS, FSx
AWS DMS Database migration only Yes (MySQL, PostgreSQL, Oracle, etc.) From $0.018/hr (t3.micro) Migrating databases with minimal downtime
AWS SMS VM migration (VMware/Hyper-V/Azure) Deprecated Being retired, use MGN Legacy VMware migrations only

Tip:

If you are moving a full Linux server (OS + applications) to EC2, use AWS MGN. If you only need files moved to S3, use DataSync. If you are migrating a MySQL or PostgreSQL database separately, combine MGN (for the app server) with DMS (for the database). Do not use SMS for new migrations as it is being retired.

Environment and Prerequisites

Ubuntu 22.04 LTS
Ubuntu 24.04 LTS
Rocky Linux 9
RHEL 9
AWS MGN
AWS EC2
Python 3.8+
Kernel: 3.10+

Requirement Details Status
AWS Account With MGN service enabled in your target region REQUIRED
IAM User (Replication) Dedicated IAM user with AWSApplicationMigrationAgentInstallationPolicy REQUIRED
Source Linux Server Root SSH access, 10 GB+ free disk, Python 3.8+, GRUB2 bootloader REQUIRED
Network Connectivity Outbound TCP 443 and TCP 1500.
Note: Port 1500 must be TCP (not UDP) and routed specifically to the Staging Subnet interface.
REQUIRED
Target VPC Pre-configured VPC with staging subnet (private) and target subnet REQUIRED
AWS CLI v2 installed on a management host for verification steps OPTIONAL
AWS Direct Connect / VPN For large servers or compliance-restricted environments OPTIONAL

Warn:

Do not use your AWS root account to create the IAM replication user. AWS MGN requires programmatic access keys, and using root credentials here is a serious security risk. Create a dedicated IAM user with the minimum required policy only. You will rotate these keys post-migration anyway (see Section 6)

For a deeper look at Linux server hardening principles that apply both before and after migration, the Linux Server Hardening Checklist on LinuxTeck covers the key security controls you should have in place on your source server before moving it to a cloud-exposed environment.

Architecture Overview

The diagram below shows the full AWS MGN migration pipeline from your on-premises Linux server to the target EC2 instance. Understanding this flow upfront will make each step in Section 4 make sense.

AWS MGN MIGRATION ARCHITECTURE — LinuxTeck.com
 ON-PREMISES ENVIRONMENT                AWS CLOUD (Target Region)
 ─────────────────────────              ─────────────────────────────────────────────

 ┌─────────────────────────┐            ┌───────────────────────────────────────────┐
 │  Source Linux Server    │            │  Your VPC  (e.g., 10.0.0.0/16)           │
 │                         │            │                                           │
 │  Ubuntu 22.04 / 24.04   │  TCP 443   │  ┌─────────────────────────────────────┐ │
 │  Rocky Linux 9          │ ─────────► │  │  Staging Area Subnet (private)      │ │
 │  RHEL 9                 │  TCP 1500  │  │                                     │ │
 │                         │ ─────────► │  │  ┌──────────────────────────────┐   │ │
 │  [AWS Replication Agent]│            │  │  │  AWS Replication Server      │   │ │
 │  (installed on source)  │            │  │  │  (EC2, auto-provisioned)     │   │ │
 └─────────────────────────┘            │  │  └──────────────┬───────────────┘   │ │
                                        │  │                 │ Continuous         │ │
                                        │  │                 │ block-level        │ │
                                        │  │                 │ replication        │ │
                                        │  └─────────────────┼───────────────────┘ │
                                        │                    │                     │
                                        │  ┌─────────────────▼───────────────────┐ │
                                        │  │  Target Subnet (public or private)  │ │
                                        │  │                                     │ │
                                        │  │  ┌──────────────────────────────┐   │ │
                                        │  │  │  Test EC2 Instance           │   │ │
                                        │  │  │  (validate before cutover)   │   │ │
                                        │  │  └──────────────────────────────┘   │ │
                                        │  │                                     │ │
                                        │  │  ┌──────────────────────────────┐   │ │
                                        │  │  │  Cutover EC2 Instance        │   │ │
                                        │  │  │  (production target)         │   │ │
                                        │  │  └──────────────────────────────┘   │ │
                                        │  └─────────────────────────────────────┘ │
                                        └───────────────────────────────────────────┘

 MIGRATION PHASES:
 ─────────────────
 Phase 1: REPLICATE  → Agent installed → Continuous replication starts
 Phase 2: TEST       → Launch test instance → Validate app + connectivity
 Phase 3: CUTOVER    → Launch cutover instance → Update DNS → Finalize
 Phase 4: VALIDATE   → Run post-migration script → Remove staging resources

 KEY PORTS (MUST BE OPEN OUTBOUND FROM SOURCE):
 ───────────────────────────────────────────────
 TCP 443  → AWS MGN API endpoint (console access, agent auth)
 TCP 1500 → AWS Replication Server (block-level data transfer)
      

Key Insight:

The replication server in the staging area subnet is automatically provisioned by AWS MGN — you do not create it manually. It is a temporary EC2 instance (typically t3.small) that acts as a data relay. It is terminated after finalized cutover. This is the most misunderstood part of the architecture for people new to MGN.

Step-by-Step Implementation

Step 0 — Pre-Migration System Readiness Checklist

Run these checks on your source Linux server before touching the AWS console. Skipping this step is how teams end up with a cutover instance that will not boot.

Before performing any production migration, ensure you have verified backups and rollback recovery points available. Our guide to Linux server backup solutions covers modern backup strategies for cloud and on-premises Linux environments.

bash
LinuxTeck.com
config • pre-migration-check.sh
#!/bin/bash
# Pre-Migration Readiness Check — LinuxTeck.com
# Run as root on the SOURCE Linux server before starting MGN setup

echo "===== 1. Kernel Version (must be 3.10 or newer) ====="
uname -r

echo ""
echo "===== 2. Bootloader Check (must be GRUB2) ====="
if command -v grub2-install >/dev/null 2>&1; then
grub2-install --version
elif command -v grub-install >/dev/null 2>&1; then
grub-install --version
else
echo "WARN: Could not detect GRUB. Check bootloader manually."
fi

echo ""
echo "===== 3. Filesystem Types (ext2/3/4, xfs, btrfs supported) ====="
df -T | grep -v tmpfs | grep -v devtmpfs

echo ""
echo "===== 4. Free Disk Space (minimum 2 GB recommended on root) ====="
df -h /

echo ""
echo "===== 5. Python Version (3.8+ required for agent) ====="
python3 --version 2>&1 || echo "WARN: python3 not found"

echo ""
echo "===== 6. Outbound Port 443 to AWS ====="
(timeout 5 bash -c 'cat /dev/tcp/mgn.us-east-1.amazonaws.com/443') 2>/dev/null \
&& echo "OK: Port 443 reachable" \
|| echo "FAIL: Port 443 blocked - check firewall"

echo ""
echo "===== 7. Outbound Port 1500 to AWS ====="
(timeout 5 bash -c 'cat /dev/tcp/mgn.us-east-1.amazonaws.com/1500') 2>/dev/null \
&& echo "OK: Port 1500 reachable" \
|| echo "FAIL: Port 1500 blocked - replication WILL stall at 0%"

echo ""
echo "===== 8. SELinux Status (Rocky/RHEL only) ====="
getenforce 2>/dev/null || echo "N/A (not SELinux-based distro)"

echo ""
echo "===== 9. Running Services Snapshot (save for post-migration compare) ====="
systemctl list-units --type=service --state=running | head -20

Pro-Tip:

We use the /dev/tcp/ bash internal method for these port checks instead of the traditional nc (netcat) command. This ensures the script is truly zero-dependency and will work perfectly on minimal installs of Rocky Linux 9, RHEL 9, and Ubuntu where netcat is often not installed by default.

Expected Output (healthy server example)

===== 1. Kernel Version =====
5.14.0-362.24.1.el9_3.x86_64

===== 2. Bootloader Check =====
grub2-install (GRUB) 2.06

===== 3. Filesystem Types =====
Filesystem     Type   Size  Used Avail Use%  Mounted on
/dev/sda1      xfs     50G   18G   32G  36%  /

===== 4. Free Disk Space =====
Filesystem  Size  Used Avail Use% Mounted on
/dev/sda1    50G   18G   32G  36% /

===== 5. Python Version =====
Python 3.11.2

===== 6. Outbound Port 443 =====
OK: Port 443 reachable

===== 7. Outbound Port 1500 =====
OK: Port 1500 reachable

===== 8. SELinux Status =====
Enforcing

===== 9. Running Services Snapshot =====
  sshd.service  loaded active running  OpenSSH server daemon
  httpd.service loaded active running  The Apache HTTP Server
 

Warn:

If port 1500 shows FAIL, do not proceed. This is the single most common cause of replication stalling at 0% after agent installation. Open TCP 1500 outbound in your on-premises firewall before continuing. Replace us-east-1 with your actual target region in the commands above.

If you are using Rocky Linux or RHEL, review these firewall-cmd command examples to verify outbound firewall rules and service access before starting replication.

Hardening: Configuring SELinux for AWS MGN

On Rocky Linux and RHEL 9, SELinux may block the agent's attempt to read the source disk at the block level. Rather than disabling security, apply the correct file context to the agent binaries.

bash
LinuxTeck.com
security • mgn-selinux-fix.sh
# Add file context mapping for the agent directory
semanage fcontext -a -t bin_t "/var/lib/aws-replication-agent(/.*)?"

# Apply the context to the filesystem
restorecon -Rv /var/lib/aws-replication-agent

Rocky/RHEL 9 Requirement:

Unlike older CentOS 7 versions, Rocky Linux 9 requires the make, gcc, and kernel-devel packages to build the replication kernel module on the fly. Use dnf to install them before running the agent:

sudo dnf install make gcc kernel-devel-$(uname -r) -y

Engineer's Tip:

Production environments rarely allow permissive mode. Using restorecon is the professional way to ensure the agent has the right permissions to read your source disks without compromising your security posture.

Step 1 — Create IAM User for the AWS Replication Agent

You need a dedicated IAM user with programmatic access. The agent will use its access key and secret during installation. Do not reuse your personal IAM user or admin credentials here.

Console Steps (with screenshots reference):

  1. Open the AWS IAM Console and navigate to Users → Create user
  2. Name the user mgn-replication-agent (or your naming convention)
  3. Select Attach policies directly
  4. Search for and attach: AWSApplicationMigrationAgentInstallationPolicy
  5. Create the user, then navigate to Security credentials → Create access key
  6. Choose Application running outside AWS and download the CSV. Store it securely — you will use it in Step 3.
  • Copy the Access Key ID and Secret Access Key securely. You will not be able to retrieve them later.
  • Senior Engineer's Security Note : IAM Hardening

    While AWS provides the AWSApplicationMigrationAgentInstallationPolicy as a standard, a production-grade setup should never rely on global permissions. To prevent "credential leak" disasters, you should add a Condition block to the policy. This ensures that even if the keys are stolen, they cannot be used from an unauthorized network.

    "Condition": {
      "IpAddress": {
        "aws:SourceIp": "YOUR_OFFICE_IP/32"
      }
    }

    Implementation Tip: If your migration source uses a static NAT gateway or a fixed VPN IP, replace the placeholder above with that specific address to lock down the installation process.

    bash
    LinuxTeck.com
    config • iam-create-user.sh
    # Create MGN replication IAM user via AWS CLI
    aws iam create-user --user-name mgn-replication-agent

    aws iam attach-user-policy \
    --user-name mgn-replication-agent \
    --policy-arn arn:aws:iam::aws:policy/AWSApplicationMigrationAgentInstallationPolicy

    aws iam create-access-key --user-name mgn-replication-agent
    # Save the AccessKeyId and SecretAccessKey from the output

    Note
    In the AWS Console, after creating the user and attaching the policy, the user list will show
    "mgn-replication-agent" with 1 attached policy. The access key creation screen shows a
    one-time download option. If you miss this, you must delete the key and create a new one.


    Create IAM User for the AWS Replication Agent

    Note:

    Screenshot reference: In the AWS Console, after creating the user and attaching the policy, the user list will show "mgn-replication-agent" with 1 attached policy. The access key creation screen shows a one-time download option. If you miss this, you must delete the key and create a new one — there is no way to retrieve the secret key again.

    Step 2 — Initialize AWS MGN and Create Replication Settings Template

    Before installing the agent on your source server, you need to initialize MGN in your target AWS region and configure where replicated data will land inside your VPC.

    1. Open the AWS MGN Console at console.aws.amazon.com/mgn
    2. Select your target region (e.g., us-east-1 or eu-west-1)
    3. Click Get started if this is your first time using MGN in this region
    4. Under Replication settings template, configure the following:
    Setting Recommended Value Notes
    Staging area subnet subnet-xxxxxxxx (private) Must have outbound internet via NAT GW
    Replication server instance type t3.small Default; use t3.medium for large disks
    EBS volume type gp3 Better cost/performance vs gp2
    Data plane routing Public internet Change to Private if using Direct Connect

    How to Migrate Linux Server to AWS Cloud: Step-by-Step 2026 4

    Screenshot Note:

    The MGN console shows a Replication settings template page with a VPC/subnet dropdown and instance type selector. The staging subnet you choose here must be in the same VPC you plan to launch your final EC2 instance in. All replicated data flows through the replication server in this subnet before landing on your EBS volumes.

    Step 3 — Install the AWS Replication Agent (Distro-Specific)

    This is where most guides fail you. The installation command is the same across distros, but the dependencies, SELinux handling, and Python requirements differ significantly between Ubuntu, Rocky Linux, and RHEL. Run the correct block for your distro.

    Ubuntu 22.04 / 24.04
    Rocky Linux 9
    RHEL 9

    bash
    LinuxTeck.com
    config • ubuntu-mgn-agent.sh • Ubuntu 22.04 / 24.04 LTS
    # Ubuntu 22.04 / 24.04 — AWS MGN Agent Installation
    # Run as root or with sudo

    # 1. Update packages and ensure Python3 + pip are present
    sudo apt-get update -y
    sudo apt-get install -y python3 python3-pip wget

    # 2. Verify Python version (must be 3.6 or higher)
    python3 --version
    # Expected: Python 3.10.x or 3.12.x

    # 3. Download the MGN agent installer
    # Replace us-east-1 with your target region

    wget -O ./aws-replication-installer-init.py \
    https://aws-application-migration-service-us-east-1.s3.amazonaws.com/latest/linux/aws-replication-installer-init.py

    # 4. Run the installer (will prompt for credentials)
    sudo python3 aws-replication-installer-init.py

    # When prompted, enter:
    # AWS Region Name: us-east-1 (your region)
    # AWS Access Key ID: AKIA... (from Step 1)
    # AWS Secret Access Key: xxxxxxx (from Step 1)
    # The installer will auto-detect volumes to replicate

    # 5. Verify agent service is running
    sudo systemctl status aws-replication-daemon
    # Expected: active (running)

    bash
    LinuxTeck.com
    config • rocky9-mgn-agent.sh • Rocky Linux 9
    # Rocky Linux 9 — AWS MGN Agent Installation
    # IMPORTANT: SELinux requires special handling on Rocky Linux 9

    # 1. Install dependencies
    sudo dnf install -y python3 python3-pip wget

    # 2. Check SELinux mode — if Enforcing, you need the step below
    getenforce
    # If output is "Enforcing", run the SELinux policy fix:
    sudo semanage permissive -a initrc_t 2>/dev/null || \
    echo "semanage not found - install: dnf install -y policycoreutils-python-utils"
    sudo dnf install -y policycoreutils-python-utils
    sudo semanage permissive -a initrc_t

    # 3. Download the agent installer
    # Replace us-east-1 with your target region

    wget -O ./aws-replication-installer-init.py \
    https://aws-application-migration-service-us-east-1.s3.amazonaws.com/latest/linux/aws-replication-installer-init.py

    # 4. Run installer
    sudo python3 aws-replication-installer-init.py

    # 5. Verify agent service
    sudo systemctl status aws-replication-daemon

    # 6. (Recommended) After agent is running, restore SELinux to Enforcing
    # The agent will continue running once the policy exception is set

    sudo semanage permissive -d initrc_t

    bash
    LinuxTeck.com
    config • rhel9-mgn-agent.sh • RHEL 9
    # RHEL 9 — AWS MGN Agent Installation
    # Note: RHEL 9 uses BYOL licensing — confirm Cloud Access entitlement

    # 1. Install dependencies
    sudo dnf install -y python3 python3-pip wget policycoreutils-python-utils

    # 2. Check subscription status (RHEL requires active subscription for dnf)
    sudo subscription-manager status
    # If not subscribed, register: sudo subscription-manager register

    # 3. SELinux — same handling as Rocky Linux 9
    getenforce
    sudo semanage permissive -a initrc_t

    # 4. Download the agent installer
    wget -O ./aws-replication-installer-init.py \
    https://aws-application-migration-service-us-east-1.s3.amazonaws.com/latest/linux/aws-replication-installer-init.py

    # 5. Run installer
    sudo python3 aws-replication-installer-init.py

    # 6. Verify
    sudo systemctl status aws-replication-daemon

    # 7. RHEL note: Your RHEL license (BYOL) carries over to EC2
    # AWS MGN detects the OS and applies BYOL automatically
    # No need to re-register with Red Hat after migration

    How to Migrate Linux Server to AWS Cloud: Step-by-Step 2026 5

    Expected Result:

    After successful agent installation, your source server will appear in the AWS MGN Console → Source servers list with status "Not ready" initially, then moving to "Ready for testing" once initial replication sync completes (typically 20 minutes to several hours depending on disk size). You will also see a new EC2 instance (the replication server) appear in your staging subnet automatically.

    Step 4 — Configure Launch Settings and Launch Test Instance

    Before cutting over to production, you launch a test instance. This is a non-destructive step — your source server keeps running, and replication continues. The test instance lets you verify the migrated server boots, services are running, and applications respond correctly.

    Configure EC2 Launch Settings in the MGN Console:

    1. In MGN Console, click your source server → Launch settings
    2. Under EC2 launch template, click Modify
    3. Configure: Instance type (match or right-size), Target subnet, Security group, Key pair
    4. Save the launch template version and set it as default
    5. Return to MGN → Source servers → Select server → Test and Cutover → Launch test instances
    6. Confirm the dialog. AWS MGN will launch a test EC2 instance in your target subnet.
    bash
    LinuxTeck.com
    config • validate-test-instance.sh • run on the test EC2 instance after launch
    # Connect to the test instance via SSH
    # Replace with your test instance IP and key file

    ssh -i ~/.ssh/your-key.pem ec2-user@<test-instance-ip>
    # Ubuntu: use 'ubuntu' instead of 'ec2-user'
    # Rocky/RHEL: use 'rocky' or 'ec2-user'

    # Once connected, verify critical services
    sudo systemctl list-units --type=service --state=running

    # Check disk mounts match source
    lsblk
    df -h

    # Check kernel (should match source)
    uname -r

    # Test application connectivity (example: Apache)
    curl -I http://localhost
    # Expected: HTTP/1.1 200 OK (or your application's expected response)

    # Check network interface
    ip a

    Expected
    All critical services from your source server should show active (running).
    Disk layout in lsblk should match the source.
    curl -I http://localhost should return HTTP/1.1 200 OK.

    How to Migrate Linux Server to AWS Cloud: Step-by-Step 2026 6

    Critical:

    Do not proceed to cutover if the test instance shows any service failures or unexpected behavior. The test instance is your safety net. Fix issues at this stage, not after you have pointed production DNS at the cutover instance.

    Step 5 — Launch Cutover Instance and Update DNS

    Cutover is the moment you switch production traffic from the on-premises server to the new EC2 instance. Preparation determines whether your downtime is 3 minutes or 3 hours.

    Pre-cutover actions (do these 24 hours before):

    bash
    LinuxTeck.com
    config • pre-cutover-prep.sh • pre-cutover DNS TTL reduction
    # Step 1: Lower DNS TTL 24 hours before cutover
    # This ensures DNS changes propagate quickly during the cutover window
    # Do this in your DNS provider (Route53, Cloudflare, etc.)
    # Example using AWS CLI for Route53:

    aws route53 change-resource-record-sets \
    --hosted-zone-id <YOUR_ZONE_ID> \
    --change-batch '{
    "Changes": [{
    "Action": "UPSERT",
    "ResourceRecordSet": {
    "Name": "app.example.com",
    "Type": "A",
    "TTL": 60,
    "ResourceRecords": [{"Value": "<CURRENT_SOURCE_IP>"}]
    }
    }]
    }'
    # Lower TTL to 60 seconds now
    # After cutover succeeds, raise it back to 300 or 3600

    # Step 2: Take a final snapshot of the source server
    # (Backup before any disruptive action)

    aws ec2 create-snapshot \
    --description "pre-cutover-backup-$(date +%Y%m%d)" \
    --volume-id <source-volume-id>

    Expected
    Route53 change returns ChangeInfo with Status: PENDING, then INSYNC within 60 seconds.
    Snapshot creation returns SnapshotId: snap-xxxxxxxxxxxxxxxxx

    Cutover steps in MGN Console:

    1. In MGN Console, select source server → Test and Cutover → Launch cutover instances
    2. Confirm the action. AWS MGN performs a final replication sync then launches the cutover EC2 instance.
    3. Once the instance shows Running in EC2, SSH into it and verify services (same checks as Step 4).
    4. Update DNS to point to the new EC2 instance's Elastic IP or private IP (via load balancer).
    5. Monitor for 15-30 minutes. Watch application logs, CPU, and connection counts.
    6. When satisfied, return to MGN Console → Finalize cutover. This terminates the replication server and stops replication.

    Critical:

    Do not finalize cutover immediately. Once you click Finalize, the replication server is terminated and you cannot roll back to the source via MGN. Give yourself at least 30 minutes of stable production traffic on the new EC2 instance before finalizing. Keep your source server running for 24-48 hours post-cutover as a manual rollback option.

    Multi-Server Migrations: Wave-Based Approach

    If you are migrating more than one Linux server, do not run them all in parallel on your first attempt. Use a phased wave approach:

    Wave Servers Goal
    Wave 0 (Pilot) 1-2 non-critical servers Validate your MGN setup, IAM, networking end-to-end
    Wave 1 Dev/test servers Refine launch settings, practice cutover procedure
    Wave 2 Internal/low-traffic production First real cutover with limited blast radius
    Wave 3+ High-traffic / business-critical Full production cutover with rollback plan in place

    Real-World Migration Problems and Solutions

    These are the six failure patterns that come up on real migrations. If you skip this section, your future self (at 2 AM, mid-cutover) will wish you had not.

    Issue 01
    Replication Agent Install Fails — Python Dependency Error

    Environment: Ubuntu 22.04 or Rocky Linux 9. The installer exits with ModuleNotFoundError or fails silently with a pip conflict error.

    Failure pattern: A production web server that had Python 2.7 still symlinked to /usr/bin/python caused the installer to invoke Python 2 instead of Python 3, producing a silent failure with no clear error. The agent never appeared in the MGN console.

    bash
    LinuxTeck.com
    config • fix
    # Verify which Python is invoked by python3
    which python3 && python3 --version

    # Ubuntu: if python3 is missing
    sudo apt-get install -y python3 python3-pip python3-venv

    # Rocky/RHEL: ensure python3 is installed
    sudo dnf install -y python3 python3-pip

    # Always call the installer explicitly with python3
    sudo python3 aws-replication-installer-init.py

    # NOT: sudo python aws-replication-installer-init.py

    Issue 02
    Replication Stuck at 0% — Port 1500 Blocked

    Environment: Any Linux distro behind a corporate firewall or strict on-premises network policy.

    Failure pattern: Agent installs successfully, source server appears in MGN console, but the Data replication status stays at 0% or "Initiating" for hours. No obvious error in the MGN console. The agent log shows repeated connection timeouts. Port 443 was open but the network team had never heard of port 1500 and it was blocked at the perimeter firewall.

    bash
    LinuxTeck.com
    config • fix
    # Test port 1500 from the source server
    nc -zv -w5 mgn.us-east-1.amazonaws.com 1500

    # If that fails, check agent logs
    sudo tail -100 /var/log/aws-replication-agent.log

    # Open TCP 1500 outbound in iptables (temporary test)
    sudo iptables -I OUTPUT -p tcp --dport 1500 -j ACCEPT

    # If that fixes it, make it permanent via your firewall rules
    # For firewalld (Rocky/RHEL):

    sudo firewall-cmd --add-port=1500/tcp --permanent
    sudo firewall-cmd --reload

    Issue 03
    Test Instance Launches But SSH Fails

    Environment: Any distro. Test or cutover EC2 instance is Running but SSH connections time out.

    Failure pattern: Two causes are common. First, the wrong key pair was selected in the EC2 launch template. Second, the security group attached to the test instance does not allow inbound TCP 22 from your IP. Both are fixable without relaunching the instance.

    bash
    LinuxTeck.com
    config • fix
    # 1. Check security group allows SSH from your IP
    aws ec2 describe-security-groups \
    --group-ids <sg-id> \
    --query 'SecurityGroups[*].IpPermissions'

    # 2. Add SSH inbound rule if missing
    aws ec2 authorize-security-group-ingress \
    --group-id <sg-id> \
    --protocol tcp \
    --port 22 \
    --cidr <your-ip>/32

    # 3. If key pair is wrong, use EC2 Instance Connect (in AWS Console)
    # or attach an SSM role to the instance and use Session Manager

    Issue 04
    Cutover Instance Kernel Panic — Bootloader Mismatch

    Environment: RHEL 7 or CentOS 7 migrated to EC2 (older bootloader edge case). Less common on modern distros but still seen on legacy workloads.

    Failure pattern: EC2 instance enters a boot loop or kernel panic visible in the EC2 serial console. Usually caused by GRUB legacy (not GRUB2) on the source, or a UEFI vs BIOS mismatch in the launch template.

    bash
    LinuxTeck.com
    config • fix
    # On source server BEFORE migration — check bootloader
    ls /boot/grub2/ 2>/dev/null && echo "GRUB2 found" || echo "GRUB2 not found"
    ls /boot/grub/ 2>/dev/null && echo "GRUB legacy found"

    # If GRUB legacy is present, upgrade to GRUB2 before migrating
    # (CentOS/RHEL 7 example — already has grub2 but may default to legacy)

    sudo grub2-install /dev/sda
    sudo grub2-mkconfig -o /boot/grub2/grub.cfg

    # In the MGN EC2 launch template:
    # Set Boot mode = Legacy BIOS (not UEFI) unless your source is UEFI
    # Check in: MGN Console > Source server > Launch settings > Edit > Boot mode

    Issue 05
    DNS Does Not Propagate After Cutover

    Environment: Any. DNS TTL was not lowered before cutover, so old IP addresses are cached by resolvers worldwide for hours.

    Failure pattern: You updated DNS to point to the new EC2 Elastic IP but customers are still hitting the old server. Some get the new server, some get the old one. The old server is already cut off from database updates. Data inconsistency begins.

    bash
    LinuxTeck.com
    config • fix / prevention
    # PREVENTION: Lower TTL 24 hours before cutover (as shown in Step 5)
    # Set TTL to 60 seconds so changes propagate within 1 minute

    # If you forgot: check current TTL
    dig +nocmd yourdomain.com +noall +answer

    # Force local DNS cache flush (test from your machine)
    # Linux:

    sudo systemd-resolve --flush-caches
    # macOS:
    sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder

    # For Route53: use a small TTL record change immediately
    # For Cloudflare: DNS propagation is typically under 30 seconds regardless of TTL

    Issue 06
    SELinux Silently Blocks Agent on Rocky Linux / RHEL

    Environment: Rocky Linux 9 or RHEL 9 with SELinux in Enforcing mode (the default on fresh installs).

    Failure pattern: The agent installer completes without error, the systemd service starts, but replication never begins. The SELinux audit log shows the agent process being denied socket operations. The MGN console shows the server as "Disconnected" 10 minutes after install.

    bash
    LinuxTeck.com
    config • fix
    # Check SELinux denials related to the agent
    sudo ausearch -m avc -ts recent | grep aws-replication

    # Or tail the audit log
    sudo tail -50 /var/log/audit/audit.log | grep denied

    # Quick diagnosis: temporarily set permissive mode
    sudo setenforce 0
    # Then check if replication starts in the MGN console (within 2 minutes)

    # Proper fix: create a targeted SELinux policy exception
    sudo dnf install -y policycoreutils-python-utils
    sudo semanage permissive -a initrc_t
    sudo setenforce 1
    # The agent now runs with SELinux enforcing but with a specific exemption

    Post-Migration Validation Script

    Run this script on the newly migrated EC2 instance immediately after cutover. It checks everything that matters: services, disks, kernel, network, and application endpoints. Save the output and compare it against your pre-migration snapshot from Step 0.

    bash
    LinuxTeck.com
    config • post-migration-validate.sh • run on the cutover EC2 instance
    #!/bin/bash
    # Post-Migration Validation Script — LinuxTeck.com
    # Run on the NEW EC2 instance after cutover
    # Compare output to pre-migration snapshot from Step 0

    echo "============================================"
    echo " POST-MIGRATION VALIDATION — $(date)"
    echo " Hostname: $(hostname)"
    echo " Instance: $(curl -s http://169.254.169.254/latest/meta-data/instance-id 2>/dev/null || echo 'N/A')"
    echo "============================================"

    echo ""
    echo "--- 1. KERNEL VERSION ---"
    uname -r

    echo ""
    echo "--- 2. DISK MOUNTS ---"
    lsblk
    echo ""
    df -h | grep -v tmpfs

    echo ""
    echo "--- 3. RUNNING SERVICES ---"
    systemctl list-units --type=service --state=running --no-pager | head -30

    echo ""
    echo "--- 4. NETWORK INTERFACES ---"
    ip a | grep -E 'inet |eth|ens|eno'

    echo ""
    echo "--- 5. DEFAULT ROUTE ---"
    ip route show default

    echo ""
    echo "--- 6. APPLICATION ENDPOINT CHECK ---"
    for port in 80 443 8080 3306; do
    (bash -c "cat /dev/tcp/localhost/$port") 2>/dev/null \
    && echo "Port $port: OPEN" \
    || echo "Port $port: CLOSED (may be expected)"
    done

    echo ""
    echo "--- 7. HTTP RESPONSE CHECK (if web server) ---"
    curl -s -o /dev/null -w "HTTP Status: %{http_code}\n" http://localhost/ 2>/dev/null \
    || echo "No HTTP server detected on port 80"

    echo ""
    echo "--- 8. MEMORY AND CPU ---"
    free -h
    echo ""
    nproc && echo "CPU core(s)"

    echo ""
    echo "--- 9. SYSTEM UPTIME ---"
    uptime

    echo ""
    echo "--- 10. LAST 20 SYSTEM LOG ERRORS ---"
    journalctl -p err -n 20 --no-pager 2>/dev/null \
    || tail -20 /var/log/messages 2>/dev/null

    echo ""
    echo "============================================"
    echo " VALIDATION COMPLETE"
    echo " Review output against pre-migration snapshot"
    echo "============================================"

    Usage
    chmod +x post-migration-validate.sh && sudo ./post-migration-validate.sh
    # Save to file:
    sudo ./post-migration-validate.sh | tee migration-report-$(date +%Y%m%d).txt

    Usage:

    Save this script to post-migration-validate.sh, run chmod +x post-migration-validate.sh && sudo ./post-migration-validate.sh and pipe the output to a file for the migration record: sudo ./post-migration-validate.sh | tee migration-report-$(date +%Y%m%d).txt

    Security and Compliance Notes

    AWS Well-Architected
    IAM Least Privilege
    CloudTrail Audit
    HIPAA / PCI DSS Ready
    EBS Encryption at Rest

    AWS MGN Pricing - The Free Tier Most Guides Skip

    AWS MGN is free for the first 90 days per migrated server. This is the most financially significant fact in this article. Here is what the numbers actually look like:

    Resource Cost During Migration Notes
    AWS MGN Service Free (90 days/server) After 90 days: $0.042/hr per replicated server
    Replication server (EC2) ~$0.023/hr (t3.small) Auto-provisioned in your staging subnet
    EBS staging volumes $0.08/GB-month (gp3) Sized to match source disk
    Data transfer $0.09/GB (internet) Free if using Direct Connect or within same region

    Practical example: Migrating a 200 GB Ubuntu server over 2 weeks via public internet costs roughly: replication server ($0.023 x 336 hrs = $7.73) + EBS staging ($0.08 x 200 GB = $16) + data transfer (~$18 for 200 GB initial sync) = approximately $42 total for the migration. The MGN service itself is free within the 90-day window.

    Post-Migration Security Hardening Checklist

    bash
    LinuxTeck.com
    config • post-migration-security.sh • run after cutover is finalized
    # 1. Delete the IAM replication access key (no longer needed post-cutover)
    aws iam delete-access-key \
    --user-name mgn-replication-agent \
    --access-key-id <AKIA_KEY_FROM_STEP_1>

    # 2. Remove staging area security group rules (staging SG no longer needed)
    # In AWS Console: EC2 > Security Groups > find staging SG > delete inbound rules

    aws ec2 revoke-security-group-ingress \
    --group-id <staging-sg-id> \
    --protocol all \
    --source-group <staging-sg-id>

    # 3. Enable EBS encryption for future volumes (set account-level default)
    aws ec2 enable-ebs-encryption-by-default

    # 4. Enable CloudTrail for the MGN project region (if not already enabled)
    aws cloudtrail create-trail \
    --name mgn-migration-audit \
    --s3-bucket-name <your-cloudtrail-bucket>
    aws cloudtrail start-logging --name mgn-migration-audit

    # 5. Remove public IP from EC2 instance if it was only needed during testing
    # Use an Elastic IP or put instance behind a load balancer instead

    # 6. Lock down the production Security Group to minimum required ports
    # Remove any 0.0.0.0/0 SSH rules — use bastion host or Systems Manager instead

    aws ec2 revoke-security-group-ingress \
    --group-id <prod-sg-id> \
    --protocol tcp \
    --port 22 \
    --cidr 0.0.0.0/0

    Expected
    Each command returns an empty response on success (AWS CLI standard for delete/revoke operations).
    Verify with: aws iam list-access-keys --user-name mgn-replication-agent

    For a detailed checklist of Linux security controls to apply to your newly migrated EC2 instance, see the top Linux security tools guide and the Linux security command cheat sheet. The network hardening steps that apply on-premises also apply in EC2 — the difference is you now also have AWS security groups, IAM, and CloudTrail as additional layers.

    Monitoring and Maintenance Checklist

    ON ALERT / IMMEDIATE

    EC2 instance CPU exceeds 90% for more than 5 minutes — right-size instance type (AWS Compute Optimizer)

    EBS volume IOPS throttling alerts — upgrade from gp3 to io2 if database workload requires it

    Application endpoint returning non-200 responses after DNS cutover — check security group and application logs immediately

    SSH or SSM connection failure to EC2 — check instance status checks in EC2 console, verify IAM instance profile

    WEEKLY

    Review AWS Cost Explorer for unexpected EC2, EBS, or data transfer charges — common in first 30 days post-migration

    Check CloudWatch metrics: CPUUtilization, NetworkIn/Out, DiskReadOps, DiskWriteOps — compare to pre-migration baseline

    Verify EBS snapshot backups are running — ensure automated snapshots via AWS Backup or custom cron are configured

    MONTHLY

    Run AWS Compute Optimizer to check right-sizing recommendations — EC2 instances are often over-provisioned to match on-prem specs

    Apply OS security patches on EC2 instance (apt-get update && apt-get upgrade or dnf update) — cloud exposure makes patching more urgent than on-prem

    Review IAM Access Advisor for the mgn-replication-agent user — confirm it has zero recent activity and consider deactivating it permanently

    QUARTERLY

    Run AWS Well-Architected Framework review on migrated workload — specifically the Reliability and Cost Optimization pillars

    Evaluate Reserved Instance or Savings Plans purchase if EC2 instance has been running consistently — typically 30-40% cost reduction vs On-Demand

    Decommission the original on-premises server hardware after 90 days of stable EC2 operation — document the decommission date for audit records

    For ongoing Linux system monitoring on your new EC2 instance, the best Linux monitoring tools guide covers both traditional sysadmin tools and cloud-native options that integrate with CloudWatch. Also see the Linux system monitoring command cheat sheet for quick reference commands you will use frequently on the EC2 instance.


    FAQ

    Frequently Asked Questions

    Does AWS MGN support Rocky Linux 9?

    Yes. AWS MGN officially supports Rocky Linux 9 as a source operating system. The installation procedure is the same as RHEL 9, with the same SELinux handling requirement. Check the AWS MGN supported operating systems page for the full current list, as it is updated regularly.

    How long does AWS cloud migration take for Linux servers?

    The initial replication sync depends on disk size and network bandwidth. A 100 GB server over a 100 Mbps internet connection takes roughly 2-3 hours for the initial sync. After that, MGN performs continuous incremental replication. The actual cutover window (when the server is unavailable) is typically under 15 minutes. Planning, testing, and validation add days or weeks for production workloads.

    What is the difference between AWS MGN, AWS SMS, and AWS DataSync?

    AWS MGN (Application Migration Service) migrates full servers including the OS, applications, and data to EC2. AWS SMS (Server Migration Service) is the older predecessor to MGN and is being retired — do not use it for new migrations. AWS DataSync moves files and data between storage systems (NFS, S3, EFS) but does not migrate an operating system. See the tool comparison table at the top of this article for a complete breakdown.

    Can I migrate a bare-metal Linux server (not a VM)?

    Yes. AWS MGN supports bare-metal physical servers. The replication agent runs directly on the physical server and replicates disk data to AWS over TCP 1500. There is no requirement for a hypervisor. Physical servers work the same as VMs in the MGN workflow. The main difference is that rollback is more disruptive since you cannot simply revert a VM snapshot.

    What happens to my IP address after migration?

    Your on-premises IP address does not carry over to EC2. Your new EC2 instance receives a private IP from your VPC CIDR range. For public-facing services, assign an Elastic IP to the instance (static public IP) and update DNS records to point to it. For internal services, update any hardcoded IP references in configuration files to use either the new EC2 private IP or, better, DNS names for service discovery.

    What Linux filesystems does AWS MGN support?

    AWS MGN supports ext2, ext3, ext4, XFS, and Btrfs on Linux source servers. XFS is the default on Rocky Linux 9 and RHEL 9 and is fully supported. Btrfs is supported but less commonly tested in production migrations. Unsupported filesystem types on the root or boot volume will cause the agent to error out during volume detection. Run df -T on your source server to confirm.

    How do I minimize downtime during cutover?

    Three actions minimize cutover downtime: (1) Lower DNS TTL to 60 seconds at least 24 hours before cutover so DNS changes propagate in under a minute. (2) Allow continuous replication to run for at least 24 hours before cutover so the final delta sync is small. (3) Schedule cutover during your lowest traffic window. With these steps, actual user-facing downtime is typically 2-5 minutes.

    Is AWS MGN actually free? What are the hidden costs?

    The MGN service itself is free for 90 days per server. The hidden costs are the replication server EC2 instance (t3.small at ~$0.023/hr), the EBS staging volumes ($0.08/GB/month on gp3), and data transfer charges ($0.09/GB over the public internet). For a typical 200 GB server migrated over 2 weeks, total costs are roughly $40-60. Use AWS Direct Connect or migrate within the same AWS region to eliminate data transfer charges.

    Conclusion

    AWS MGN has made the process for migrating a Linux server genuinely straightforward compared to the CloudEndure and SMS era. The agent installs within minutes, continuous replication runs in the background, and the test instance model lets you validate before going live. The issues that keep teams working round the clock are almost always the same three: a firewall blocking port 1500 that the network team was never told about, SELinux silently killing the agent on Rocky Linux, and a DNS TTL that was never lowered before cutover.

    Long-term trends: Lift-and-shift is an entry point, not a final destination. It is typically followed by right-sizing, then Auto Scaling for variable workloads, and later evaluating whether containerization makes sense for stateless application components.
    The Linux DevOps Career Guide provides a practical overview of how teams can progress through these stages after migration.

    Once workloads are successfully migrated, the next challenge is optimizing cloud infrastructure costs, security, and long-term operational reliability. Our guide to Linux cloud hosting environments explores production hosting considerations for modern Linux deployments.

    For teams managing many servers across Rocky Linux 9 and RHEL environments, understanding the differences between those distributions before migration matters more than most guides admit. The RHEL vs Ubuntu Server comparison is worth reading if your migration involves mixed distro environments, since post-migration management differences compound over time on EC2. Also keep an eye on Linux security threats in 2026 — moving to a cloud-exposed EC2 instance increases your attack surface compared to a server sitting behind an on-premises firewall.

    LinuxTeck — Linux Server Migration to AWS Cloud: Step-by-Step 2026
    This guide covered how to migrate Linux servers from on-premises to AWS using AWS Application Migration Service (MGN) with distro-specific steps for Ubuntu, Rocky Linux, and RHEL.
    LinuxTeck's Enterprise Linux category focuses on production-ready Linux infrastructure skills including:
    AWS cloud migration for Linux servers, AWS MGN replication agent setup,
    Ubuntu and Rocky Linux EC2 migration, lift-and-shift server migration,
    post-migration validation and security hardening, and on-premises Linux to AWS cutover workflows.


    About John Britto

    John Britto Founder & Chief-Editor @LinuxTeck. A Computer Geek and Linux Intellectual having more than 20+ years of experience in Linux and Open Source technologies.

    View all posts by John Britto →

    Leave a Reply

    Your email address will not be published.

    L