# Fix AWS VPN Connection Down

Your Site-to-Site VPN connection to AWS shows as DOWN, or traffic isn't flowing between your on-premises network and VPC. VPN connections have two tunnels for redundancy, but when both fail, you lose connectivity entirely. The issue could be with the VPN configuration, your customer gateway device, routing, or even the underlying network.

This guide covers diagnosing VPN failures and restoring connectivity.

Diagnosis Commands

First, check the VPN connection status:

bash
aws ec2 describe-vpn-connections \
  --vpn-connection-ids vpn-1234567890abcdef0 \
  --query 'VpnConnections[*].[VpnConnectionId,State,Type,VgwTelemetry]'

Get detailed tunnel telemetry:

bash
aws ec2 describe-vpn-connections \
  --vpn-connection-ids vpn-1234567890abcdef0 \
  --query 'VpnConnections[0].VgwTelemetry[*].[OutsideIpAddress,Status,StatusMessage,LastStatusChange]'

Check the VPN gateway (VGW):

bash
aws ec2 describe-vpn-gateways \
  --vpn-gateway-ids vgw-1234567890abcdef0 \
  --query 'VpnGateways[*].[VpnGatewayId,State,Type,VpcAttachments[*].State]'

Check the customer gateway configuration:

bash
aws ec2 describe-customer-gateways \
  --customer-gateway-ids cgw-1234567890abcdef0 \
  --query 'CustomerGateways[*].[CustomerGatewayId,State,Type,IpAddress,BgpAsn]'

Get the VPN configuration for your device:

bash
aws ec2 get-vpn-connection-configuration \
  --vpn-connection-id vpn-1234567890abcdef0 \
  --query 'VpnConnectionConfiguration'

Check routes propagated to route tables:

bash
aws ec2 describe-route-tables \
  --filters "Name=vpc-id,Values=vpc-12345" \
  --query 'RouteTables[*].Routes[?Origin==`VpnGateway`]'

Check VPC route tables for static VPN routes:

bash
aws ec2 describe-route-tables \
  --filters "Name=vpc-id,Values=vpc-12345" \
  --query 'RouteTables[*].Routes[?GatewayId==`vpn-1234567890abcdef0`]'

Common Causes and Solutions

Tunnel Not Established

VPN tunnel shows DOWN or IPSEC_NEGOTIATION_ERROR:

Check tunnel status:

bash
aws ec2 describe-vpn-connections \
  --vpn-connection-ids vpn-1234567890abcdef0 \
  --query 'VpnConnections[0].VgwTelemetry[*].[OutsideIpAddress,Status,StatusMessage]'

Common status messages and causes:

IPSEC_NEGOTIATION_ERROR: - Pre-shared keys don't match - IKE versions incompatible - Encryption algorithms mismatch

Check your customer gateway configuration:

bash
aws ec2 get-vpn-connection-configuration \
  --vpn-connection-id vpn-1234567890abcdef0 \
  --output text > vpn-config.txt

Compare settings with your on-premises device: - Pre-shared key (PSK) - IKE version (v1 or v2) - Encryption algorithms (AES-128, AES-256) - Integrity algorithms (SHA1, SHA2-256, SHA2-384) - Diffie-Hellman groups (2, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24)

On your customer gateway device (e.g., Cisco ASA):

```bash # Check IPsec status show crypto ipsec sa

# Check IKE status show crypto ikev2 sa

# Check tunnel interface show interface tunnel0 ```

Update VPN connection options if needed:

bash
aws ec2 modify-vpn-connection-options \
  --vpn-connection-id vpn-1234567890abcdef0 \
  --local-ipv4-network-cidr 10.0.0.0/16 \
  --remote-ipv4-network-cidr 192.168.1.0/24

BGP Not Establishing

For BGP-based VPN, the tunnel might establish but BGP doesn't:

bash
aws ec2 describe-vpn-connections \
  --vpn-connection-ids vpn-1234567890abcdef0 \
  --query 'VpnConnections[0].VgwTelemetry[*].[Status,BgpStatus]'

If BGP shows DOWN:

Verify BGP ASN matches:

bash
aws ec2 describe-customer-gateways \
  --customer-gateway-ids cgw-1234567890abcdef0 \
  --query 'CustomerGateways[*].BgpAsn'

On your device, check BGP configuration:

```bash # Cisco example show bgp summary show bgp neighbors

# Juniper example show bgp summary show bgp neighbor 169.254.x.x ```

BGP peering uses 169.254.x.x addresses inside the tunnel:

bash
# Get BGP peer IPs from VPN configuration
aws ec2 describe-vpn-connections \
  --vpn-connection-ids vpn-1234567890abcdef0 \
  --query 'VpnConnections[0].Routes'

