Connect an AWS VPC to a VPNGeek gateway over an IKEv2 Site-to-Site VPN — customer gateway, VPN connection with two tunnels, and static or BGP routing, end to end.
This guide connects an AWS VPC to a VPNGeek gateway using AWS Site-to-Site VPN over IKEv2. AWS terminates the tunnel on a virtual private gateway (VGW) attached to a single VPC, or on a transit gateway (TGW) when you need to reach many VPCs. Your VPNGeek gateway is registered as a customer gateway, and the VPN connection AWS creates always exposes two tunnel endpoints for redundancy. When you finish, the VPC and the VPNGeek side reach each other over an encrypted link with automatic failover between the two tunnels.
Before you start
Collect the following before you touch either side. Getting these straight now avoids the most common route and phase-mismatch problems later.
- A VPNGeek plan that includes IPsec Gateways, with a static public IP on the gateway — AWS requires a fixed customer gateway address.
- An AWS account with permission to create VPN resources (
ec2:*VpnConnection*,*CustomerGateway*,*VpnGateway*) and to edit route tables. - The AWS CLI v2 configured, or access to the VPC console.
- Non-overlapping CIDRs — for example 10.20.0.0/16 at the VPNGeek side and a VPC CIDR of 10.100.0.0/16.
- Decide up front: static routing (simplest) or BGP (dynamic, needed for TGW and multi-route setups). For BGP, pick a private ASN for each side, e.g. 65010 (AWS) and 65020 (VPNGeek).
1. Create the customer gateway
The customer gateway is AWS's record of your VPNGeek gateway: its public IP and, for BGP, its ASN. Create it first — the VPN connection references it.
aws ec2 create-customer-gateway \
--type ipsec.1 \
--public-ip 203.0.113.10 \
--bgp-asn 65020 \
--tag-specifications \
'ResourceType=customer-gateway,Tags=[{Key=Name,Value=vpngeek-cgw}]'
# For STATIC routing, AWS still requires a BGP ASN field;
# any private ASN is fine since it is unused:
# --bgp-asn 65000
2. Create or identify the AWS-side gateway
Attach a virtual private gateway to the VPC for a single-VPC design, or use an existing transit gateway for a hub that fans out to many VPCs. TGW connections require BGP.
aws ec2 create-vpn-gateway --type ipsec.1 \
--tag-specifications \
'ResourceType=vpn-gateway,Tags=[{Key=Name,Value=vpngeek-vgw}]'
aws ec2 attach-vpn-gateway \
--vpn-gateway-id vgw-0abc123 --vpc-id vpc-0def456
# Option B — reuse an existing Transit Gateway (BGP only)
aws ec2 describe-transit-gateways \
--query 'TransitGateways[].TransitGatewayId'
3. Create the VPN connection
The VPN connection ties the customer gateway to the VGW or TGW. AWS provisions two tunnels, each with its own outside (public) endpoint and inside (169.254.x.x/30) addresses. Use --options StaticRoutesOnly=true for static routing, or omit it for BGP.
aws ec2 create-vpn-connection \
--type ipsec.1 \
--customer-gateway-id cgw-0abc123 \
--vpn-gateway-id vgw-0abc123 \
--options TunnelInsideIpVersion=ipv4
# STATIC routing variant (VGW):
# --options StaticRoutesOnly=true
# To land on a Transit Gateway instead, swap the target:
# --transit-gateway-id tgw-0abc123 # (BGP required)
4. Download the tunnel configuration
AWS generates per-tunnel parameters — outside IPs, inside CIDRs, pre-shared keys, and IKE/IPsec proposals. Pull them and mirror the values on the VPNGeek gateway.
aws ec2 describe-vpn-connections \
--vpn-connection-ids vpn-0abc123 \
--query 'VpnConnections[0].CustomerGatewayConfiguration' \
--output text
# Key fields you will copy to VPNGeek, per tunnel:
# OutsideIpAddress 198.51.100.20 / 198.51.100.21
# TunnelInsideCidr 169.254.21.0/30, 169.254.22.0/30
# PreSharedKey (unique per tunnel)
# IKE version 2 (set IKEv2 explicitly)
# phase1/2 proposal aes256-sha256, DH group 14
5. Configure the two tunnels on VPNGeek
In the dashboard open Gateways > Tunnels and add a tunnel for each AWS outside IP. Set IKE version 2, mirror the AWS proposal, and paste the matching per-tunnel PSK. For BGP, also configure the inside /30 addresses and the eBGP peering.
peer_address: 198.51.100.20 # AWS tunnel 1 outside IP
ike_version: 2
proposal: aes256-sha256 # phase 1 & 2
dh_group: 14
local_subnet: 10.20.0.0/16 # VPNGeek side
remote_subnet: 10.100.0.0/16 # VPC CIDR (static routing)
psk: <aws-tunnel-1-psk>
# BGP (skip remote_subnet, use inside /30 + peering):
# inside_local: 169.254.21.2/30
# inside_peer: 169.254.21.1
# local_asn: 65020
# peer_asn: 65010
# Tunnel 2 — same, with 198.51.100.21 and tunnel-2 PSK
6. Set up routing and route propagation
AWS must know how to reach 10.20.0.0/16, and the VPC subnets' route tables must point that CIDR at the gateway. With BGP, VPNGeek advertises the route and AWS installs it automatically once you enable propagation; with static routing you add it by hand.
aws ec2 create-vpn-connection-route \
--vpn-connection-id vpn-0abc123 \
--destination-cidr-block 10.20.0.0/16
# Enable route propagation into the subnet route table (VGW)
aws ec2 enable-vgw-route-propagation \
--route-table-id rtb-0abc123 --gateway-id vgw-0abc123
# BGP — no manual route needed; verify learned routes:
aws ec2 describe-vpn-connections \
--vpn-connection-ids vpn-0abc123 \
--query 'VpnConnections[0].Routes'
7. Verify the connection
Both tunnels should report UP on the AWS side and ESTABLISHED in the VPNGeek dashboard within about a minute. Confirm the tunnel state, then send real traffic between an EC2 instance and a host on the VPNGeek side.
aws ec2 describe-vpn-connections \
--vpn-connection-ids vpn-0abc123 \
--query 'VpnConnections[0].VgwTelemetry[].{ip:OutsideIpAddress,status:Status,routes:AcceptedRouteCount}'
# From an EC2 instance in the VPC:
ping 10.20.0.1
# Make sure the instance's security group + NACL allow ICMP/traffic
# from 10.20.0.0/16 before blaming the tunnel.
Troubleshooting
Tunnels stuck DOWN / negotiating
Almost always a per-tunnel PSK pasted into the wrong tunnel, an IKE version mismatch (force IKEv2 on VPNGeek — AWS accepts either), or a proposal/DH-group mismatch. Confirm aes256-sha256 and DH group 14 on both sides for both tunnels.
Tunnels UP but no traffic
Missing route propagation, a subnet route table that does not point 10.20.0.0/16 at the VGW/TGW, or a security group / NACL blocking the traffic. For static routing, confirm the create-vpn-connection-route ran. For BGP, check AcceptedRouteCount is non-zero.
Only one tunnel comes up
Expected in steady state — AWS keeps the second as standby. It becomes a problem only if the primary drops and the second was misconfigured. Verify both outside IPs and both PSKs are set on VPNGeek.
BGP session will not establish
Check the inside /30 addresses match AWS's assignment exactly (VPNGeek uses .2, AWS uses .1) and that the local/peer ASNs are not swapped. AWS uses 64512–65534 private ASNs by default.
