I tried bypassing CloudFront VPC origin failures using Inter-Region VPC peering
This page has been translated by machine translation. View original
Introduction
From 16:45 JST (12:45 AM PDT) on July 16, 2026 to 20:18 JST (4:18 AM PDT), an outage occurred in which 5xx errors increased for connections via CloudFront VPC Origins. The following is the timeline according to the final report from the AWS Service Health Dashboard (SHD).
| Time (PDT) | Time (JST) | Description |
|---|---|---|
| 12:45 AM | 16:45 | Outage begins (5xx errors increase for VPC Origins users) |
| 2:57 AM | 18:57 | Root cause identified |
| 3:52 AM | 19:52 | Mitigation implemented |
| 4:18 AM | 20:18 | Full recovery |
The root cause was that the fleet managing private connections to VPC origins reached an internal constraint. When this constraint was exceeded, the routing configuration was no longer correctly delivered to network processors, affecting connections via VPC origins.

Between 12:45 AM and 4:18 AM PDT, we experienced increased 5xx errors for CloudFront customers utilizing VPC Origins connectivity. [...] We identified the root cause of the issue as an internal constraint on the fleet that manages connections to private VPC origins. When this constraint was reached, the system responsible for distributing routing configuration to our network processors failed to load the updated configuration data correctly, affecting routing of VPC Origin connections.
As a workaround, users were advised to "change their origin type" to an origin type other than VPC origins. This article documents a practical example of following that recommended workaround — how we designed and built a route that does not go through VPC origins, and how long it took to recover. The prerequisite configuration of the target service is explained in the following article.
Observing the Outage
CloudFront access logs v2 were extracted using Amazon Athena and aggregated per minute.

The following shows the count of status=0 (ClientCommError) and latency trends that increased in temporal alignment with the VPC origins outage.
| Time | Total | status=0 | 0 rate | 404 | P95(s) | P99(s) |
|---|---|---|---|---|---|---|
| 16:45 | 1,542 | 1 | 0.1% | 8 | 0.796 | 1.224 |
| 16:46 | 1,724 | 0 | 0.0% | 6 | 0.871 | 1.134 |
| 16:47 | 1,346 | 0 | 0.0% | 16 | 0.770 | 1.187 |
| 16:48 | 1,441 | 1 | 0.1% | 3 | 0.765 | 1.253 |
| 16:49 | 1,273 | 0 | 0.0% | 8 | 0.831 | 1.646 |
| 16:50 | 1,331 | 0 | 0.0% | 17 | 0.792 | 1.408 |
| 16:51 | 1,657 | 0 | 0.0% | 3 | 0.799 | 1.446 |
| 16:52 | 1,479 | 0 | 0.0% | 34 | 0.802 | 1.469 |
| 16:53 | 1,152 | 39 | 3.4% | 26 | 0.751 | 1.700 |
| 16:54 | 729 | 200 | 27.4% | 53 | 30.518 | 30.784 |
| 16:55 | 732 | 250 | 34.2% | 60 | 30.326 | 30.554 |
| 16:56 | 643 | 245 | 38.1% | 53 | 30.311 | 30.613 |
| 16:57 | 826 | 278 | 33.7% | 42 | 30.339 | 30.627 |
| 16:58 | 703 | 261 | 37.1% | 62 | 30.312 | 30.562 |
| 16:59 | 674 | 299 | 44.4% | 69 | 30.312 | 30.448 |
The breakdown by major HTTP status codes is shown below. The "normal rate" is calculated as "(total − status=0 − 404) / total."
| Time | Total | 200 | 301 | 404 | 0 | 200 rate | Normal rate |
|---|---|---|---|---|---|---|---|
| 16:45 | 1,542 | 1,417 | 87 | 8 | 1 | 91.9% | 99.4% |
| 16:46 | 1,724 | 1,561 | 126 | 6 | 0 | 90.5% | 99.7% |
| 16:47 | 1,346 | 1,263 | 37 | 16 | 0 | 93.8% | 98.8% |
| 16:48 | 1,441 | 1,369 | 43 | 3 | 1 | 95.0% | 99.7% |
| 16:49 | 1,273 | 1,210 | 27 | 8 | 0 | 95.1% | 99.4% |
| 16:50 | 1,331 | 1,191 | 49 | 17 | 0 | 89.5% | 98.7% |
| 16:51 | 1,657 | 1,600 | 29 | 3 | 0 | 96.6% | 99.8% |
| 16:52 | 1,479 | 1,364 | 41 | 34 | 0 | 92.2% | 97.2% |
| 16:53 | 1,152 | 1,028 | 33 | 26 | 39 | 89.2% | 94.4% |
| 16:54 | 729 | 436 | 27 | 53 | 200 | 59.8% | 65.3% |
| 16:55 | 732 | 357 | 47 | 60 | 250 | 48.8% | 57.7% |
| 16:56 | 643 | 311 | 19 | 53 | 245 | 48.4% | 53.7% |
| 16:57 | 826 | 445 | 47 | 42 | 278 | 53.9% | 61.3% |
| 16:58 | 703 | 328 | 36 | 62 | 261 | 46.7% | 54.1% |
| 16:59 | 674 | 259 | 31 | 69 | 299 | 38.4% | 45.4% |
The progression of the outage is as follows.
- Up to 16:52: Normal (normal rate above 97%, P95 under 1 second)
- 16:53: First signs (39 ClientCommErrors appear)
- 16:54: Outage becomes apparent (
status=0reaches 200, P95 spikes to 30 seconds, per-minute log counts decrease) - 16:55 onward: Normal rate hovers around 50% with no recovery
Since processing times in the logs had extended to approximately 30 seconds, most of the connection failures that occurred at 16:53 are thought to have been recorded in the 16:54 logs.
Degraded Behavior of Existing Failover