Ensure your device advertises correct routes:

bash
# Cisco - advertise routes
router bgp 65000
  network 192.168.1.0 mask 255.255.255.0
  neighbor 169.254.x.x remote-as 64512
  neighbor 169.254.x.x activate

Customer Gateway IP Wrong

The customer gateway IP doesn't match your device's public IP:

bash
aws ec2 describe-customer-gateways \
  --customer-gateway-ids cgw-1234567890abcdef0 \
  --query 'CustomerGateways[*].IpAddress'

Compare with your device's actual public IP:

bash
# Check your firewall/router's WAN interface
show interface outside
# or
show interface GigabitEthernet0/0

If they don't match, recreate the customer gateway:

```bash # Delete old customer gateway (must delete VPN first) aws ec2 delete-vpn-connection --vpn-connection-id vpn-1234567890abcdef0 aws ec2 delete-customer-gateway --customer-gateway-id cgw-1234567890abcdef0

# Create new with correct IP aws ec2 create-customer-gateway \ --type ipsec.1 \ --public-ip 203.0.113.50 \ --bgp-asn 65000

# Create new VPN connection aws ec2 create-vpn-connection \ --type ipsec.1 \ --customer-gateway-id cgw-new \ --vpn-gateway-id vgw-1234567890abcdef0 ```

Firewall Blocking VPN Traffic

Your on-premises firewall blocks VPN ports:

Required ports for AWS VPN: - UDP 500 (IKE) - UDP 4500 (NAT-T for IPsec) - IP protocol 50 (ESP) - if not using NAT-T

Check firewall rules:

```bash # Cisco ASA show access-list show run access-list outside_in

# Palo Alto show running security-policy ```

Add rules to allow VPN traffic:

bash
# Cisco ASA configuration
access-list outside_in extended permit udp host 203.0.113.50 host <AWS_VPN_IP> eq 500
access-list outside_in extended permit udp host 203.0.113.50 host <AWS_VPN_IP> eq 4500
access-list outside_in extended permit esp host 203.0.113.50 host <AWS_VPN_IP>

NAT Traversal Issues

If your device is behind NAT, NAT-T must be enabled:

bash
aws ec2 describe-vpn-connections \
  --vpn-connection-ids vpn-1234567890abcdef0 \
  --query 'VpnConnections[0].Options.EnableTunnelInsideNat'

If your customer gateway is behind NAT:

```bash # Enable NAT traversal on your device # Cisco ASA crypto ikev2 policy 10 encryption aes-cbc-256 integrity sha256 group 19 prf sha256 lifetime seconds 28800

crypto ipsec transform-set ESP-AES-256-SHA esp-aes-256 esp-sha-hmac mode tunnel

# NAT-T is usually auto-enabled crypto map outside_map 10 set nat-t keepalive ```

Routing Not Propagated

BGP is up but routes aren't in VPC route table:

bash
aws ec2 describe-route-tables \
  --route-table-ids rtb-12345 \
  --query 'RouteTables[*].Routes[?Origin==`VpnGateway`]'

Enable route propagation:

bash
aws ec2 enable-vgw-route-propagation \
  --route-table-id rtb-12345 \
  --gateway-id vgw-1234567890abcdef0

Check if your device is advertising routes:

```bash # On your device, check advertised routes show bgp advertised-routes

# Or show route advertising-protocol bgp ```

Static Routes Not Configured

For static VPN (non-BGP), you need to add routes manually:

bash
aws ec2 create-route \
  --route-table-id rtb-12345 \
  --destination-cidr-block 192.168.1.0/24 \
  --gateway-id vpn-1234567890abcdef0

On your side, add routes pointing to tunnel interface:

bash
# Cisco example
ip route vrf AWS 10.0.0.0 255.255.0.0 Tunnel0

VPC Attachment Issues

VGW not attached to VPC:

bash
aws ec2 describe-vpn-gateways \
  --vpn-gateway-ids vgw-1234567890abcdef0 \
  --query 'VpnGateways[*].VpcAttachments[*].[VpcId,State]'

If detached, attach it:

bash
aws ec2 attach-vpn-gateway \
  --vpn-gateway-id vgw-1234567890abcdef0 \
  --vpc-id vpc-12345

Overlapping CIDR Blocks

VPN CIDRs overlap with VPC or other networks:

bash
aws ec2 describe-vpn-connections \
  --vpn-connection-ids vpn-1234567890abcdef0 \
  --query 'VpnConnections[*].Options.[LocalIpv4NetworkCidr,RemoteIpv4NetworkCidr]'

Check VPC CIDR:

bash
aws ec2 describe-vpcs \
  --vpc-ids vpc-12345 \
  --query 'Vpcs[*].CidrBlock'

