← Back to list

The Complete Guide to Building a Production-Ready AWS Site-to-Site VPN (IPSec)

Securely connecting an on-premises data center to AWS — from design to day-2 troubleshooting

Bishaldhimal · 2026-08-04 05:46 · 0 claps · 24.1 min read
#aws-site-to-site-vpn #vpn-connection #onpremise-to-cloud #cloud-migration #onprem-migration
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud

The Complete Guide to Building a Production-Ready AWS Site-to-Site VPN (IPSec)

Securely connecting an on-premises data center to AWS — from design to day-2 troubleshooting

Table of Contents

  1. Introduction
  2. Hybrid Network Architecture
  3. Core AWS VPN Components
  4. IPSec and IKE Fundamentals
  5. VPN Packet Flow
  6. On-Premises to AWS: Detailed Component & Packet Walkthrough
  7. Network Planning
  8. Building the AWS Side
  9. Configuring the Customer Gateway Device
  10. Detailed Step-by-Step Implementation Walkthrough (Worked Example)
  11. Understanding the “Download Configuration” Vendor Selection
  12. Configuring IPSec (StrongSwan Example)
  13. Routing: Static vs. BGP
  14. Tunnel Monitoring and Automatic Failover
  15. Verification
  16. Troubleshooting Playbook
  17. Case Study: Reading Real Cisco Nexus + VPC Flow Log Output
  18. The “VPN Connection Available but Both Tunnels Down” Failure Mode
  19. Security Best Practices
  20. Cost Considerations
  21. Conclusion
  22. Appendix: Command & Terminology Reference

1. Introduction

Connecting an on-premises data center to AWS is one of the most common first steps in a cloud journey. Rather than exposing internal systems to the public internet, organizations build an encrypted tunnel between their data center and their AWS Virtual Private Cloud (VPC).

This guide walks through AWS Managed Site-to-Site (S2S) VPN, using both a Linux/StrongSwan gateway and a Cisco Nexus gateway as reference implementations, and — critically — how to operate and troubleshoot the connection once it’s live. Most tutorials stop at “tunnel is UP.” This one goes further, into packet flow, flow log interpretation, and the specific failure mode where the VPN connection shows “Available” while both tunnels are down.

AWS Managed VPN vs. Direct Connect: VPN is IPSec-encrypted, runs over the public internet, spins up in minutes, and costs little to provision — ideal for moderate traffic, DR links, and getting started quickly. Direct Connect is a dedicated private circuit into an AWS Direct Connect location, offering consistent low latency and higher bandwidth, but requires physical cross-connects and longer lead times. Many production environments run VPN as a backup path even after Direct Connect is in place.

2. Hybrid Network Architecture

AWS always provisions two tunnels per VPN connection, terminating on two different public IP addresses in different AWS availability zones/data centers. This is not optional — it’s how AWS guarantees the SLA. If Tunnel 1 fails (maintenance, ISP issue, device restart), Tunnel 2 keeps carrying traffic.

3. Core AWS VPN Components

4. IPSec and IKE Fundamentals

Every VPN device — Cisco, Fortinet, Palo Alto, StrongSwan, pfSense — speaks the same underlying standard: IKE (Internet Key Exchange) and IPSec. The protocol is universal; the configuration syntax is vendor-specific (more on this in Section 9).

  • IKE Phase 1 (IKE SA): Negotiates a secure, authenticated channel between the two peers using pre-shared keys (or certificates), an encryption algorithm, a hash algorithm, and a Diffie-Hellman (DH) group.
  • IKE Phase 2 (Child SA / IPSec SA): Uses the Phase 1 channel to negotiate the actual data-encryption parameters and establishes the tunnel that carries traffic.
  • ESP (Encapsulating Security Payload): The protocol that actually encrypts and authenticates the data packets (IP protocol 50).
  • Perfect Forward Secrecy (PFS): Ensures that even if a key is later compromised, past traffic can’t be decrypted, because each session generates fresh key material.
  • Dead Peer Detection (DPD): Periodic keepalive/heartbeat so each side can detect a dead peer and tear down/rebuild the tunnel instead of blackholing traffic.
  • Rekeying: Both Phase 1 and Phase 2 SAs have a lifetime (AWS typically negotiates ~8 hours for Phase 1) and are renegotiated before expiry to avoid a connectivity gap.

5. VPN Packet Flow

Only traffic matching the traffic selectors (the CIDR pairs agreed during Phase 2 negotiation — e.g., on-prem 10.9.0.0/16 ↔ AWS 10.27.0.0/16) is sent through the tunnel. Anything else takes the normal internet path.

6. On-Premises to AWS: Detailed Component & Packet Walkthrough

Section 5 showed the packet flow at a high level. This section clears up a common misconception about which devices actually participate in the VPN, then walks the same journey again in full detail — from a private on-prem host, through the firewall, across the internet, into AWS, and back.

