AWS provides a feature called VPC Peering that allows you to connect two VPCs in the same region. But what if you want to connect VPCs in two different AWS regions? What if you want a machine to be able to access another machine in another region using its private IP address? This guide will help you set that up.

1. Setting Up The VPCs

Look at the following diagram.

VPN architecture.

There are 4 instances in the diagram. Two VPNs, one each in the public subnet of the VPC in each region, and another 2 test machines, in the private subnet of the VPC in each region. Our goal is to be able to connect the test machines to each other. You should be able to ping one of those machines from the other using the private IP address.

First, let’s create 2 VPCs, one in Virginia and one in Oregon, with the following configuration.

Component ayush-virginia-vpc ayush-oregon-vpc
CIDR 10.0.0.0/16 172.16.0.0/16
Public Subnet 10.0.0.0/24 172.16.0.0/24
Private Subnet 10.0.1.0/24 172.16.1.0/24

2. Setting Up The VPNs

2a. Launching The Machines

Now we’ll create 2 Ubuntu instances, one in Virginia and one in Oregon, in the newly created VPCs that will act as our VPNs. Note that:

  • These machines must be in the public subnet of their VPCs.
  • Make sure their security groups allow incoming and outgoing traffic from all ports. This is not very secure, but will make our configuration easier. You can tighten ports later. Especially open UDP 500 and UDP 4500.
  • Disable “Source/Destination check” on both machines.
  • Teardown AppArmor on both machines using /etc/init.d/apparmor teardown.
  • Enable IP forwarding on both VPNs by running sysctl -w net.ipv4.ip_forward=1. This tiny step is very important, and will save you a lot of headache.

Once the machines have been launched, assign them an Elastic IP address, and note their public and private IP addresses. Like so:

Component ayush-virginia-vpc ayush-oregon-vpc
VPN Instance Name ayush-virginia-vpn ayush-oregon-vpn
VPN Private IP 10.0.0.207 172.16.0.29
VPN Instance EIP 54.197.XXX.XXX 35.162.XXX.XXX

2b. Installing Strongswan

Use the following:

apt-get -y install strongswan

2c. Configuring Strongswan On Both VPNs:

Let’s add some logging to /etc/strongswan.d/charon-logging.conf:

charon {

    filelog {
        /var/log/strongswan.log {
            # add a timestamp prefix
            time_format = %b %e %T
            # prepend connection name, simplifies grepping
            ike_name = yes
            # overwrite existing files
            append = yes
            # increase default loglevel for all daemon subsystems
            default = 2
            # flush each line to disk
            flush_line = yes
        }
        stderr {
            # more detailed loglevel for a specific subsystem, overriding the
            # default loglevel.
            ike = 2
            knl = 3
        }
    }
}

Let’s configure defaults on both VPNs in /etc/ipsec.conf:

config setup
  charondebug="all"
  uniqueids=yes
  strictcrlpolicy=no

conn %default
  ikelifetime=60m
  keylife=20m
  rekeymargin=3m
  keyingtries=1
  keyexchange=ikev2

include /etc/ipsec.d/*.conf

2d. Configuring Virginia VPN

Add the following to /etc/ipsec.d/vpc-virginia.conf:

conn vpc-virginia
        type=tunnel
        authby=secret
        left=10.0.0.207
        leftid=54.197.XXX.XXX
        leftsubnet=10.0.0.0/16
        right=35.162.XXX.XXX
        rightsubnet=172.16.0.0/16
        leftauth=psk
        rightauth=psk
        esp=aes256-sha1-modp1536
        ike=aes256-sha1-modp1536
        auto=start

Add the following to /etc/ipsec.secrets:

10.0.0.207 35.162.XXX.XXX : PSK "THIS__IS__SPARTA!!!"
54.197.XXX.XXX 35.162.XXX.XXX : PSK "THIS__IS__SPARTA!!!"

2e. Configuring Oregon VPN

Add the following to /etc/ipsec.d/vpc-oregon.conf:

conn vpc-oregon
        type=tunnel
        authby=secret
        left=172.16.0.29
        leftid=35.162.XXX.XXX
        leftsubnet=172.16.0.0/16
        right=54.197.XXX.XXX
        rightsubnet=10.0.0.0/16
        leftauth=psk
        rightauth=psk
        esp=aes256-sha1-modp1536
        ike=aes256-sha1-modp1536
        auto=start

Add the following to /etc/ipsec.secrets:

172.16.0.29 54.197.XXX.XXX : PSK "THIS__IS__SPARTA!!!"
35.162.XXX.XXX 54.197.XXX.XXX : PSK "THIS__IS__SPARTA!!!"

3. Restart Services

On both VPN machines, do:

service strongswan restart
ipsec stop
ipsec start

4. Checking The Tunnel

Do ipsec status on both machines and you should see the following.

On the Virginia VPN:

vpc-virginia[1]: ESTABLISHED 43 minutes ago, 10.0.0.207[54.197.XXX.XXX]...35.162.XXX.XXX[35.162.XXX.XXX]
vpc-virginia{4}:  INSTALLED, TUNNEL, reqid 1, ESP in UDP SPIs: cdb651d5_i c70b50c8_o
vpc-virginia{4}:   10.0.0.0/16 === 172.16.0.0/16

On the Oregon VPN:

vpc-oregon[2]: ESTABLISHED 44 minutes ago, 172.16.0.29[35.162.XXX.XXX]...54.197.XXX.XXX[54.197.XXX.XXX]
vpc-oregon{5}:  INSTALLED, TUNNEL, reqid 2, ESP in UDP SPIs: c70b50c8_i cdb651d5_o
vpc-oregon{5}:   172.16.0.0/16 === 10.0.0.0/16

5. Routing table

This is the main part. In the Virginia VPC, we need to tell it to route the requests to 172.16.0.0/16 through the Virginia VPN, and the reverse for Oregon. Your routing table configuration should look like this:

For Virginia:

VPN routing table for Virginia.

For Oregon:

VPN routing table for Oregon.

6. Testing

Launch two new machines, “Virginia Test” and “Oregon Test”, as in the diagram. Make sure you allow traffic from all ports and launch them in the VPCs you created. Like so:

Component ayush-virginia-vpc ayush-oregon-vpc
Private Instance Name ayush-virginia-private-test ayush-oregon-private-test
Private Instance IP 10.0.1.105 172.16.1.128

If the configuration is correct, you should be able to ping each machine from the others using their private IP addresses.

From Virginia:

Testing VPN from Virginia ping 1.

Testing VPN from Virginia ping 2.

From Oregon:

Testing VPN from Oregon ping 1.

Testing VPN from Oregon ping 2.

And that’s it!

Good luck ;)