If overlapping, use specific subnet CIDRs:

bash
aws ec2 modify-vpn-connection-options \
  --vpn-connection-id vpn-1234567890abcdef0 \
  --local-ipv4-network-cidr 10.0.1.0/24 \
  --remote-ipv4-network-cidr 192.168.1.0/24

Dead Peer Detection (DPD)

DPD timeout causing tunnel resets:

AWS VPN uses DPD to detect dead peers. If your device doesn't respond, AWS tears down the tunnel.

Configure DPD on your device:

```bash # Cisco ASA crypto ikev2 dpd 10 2 on-demand

# Juniper SRX set security ike policy ike-policy1 dead-peer-detection interval 10 threshold 5 mode optimize ```

Tunnel Inside IP Conflict

Inside tunnel IPs (169.254.x.x) conflict:

bash
aws ec2 describe-vpn-connections \
  --vpn-connection-ids vpn-1234567890abcdef0 \
  --query 'VpnConnections[0].VgwTelemetry[*].InsideIpAddress'

If you have multiple VPNs, ensure tunnel inside IPs don't overlap. They're automatically assigned by AWS, so conflicts are rare.

Verification Steps

After fixing, verify VPN status:

```bash # Check tunnel status aws ec2 describe-vpn-connections \ --vpn-connection-ids vpn-1234567890abcdef0 \ --query 'VpnConnections[0].VgwTelemetry[*].[Status,BgpStatus,LastStatusChange]'

# Check routes aws ec2 describe-route-tables \ --filters "Name=route.state,Values=active" "Name=route.origin,Values=VpnGateway" \ --query 'RouteTables[*].Routes[?GatewayId==vpn-1234567890abcdef0]' ```

Test connectivity:

```bash # Ping from EC2 instance to on-premises ping 192.168.1.10

# SSH or connect to on-premises server ssh user@192.168.1.10

# Check from on-premises to AWS ping 10.0.1.50 ```

VPN diagnostic script:

```bash #!/bin/bash VPN_ID="vpn-1234567890abcdef0"

echo "AWS VPN Connection Diagnostics" echo "==============================="

echo "1. VPN Connection Status:" aws ec2 describe-vpn-connections \ --vpn-connection-ids $VPN_ID \ --query 'VpnConnections[*].[VpnConnectionId,State]'

echo "" echo "2. Tunnel Telemetry:" aws ec2 describe-vpn-connections \ --vpn-connection-ids $VPN_ID \ --query 'VpnConnections[0].VgwTelemetry[*].[OutsideIpAddress,Status,BgpStatus,StatusMessage,LastStatusChange]'

echo "" echo "3. VPN Gateway Status:" VGW=$(aws ec2 describe-vpn-connections --vpn-connection-ids $VPN_ID --query 'VpnConnections[0].VpnGatewayId' --output text) aws ec2 describe-vpn-gateways \ --vpn-gateway-ids $VGW \ --query 'VpnGateways[*].[VpnGatewayId,State,VpcAttachments[*].State]'

echo "" echo "4. Customer Gateway:" CGW=$(aws ec2 describe-vpn-connections --vpn-connection-ids $VPN_ID --query 'VpnConnections[0].CustomerGatewayId' --output text) aws ec2 describe-customer-gateways \ --customer-gateway-ids $CGW \ --query 'CustomerGateways[*].[CustomerGatewayId,IpAddress,BgpAsn,State]'

echo "" echo "5. Routes in VPC Route Tables:" VPC=$(aws ec2 describe-vpn-gateways --vpn-gateway-ids $VGW --query 'VpnGateways[0].VpcAttachments[0].VpcId' --output text) aws ec2 describe-route-tables \ --filters "Name=vpc-id,Values=$VPC" \ --query 'RouteTables[*].Routes[?GatewayId=='${VPN_ID}']'

echo "" echo "6. Route Propagation Status:" aws ec2 describe-route-tables \ --filters "Name=vpc-id,Values=$VPC" \ --query 'RouteTables[*].PropagatingVgws[*].GatewayId' ```

Set up monitoring:

bash
# CloudWatch alarm for tunnel down
aws cloudwatch put-metric-alarm \
  --alarm-name vpn-tunnel-down \
  --alarm-description "VPN tunnel is down" \
  --namespace AWS/VPN \
  --metric-name TunnelState \
  --dimensions Name=VpnConnectionId,Value=$VPN_ID Name=TunnelIpAddress,Value=<tunnel-ip> \
  --statistic Minimum \
  --period 60 \
  --threshold 1 \
  --comparison-operator LessThanThreshold \
  --evaluation-periods 2 \
  --alarm-actions arn:aws:sns:us-east-1:123456789012:alerts