Clearing up the Customer Gateway misconception

The AWS Customer Gateway (CGW) is not an actual gateway device — it’s a logical AWS object.

So the two devices that actually build and terminate the IPSec tunnel are your on-prem firewall and AWS’s Virtual Private Gateway — not the CGW object, and not your private servers or EC2 instances.

The on-premises side

The firewall has an inside interface facing the private company network and an outside interface facing the internet. Private hosts (10.9.1.10, 10.9.2.20, 10.9.3.30) never talk to the internet directly — all VPN-bound traffic passes through this firewall.

The AWS side

EC2, RDS, and ECS resources are entirely private. They have no awareness of your on-prem public IP or of encryption at all — they simply see private IP traffic arrive, exactly as if it came from another private subnet.

What AWS stores before any packet flows

Customer Gateway (metadata only):

Public IP:       116.68.210.105
Routing:         Static
Remote Network:  10.9.0.0/16

This is AWS’s note to itself: “If I need to reach the customer’s network, build tunnels to 116.68.210.105.”

Virtual Private Gateway (the real endpoint): It owns two public tunnel endpoints, e.g.:

Tunnel 1:  3.108.103.116
Tunnel 2:  13.234.88.25

These are the actual public IPs your on-prem firewall connects to.

Tunnel establishment

Internet

116.68.210.105  <=================> 3.108.103.116
     Firewall          IPSec Tunnel        AWS VGW

116.68.210.105  <=================> 13.234.88.25
     Firewall          IPSec Tunnel        AWS VGW

The tunnels exist strictly between the firewall and the Virtual Private Gateway — never between the CGW object, private servers, or EC2 directly.

Step-by-step packet journey

  1. A packet starts on-prem. An application server at 10.9.1.10 wants to reach an EC2 instance at 10.27.1.100:
SRC = 10.9.1.10
DST = 10.27.1.100

2. The packet reaches the firewall. It checks its VPN policy (traffic selector): does 10.9.0.0/16 → 10.27.0.0/16 match? Yes — so the packet is marked for encryption.

3. Encryption / encapsulation. The original packet is wrapped inside a new, encrypted IPSec packet with a new outer header:

+-----------------------------------------+
| Public Header                           |
| SRC = 116.68.210.105                    |
| DST = 3.108.103.116                     |
+-----------------------------------------+
| Encrypted Payload                       |
| SRC = 10.9.1.10                         |
| DST = 10.27.1.100                       |
+-----------------------------------------+

4. Across the internet. Every router in between sees only the outer, public header (116.68.210.105 → 3.108.103.116). None of them have visibility into the private 10.9.x.x or 10.27.x.x addresses — those stay encrypted inside the payload.

5. AWS receives and decrypts. The Virtual Private Gateway receives the outer packet, decrypts it, and recovers the original:

SRC = 10.9.1.10
DST = 10.27.1.100

6. AWS routing. The VPC route table sends traffic destined for 10.9.0.0/16 to the VGW, and the VGW forwards the now-decrypted packet into the VPC. The EC2 instance receives it exactly as if it arrived from another private network — no awareness of encryption or the public internet hop involved.

7. Return traffic. The EC2 instance replies with SRC = 10.27.1.100, DST = 10.9.1.10. The VPC route table sends this back to the VGW, which encrypts it and sends it through the tunnel to the firewall, which decrypts it and forwards it to 10.9.1.10 on the LAN.

Complete flow, end to end

The core mental model to keep

  • Private servers do not build the VPN — they just send and receive normal private IP traffic.
  • Firewalls (or dedicated VPN appliances) build the VPN, not the servers behind them.
  • The AWS Customer Gateway does not process traffic — it’s only a configuration object describing your on-prem endpoint to AWS.
  • The Virtual Private Gateway is the real AWS-side VPN endpoint that performs actual encryption and decryption.
  • Only the firewall and the VGW ever terminate IPSec — everything behind them, on either side, just exchanges ordinary private IP traffic through what looks like a transparent, secure doorway between the two networks.

This mental model is the foundation for everything that follows — routing, failover, and troubleshooting all make far more sense once it’s clear which two devices are actually doing the encryption work.

7. Network Planning

Before touching the AWS console, design:

  • VPC CIDR (e.g., 10.0.0.0/16 or 10.27.0.0/16)
  • On-premises CIDR (e.g., 172.16.0.0/16 or 10.9.0.0/16)
  • No overlap between the two — overlapping CIDRs are one of the most common reasons a VPN “works” (tunnel UP) but routing behaves unpredictably
  • BGP ASN if using dynamic routing (AWS default ASN is 64512, but you can specify a custom on-prem ASN)
  • Security policy: which subnets on each side are actually allowed to talk to which, and over which protocols