This service had CloudFront origin failover configured, with Cloudflare Workers registered as the secondary origin. Even after connections via VPC origins began failing, the top page and article pages were being served normally via this fallback destination. However, dynamic features such as pre-publication previews were not covered by the fallback destination and were experiencing issues, so we implemented a recovery response using a bypass configuration.
Design Decisions for the Bypass Configuration
The approach was to add a route to CloudFront that does not go through VPC origins. Since the failure rate was rising for requests going through VPC origins, we determined that routing around that segment and reaching the existing backend (ALB → ECS in the Tokyo region) would restore functionality.
At the time we began work, there was no certainty that it was a VPC origins outage. Considering the possibility that there was a problem with the route directly entering the Tokyo region VPC via VPC origins from CloudFront, we chose a public ALB in US East (N. Virginia, us-east-1) as the entry point for the route.
The final route is as follows.
CloudFront → Virginia ALB (HTTPS) → Inter-Region VPC Peering → Tokyo NLB (fixed IP) → Tokyo ALB → ECS

Since ALB private IPs can change, a NLB (target type ALB) is placed on the Tokyo side to fix the target across the VPC peering.
Steps to Build the Bypass Configuration
The steps to reach the final configuration are listed in order. Resource identifiers have been replaced with dummy values.
Creating the Inter-Region VPC Peering
A VPC peering connection was created with the default VPC in US East (N. Virginia) (172.31.0.0/16) as the requester and the production VPC in Tokyo (192.168.0.0/18) as the accepter.
aws ec2 create-vpc-peering-connection \
--vpc-id vpc-xxxxxxxxxxxxxxxxx \
--peer-vpc-id vpc-xxxxxxxxxxxxxxxxx \
--peer-region ap-northeast-1 \
--tag-specifications 'ResourceType=vpc-peering-connection,Tags=[{Key=Name,Value=temp-bypass-interregion}]' \
--region us-east-1
VpcPeeringConnectionId: pcx-xxxxxxxxxxxxxxxxx
Status: initiating-request
Accept on the Tokyo region side.
aws ec2 accept-vpc-peering-connection \
--vpc-peering-connection-id pcx-xxxxxxxxxxxxxxxxx \
--region ap-northeast-1
Status: active
Route Table Configuration (Bidirectional)
Add routes to the other side's CIDR to the route tables of both VPCs.
# Virginia side: add route to Tokyo VPC CIDR
aws ec2 create-route \
--route-table-id rtb-xxxxxxxxx \
--destination-cidr-block 192.168.0.0/18 \
--vpc-peering-connection-id pcx-xxxxxxxxxxxxxxxxx \
--region us-east-1
# Tokyo side: add route to Virginia VPC CIDR
aws ec2 create-route \
--route-table-id rtb-xxxxxxxxxxxxxxxxx \
--destination-cidr-block 172.31.0.0/16 \
--vpc-peering-connection-id pcx-xxxxxxxxxxxxxxxxx \
--region ap-northeast-1
Security Group Configuration
A security group for the ALB was created on the Virginia side, allowing HTTP/HTTPS from the internet.
aws ec2 create-security-group \
--group-name temp-bypass-alb-sg \
--description "Temporary bypass ALB SG" \
--vpc-id vpc-xxxxxxxxxxxxxxxxx \
--region us-east-1
aws ec2 authorize-security-group-ingress \
--group-id sg-xxxxxxxxxxxxxxxxx \
--protocol tcp --port 443 --cidr 0.0.0.0/0 \
--region us-east-1
aws ec2 authorize-security-group-ingress \
--group-id sg-xxxxxxxxxxxxxxxxx \
--protocol tcp --port 80 --cidr 0.0.0.0/0 \
--region us-east-1
On the Tokyo side, HTTP from the Virginia VPC was allowed in the existing ALB's security group.
aws ec2 authorize-security-group-ingress \
--group-id sg-xxxxxxxxxxxxxxxxx \
--protocol tcp --port 80 --cidr 172.31.0.0/16 \
--region ap-northeast-1
Tokyo: Creating an Internal NLB (Fixed Private IP, Target Type ALB)
An internal NLB was created in Tokyo to fix the IP as the target across the peering. Private IPs are explicitly assigned to each subnet.
aws elbv2 create-load-balancer \
--name temp-bypass-nlb \
--type network \
--scheme internal \
--subnet-mappings \
SubnetId=subnet-xxxxxxxxxxxxxxxxx,PrivateIPv4Address=192.168.0.10 \
SubnetId=subnet-xxxxxxxxxxxxxxxxx,PrivateIPv4Address=192.168.16.10 \
SubnetId=subnet-xxxxxxxxxxxxxxxxx,PrivateIPv4Address=192.168.32.10 \
--region ap-northeast-1
Fixed IPs: 192.168.0.10, 192.168.16.10, 192.168.32.10
Create a target group with target type alb, register the existing ALB, and create a TCP:80 listener.
aws elbv2 create-target-group \
--name temp-bypass-nlb-tg \
--protocol TCP \
--port 80 \
--target-type alb \
--vpc-id vpc-xxxxxxxxxxxxxxxxx \
--region ap-northeast-1
aws elbv2 register-targets \
--target-group-arn arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/temp-bypass-nlb-tg/xxxxxxxxxxxxxxxx \
--targets Id=arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/existing-alb/xxxxxxxxxxxxxxxx \
--region ap-northeast-1
aws elbv2 create-listener \
--load-balancer-arn arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/net/temp-bypass-nlb/xxxxxxxxxxxxxxxx \
--protocol TCP \
--port 80 \
--default-actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/temp-bypass-nlb-tg/xxxxxxxxxxxxxxxx \
--region ap-northeast-1
Virginia: Creating an Internet-Facing ALB (HTTPS, ACM Wildcard Certificate)
An internet-facing ALB was created in Virginia to serve as the CloudFront origin.
aws elbv2 create-load-balancer \
--name temp-bypass-alb \
--type application \
--scheme internet-facing \
--subnets subnet-xxxxxxxxxxxxxxxxx subnet-xxxxxxxxxxxxxxxxx \
--security-groups sg-xxxxxxxxxxxxxxxxx \
--region us-east-1
DNSName: temp-bypass-alb-xxxxxxxxxx.us-east-1.elb.amazonaws.com
A target group with target type ip was created, and an ACM wildcard certificate was associated with the HTTPS listener. HTTP is redirected to HTTPS.
aws elbv2 create-target-group \
--name temp-bypass-tg \
--protocol HTTP \
--port 80 \
--target-type ip \
--vpc-id vpc-xxxxxxxxxxxxxxxxx \
--region us-east-1
aws elbv2 create-listener \
--load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/temp-bypass-alb/xxxxxxxxxxxxxxxx \
--protocol HTTPS \
--port 443 \
--certificates CertificateArn=arn:aws:acm:us-east-1:123456789012:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
--default-actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/temp-bypass-tg/xxxxxxxxxxxxxxxx \
--region us-east-1
aws elbv2 create-listener \
--load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/temp-bypass-alb/xxxxxxxxxxxxxxxx \
--protocol HTTP \
--port 80 \
--default-actions 'Type=redirect,RedirectConfig={Protocol=HTTPS,Port=443,StatusCode=HTTP_301}' \
--region us-east-1
Registering Virginia ALB → Tokyo NLB Fixed IPs as Targets
Register the fixed private IPs of the Tokyo NLB in the Virginia ALB's target group. Since these are IP targets across VPC peering, AvailabilityZone=all is specified.
aws elbv2 register-targets \
--target-group-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/temp-bypass-tg/xxxxxxxxxxxxxxxx \
--targets Id=192.168.0.10,Port=80,AvailabilityZone=all \
Id=192.168.16.10,Port=80,AvailabilityZone=all \
Id=192.168.32.10,Port=80,AvailabilityZone=all \
--region us-east-1
Registering a DNS CNAME Record
bypass.example.com was set up to reach the ALB, and this hostname was made to match the target domain of the ACM wildcard certificate configured on the ALB's HTTPS listener. This allows it to be used as an HTTPS origin from CloudFront.
Adding an Origin to CloudFront + Switching the Primary in the Failover Group
A new origin bypass-alb-origin was added to the CloudFront distribution. The domain bypass.example.com was specified with HTTPS only (TLSv1.2) as the protocol. The primary in the existing origin failover group was switched to bypass-alb-origin, while the secondary remains the Cloudflare Workers origin.
Recovery Confirmation
Normal operation via the bypass route was confirmed at 18:42 JST. After waiting approximately 1 hour for AWS to recover from the outage (which began at 16:53) without success, work on building the bypass configuration began at 18:03. It took approximately 39 minutes from the start of work to recovery. Normal operation of features such as pre-publication previews was confirmed.
Summary
In response to this CloudFront VPC Origins outage, we followed the guidance from AWS Health to "change their origin type" to one other than VPC origins and switched to a bypass route that does not go through VPC origins. This allowed us to restore the affected dynamic features.
Since the bypass configuration was built for temporary recovery purposes, the added NLB and ALB are scheduled to be removed to avoid unnecessary costs. Going forward, whether to prepare a public subnet in the Tokyo VPC in advance in case of a similar outage is a topic for consideration. Since this workload does not require blocking public access, simply adding a public subnet would have no cost impact. On the other hand, the very existence of a public subnet introduces the risk of IPv4 address charges and unintended exposure. We will consider these tradeoffs as we move forward.
