Setting up an Azure Site-to-Site VPN to a Ubiquiti EdgeRouter through NAT
I have a Home Lab with a couple of devices for experiments and testing. It’s set up on a separate physical network — using a Ubiquiti EdgeRouter X — but I wanted to connect this to the outside world and get access to public IPs I could proxy to local services.
A while ago, I started using Azure for other experiments (because I have a
bunch of credits to use). I’ve also found the cost of the more basic virtual
machines cheaper than other cloud providers. At the time of writing, a B1s
is £3.19/m on pay-as-you-go and down to £1.20/m reserved for three years)
and importantly, allowed me to allocate the most IPs to a single virtual
machine.
On the Azure side, I’m using a VPN Gateway associated with a virtual network. On the Home Lab side, a Ubiquiti EdgeRouter X behind a Ubiquiti Security Gateway (which is doing NAT for my home network). I don’t have a static IP, but it changes infrequently, so this shouldn’t be too much of a problem.
To configure a Site-to-Site VPN, both sides of the connection need to know about each other. We can’t do this with NAT — as NAT hides the devices behind it — but we can work around this by forwarding the necessary ports for IPSec on the local side. In some ways, this is a bit of a cop-out solution, but otherwise, we’d need a Point-to-Site that isn’t supported on the lower-end VPN Gateway.
(I initially started this project by trying to build a custom VyOS image and do this using a VyOS VM on the Azure side and the EdgeRouter locally. After months of on-and-off effort, I got the VM working, but it’s challenging to configure when both sides are behind NAT. I also realised that the lowest-tier VPN Gateway worked out to be about £22/m, which is fine.)
For the rest of this article, I’ve based it on this Ubiquiti help guide, but using Terraform for the configuration. We’ll configure an IKEv1/IPSec VPN using a shared secret and end up being to connect our local network to virtual machines running in our Azure virtual network.
Local Network Adjustments
IPSec uses UDP ports 4500 and 500 over UDP. I configured that in the UniFi controller to point to the EdgeRouter.

Configuring the Azure Virtual Network Gateway using Terraform
We need to configure a few things to get this up and running (and this assumes
you already have a resource group (named rg
here):
resource "azurerm_local_network_gateway" "home_lab" {
name = "HomeLab"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
gateway_address = "LOCAL_NETWORK_PUBLIC_IP"
address_space = ["10.1.0.0/24"] # local network subnet
}
resource "azurerm_subnet" "gateway" {
name = "GatewaySubnet"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.core.name
address_prefixes = ["10.0.1.0/24"]
}
resource "azurerm_public_ip" "gateway" {
name = "Gateway"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
allocation_method = "Dynamic"
}
resource "azurerm_virtual_network_gateway" "gateway" {
name = "Gateway"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
type = "Vpn"
vpn_type = "PolicyBased"
active_active = false
enable_bgp = false
sku = "Basic"
ip_configuration {
name = "Gateway"
public_ip_address_id = azurerm_public_ip.gateway.id
private_ip_address_allocation = "Dynamic"
subnet_id = azurerm_subnet.gateway.id
}
}
resource "azurerm_virtual_network_gateway_connection" "home_lab" {
name = "HomeLab"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
type = "IPsec"
virtual_network_gateway_id = azurerm_virtual_network_gateway.gateway.id
local_network_gateway_id = azurerm_local_network_gateway.home_lab.id
shared_key = "SHARED_KEY"
}
In the azurerm_local_network_gateway
resource, we define the local network:
the IP we’ll be configuring the VPN to use and what the local network looks
like. azurerm_virtual_network_gateway
represents the primary resource, and
then azurerm_virtual_network_gateway_connection
builds the connection to the
local network.
I made up the shared key using openssl rand -base64 20
, removing
non-alphanumeric characters as these caused the connection to fail to
authenticate. I couldn’t tell which side had a problem with it. You probably
want to keep the secret in a Key Vault.
The Virtual Network Gateway will take a decent amount of time to be operational — it took about 25 minutes most times.
Configuring the EdgeRouter
Connect over SSH and then in configuration mode:
configure
Followed by configuring the firewall rules, IKE/ESP groups, then setup the connection on both sides:
set vpn ipsec auto-firewall-nat-exclude enable
set vpn ipsec ike-group FOO0 key-exchange ikev1
set vpn ipsec ike-group FOO0 lifetime 28800
set vpn ipsec ike-group FOO0 proposal 1 dh-group 2
set vpn ipsec ike-group FOO0 proposal 1 encryption aes256
set vpn ipsec ike-group FOO0 proposal 1 hash sha1
set vpn ipsec esp-group FOO0 lifetime 3600
set vpn ipsec esp-group FOO0 pfs disable
set vpn ipsec esp-group FOO0 proposal 1 encryption aes256
set vpn ipsec esp-group FOO0 proposal 1 hash sha1
set vpn ipsec site-to-site peer AZURE_GATEWAY_IP authentication mode pre-shared-secret
set vpn ipsec site-to-site peer AZURE_GATEWAY_IP authentication pre-shared-secret SHARED_KEY
set vpn ipsec site-to-site peer AZURE_GATEWAY_IP connection-type respond
set vpn ipsec site-to-site peer AZURE_GATEWAY_IP description ipsec
set vpn ipsec site-to-site peer AZURE_GATEWAY_IP local-address 0.0.0.0
set vpn ipsec site-to-site peer AZURE_GATEWAY_IP ike-group FOO0
set vpn ipsec site-to-site peer AZURE_GATEWAY_IP tunnel 1 esp-group FOO0
set vpn ipsec site-to-site peer AZURE_GATEWAY_IP tunnel 1 local prefix 10.1.0.0/24
set vpn ipsec site-to-site peer AZURE_GATEWAY_IP tunnel 1 remote prefix 10.0.0.0/22
Then:
commit ; save
Setting the EdgeRouter to listen on 0.0.0.0
rather than the public IP allows
us to work around the public IP not being configured — and helpfully means we
wouldn’t need to reconfigure the EdgeRouter when the public IP changes.
Testing the Connection
After some time, the connection should hopefully be established. Azure will report back if it doesn’t work, and it’s possible to view the connection status on the EdgeRouter by using
show vpn status
show vpn sa
You can see the connection state in the Azure portal, too:

VPNs can be notoriously difficult to debug when they go wrong. I’d start by checking the configuration on either side, then randomly changing things until it works, if it doesn’t eventually come up. Good luck.