8. Building the AWS Side

  1. Create a Customer Gateway — VPC Console → Customer Gateways → Create. Provide your on-prem device’s static public IP and routing type (static or BGP/dynamic).
  2. Create a Virtual Private Gateway — VPC → Virtual Private Gateways → Create, then Attach to VPC.
  3. Create the Site-to-Site VPN Connection — select the VGW and CGW, choose static or dynamic routing (enter your on-prem CIDR if static). AWS automatically provisions two tunnels with distinct public IPs, PSKs, and inside-tunnel IP ranges.
  4. Download the configuration — Actions → Download Configuration, selecting the vendor/platform/software that matches your device (see Section 9).
  5. Update the VPC route table — add a route for the on-prem CIDR with the VGW (or TGW) as the target, propagated automatically if you enable route propagation.
  6. Update Security Groups / NACLs — allow the required protocols (ICMP, SSH, RDP, app ports) from the on-prem CIDR.
  7. Launch a private EC2 instance (no public IP) to validate that connectivity works without exposing the workload to the internet.

9. Configuring the Customer Gateway Device

StrongSwan (Linux)

sudo apt update
sudo apt install strongswan
ipsec version

Paste AWS’s generated tunnel parameters into /etc/ipsec.conf (local/remote IDs, encryption, DH group, lifetime, rekey margin) and the PSKs into /etc/ipsec.secrets:

<local-public-ip> <remote-tunnel-ip> : PSK "generated-by-aws"
sudo systemctl restart strongswan
sudo ipsec statusall

Cisco IOS / IOS XE / Nexus (NX-OS)

Identify your exact platform first:

show version
show inventory

Configuration centers on crypto isakmp policy, crypto ipsec transform-set, a crypto map bound to the outside interface, and an extended ACL defining the traffic selector (the same permit ip <on-prem CIDR> <aws CIDR> pattern seen in the case study below).

FortiGate

config vpn ipsec phase1-interface
config vpn ipsec phase2-interface

Configured via CLI or GUI under VPN → IPsec Tunnels.

Palo Alto

Configured almost entirely through the GUI: Network → IPSec Tunnels, IKE Crypto Profile, IPSec Crypto Profile.

All of these ultimately negotiate the same IKE/IPSec parameters — they just express them differently.

10. Detailed Step-by-Step Implementation Walkthrough (Worked Example)

Sections 7–9 covered the process at a conceptual level. This section walks through the entire build, end to end, with exact console steps, exact on-prem device steps, firewall rule management, and verification — using a real downloaded AWS configuration file as the worked example so every value below is concrete rather than abstract.

10.1 Prerequisites checklist

Before opening the AWS console, confirm you have:

  • Customer gateway device identified — vendor, platform, and software version (or “Generic” if using a Linux/StrongSwan box or an unlisted device)
  • A static, internet-routable public IP on the device’s outside/WAN interface
  • Decision on routing type: static (simplest, good for a single fixed on-prem CIDR) or dynamic/BGP (requires an ASN — AWS applies a default ASN if you don’t specify one; optionally a private certificate from AWS Private CA if authenticating the VPN via certificate instead of PSK)
  • The on-prem CIDR(s) that need to reach AWS, and the VPC CIDR they need to reach
  • Administrative/console access to both the AWS account and the on-prem firewall
  • Confirmation that no other VPN or route already uses an overlapping CIDR

10.2 AWS Console — Step by Step

Step 1 — Create the Customer Gateway

VPC Console → Customer GatewaysCreate Customer Gateway

Click Create Customer Gateway. AWS assigns it an ID like cgw-0ee2bdf986914f4a6. Remember: this is metadata only — it tells AWS where your device is, it does not process traffic (see Section 6).

Step 2 — Create the Target Gateway (VGW or Transit Gateway)

Option A — Virtual Private Gateway (single VPC): VPC Console → Virtual Private GatewaysCreate Virtual Private Gateway → give it a name → optionally set a custom ASN → Create.

Then: select it → ActionsAttach to VPC → choose the target VPC.

Option B — Transit Gateway (multiple VPCs/accounts, hub-and-spoke): VPC Console → Transit GatewaysCreate Transit Gateway, then attach your VPC(s) to it via a Transit Gateway VPC Attachment. Use this instead of a VGW when you expect to connect more than one VPC to the same on-prem network.

Step 3 — Create the Site-to-Site VPN Connection

VPC Console → Site-to-Site VPN ConnectionsCreate VPN Connection

Click Create VPN Connection. AWS provisions it in a few minutes and assigns an ID like vpn-04c77bd0402b4c697. It will show as Available once provisioned — remember this reflects AWS-side provisioning only, not that tunnels are actually UP (see Section 18).

AWS automatically creates two tunnels, each with its own outside public IP on the AWS side. In the reference configuration used throughout this section:

