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.
Enlarge 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.

ayush-virginia-vpc
CIDR: 10.0.0.0/16
Public subnet: 10.0.0.0/24
Private subnet: 10.0.1.0/24

ayush-oregon-vpc
CIDR: 172.16.0.0/16
Public subnet: 172.16.0.0/24
Private subnet: 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:

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

ayush-virginia-vpc
VPN Instance Name: ayush-virginia-vpn
VPN Private IP: 10.0.0.207
VPN Instance EIP: 54.197.XXX.XXX

ayush-oregon-vpc
VPN Instance Name: ayush-oregon-vpn
VPN Private IP: 172.16.0.29
VPN Instance EIP: 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.
Enlarge VPN routing table for Virginia.

For Oregon:

VPN routing table for Oregon.
Enlarge 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:

ayush-virginia-vpc
Private Instance Name: ayush-virginia-private-test
Private Instance IP: 10.0.1.105

ayush-oregon-vpc
Private Instance Name: ayush-oregon-private-test
Private Instance IP: 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.
Enlarge Testing VPN from Virginia ping 1.
Testing VPN from Virginia ping 2.
Enlarge Testing VPN from Virginia ping 2.

From Oregon:

Testing VPN from Oregon ping 1.
Enlarge Testing VPN from Oregon ping 1.
Testing VPN from Oregon ping 2.
Enlarge Testing VPN from Oregon ping 2.

And that’s it!

Good luck ;)