Guide · AWS ECR · Multi-Region Deployment
ECR Replication for MCP Servers — Cross-Region and Cross-Account Image Distribution
ECR replication automatically copies images pushed to a source registry to one or more destination registries — eliminating the need to push to multiple regions in CI and ensuring ECS tasks in every region pull from a local ECR endpoint. Three things catch teams early: replication is not retroactive — only images pushed after the replication configuration is applied are replicated; pre-existing images must be pushed again or copied manually; the replication configuration is a single object that replaces the entire existing configuration — adding a new destination region requires you to PUT the complete updated config, not just append a new rule; and cross-account replication requires a registry policy in the destination account granting the source account ecr:ReplicateImage — without it, replication silently fails with no error in the source account's CloudTrail.
TL;DR
Call put-replication-configuration with the complete rules array (one destination per region/account pair). For cross-account, also call put-registry-policy in the destination account. Replication applies to new pushes only — existing images are not backfilled. Check status with describe-image-replication-status. Add lifecycle policies in destination regions to cap storage. Budget $0.02/GB per replication transfer plus destination storage costs.
Replication configuration: cross-region
Replication is configured at the registry level (account + region) with a single put-replication-configuration call. The configuration applies to all repositories in the source registry, optionally filtered by repository name prefix.
## Configure cross-region replication: us-east-1 → eu-west-1 + ap-southeast-1
aws ecr put-replication-configuration \
--replication-configuration '{
"rules": [
{
"destinations": [
{ "region": "eu-west-1", "registryId": "123456789012" },
{ "region": "ap-southeast-1", "registryId": "123456789012" }
],
"repositoryFilters": [
{
"filter": "mcp-server",
"filterType": "PREFIX_MATCH"
}
]
}
]
}'
## IMPORTANT: the above replaces the ENTIRE existing configuration.
## If you had an existing rule for eu-central-1 and only PUT the above,
## the eu-central-1 rule is removed.
## Verify current replication configuration
aws ecr describe-registry
Repository filters: the repositoryFilters array (optional) restricts which repositories are replicated. Filter type PREFIX_MATCH matches any repository whose name starts with the specified string. Omitting repositoryFilters replicates all repositories in the source registry. In most MCP deployments, filtering to mcp-server is preferable to replicating all repositories (which would include test, scratch, and tool images).
Cross-account replication
Cross-account replication copies images from one AWS account's registry to another account's registry. This is used in multi-account setups where images are built and stored in a centralized "tools" or "shared-services" account and deployed from regional production accounts.
## Step 1: In the SOURCE account (where images are built)
## Configure replication to a different account in eu-west-1
aws ecr put-replication-configuration \
--replication-configuration '{
"rules": [
{
"destinations": [
{
"region": "eu-west-1",
"registryId": "999888777666" // DESTINATION account ID
}
],
"repositoryFilters": [
{ "filter": "mcp-server", "filterType": "PREFIX_MATCH" }
]
}
]
}'
## Step 2: In the DESTINATION account (999888777666), create a registry policy
## granting the source account permission to replicate images
aws ecr put-registry-policy \
--policy-text '{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowSourceAccountReplication",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root" // SOURCE account ID
},
"Action": [
"ecr:CreateRepository",
"ecr:ReplicateImage"
],
"Resource": "arn:aws:ecr:eu-west-1:999888777666:repository/*"
}
]
}'
## Verify registry policy
aws ecr get-registry-policy
The ecr:CreateRepository permission in the registry policy is necessary because ECR creates the destination repository on first replication if it doesn't exist. Without it, replication fails when the image has never been replicated before.
Replication status and monitoring
Check whether a specific image has been replicated to destination regions using describe-image-replication-status. This is useful in CI pipelines to wait for replication before updating ECS task definitions in destination regions.
## Check replication status for a specific image
aws ecr describe-image-replication-status \
--repository-name mcp-server \
--image-id imageTag=v1.2.3
## Example output:
# {
# "repositoryName": "mcp-server",
# "imageId": { "imageTag": "v1.2.3", "imageDigest": "sha256:..." },
# "replicationStatuses": [
# {
# "region": "eu-west-1",
# "registryId": "123456789012",
# "status": "COMPLETE",
# "failureCode": null
# },
# {
# "region": "ap-southeast-1",
# "registryId": "123456789012",
# "status": "IN_PROGRESS",
# "failureCode": null
# }
# ]
# }
#!/usr/bin/env bash
# wait-for-replication.sh — wait until image is replicated to all regions
REPO=$1
TAG=$2
REGIONS=("eu-west-1" "ap-southeast-1")
MAX_WAIT=300
echo "Waiting for replication of $REPO:$TAG..."
ELAPSED=0
while [ "$ELAPSED" -lt "$MAX_WAIT" ]; do
ALL_COMPLETE=true
for REGION in "${REGIONS[@]}"; do
STATUS=$(aws ecr describe-image-replication-status \
--repository-name "$REPO" \
--image-id imageTag="$TAG" \
--query "replicationStatuses[?region=='$REGION'].status" \
--output text)
if [ "$STATUS" != "COMPLETE" ]; then
ALL_COMPLETE=false
echo " $REGION: $STATUS"
fi
done
if [ "$ALL_COMPLETE" = true ]; then
echo "Replication complete in all regions."
exit 0
fi
sleep 15
ELAPSED=$((ELAPSED + 15))
done
echo "Replication timed out — proceeding with caution"
exit 1
Replication typically completes within 1–2 minutes for cross-region within the same account. Cross-account replication can take 2–5 minutes. EventBridge fires ECR Image Replication events when replication status changes — subscribe to receive async notification instead of polling.
CDK: replication configuration
// CDK: configure ECR cross-region replication via CfnRegistryPolicy and custom resource
// (No native L2 CDK construct for replication configuration as of CDK v2)
import * as cr from "aws-cdk-lib/custom-resources";
new cr.AwsCustomResource(this, "EcrReplication", {
onCreate: {
service: "ECR",
action: "putReplicationConfiguration",
parameters: {
replicationConfiguration: {
rules: [
{
destinations: [
{ region: "eu-west-1", registryId: this.account },
{ region: "ap-southeast-1", registryId: this.account },
],
repositoryFilters: [
{ filter: "mcp-server", filterType: "PREFIX_MATCH" },
],
},
],
},
},
physicalResourceId: cr.PhysicalResourceId.of("EcrReplication"),
},
onUpdate: {
service: "ECR",
action: "putReplicationConfiguration",
parameters: {
replicationConfiguration: {
rules: [
{
destinations: [
{ region: "eu-west-1", registryId: this.account },
{ region: "ap-southeast-1", registryId: this.account },
],
repositoryFilters: [
{ filter: "mcp-server", filterType: "PREFIX_MATCH" },
],
},
],
},
},
physicalResourceId: cr.PhysicalResourceId.of("EcrReplication"),
},
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
}),
});
Cost model
| Cost component | Rate | Notes |
|---|---|---|
| Data transfer for replication | $0.02/GB per replication | Charged in the source region; same rate as standard inter-region data transfer for ECR |
| Destination ECR storage | $0.10/GB-month | Replicated images stored in destination registry; add lifecycle policies in destination regions too |
| ECS task pull from same-region ECR | Free | No data transfer charge for ECS pulling from ECR in the same region |
Cost example: a 500 MB MCP server image replicated to 3 destination regions: $0.02 × 0.5 GB × 3 destinations = $0.03 per release. For 2 releases per week over a month = $0.24/month transfer. Destination storage for 10 kept images × 500 MB × 3 regions = 15 GB × $0.10 = $1.50/month. Total: ~$1.74/month for 3-region replication — negligible compared to the ECS and data transfer costs of the deployment itself.
AliveMCP: multi-region probe worker replication
AliveMCP's probe workers run in three AWS regions to minimize round-trip latency to MCP endpoints in different geographies: us-east-1 (primary, where CI builds and pushes), eu-west-1 (European MCP endpoints), and ap-southeast-1 (Asia-Pacific MCP endpoints). ECR cross-region replication propagates each new probe worker image from us-east-1 to the two secondary regions within 2 minutes of push. The CI deployment pipeline calls wait-for-replication.sh before updating ECS task definitions in eu-west-1 and ap-southeast-1 — this prevents ECS from deploying with a task definition pointing to an image that hasn't arrived yet. Lifecycle policies are applied in all three regional ECR repos, keeping each to the last 10 images. The replication configuration uses a PREFIX_MATCH filter on mcp-server — dev, tooling, and migration images are not replicated.
Common failure modes
| Symptom | Cause | Fix |
|---|---|---|
Replication status stays IN_PROGRESS indefinitely; never COMPLETE | Missing registry policy in destination account for cross-account replication; or destination account doesn't allow ecr:ReplicateImage | Add registry policy to destination account with ecr:CreateRepository and ecr:ReplicateImage for the source account principal |
| Images in us-east-1 are not being replicated to eu-west-1 after adding new destination | Added a new destination but the put-replication-configuration only included the new rule, dropping the existing rules | Always PUT the complete replication configuration with all destinations — the call replaces the entire config |
| Pre-existing images are not in destination regions | Replication is not retroactive — only new pushes after configuration is applied are replicated | Re-tag and re-push existing images, or use aws ecr batch-get-image + ecr put-image to copy manifests programmatically |
| ECS task definition update in eu-west-1 fails: image not found | Deployment proceeded before replication completed | Wait for replication status COMPLETE before updating task definitions in secondary regions |
| Cross-account replication fails silently; no error in source CloudTrail | Destination registry policy is missing or has incorrect account ID; failure is logged in destination account's CloudTrail, not source | Check CloudTrail in the destination account for ECR:ReplicateImage AccessDenied events |
| Storage grows in destination regions even with lifecycle policy in source | Lifecycle policies are per-repository per-region; a policy in us-east-1 does not apply to the replicated repo in eu-west-1 | Apply the same lifecycle policy to replicated repositories in each destination region |