Tunnel 1 outside (AWS)  : 3.111.62.140
Tunnel 2 outside (AWS)  : 43.204.61.4
Customer Gateway outside: 116.68.214.251   (same for both tunnels)

Step 4 — Configure Routing

VPC Console → Route Tables → select the route table(s) associated with the subnets that need on-prem access → Edit routesAdd route:

If using a VGW, you can alternatively enable Route Propagation (Route Table → Route Propagation tab → Edit → enable for the VGW) so AWS automatically populates and maintains this route — recommended for BGP, optional but convenient for static routing too.

Step 5 — Update Security Groups

Go to EC2 → Security Groups, select the security group attached to the instances that need to be reached from on-prem, and add inbound rules scoped to the on-prem CIDR only:

Also check Network ACLs on the relevant subnets — unlike security groups, NACLs are stateless, so you need explicit inbound and outbound rules if you’ve customized them away from the default “allow all.”

Step 6 — Download the Configuration File

Select the VPN connection → Download Configuration → choose the Vendor / Platform / Software / IKE version matching your device (or Generic / Generic / Vendor Agnostic if unlisted) → Download.

This file is the single source of truth for configuring the on-prem device — it contains real, connection-specific values, not placeholders. From the reference file used here:

IPSec Tunnel #1
  IKE version              : IKEv2
  Pre-Shared Key           : 7EvYeQTxxxxxxxxxxxxxxxx
  Authentication Algorithm : sha1
  Encryption Algorithm     : aes-128-cbc
  Lifetime (Phase 1)       : 28800 seconds
  Diffie-Hellman           : Group 2
  Protocol (Phase 2)       : esp
  Auth Algorithm (Phase 2) : hmac-sha1-96
  Lifetime (Phase 2)       : 3600 seconds
  PFS                      : DH Group 2
  DPD Interval / Retries   : 10 / 3
  Outside IPs              : CGW 116.68.214.251  ↔  VGW 3.111.62.140
  Inside IPs                : CGW 169.254.12.90/30 ↔ VGW 169.254.12.89/30
  Tunnel interface MTU     : 1436 bytes
  TCP MSS Adjustment       : 1379 bytes
  Static route next hop    : 169.254.12.89

IPSec Tunnel #2
  Pre-Shared Key           : TjO82.cRt4xxxxxxxxxxxxxxxx
  Outside IPs               : CGW 116.68.214.251  ↔  VGW 43.204.61.4
  Inside IPs                : CGW 169.254.36.22/30 ↔ VGW 169.254.36.21/30
  Static route next hop    : 169.254.36.21

⚠️ Note on these crypto parameters: the AWS-generated default/generic sample uses AES-128-CBC, SHA-1, and DH Group 2 — this is a documented minimum, kept for broad device compatibility. For a production deployment, override the tunnel options when creating the VPN connection (or edit them afterward) to use AES-256, SHA-256, and DH Group 14+ as recommended in Section 19. Treat the values above as a structural example of what fields exist, not as the crypto strength to actually deploy.

⚠️ Handle the Pre-Shared Keys as secrets. Store them in a secrets manager (AWS Secrets Manager, Vault, etc.) rather than in plaintext files or tickets, and restrict who can view the downloaded configuration.

10.3 On-Premises Device — Step by Step

The exact commands differ by vendor (see Section 9), but every device configuration walks through the same logical steps, using the downloaded file as the reference:

Step 1 — Configure the IKE (Phase 1) policy, per tunnel

Enter, for each tunnel, the exact values from the downloaded file: IKE version (IKEv2), authentication method (Pre-Shared Key), the PSK itself, hash algorithm, encryption algorithm, DH group, lifetime, and negotiation mode (main mode for IKEv1 devices; not applicable for IKEv2).

Step 2 — Configure the IPSec (Phase 2 / Child SA) policy, per tunnel

Enter protocol (ESP), authentication algorithm, encryption algorithm, lifetime, mode (tunnel), and PFS group — again matching the downloaded file exactly. A mismatch on any single one of these values between AWS and the device is enough to prevent the tunnel from establishing.

Step 3 — Configure the tunnel interface

Create a tunnel/VTI (virtual tunnel interface) per tunnel, and assign it the inside IP address given for the customer gateway side (e.g., 169.254.12.90/30 for Tunnel 1, 169.254.36.22/30 for Tunnel 2). Bind the outside interface (public IP 116.68.214.251) as the tunnel source, and the AWS outside IP (3.111.62.140 / 43.204.61.4) as the tunnel destination/peer.

Step 4 — Apply MTU and fragmentation settings

