A single Direct Connect link is a single point of failure. A fiber cut or a facility outage can take your entire hybrid network down. The standard, cheap insurance is a Site-to-Site VPN over the public internet, attached to the same Transit Gateway, that carries traffic only when Direct Connect is unavailable.
This page builds that backup from the SDK: register the on-premises router, create the VPN connection to the Transit Gateway, and rely on BGP so failover is automatic. No packet-mover here is physical - the VPN is entirely software over an internet path you already have.
Two calls stand up the AWS side. CreateCustomerGateway describes your on-premises router; CreateVpnConnection builds the IPsec connection from AWS to it, attached to the Transit Gateway.
# --- Python (boto3) ---import boto3ec2 = boto3.client("ec2", region_name="us-east-1")cgw = ec2.create_customer_gateway( Type="ipsec.1", IpAddress="203.0.113.10", # your router's public IP BgpAsn=65001, # your on-prem BGP ASN)cgw_id = cgw["CustomerGateway"]["CustomerGatewayId"]vpn = ec2.create_vpn_connection( Type="ipsec.1", CustomerGatewayId=cgw_id, TransitGatewayId="tgw-0abc123", Options={"StaticRoutesOnly": False}, # dynamic (BGP) routing)print(vpn["VpnConnection"]["VpnConnectionId"])
StaticRoutesOnly: false selects dynamic routing over BGP, which is what makes failover automatic. Attaching to TransitGatewayId puts the VPN on the same hub as Direct Connect, so both advertise the same on-premises prefixes and the hub can choose between them.
The VPN connection ships with configuration for your router. Pull it out of the response and hand it to your network team - it contains the two tunnels' endpoints and pre-shared keys.
# --- Python (boto3) ---resp = ec2.describe_vpn_connections( VpnConnectionIds=["vpn-0abc123"],)conn = resp["VpnConnections"][0]print("state:", conn["State"])for t in conn["VgwTelemetry"]: print("tunnel", t["OutsideIpAddress"], t["Status"]) # UP or DOWN# conn["CustomerGatewayConfiguration"] is the full XML for your router
// --- TypeScript (AWS SDK v3) ---import { DescribeVpnConnectionsCommand } from "@aws-sdk/client-ec2";const resp = await ec2.send(new DescribeVpnConnectionsCommand({ VpnConnectionIds: ["vpn-0abc123"],}));const conn = resp.VpnConnections?.[0];console.log("state:", conn?.State);for (const t of conn?.VgwTelemetry ?? []) { console.log("tunnel", t.OutsideIpAddress, t.Status); // UP or DOWN}// conn.CustomerGatewayConfiguration is the full XML for your router
VgwTelemetry reports each tunnel's status. AWS always provisions two tunnels per VPN connection for redundancy, terminating on different AWS endpoints. Your router should establish both; a healthy backup has both tunnels UP even while idle.
The whole point of the backup is that no human has to flip anything when Direct Connect drops. That comes from BGP path selection on the Transit Gateway.
When both the transit VIF (Direct Connect) and the VPN advertise the same on-premises prefixes, the Transit Gateway prefers Direct Connect. AWS documents this preference order: a Direct Connect route is chosen over an equivalent VPN route. So while DX is healthy the VPN sits idle, both tunnels up but carrying no production traffic. When DX withdraws its routes - because the link went down - the VPN's routes are the only ones left, and traffic shifts to it within BGP's reconvergence time.
You do not script any of this. You wire both attachments to the hub with dynamic routing and let route withdrawal do the work.
If you want to nudge which path wins - for example to prefer one tunnel, or to make on-premises prefer DX for the return path - you influence it from your router with BGP attributes like AS-path prepending and local preference, not from the SDK. The AWS side honors the routes it receives.
You can, however, control which prefixes the VPN advertises by adjusting the on-premises BGP config, and on the AWS side you manage propagation into the Transit Gateway route table the same way as any attachment.
# --- Python (boto3) ---# let the VPN attachment propagate its routes into the hub's route tableec2.enable_transit_gateway_route_table_propagation( TransitGatewayRouteTableId="tgw-rtb-corp", TransitGatewayAttachmentId="tgw-attach-0vpn",)
// --- TypeScript (AWS SDK v3) ---import { EnableTransitGatewayRouteTablePropagationCommand } from "@aws-sdk/client-ec2";// let the VPN attachment propagate its routes into the hub's route tableawait ec2.send(new EnableTransitGatewayRouteTablePropagationCommand({ TransitGatewayRouteTableId: "tgw-rtb-corp", TransitGatewayAttachmentId: "tgw-attach-0vpn",}));
With both the DX and VPN attachments propagating the same prefixes into the table, the Transit Gateway holds both and its preference logic picks DX until it disappears.
If your on-premises router does not speak BGP, set StaticRoutesOnly: true and add the prefixes with CreateVpnConnectionRoute. But understand the cost: static routes do not withdraw on failure, so a static VPN behind a Direct Connect link does not give you clean automatic failover. Prefer dynamic routing for any backup role.
Using static routing for a backup. Static routes never withdraw, so failover is not automatic. Use BGP (StaticRoutesOnly: false) so a downed DX link cleanly cedes to the VPN.
Bringing up only one tunnel. AWS provisions two tunnels per connection for redundancy. Configure both on your router, or you lose the VPN's own resilience.
Expecting to script failover. You do not. BGP route withdrawal shifts traffic automatically; there is no SDK call that "fails over" the network.
Attaching the VPN to a different hub. The VPN must attach to the same Transit Gateway as Direct Connect so both advertise the same prefixes and the hub can choose between them.
Forgetting the customer gateway's public IP or ASN.CreateCustomerGateway needs your router's real public IP and BGP ASN; a wrong value means tunnels or BGP never come up.
Assuming the VPN matches DX bandwidth. A single VPN tunnel is capped (around 1.25 Gbps of aggregate throughput). It is a survival path, not a full-bandwidth replacement.
A second Direct Connect connection at another location for a backup that matches primary bandwidth and stays fully private - at higher cost than a VPN.
Two VPN connections to different customer gateways when you have no Direct Connect at all and want internet-based redundancy on its own.
Accelerated Site-to-Site VPN (using AWS Global Accelerator) when the plain internet path to the VPN endpoints is too jittery.
Static-route VPN only when the on-premises device cannot run BGP - accepting that failover is then manual or slow.
Pair every Direct Connect link with a dynamic-routing Site-to-Site VPN on the same hub as cheap automatic insurance; upgrade the backup to a second DX at another location when the workload cannot tolerate reduced bandwidth during an outage.
A single Direct Connect link is a single point of failure. A Site-to-Site VPN over the internet, attached to the same Transit Gateway, is a cheap path that carries traffic only when Direct Connect is down.
How does failover happen automatically?
Through BGP. Both paths advertise the same prefixes; the Transit Gateway prefers Direct Connect. When DX withdraws its routes on failure, only the VPN routes remain and traffic shifts, with no manual action.
How many tunnels does a VPN connection have?
Two. AWS always provisions two tunnels per Site-to-Site VPN connection, terminating on different endpoints for redundancy. Configure both on your router so the backup is itself resilient.
Should I use static or dynamic routing for the backup?
Dynamic (BGP). Static routes do not withdraw on failure, so a static VPN behind Direct Connect will not fail over cleanly. Set StaticRoutesOnly to false.
Does the SDK trigger the failover?
No. There is no failover API call. You wire both attachments to the hub with BGP and let route withdrawal move traffic. The SDK only sets up the connection.
What does CreateCustomerGateway need?
Your on-premises router's public IP address and BGP ASN, plus Type of ipsec.1. These must match the real device or the tunnels and BGP session will not establish.
Can the VPN carry the same bandwidth as Direct Connect?
Not usually. A VPN tunnel is capped around 1.25 Gbps of aggregate throughput. Treat it as a survival path; if you need matching bandwidth on failure, use a second Direct Connect connection instead.
How do I check the VPN tunnels are healthy?
Call DescribeVpnConnections and read VgwTelemetry, which reports each tunnel's Status as UP or DOWN. A healthy idle backup shows both tunnels UP.