Set the tunnel interface MTU to 1436 bytes, enable TCP MSS clamping/adjustment to 1379 bytes, clear the “Don’t Fragment” bit, and configure fragmentation to occur before encryption. Skipping this step is a common, hard-to-diagnose cause of connections that establish fine but silently drop larger packets (e.g., HTTPS handshakes with large certificates, RDP, file transfers) while ping still works, because ICMP echo packets are small enough to pass unfragmented.

Step 5 — Configure Dead Peer Detection

Set DPD interval to 10 seconds and retry count to 3 (matching what AWS enables on its side) so a failed peer is detected quickly and the tunnel is torn down/rebuilt rather than blackholing traffic silently.

Step 6 — Configure static routing

Add a static route for the destination VPC CIDR (e.g., 10.27.0.0/16) with the next hop set to the tunnel's inside VGW address169.254.12.89 for Tunnel 1, 169.254.36.21 for Tunnel 2. If your device supports route-based failover (e.g., via route metrics or IP SLA tracking), give Tunnel 1's route a lower metric so it's preferred, with Tunnel 2 as automatic backup. If using BGP instead, configure the BGP neighbor as the tunnel inside address and let routes propagate dynamically instead of static entries.

Step 7 — Apply and verify locally

Save/commit the configuration, then check the device’s local IPSec/IKE status commands (see Section 15) to confirm both Phase 1 and Phase 2 negotiate successfully on both tunnels.

10.4 On-Premises Firewall Rule Management

This is the step most often under-scoped, because “the VPN device” and “the perimeter firewall” are sometimes the same box and sometimes two separate devices sitting in series. Configure rules on whichever device actually sits between the internet and the VPN device’s outside interface:

Inbound, from the internet toward the customer gateway device’s outside IP:

Outbound/internal, from the customer gateway device toward the private LAN:

  • Permit the decrypted traffic (now appearing as normal 10.9.x.x → 10.27.x.x IP traffic) to reach the internal core switch/router and onward to destination hosts.
  • If a separate internal firewall sits between the VPN device and the private servers, it needs its own rule permitting 10.9.0.0/16 ↔ 10.27.0.0/16 for the specific protocols/ports required (mirroring the AWS Security Group rules from Step 5 above, but in the opposite direction of control).

NAT-T decision:

  • If the customer gateway’s outside interface has a direct, non-NAT’d public IP (as in this reference example) and you are not using AWS Accelerated VPN, AWS’s own guidance is to disable NAT-T — leaving it enabled unnecessarily can sometimes cause instability.
  • If the device sits behind a NAT (common with cloud-hosted or CPE-provided VPN appliances), NAT-T must be enabled and UDP 4500 explicitly unblocked, or Phase 1 will complete but Phase 2 will fail intermittently.
  • If using Accelerated VPN, NAT-T must be enabled regardless of whether NAT is present.

Common firewall-management mistakes to check for:

  • Rules written to a specific old AWS tunnel public IP that no longer matches after a VPN connection was recreated (AWS assigns new tunnel IPs on connection recreation) — always re-verify against the current downloaded configuration.
  • ESP (protocol 50) blocked by a generic “deny all IP protocols except TCP/UDP” catch-all rule further upstream (ISP-provided router, cloud provider security group if the VPN device itself is hosted in another cloud).
  • Egress filtering on the firewall blocking outbound UDP 500/4500/ESP — inbound rules alone aren’t sufficient; IPSec is bidirectional by nature.
  • A stateful firewall timing out the UDP 500/4500 session faster than DPD keepalives are sent, causing intermittent, hard-to-reproduce tunnel drops — extend the relevant idle-timeout for these ports/protocols if this pattern is observed.

10.5 Testing and Verification

Work through these checks in order — each one isolates a different layer, so stop at the first failure and fix that layer before moving to the next.

  1. Confirm internet reachability to AWS’s tunnel endpoints (not the tunnel itself):
ping 3.111.62.140
ping 43.204.61.4

Success here only proves basic internet connectivity from the device to AWS — it says nothing about IKE/IPSec yet.

2. Confirm Phase 1 (IKE) and Phase 2 (Child SA) are both UP, using the vendor-appropriate command (see Section 15’s Appendix), and confirm this for both tunnels independently, not just one.

3. Confirm the AWS console agrees: VPC → Site-to-Site VPN Connections → select the connection → Tunnel Details tab. Both tunnels should show UP, with non-zero and increasing Bytes In/Out once traffic flows.

4. Test connectivity to the private AWS IP — not the public tunnel IP:

ping 10.27.1.100

This is the step people most often skip, mistakenly treating a successful ping to the public AWS tunnel endpoint (Step 1) as proof the VPN works end-to-end.

5. Test the return path from the AWS side, if you have access to the EC2 instance (via Session Manager or a bastion, without exposing SSH publicly):

ping 10.9.1.10

A one-directional failure (on-prem → AWS works, AWS → on-prem doesn’t) almost always points to a missing return route on either the VPC route table or the on-prem device, or a stateless NACL missing the return-traffic rule.

6. Test the actual application ports, not just ICMP — a tunnel can be fully healthy for ping while a specific TCP port is still blocked by a Security Group, NACL, or an intermediate firewall:

telnet 10.27.1.100 443
# or
nc -vz 10.27.1.100 443

7. Check VPC Flow Logs on the relevant ENI to confirm AWS is seeing and ACCEPT-ing the traffic (see Section 17's case study for how to read flow log entries in detail).

8. Check for fragmentation-related failures specifically, since these often pass small-packet tests (ping) while failing larger real traffic:

ping -M do -s 1400 10.27.1.100    # test with a larger payload and the "don't fragment" bit set

If large pings fail while small ones succeed, revisit the MTU/MSS clamping settings from Step 4 in Section 10.3.

9. Deliberately test failover, once steady-state connectivity is confirmed: disable Tunnel 1 on the on-prem device (or in the AWS console) and confirm traffic continues to flow — automatically, if using BGP, or after the static route/metric takes effect if using static routing — over Tunnel 2. Re-enable Tunnel 1 afterward and confirm it re-establishes cleanly.

11. Understanding the “Download Configuration” Vendor Selection

A frequent point of confusion: why does AWS make you pick a vendor, platform, software, and IKE version before downloading a config file — and does picking the wrong one break anything?

No, it doesn’t. The VPN connection, its tunnels, PSKs, and encryption settings are already created and stored on the AWS side the moment you create the Site-to-Site VPN Connection. The Vendor/Platform/Software selection only determines the syntax of the sample configuration file AWS hands you — it’s documentation, not configuration.

Think of it like assembly instructions for furniture that’s already built: choosing “Cisco” gives you the manual written in Cisco CLI; choosing “StrongSwan” gives you Linux config syntax; choosing Generic / Vendor Agnostic gives you a vendor-neutral list of the same parameters (tunnel IPs, PSKs, encryption/hash algorithms, DH group, DPD settings, BGP info if applicable) that you can manually map onto any standards-compliant IPSec device.

If your exact hardware model isn’t in AWS’s list (e.g., a Cisco Nexus acting as the IPSec endpoint, as in the case study below), pick the closest matching platform or fall back to Generic — the underlying VPN behaves identically either way.

12. Configuring IPSec (StrongSwan Example)

Key parameters to transcribe accurately from AWS’s downloaded config into ipsec.conf:

  • Tunnel 1 and Tunnel 2 outside IPs (yours and AWS’s)
  • Encryption algorithm (commonly AES-256), hash (SHA-256), DH group (14 or higher)
  • IKE version (AWS supports both IKEv1 and IKEv2; IKEv2 is recommended)
  • Local/remote traffic selectors matching your actual CIDRs
  • Rekey margin and lifetime values matching AWS’s side, to avoid rekey mismatches

A mismatch in any of these — especially the PSK or the traffic selector CIDRs — is the single most common cause of a tunnel failing to come up.

13. Routing: Static vs. BGP

For production, BGP is strongly recommended: it lets both sides exchange routes dynamically, converges faster during tunnel failover, and avoids manually re-entering CIDRs every time the network changes.

14. Tunnel Monitoring and Automatic Failover

Tunnel 1
❌ Failed
 │
 ▼
Tunnel 2
✅ Active

Both StrongSwan and Cisco devices run DPD to detect a dead peer within seconds, at which point routing (static route metrics, or BGP route withdrawal) shifts traffic to the healthy tunnel. In production:

  • Monitor tunnel state with CloudWatch metrics (TunnelState, TunnelDataIn, TunnelDataOut) and set CloudWatch Alarms feeding an SNS notification.
  • Periodically test failover deliberately (disable Tunnel 1) rather than discovering it doesn’t work during a real outage.
  • Keep both tunnels active at all times, even though only one may be carrying traffic under static routing — this is what gives you the AWS SLA.

15. Verification

On AWS: VPC → Site-to-Site VPN Connections → check Tunnel 1 and Tunnel 2 status, Bytes In/Out, and Last Status Change. Both should read UP.

On StrongSwan:

sudo ipsec statusall
sudo journalctl -u strongswan

On Cisco:

show crypto ikev2 sa
show crypto ipsec sa
show crypto session

End-to-end:

ping 10.27.xxx.237      # private IP inside the VPC, NOT the AWS tunnel endpoint public IP
ssh ec2-user@10.27.xxx.237

Also useful: VPC Reachability Analyzer, which traces the actual path a packet would take and flags the specific hop (SG, NACL, route table) that would block it.

16. Troubleshooting Playbook

Tunnel stays DOWN

  • PSK mismatch between AWS and the on-prem device
  • Upstream firewall/NAT blocking UDP 500, UDP 4500, or ESP (IP protocol 50)
  • Wrong public IP configured as the peer on either side
  • Phase 1 parameter mismatch (encryption, hash, DH group, IKE version)
  • ISP-level issue on the on-prem circuit

Tunnel is UP but ping fails

  • Missing route in the AWS VPC route table for the on-prem CIDR
  • Missing return route on the on-prem device for the AWS CIDR
  • Security Group or NACL blocking ICMP (or the specific protocol/port being tested)
  • The destination EC2 instance’s own OS-level firewall blocking ICMP
  • Traffic selector / crypto ACL mismatch — the packet’s actual source/destination doesn’t match the CIDR pair negotiated in Phase 2, so it never enters the tunnel at all

Tunnel is UP but no traffic / intermittent traffic

  • Check packet counters (show crypto ipsec sa on Cisco, or tunnel byte counters in the AWS console) — encaps/decaps counters that aren't incrementing mean packets aren't reaching the crypto engine
  • Check VPC Flow Logs for ACCEPT vs REJECT entries on the relevant ENI
  • Asymmetric routing: traffic egressing on-prem via the VPN but the return path taking a different, non-VPN route (common when there are multiple internet-facing links)

17. Case Study: Reading Real Cisco Nexus + VPC Flow Log Output

This section walks through a real diagnostic session to illustrate the method, not just the theory.

Step 1 — Confirm internet reachability to AWS’s endpoint (not the tunnel itself):

ping 3.108.xxx.116
Success rate is 100 percent (5/5)

This only proves the Cisco device can reach AWS’s public VPN IP over the internet — it says nothing about the tunnel yet.

Step 2 — Check the IKE/IPSec session:

Status: UP-ACTIVE, IKE count:1, CHILD count:1
Encr: AES-CBC-256, Hash: SHA256, DH Grp:14, Auth: PSK
Life/Active Time: 28800/63 sec
DPD configured for 10 seconds, retry 2
NAT-T is not detected

This confirms Phase 1 and Phase 2 both completed successfully, using AES-256/SHA-256/DH14/PSK — a solid, common AWS-compatible cipher suite — with no NAT device between the peers (so plain ESP is used instead of UDP 4500 encapsulation).

Step 3 — Check the Child SA / traffic selector:

local selector  10.9.x.x/16
remote selector 10.27.x.x/16
ESP spi in/out: 0xd5d0d588/0xc5425889
mode tunnel

Only traffic between 10.9.x.x/16 and 10.27.x.x/16 is eligible for encryption — anything else takes the normal internet path, tunnel or no tunnel.

Step 4 — Check the crypto ACL:

access-list permit ip 10.9.x.x 255.255.0.0 10.27.x.x 255.255.0.0

This is the gatekeeper: a packet must match this ACL to be encrypted and sent into the tunnel at all. If a host’s actual source IP falls outside 10.9.x.x/16, it will never enter the VPN, tunnel status notwithstanding.

Step 5 — Check packet counters:

#pkts encaps: 135, #pkts encrypt: 135, #pkts digest: 135
#pkts decaps: 149, #pkts decrypt: 149, #pkts verify: 149

Counters incrementing on both directions with no failures confirm the tunnel is actively carrying traffic successfully.

Step 6 — Cross-check with VPC Flow Logs on the AWS side:

18. The “VPN Connection Available but Both Tunnels Down” Failure Mode

This is a distinct, important failure mode worth calling out on its own, because it’s counter-intuitive: the AWS console can show the VPN Connection as Available while both Tunnel 1 and Tunnel 2 show DOWN. Available only means the AWS-side resource is provisioned correctly — it says nothing about whether IKE/IPSec negotiation with your on-prem device has succeeded.

Common root causes when both tunnels are down simultaneously (as opposed to just one):

  • A single upstream device or firewall rule blocking both tunnels at once — since both AWS tunnel endpoints are reached via the same on-prem public IP and the same egress path, a single misconfigured ACL blocking UDP 500/4500 or ESP affects both tunnels identically.
  • On-prem device only has one crypto map / one peer configured, pointing at just one of the two AWS tunnel endpoints — the second tunnel was never actually configured on the customer gateway side, so it will always show down regardless of AWS health.
  • PSK or IKE version copy-paste error applied identically to both tunnel configs — a single mistake duplicated into both tunnel definitions in ipsec.conf or the Cisco crypto map.
  • On-prem device reload/failover event that dropped all IKE SAs — check show crypto ikev2 sa history or StrongSwan logs around the timestamp both tunnels dropped.
  • ISP-level outage or route flap on the single circuit the on-prem gateway uses to reach the internet — since both AWS endpoints are reached over the same physical uplink, one ISP issue takes both down together.
  • AWS-side maintenance on the VPN endpoint — rare, but AWS does occasionally replace/rotate tunnel endpoints; check the Site-to-Site VPN connection’s event history and AWS Health Dashboard for any scheduled maintenance notices around the outage window.
  • MTU/fragmentation issues on the on-prem uplink that only manifest under certain packet sizes, which can cause Phase 1 fragments to be dropped consistently on both tunnels if the underlying path has a low MTU (note the IKEv2 fragmentation MTU seen in the Nexus output above — misconfiguring this value identically on both tunnels can silently break both).

Diagnostic order for this specific symptom:

  1. Confirm the on-prem device can still reach the internet at all (basic ping to a known-good external IP).
  2. Confirm both AWS tunnel public IPs are individually reachable from on-prem.
  3. Check the on-prem device’s crypto/IKE configuration — verify two distinct peer/crypto-map entries actually exist, one per AWS tunnel IP, not just one.
  4. Compare PSKs and IKE parameters against the most recently downloaded AWS configuration file — a VPN connection recreated or modified in AWS regenerates new PSKs, and a stale local config is a very common cause of a simultaneous, sudden double-tunnel failure.
  5. Check on-prem device logs for a reload, HA failover, or config change timestamp that lines up with when both tunnels dropped.
  6. Check the AWS Health Dashboard and the VPN connection’s tunnel event history in the console for AWS-side maintenance.

19. Security Best Practices

  • Prefer IKEv2 over IKEv1
  • Use AES-256 encryption and SHA-256 or SHA-384 for integrity
  • Use DH Group 14 or higher
  • Rotate PSKs periodically per your security policy
  • Scope Security Groups to only the specific on-prem CIDRs and ports actually needed
  • Enable VPC Flow Logs on relevant ENIs/subnets for ongoing visibility and incident response
  • Document every network/routing change — VPN issues are disproportionately caused by undocumented drift between the AWS side and the on-prem device config
  • Test failover on a schedule, not just when something breaks
  • Where the on-prem device supports it, consider certificate-based authentication instead of PSK for stronger peer authentication

20. Cost Considerations

  • AWS charges an hourly rate per VPN connection, plus standard data transfer out charges for traffic leaving AWS through the tunnel.
  • For sustained high-bandwidth or latency-sensitive workloads, AWS Direct Connect (optionally paired with a VPN as backup) is usually more cost-effective and performant at scale than VPN alone.
  • If connecting many VPCs/accounts to the same on-prem network, a Transit Gateway centralizes routing and avoids a full mesh of individual VPN connections per VPC.

21. Conclusion

Planning → Network Design → AWS Configuration → Customer Gateway Configuration
   → Tunnel Establishment → Verification → Monitoring → Troubleshooting → Production Ops

AWS Site-to-Site VPN is a fast, secure way to extend an on-premises network into AWS. The mechanics — CGW, VGW, two IPSec tunnels, IKE/IPSec negotiation — are the same regardless of vendor; what differs is configuration syntax and the discipline applied to monitoring and troubleshooting once it’s live. Treat “tunnel is UP” as the start of validation, not the end: confirm traffic selectors match intent, routes exist on both sides, and Security Groups/NACLs permit the traffic — and keep the AWS-side and on-prem-side configs in sync any time either changes.

22. Appendix: Command & Terminology Reference

StrongSwan

ipsec status
ipsec statusall
journalctl -u strongswan
tcpdump -ni <interface> esp or udp port 500 or udp port 4500

Cisco IOS / Nexus

show crypto ikev2 sa
show crypto ipsec sa
show crypto ipsec sa peer <peer-ip>
show crypto session
show version
show inventory

AWS CLI

aws ec2 describe-vpn-connections
aws ec2 describe-vpn-connections --vpn-connection-ids vpn-xxxxxxxx

Key terms

FAQ

  • Why does AWS ask for Vendor/Platform/Software before downloading the config? — Purely to generate the sample file in the right syntax; it doesn’t change the VPN itself. See Section 9.
  • Why is the VPN Connection “Available” but both tunnels “Down”?Available reflects AWS-side provisioning only, not IKE/IPSec negotiation success. See Section 16.
  • Can I download the configuration after the VPN is already created? — Yes, anytime, and re-downloading doesn’t affect the live connection.

메타데이터
post_id
daf72bcd8979
slug
the-complete-guide-to-building-a-production-ready-aws-site-to-site-vpn-ipsec-daf72bcd8979
url
https://medium.com/@bishaldhimal321/the-complete-guide-to-building-a-production-ready-aws-site-to-site-vpn-ipsec-daf72bcd8979
canonical_url
https://medium.com/@bishaldhimal321/the-complete-guide-to-building-a-production-ready-aws-site-to-site-vpn-ipsec-daf72bcd8979
author_url
https://medium.com/@bishaldhimal321
status
ok
fetched_at
2026-08-19 22:50:33