Home Lab – Utilizing the Cloud – Dynamic VPN


In a previous post, we discussed how to save money on a home lab. One section was cloud utilization. Let’s expand on that section and have a more in-depth conversation about how to create dynamic resources in Azure. This article will focus on creating a VPN dynamically.

Azure networking is not the most noticeable part of an enterprise bill. In the homelab scenario, it can be a running cost that adds up when not needed. Remember the entire purpose of a homelab is to run most, if not all, items… well in your home, at least. To alleviate this running cost, the components needed in an Azure Site-to-Site VPN can instead be created dynamically to utilize whenever it is required.

Due to the time involved in creating a VPN Gateway in Azure, this won’t be something that can be created and destroyed the same way a virtual machine or container could be. For the VPN Gateway, there should be at least one hour to guarantee that the VPN Gateway and other components can be created in time to meet demand load.

Let’s imagine a scenario where ad-hoc processing power is needed for an upcoming marketing campaign where traffic is expected to exceed our current capacity. In this scenario, our servers will be replicated in Azure Virtual Machines and allow for increased traffic. (This is a basic setup; in later posts, we’ll discuss more advanced scenarios.) To accomplish this, we need to set up a Site-to-Site VPN in Azure from our homelab.

Diagram showing an on-premises network on the left which consists of three computer screens and a gateway. A double sided arrow connecting the on-premises to a cloud labeled internet with “Site-to-site VPN tunnel” above the double sided arrow. Another double sided arrow connects the internet cloud to its right through a dotted rectangle labeled “Azure Virtual Network”. The arrow connects to an item labeled VPN gateway. That gateway has a single arrow leaving it to the right pointing to a load balancer which is pointing to three identical virtual machines.

The steps to accomplish this are:

  1. Supported Routers
  2. Creating a Site-to-Site Connection
  3. Replicating Virtual Machines / Containers
  4. Tear Down

Supported Routers (official docs)

Microsoft keeps an updated set of documentation for supported VPN routers. A VPN device is required to configure a Site-to-Site (S2S) cross-premises VPN connection using a VPN gateway. Site-to-Site connections can be used to create a hybrid solution, or whenever you want secure connections between your on-premises networks and your virtual networks.

Important – If you are experiencing connectivity issues between your on-premises VPN devices and VPN gateways, refer to Known device compatibility issues.

Items to note when viewing the tables:

  • There has been a terminology change for Azure VPN gateways. Only the names have changed. There is no functionality change.
    • Static Routing = PolicyBased
    • Dynamic Routing = RouteBased
  • Specifications for HighPerformance VPN gateway and RouteBased VPN gateway are the same, unless otherwise noted. For example, the validated VPN devices that are compatible with RouteBased VPN gateways are also compatible with the HighPerformance VPN gateway.

Validated VPN devices and device configuration guides

In partnership with device vendors, we have validated a set of standard VPN devices. All of the devices in the device families in the following list should work with VPN gateways. See About VPN Gateway Settings to understand the VPN type use (PolicyBased or RouteBased) for the VPN Gateway solution you want to configure.

To help configure your VPN device, refer to the links that correspond to the appropriate device family. The links to configuration instructions are provided on a best-effort basis. For VPN device support, contact your device manufacturer.

VendorDevice familyMinimum OS versionPolicyBased configuration instructionsRouteBased configuration instructions
A10 Networks, Inc.Thunder CFWACOS 4.1.1Not compatibleConfiguration guide
Allied TelesisAR Series VPN RoutersAR-Series 5.4.7+Configuration guideConfiguration guide
AristaCloudEOS RoutervEOS 4.24.0FX(not tested)Configuration guide
Barracuda Networks, Inc.Barracuda CloudGen FirewallPolicyBased: 5.4.3
RouteBased: 6.2.0
Configuration guideConfiguration guide
Check PointSecurity GatewayR80.10Configuration guideConfiguration guide
8.4+ (IKEv2*)
SupportedConfiguration guide*
CiscoASRPolicyBased: IOS 15.1
RouteBased: IOS 15.2
CiscoCSRRouteBased: IOS-XE 16.10(not tested)Configuration script
CiscoISRPolicyBased: IOS 15.0
RouteBased*: IOS 15.1
CiscoMeraki (MX)MX v15.12Not compatibleConfiguration guide
CiscovEdge (Viptela OS)18.4.0 (Active/Passive Mode)

19.2 (Active/Active Mode)
Not compatibleManual configuration (Active/Passive)

Cloud Onramp configuration (Active/Active)
CitrixNetScaler MPX, SDX, VPX10.1 and aboveConfiguration guideNot compatible
F5BIG-IP series12.0Configuration guideConfiguration guide
FortinetFortiGateFortiOS 5.6(not tested)Configuration guide
Hillstone NetworksNext-Gen Firewalls (NGFW)5.5R7(not tested)Configuration guide
Internet Initiative Japan (IIJ)SEIL SeriesSEIL/X 4.60
SEIL/B1 4.60
SEIL/x86 3.20
Configuration guideNot compatible
JuniperSRXPolicyBased: JunOS 10.2
Routebased: JunOS 11.4
SupportedConfiguration script
JuniperJ-SeriesPolicyBased: JunOS 10.4r9
RouteBased: JunOS 11.4
SupportedConfiguration script
JuniperISGScreenOS 6.3SupportedConfiguration script
JuniperSSGScreenOS 6.2SupportedConfiguration script
JuniperMXJunOS 12.xSupportedConfiguration script
MicrosoftRouting and Remote Access ServiceWindows Server 2012Not compatibleSupported
Open Systems AGMission Control Security GatewayN/AConfiguration guideNot compatible
Palo Alto NetworksAll devices running PAN-OSPAN-OS
PolicyBased: 6.1.5 or later
RouteBased: 7.1.4
SupportedConfiguration guide
Sentrium (Developer)VyOSVyOS 1.2.2(not tested)Configuration guide
ShareTechNext Generation UTM (NU series) compatibleConfiguration guide
SonicWallTZ Series, NSA Series
SuperMassive Series
E-Class NSA Series
SonicOS 5.8.x
SonicOS 5.9.x
SonicOS 6.x
Not compatibleConfiguration guide
SophosXG Next Gen FirewallXG v17(not tested)Configuration guide

Configuration guide – Multiple SAs
SRM1.1.5/VpnPlusServer-1.2.0(not tested)Configuration guide
UbiquitiEdgeRouterEdgeOS v1.10(not tested)BGP over IKEv2/IPsec

VTI over IKEv2/IPsec
Ultra3E-636L35.2.0.T3 Build-13(not tested)Configuration guide
WatchGuardAllFireware XTM
PolicyBased: v11.11.x
RouteBased: v11.12.x
Configuration guideConfiguration guide
ZyxelZyWALL USG series
ZyWALL ATP series
ZyWALL VPN series
ZLD v4.32+(not tested)VTI over IKEv2/IPsec

BGP over IKEv2/IPsec

(*) Cisco ASA versions 8.4+ add IKEv2 support, can connect to Azure VPN gateway using custom IPsec/IKE policy with “UsePolicyBasedTrafficSelectors” option. Refer to this how-to article.

(**) ISR 7200 Series routers only support PolicyBased VPNs.

Download VPN device configuration scripts from Azure

For certain devices, you can download configuration scripts directly from Azure. For more information and download instructions, see Download VPN device configuration scripts.

Devices with available configuration scripts

VendorDevice familyFirmware version
CiscoISRIOS 15.1 (Preview)
CiscoASAASA ( * ) RouteBased (IKEv2- No BGP) for ASA below 9.8
CiscoASAASA RouteBased (IKEv2 – No BGP) for ASA 9.8+
JuniperSSG_GAScreenOS 6.2.x
JuniperJSeries_GAJunOS 12.x
JuniperSRXJunOS 12.x RouteBased BGP
UbiquitiEdgeRouterEdgeOS v1.10x RouteBased VTI
UbiquitiEdgeRouterEdgeOS v1.10x RouteBased BGP

( * ) Required: NarrowAzureTrafficSelectors (enable UsePolicyBasedTrafficSelectors option) and CustomAzurePolicies (IKE/IPsec)

Non-validated VPN devices

If you don’t see your device listed in the Validated VPN devices table, your device still may work with a Site-to-Site connection. Contact your device manufacturer for additional support and configuration instructions.

Editing device configuration samples

After you download the provided VPN device configuration sample, you’ll need to replace some of the values to reflect the settings for your environment.

To edit a sample:

  1. Open the sample using Notepad.
  2. Search and replace all <text> strings with the values that pertain to your environment. Be sure to include < and >. When a name is specified, the name you select should be unique. If a command does not work, consult your device manufacturer documentation.
Sample textChange to
<RP_OnPremisesNetwork>Your chosen name for this object. Example: myOnPremisesNetwork
<RP_AzureNetwork>Your chosen name for this object. Example: myAzureNetwork
<RP_AccessList>Your chosen name for this object. Example: myAzureAccessList
<RP_IPSecTransformSet>Your chosen name for this object. Example: myIPSecTransformSet
<RP_IPSecCryptoMap>Your chosen name for this object. Example: myIPSecCryptoMap
<SP_AzureNetworkIpRange>Specify range. Example:
<SP_AzureNetworkSubnetMask>Specify subnet mask. Example:
<SP_OnPremisesNetworkIpRange>Specify on-premises range. Example:
<SP_OnPremisesNetworkSubnetMask>Specify on-premises subnet mask. Example:
<SP_AzureGatewayIpAddress>This information specific to your virtual network and is located in the Management Portal as Gateway IP address.
<SP_PresharedKey>This information is specific to your virtual network and is located in the Management Portal as Manage Key.

Default IPsec/IKE parameters

The tables below contain the combinations of algorithms and parameters Azure VPN gateways use in default configuration (Default policies). For route-based VPN gateways created using the Azure Resource Management deployment model, you can specify a custom policy on each individual connection. Please refer to Configure IPsec/IKE policy for detailed instructions.

Additionally, you must clamp TCP MSS at 1350. Or if your VPN devices do not support MSS clamping, you can alternatively set the MTU on the tunnel interface to 1400 bytes instead.

In the following tables:

  • SA = Security Association
  • IKE Phase 1 is also called “Main Mode”
  • IKE Phase 2 is also called “Quick Mode”

IKE Phase 1 (Main Mode) parameters

IKE VersionIKEv1IKEv1 and IKEv2
Diffie-Hellman GroupGroup 2 (1024 bit)Group 2 (1024 bit)
Authentication MethodPre-Shared KeyPre-Shared Key
Encryption & Hashing Algorithms1. AES256, SHA256
2. AES256, SHA1
3. AES128, SHA1
4. 3DES, SHA1
1. AES256, SHA1
2. AES256, SHA256
3. AES128, SHA1
4. AES128, SHA256
5. 3DES, SHA1
6. 3DES, SHA256
SA Lifetime28,800 seconds28,800 seconds

IKE Phase 2 (Quick Mode) parameters

IKE VersionIKEv1IKEv1 and IKEv2
Encryption & Hashing Algorithms1. AES256, SHA256
2. AES256, SHA1
3. AES128, SHA1
4. 3DES, SHA1
RouteBased QM SA Offers
SA Lifetime (Time)3,600 seconds27,000 seconds
SA Lifetime (Bytes)102,400,000 KB102,400,000 KB
Perfect Forward Secrecy (PFS)NoRouteBased QM SA Offers
Dead Peer Detection (DPD)Not supportedSupported

RouteBased VPN IPsec Security Association (IKE Quick Mode SA) Offers

The following table lists IPsec SA (IKE Quick Mode) Offers. Offers are listed the order of preference that the offer is presented or accepted.

Azure Gateway as initiator
EncryptionAuthenticationPFS Group
1GCM AES256GCM (AES256)None
Azure Gateway as responder
EncryptionAuthenticationPFS Group
1GCM AES256GCM (AES256)None
  • You can specify IPsec ESP NULL encryption with RouteBased and HighPerformance VPN gateways. Null based encryption does not provide protection to data in transit, and should only be used when maximum throughput and minimum latency is required. Clients may choose to use this in VNet-to-VNet communication scenarios, or when encryption is being applied elsewhere in the solution.
  • For cross-premises connectivity through the Internet, use the default Azure VPN gateway settings with encryption and hashing algorithms listed in the tables above to ensure security of your critical communication.

Creating a VPN Gateway (official docs)

Site-to-Site VPN Gateway cross-premises connection diagram

A Site-to-Site VPN gateway connection is used to connect your on-premises network to an Azure virtual network over an IPsec/IKE (IKEv1 or IKEv2) VPN tunnel. This type of connection requires a VPN device located on-premises that has an externally facing public IP address assigned to it. For more information about VPN gateways, see About VPN gateway.

Before you begin

Verify that you have met the following criteria before beginning configuration:

  • Make sure you have a compatible VPN device and someone who is able to configure it. For more information about compatible VPN devices and device configuration, see About VPN Devices.
  • Verify that you have an externally facing public IPv4 address for your VPN device.
  • If you are unfamiliar with the IP address ranges located in your on-premises network configuration, you need to coordinate with someone who can provide those details for you. When you create this configuration, you must specify the IP address range prefixes that Azure will route to your on-premises location. None of the subnets of your on-premises network can over lap with the virtual network subnets that you want to connect to.
  • Use the Bash environment in Azure Cloud Shell.
  • If you prefer, install the Azure CLI to run CLI reference commands.
    • If you’re using a local installation, sign in to the Azure CLI by using the az login command. To finish the authentication process, follow the steps displayed in your terminal. For additional sign-in options, see Sign in with the Azure CLI.
    • When you’re prompted, install Azure CLI extensions on first use. For more information about extensions, see Use extensions with the Azure CLI.
    • Run az version to find the version and dependent libraries that are installed. To upgrade to the latest version, run az upgrade.
  • This article requires version 2.0 or later of the Azure CLI. If using Azure Cloud Shell, the latest version is already installed.

Example values

You can use the following values to create a test environment, or refer to these values to better understand the examples in this article:Copy

#Example values

VnetName                = TestVNet1 
ResourceGroup           = TestRG1 
Location                = eastus 
AddressSpace            = 
SubnetName              = Subnet1 
Subnet                  = 
GatewaySubnet           = 
LocalNetworkGatewayName = Site2 
LNG Public IP           = <VPN device IP address>
LocalAddrPrefix1        =
LocalAddrPrefix2        =   
GatewayName             = VNet1GW 
PublicIP                = VNet1GWIP 
VPNType                 = RouteBased 
GatewayType             = Vpn 
ConnectionName          = VNet1toSite2

1. Connect to your subscription

If you choose to run CLI locally, connect to your subscription. If you are using Azure Cloud Shell in the browser, you don’t need to connect to your subscription. You will connect automatically in Azure Cloud Shell. However, you may want to verify that you are using the correct subscription after you connect.

Sign in to your Azure subscription with the az login command and follow the on-screen directions. For more information about signing in, see Get Started with Azure CLI.

az login

If you have more than one Azure subscription, list the subscriptions for the account.

az account list --all

Specify the subscription that you want to use.

az account set --subscription <replace_with_your_subscription_id>

2. Create a resource group

The following example creates a resource group named ‘TestRG1’ in the ‘eastus’ location. If you already have a resource group in the region that you want to create your VNet, you can use that one instead.

az group create --name TestRG1 --location eastus

3. Create a virtual network

If you don’t already have a virtual network, create one using the az network vnet create command. When creating a virtual network, make sure that the address spaces you specify don’t overlap any of the address spaces that you have on your on-premises network.

 Note – In order for this VNet to connect to an on-premises location, you need to coordinate with your on-premises network administrator to carve out an IP address range that you can use specifically for this virtual network. If a duplicate address range exists on both sides of the VPN connection, traffic does not route the way you may expect it to. Additionally, if you want to connect this VNet to another VNet, the address space cannot overlap with other VNet. Take care to plan your network configuration accordingly.

The following example creates a virtual network named ‘TestVNet1’ and a subnet, ‘Subnet1’.

az network vnet create --name TestVNet1 --resource-group TestRG1 --address-prefix --location eastus --subnet-name Subnet1 --subnet-prefix

4. Create the gateway subnet

The virtual network gateway uses specific subnet called the gateway subnet. The gateway subnet is part of the virtual network IP address range that you specify when configuring your virtual network. It contains the IP addresses that the virtual network gateway resources and services use. The subnet must be named ‘GatewaySubnet’ in order for Azure to deploy the gateway resources. You can’t specify a different subnet to deploy the gateway resources to. If you don’t have a subnet named ‘GatewaySubnet’, when you create your VPN gateway, it will fail.

When you create the gateway subnet, you specify the number of IP addresses that the subnet contains. The number of IP addresses needed depends on the VPN gateway configuration that you want to create. Some configurations require more IP addresses than others. We recommend that you create a gateway subnet that uses a /27 or /28.

If you see an error that specifies that the address space overlaps with a subnet, or that the subnet is not contained within the address space for your virtual network, check your VNet address range. You may not have enough IP addresses available in the address range you created for your virtual network. For example, if your default subnet encompasses the entire address range, there are no IP addresses left to create additional subnets. You can either adjust your subnets within the existing address space to free up IP addresses, or specify an additional address range and create the gateway subnet there.

Use the az network vnet subnet create command to create the gateway subnet.

az network vnet subnet create --address-prefix --name GatewaySubnet --resource-group TestRG1 --vnet-name TestVNet1

 Important – When working with gateway subnets, avoid associating a network security group (NSG) to the gateway subnet. Associating a network security group to this subnet may cause your virtual network gateway (VPN and Express Route gateways) to stop functioning as expected. For more information about network security groups, see What is a network security group?.

5. Create the local network gateway

The local network gateway typically refers to your on-premises location. You give the site a name by which Azure can refer to it, then specify the IP address of the on-premises VPN device to which you will create a connection. You also specify the IP address prefixes that will be routed through the VPN gateway to the VPN device. The address prefixes you specify are the prefixes located on your on-premises network. If your on-premises network changes, you can easily update the prefixes.

Use the following values:

  • The –gateway-ip-address is the IP address of your on-premises VPN device.
  • The –local-address-prefixes are your on-premises address spaces.

Use the az network local-gateway create command to add a local network gateway with multiple address prefixes:

az network local-gateway create --gateway-ip-address --name Site2 --resource-group TestRG1 --local-address-prefixes

6. Request a Public IP address

A VPN gateway must have a Public IP address. You first request the IP address resource, and then refer to it when creating your virtual network gateway. The IP address is dynamically assigned to the resource when the VPN gateway is created. VPN Gateway currently only supports Dynamic Public IP address allocation. You cannot request a Static Public IP address assignment. However, this does not mean that the IP address changes after it has been assigned to your VPN gateway. The only time the Public IP address changes is when the gateway is deleted and re-created. It doesn’t change across resizing, resetting, or other internal maintenance/upgrades of your VPN gateway.

Use the az network public-ip create command to request a Dynamic Public IP address.

az network public-ip create --name VNet1GWIP --resource-group TestRG1 --allocation-method Dynamic

7. Create the VPN gateway

Create the virtual network VPN gateway. Creating a gateway can often take 45 minutes or more, depending on the selected gateway SKU.

Use the following values:

  • The –gateway-type for a Site-to-Site configuration is Vpn. The gateway type is always specific to the configuration that you are implementing. For more information, see Gateway types.
  • The –vpn-type can be RouteBased (referred to as a Dynamic Gateway in some documentation), or PolicyBased (referred to as a Static Gateway in some documentation). The setting is specific to requirements of the device that you are connecting to. For more information about VPN gateway types, see About VPN Gateway configuration settings.
  • Select the Gateway SKU that you want to use. There are configuration limitations for certain SKUs. For more information, see Gateway SKUs.

Create the VPN gateway using the az network vnet-gateway create command. If you run this command using the ‘–no-wait’ parameter, you don’t see any feedback or output. This parameter allows the gateway to create in the background. It takes 45 minutes or more to create a gateway.

az network vnet-gateway create --name VNet1GW --public-ip-address VNet1GWIP --resource-group TestRG1 --vnet TestVNet1 --gateway-type Vpn --vpn-type RouteBased --sku VpnGw1 --no-wait 

8. Configure your VPN device

Site-to-Site connections to an on-premises network require a VPN device. In this step, you configure your VPN device. When configuring your VPN device, you need the following:

  • A shared key. This is the same shared key that you specify when creating your Site-to-Site VPN connection. In our examples, we use a basic shared key. We recommend that you generate a more complex key to use.
  • The Public IP address of your virtual network gateway. You can view the public IP address by using the Azure portal, PowerShell, or CLI. To find the public IP address of your virtual network gateway, use the az network public-ip list command. For easy reading, the output is formatted to display the list of public IPs in table format.
az network public-ip list --resource-group TestRG1 --output table

To download VPN device configuration scripts:

Depending on the VPN device that you have, you may be able to download a VPN device configuration script. For more information, see Download VPN device configuration scripts.

See the following links for additional configuration information:

9. Create the VPN connection

Create the Site-to-Site VPN connection between your virtual network gateway and your on-premises VPN device. Pay particular attention to the shared key value, which must match the configured shared key value for your VPN device.

Create the connection using the az network vpn-connection create command.

az network vpn-connection create --name VNet1toSite2 --resource-group TestRG1 --vnet-gateway1 VNet1GW -l eastus --shared-key abc123 --local-gateway2 Site2

After a short while, the connection will be established.

10. Verify the VPN connection

You can verify that your connection succeeded by using the az network vpn-connection show command. In the example, ’–name’ refers to the name of the connection that you want to test. When the connection is in the process of being established, its connection status shows ‘Connecting’. Once the connection is established, the status changes to ‘Connected’.

az network vpn-connection show --name VNet1toSite2 --resource-group TestRG1

If you want to use another method to verify your connection, see Verify a VPN Gateway connection.

To connect to a virtual machine

You can connect to a VM that is deployed to your VNet by creating a Remote Desktop Connection to your VM. The best way to initially verify that you can connect to your VM is to connect by using its private IP address, rather than computer name. That way, you are testing to see if you can connect, not whether name resolution is configured properly.

  1. Locate the private IP address. You can find the private IP address of a VM by either looking at the properties for the VM in the Azure portal, or by using PowerShell.
    • Azure portal – Locate your virtual machine in the Azure portal. View the properties for the VM. The private IP address is listed.
    • PowerShell – Use the example to view a list of VMs and private IP addresses from your resource groups. You don’t need to modify this example before using it.Azure PowerShellCopyTry It$VMs = Get-AzVM $Nics = Get-AzNetworkInterface | Where VirtualMachine -ne $null foreach($Nic in $Nics) { $VM = $VMs | Where-Object -Property Id -eq $Nic.VirtualMachine.Id $Prv = $Nic.IpConfigurations | Select-Object -ExpandProperty PrivateIpAddress $Alloc = $Nic.IpConfigurations | Select-Object -ExpandProperty PrivateIpAllocationMethod Write-Output "$($VM.Name): $Prv,$Alloc" }
  2. Verify that you are connected to your VNet using the Point-to-Site VPN connection.
  3. Open Remote Desktop Connection by typing “RDP” or “Remote Desktop Connection” in the search box on the taskbar, then select Remote Desktop Connection. You can also open Remote Desktop Connection using the ‘mstsc’ command in PowerShell.
  4. In Remote Desktop Connection, enter the private IP address of the VM. You can click “Show Options” to adjust additional settings, then connect.

Troubleshoot a connection

If you are having trouble connecting to a virtual machine over your VPN connection, check the following:

  • Verify that your VPN connection is successful.
  • Verify that you are connecting to the private IP address for the VM.
  • If you can connect to the VM using the private IP address, but not the computer name, verify that you have configured DNS properly. For more information about how name resolution works for VMs, see Name Resolution for VMs.
  • For more information about RDP connections, see Troubleshoot Remote Desktop connections to a VM.

Common tasks

This section contains common commands that are helpful when working with site-to-site configurations. For the full list of CLI networking commands, see Azure CLI – Networking.

To view local network gateways

To view a list of the local network gateways, use the az network local-gateway list command.

az network local-gateway list --resource-group TestRG1

To modify local network gateway IP address prefixes – no gateway connection

If you don’t have a gateway connection and you want to add or remove IP address prefixes, you use the same command that you use to create the local network gateway, az network local-gateway create. You can also use this command to update the gateway IP address for the VPN device. To overwrite the current settings, use the existing name of your local network gateway. If you use a different name, you create a new local network gateway, instead of overwriting the existing one.

Each time you make a change, the entire list of prefixes must be specified, not just the prefixes that you want to change. Specify only the prefixes that you want to keep. In this case, and

az network local-gateway create --gateway-ip-address --name Site2 -g TestRG1 --local-address-prefixes

To modify local network gateway IP address prefixes – existing gateway connection

If you have a gateway connection and want to add or remove IP address prefixes, you can update the prefixes using az network local-gateway update. This results in some downtime for your VPN connection. When modifying the IP address prefixes, you don’t need to delete the VPN gateway.

Each time you make a change, the entire list of prefixes must be specified, not just the prefixes that you want to change. In this example, and are already present. We add the prefixes and and specify all 4 of the prefixes when updating.

az network local-gateway update --local-address-prefixes --name VNet1toSite2 -g TestRG1

To modify the local network gateway ‘gatewayIpAddress’

If the VPN device that you want to connect to has changed its public IP address, you need to modify the local network gateway to reflect that change. The gateway IP address can be changed without removing an existing VPN gateway connection (if you have one). To modify the gateway IP address, replace the values ‘Site2’ and ‘TestRG1’ with your own using the az network local-gateway update command.

az network local-gateway update --gateway-ip-address --name Site2 --resource-group TestRG1

Verify that the IP address is correct in the output:Copy

"gatewayIpAddress": "",

To verify the shared key values

Verify that the shared key value is the same value that you used for your VPN device configuration. If it is not, either run the connection again using the value from the device, or update the device with the value from the return. The values must match. To view the shared key, use the az network vpn-connection-list.

az network vpn-connection shared-key show --connection-name VNet1toSite2 --resource-group TestRG1

To view the VPN gateway Public IP address

To find the public IP address of your virtual network gateway, use the az network public-ip list command. For easy reading, the output for this example is formatted to display the list of public IPs in table format.

az network public-ip list --resource-group TestRG1 --output table

With the gateway and router setup complete, the next step is replicating the virtual machines

Replicating Virtual Machines / Containers

Due to the number of different ways to migrate Virtual Machines into Azure from the private cloud, we will not cover migration in depth this time. Whether you use Windows, Linux, KVM, VMWare, Unix, Hyper-V, Docker, K8s, Proxmox, or anything else, Microsoft has a number of guides for migration. Leave questions on this article, if there is information you can’t find.

There are a few items to keep in mind when migrating Virtual Machines / Containers from a homelab to Azure. A major one is that the migration is likely not permanent and likely not one way. Azure has a number of tools and technologies for migrating infrastructure into Azure; it does not, however, have many tools for migrating instances out of Azure (and rightly so). This means that your migration strategy will need to be able to synchronize back to the homelab. Prepare for a bi-directional migration process, if migration is required for entire machines.

Bi-Directional Migrations

Virtual Machines

Bi-directional migration options will differ depending on the hosting technology you use for your homelab. The most basic case, Virtual Machines (KVM, VMWare, Hyper-V, Xen, etc.), has two options based on deployment type:

  • Immutable – Due to the stateless nature of immutable instances, the synchronization mechanism would target the underlying state storage mechanism if there is one. In the case of a blob or file store, the data can be easily copied between Azure and homelab using any number of tools.
  • Mutable – Mutable instances will most likely need to have the (virtual) machine disks copied between each host. Use appropriate disk conversion technology so that the disk type is appropriate the host (Azure VHD vs KVM qcow2, etc).

It should be noted that migrations of certain products, like SQL Server, have more advanced migration and synchronization methods. These products are outside the scope of this discussion. For an example, a PostgreSQL cluster has the option to migrate via replication.


Data Sync

Azure has a number of different options to sync blobs between the home lab and Azure:

Front Doors

Direct Entry

Another item to consider is what will be the front door into your homelab. The usage of front door here is describing how the applications are accessed over the internet. If the homelab will still use its internet as the front door for application access, then will the available bandwidth be enough for the migration increase? If Azure is to be the front door, then how do you simultaneously handle having two front doors as the DNS update propagates?

Diagram showing an on-premises network on the left, which consists of three computer screens and a gateway. A double-sided arrow connecting the on-premises to a cloud labeled internet with “Site-to-site VPN tunnel” above the double-sided arrow. Another double-sided arrow connects the internet cloud to its right, through a dotted rectangle labeled “Azure Virtual Network”. The arrow connects to an item labeled VPN gateway. That gateway has a single-arrow leaving it to the right pointing to a load balancer which is pointing to three identical virtual machines. At the bottom, there is a computer monitor labeled user. Between the computer monitor labeled user and the cloud labeled internet is two doors. The left door is labeled on-premises front door. The right door is labeled Azure Front Door. There is a blue arrow for each door pointing from the computer labeled user. There is a blue arrow from each door pointing to the cloud labeled internet.

If you wish to use both as a front door, make sure you have an ingress option available that can properly route between the different subnets and servers. In the case of a basic web server, use something like Nginx or HA Proxy for ingress and basic routing, so that it can be mirrored between homelab and Azure.

Once our event is complete, it’s time to synchronize our systems and tear down our gateway.

Tear Down (official docs)

There are a couple of different approaches you can take when you want to delete a virtual network gateway for a VPN gateway configuration.

  • If you want to delete everything and start over, as in the case of a test environment, you can delete the resource group. When you delete a resource group, it deletes all the resources within the group. This is method is only recommended if you don’t want to keep any of the resources in the resource group. You can’t selectively delete only a few resources using this approach.
  • If you want to keep some of the resources in your resource group, deleting a virtual network gateway becomes slightly more complicated. Before you can delete the virtual network gateway, you must first delete any resources that are dependent on the gateway. The steps you follow depend on the type of connections that you created and the dependent resources for each connection.

Before beginning

1. Download the latest Azure Resource Manager PowerShell cmdlets.

Download and install the latest version of the Azure Resource Manager PowerShell cmdlets. For more information about downloading and installing PowerShell cmdlets, see How to install and configure Azure PowerShell.

2. Connect to your Azure account.

Open your PowerShell console and connect to your account. Use the following example to help you connect:


Check the subscriptions for the account.


If you have more than one subscription, specify the subscription that you want to use.

Select-AzSubscription -SubscriptionName "Replace_with_your_subscription_name"

Delete a Site-to-Site VPN gateway

To delete a virtual network gateway for a S2S configuration, you must first delete each resource that pertains to the virtual network gateway. Resources must be deleted in a certain order due to dependencies. When working with the examples below, some of the values must be specified, while other values are an output result. We use the following specific values in the examples for demonstration purposes:

VNet name: VNet1
Resource Group name: RG1
Virtual network gateway name: GW1

The following steps apply to the Resource Manager deployment model.

1. Get the virtual network gateway that you want to delete.

$GW=get-Azvirtualnetworkgateway -Name "GW1" -ResourceGroupName "RG1"

2. Check to see if the virtual network gateway has any connections.

get-Azvirtualnetworkgatewayconnection -ResourceGroupName "RG1" | where-object {$_.VirtualNetworkGateway1.Id -eq $GW.Id}
$Conns=get-Azvirtualnetworkgatewayconnection -ResourceGroupName "RG1" | where-object {$_.VirtualNetworkGateway1.Id -eq $GW.Id}

3. Delete all connections.

You may be prompted to confirm the deletion of each of the connections.

$Conns | ForEach-Object {Remove-AzVirtualNetworkGatewayConnection -Name $_.name -ResourceGroupName $_.ResourceGroupName}

4. Delete the virtual network gateway.

You may be prompted to confirm the deletion of the gateway. If you have a P2S configuration to this VNet in addition to your S2S configuration, deleting the virtual network gateway will automatically disconnect all P2S clients without warning.

Remove-AzVirtualNetworkGateway -Name "GW1" -ResourceGroupName "RG1"

At this point, your virtual network gateway has been deleted. You can use the next steps to delete any resources that are no longer being used.

5 Delete the local network gateways.

Get the list of the corresponding local network gateways.

$LNG=Get-AzLocalNetworkGateway -ResourceGroupName "RG1" | where-object {$_.Id -In $Conns.LocalNetworkGateway2.Id}

Delete the local network gateways. You may be prompted to confirm the deletion of each of the local network gateway.

$LNG | ForEach-Object {Remove-AzLocalNetworkGateway -Name $_.Name -ResourceGroupName $_.ResourceGroupName}

6. Delete the Public IP address resources.

Get the IP configurations of the virtual network gateway.

$GWIpConfigs = $Gateway.IpConfigurations

Get the list of Public IP address resources used for this virtual network gateway. If the virtual network gateway was active-active, you will see two Public IP addresses.

$PubIP=Get-AzPublicIpAddress | where-object {$_.Id -In $GWIpConfigs.PublicIpAddress.Id}

Delete the Public IP resources.

$PubIP | foreach-object {remove-AzpublicIpAddress -Name $_.Name -ResourceGroupName "RG1"}

7. Delete the gateway subnet and set the configuration.

$GWSub = Get-AzVirtualNetwork -ResourceGroupName "RG1" -Name "VNet1" | Remove-AzVirtualNetworkSubnetConfig -Name "GatewaySubnet"
Set-AzVirtualNetwork -VirtualNetwork $GWSub

Delete a VPN gateway by deleting the resource group

If you are not concerned about keeping any of your resources in the resource group and you just want to start over, you can delete an entire resource group. This is a quick way to remove everything. The following steps apply only to the Resource Manager deployment model.

1. Get a list of all the resource groups in your subscription.


2. Locate the resource group that you want to delete.

Locate the resource group that you want to delete and view the list of resources in that resource group. In the example, the name of the resource group is RG1. Modify the example to retrieve a list of all the resources.

Find-AzResource -ResourceGroupNameContains RG1

3. Verify the resources in the list.

When the list is returned, review it to verify that you want to delete all the resources in the resource group, as well as the resource group itself. If you want to keep some of the resources in the resource group, use the steps in the earlier sections of this article to delete your gateway.

4. Delete the resource group and resources.

To delete the resource group and all the resource contained in the resource group, modify the example and run.

Remove-AzResourceGroup -Name RG1

5. Check the status.

It takes some time for Azure to delete all the resources. You can check the status of your resource group by using this cmdlet.

Get-AzResourceGroup -ResourceGroupName RG1

The result that is returned shows ‘Succeeded’.

ResourceGroupName : RG1
Location          : eastus
ProvisioningState : Succeeded

TrueNAS Azure Sync for Proxmox

Previously, we discuss TrueNAS NFS for Proxmox. Now that Proxmox is using TrueNAS for storage, a Cloud Sync Task can be used to copy the TrueNAS NFS to Azure Blob Storage as a backup. The following steps are required:

  • Create Azure Blob Storage Account
  • Create TrueNAS Cloud Credentials
  • Create Cloud Sync Tasks

Create Azure Blob Storage Account

Create a storage account

Every storage account must belong to an Azure resource group. A resource group is a logical container for grouping your Azure services. When you create a storage account, you have the option to either create a new resource group, or use an existing resource group. This article shows how to create a new resource group.

general-purpose v2 storage account provides access to all of the Azure Storage services: blobs, files, queues, tables, and disks. The steps outlined here create a general-purpose v2 storage account, but the steps to create any type of storage account are similar. For more information about types of storage accounts and other storage account settings, see Azure storage account overview.


To create a general-purpose v2 storage account in the Azure portal, follow these steps:

  1. On the Azure portal menu, select All services. In the list of resources, type Storage Accounts. As you begin typing, the list filters based on your input. Select Storage Accounts.
  2. On the Storage Accounts window that appears, choose Add.
  3. On the Basics tab, select the subscription in which to create the storage account.
  4. Under the Resource group field, select your desired resource group, or create a new resource group. For more information on Azure resource groups, see Azure Resource Manager overview.
  5. Next, enter a name for your storage account. The name you choose must be unique across Azure. The name also must be between 3 and 24 characters in length, and may include only numbers and lowercase letters.
  6. Select a location for your storage account, or use the default location.
  7. Select a performance tier. The default tier is Standard.
  8. Set the Account kind field to Storage V2 (general-purpose v2).
  9. Specify how the storage account will be replicated. The default replication option is Read-access geo-redundant storage (RA-GRS). For more information about available replication options, see Azure Storage redundancy.
  10. Additional options are available on the NetworkingData protectionAdvanced, and Tags tabs. To use Azure Data Lake Storage, choose the Advanced tab, and then set Hierarchical namespace to Enabled. For more information, see Azure Data Lake Storage Gen2 Introduction
  11. Select Review + Create to review your storage account settings and create the account.
  12. Select Create.

The following image shows the settings on the Basics tab for a new storage account:

Screenshot showing how to create a storage account in the Azure portal

Create a container

To create a container in the Azure portal, follow these steps:

  1. Navigate to your new storage account in the Azure portal.
  2. In the left menu for the storage account, scroll to the Blob service section, then select Containers.
  3. Select the + Container button.
  4. Type a name for your new container. The container name must be lowercase, must start with a letter or number, and can include only letters, numbers, and the dash (-) character. For more information about container and blob names, see Naming and referencing containers, blobs, and metadata.
  5. Set the level of public access to the container. The default level is Private (no anonymous access).
  6. Select OK to create the container.Screenshot showing how to create a container in the Azure portal

Create TrueNAS Cloud Credentials

To begin integrating TrueNAS with a Cloud Storage provider, register the account credentials on the system. After saving any credentials, a Cloud Sync Task allows sending or receiving data from that Cloud Storage Provider.

Saving a Cloud Storage Credential

Transferring data from TrueNAS to the Cloud requires saving Cloud Storage Provider credentials on the system.

It is recommended to have another browser tab open and logged in to the Cloud Storage Provider account you intend to link with TrueNAS. Some providers require additional information that is generated on the storage provider account page. For example, saving an Amazon S3 credential on TrueNAS could require logging in to the S3 account and generating an access key pair on the Security Credentials > Access Keys page.

To save cloud storage provider credentials, go to System > Cloud Credentials and click Add.

Using the Azure Portal we can retrieve our access keys.

Create Cloud Sync Tasks

TrueNAS can send, receive, or synchronize data with a Cloud Storage provider. Cloud Sync tasks allow for single time transfers or recurring transfers on a schedule, and are an effective method to back up data to a remote location.

Go to Tasks > Cloud Sync Tasks and click Add.


Give the task a memorable Description and select an existing cloud Credential. TrueNAS connects to the chosen Cloud Storage Provider and shows the available storage locations. Decide if data is transferring to (PUSH) or from (PULL) the Cloud Storage location (Remote). Choose a Transfer Mode:

Next, Control when the task runs by defining a Schedule. When a specific Schedule is required, choose Custom and use the Advanced Scheduler.Advanced Schedulerexpand

Unsetting Enable makes the configuration available without allowing the Schedule to run the task. To manually activate a saved task, go to Tasks > Cloud Sync Tasks, click  to expand a task, and click RUN NOW.

The remaining options allow tuning the task to your specific requirements.Specific Optionsexpand


DescriptionEnter a description of the Cloud Sync Task.
DirectionPUSH sends data to cloud storage. PULL receives data from cloud storage. Changing the direction resets the Transfer Mode to COPY.
Transfer ModeSYNC: Files on the destination are changed to match those on the source. If a file does not exist on the source, it is also deleted from the destination. COPY: Files from the source are copied to the destination. If files with the same names are present on the destination, they are overwritten. MOVE: After files are copied from the source to the destination, they are deleted from the source. Files with the same names on the destination are overwritten.
Directory/FilesSelect the directories or files to be sent to the cloud for Push syncs, or the destination to be written for Pull syncs. Be cautious about the destination of Pull jobs to avoid overwriting existing files.


CredentialSelect the cloud storage provider credentials from the list of available Cloud Credentials.


ScheduleSelect a schedule preset or choose Custom to open the advanced scheduler.
EnabledEnable this Cloud Sync Task. Unset to disable this Cloud Sync Task without deleting it.

Advanced Options

Follow SymlinksFollow symlinks and copy the items to which they link.
Pre-ScriptScript to execute before running sync.
Post-ScriptScript to execute after running sync.
ExcludeList of files and directories to exclude from sync. Separate entries by pressing Enter. See rclone filtering for more details about the --exclude option.

Advanced Remote Options

Remote EncryptionPUSH: Encrypt files before transfer and store the encrypted files on the remote system. Files are encrypted using the Encryption Password and Encryption Salt values. PULL: Decrypt files that are being stored on the remote system before the transfer. Transferring the encrypted files requires entering the same Encryption Password and Encryption Salt that was used to encrypt the files. Additional details about the encryption algorithm and key derivation are available in the rclone crypt File formats documentation.
TransfersNumber of simultaneous file transfers. Enter a number based on the available bandwidth and destination system performance. See rclone –transfers.
Bandwidth limitA single bandwidth limit or bandwidth limit schedule in rclone format. Separate entries by pressing Enter. Example: 08:00,512 12:00,10MB 13:00,512 18:00,30MB 23:00,off. Units can be specified with the beginning letter: b, k (default), M, or G. See rclone –bwlimit.

Scripting and Environment Variables

Advanced users can write scripts that run immediately before or after the Cloud Sync task. The Post-script field is only run when the Cloud Sync task successfully completes. You can pass a variety of task environment variables into the Pre- and Post- script fields:


There also are provider-specific variables like CLOUD_SYNC_CLIENT_ID or CLOUD_SYNC_TOKEN or CLOUD_SYNC_CHUNK_SIZE

Remote storage settings:


Local storage settings:


Testing Settings

Test the settings before saving by clicking DRY RUN. TrueNAS connects to the Cloud Storage Provider and simulates a file transfer. No data is actually sent or received. A dialog shows the test status and allows downloading the task logs.


Cloud Sync Behavior

Saved tasks are activated according to their schedule or by clicking RUN NOW. An in-progress cloud sync must finish before another can begin. Stopping an in-progress task cancels the file transfer and requires starting the file transfer over.

To view logs about a running or the most recent run of a task, click the task status.

Cloud Sync Restore

To quickly create a new Cloud Sync that uses the same options but reverses the data transfer, expand () an existing Cloud Sync and click RESTORE.


Enter a new Description for this reversed task and define the path to a storage location for the transferred data.

The restored cloud sync is saved as another entry in Tasks > Cloud Sync Tasks.

Using Cognitive Services: Custom Vision Service with Azure IoT Edge

This is a guide on how to use Cognitive Services: Custom Vision Service with Azure IoT Edge without having the Edge module host a web endpoint but instead use the built in Module to Module communication. This post will break down the steps into four major sections:

  • Creating the Custom Vision Model
  • Creating the Edge Module in Python
  • Adding the model and custom code for Custom Vision
  • Deploy the Module

Creating the Custom Vision Model

To use the Custom Vision Service for image classification, you must first build a classifier model. In this guide, you’ll learn how to build a classifier through the Custom Vision website.


  • A valid Azure subscription. Create an account for free.
  • A set of images with which to train your classifier. See below for tips on choosing images.

Create Custom Vision resources in the Azure portal

To use Custom Vision Service, you will need to create Custom Vision Training and Prediction resources in the Azure portal. This will create both a Training and Prediction resource.

Create a new project

In your web browser, navigate to the Custom Vision web page and select Sign in. Sign in with the same account you used to sign into the Azure portal.

Image of the sign-in page

  1. To create your first project, select New Project. The Create new project dialog box will appear.The new project dialog box has fields for name, description, and domains.
  2. Enter a name and a description for the project. Then select a Resource Group. If your signed-in account is associated with an Azure account, the Resource Group dropdown will display all of your Azure Resource Groups that include a Custom Vision Service Resource.
  3. Select Classification under Project Types. Then, under Classification Types, choose either Multilabel or Multiclass, depending on your use case. Multilabel classification applies any number of your tags to an image (zero or more), while multiclass classification sorts images into single categories (every image you submit will be sorted into the most likely tag). You will be able to change the classification type later if you wish.
  4. Next, select one of the available domains. Each domain optimizes the classifier for specific types of images, as described in the following table. You will be able to change the domain later if you wish.
    Domain Purpose
    Generic Optimized for a broad range of image classification tasks. If none of the other domains are appropriate, or you are unsure of which domain to choose, select the Generic domain.
    Food Optimized for photographs of dishes as you would see them on a restaurant menu. If you want to classify photographs of individual fruits or vegetables, use the Food domain.
    Landmarks Optimized for recognizable landmarks, both natural and artificial. This domain works best when the landmark is clearly visible in the photograph. This domain works even if the landmark is slightly obstructed by people in front of it.
    Retail Optimized for images that are found in a shopping catalog or shopping website. If you want high precision classifying between dresses, pants, and shirts, use this domain.
    Compact domains Optimized for the constraints of real-time classification on mobile devices. The models generated by compact domains can be exported to run locally.
  5. Finally, select Create project.

Choose training images

As a minimum, we recommend you use at least 30 images per tag in the initial training set. You’ll also want to collect a few extra images to test your model once it is trained.

In order to train your model effectively, use images with visual variety. Select images with that vary by:

  • camera angle
  • lighting
  • background
  • visual style
  • individual/grouped subject(s)
  • size
  • type

Additionally, make sure all of your training images meet the following criteria:

  • .jpg, .png, or .bmp format
  • no greater than 6MB in size (4MB for prediction images)
  • no less than 256 pixels on the shortest edge; any images shorter than this will be automatically scaled up by the Custom Vision Service

Upload and tag images

In this section you will upload and manually tag images to help train the classifier.

  1. To add images, click the Add images button and then select Browse local files. Select Open to move to tagging. Your tag selection will be applied to the entire group of images you’ve selected to upload, so it is easier to upload images in separate groups according to their desired tags. You can also change the tags for individual images after they have been uploaded.The add images control is shown in the upper left, and as a button at bottom center.
  2. To create a tag, enter text in the My Tags field and press Enter. If the tag already exists, it will appear in a dropdown menu. In a multilabel project, you can add more than one tag to your images, but in a multiclass project you can add only one. To finish uploading the images, use the Upload [number] files button.Image of the tag and upload page
  3. Select Done once the images have been uploaded.The progress bar shows all tasks completed.

To upload another set of images, return to the top of this section and repeat the steps.

Train the classifier

To train the classifier, select the Train button. The classifier uses all of the current images to create a model that identifies the visual qualities of each tag.

The train button in the top right of the web page's header toolbar

The training process should only take a few minutes. During this time, information about the training process is displayed in the Performance tab.

The browser window with a training dialog in the main section

Custom Vision Service supports the following exports:

  • Tensorflow for Android.
  • CoreML for iOS11.
  • ONNX for Windows ML.
  • A Windows or Linux container. The container includes a Tensorflow model and service code to use the Custom Vision Service API.

Convert to a compact domain

To convert the domain of an existing classifier, use the following steps:

  1. From the Custom vision page, select the Home icon to view a list of your projects. You can also use the https://customvision.ai/projects to see your projects.Image of the home icon and projects list
  2. Select a project, and then select the Gear icon in the upper right of the page.Image of the gear icon
  3. In the Domains section, select a compact domain. Select Save Changes to save the changes.Image of domains selection
  4. From the top of the page, select Train to retrain using the new domain.

Export your model

To export the model after retraining, use the following steps:

  1. Go to the Performance tab and select Export.Image of the export icon


    If the Export entry is not available, then the selected iteration does not use a compact domain. Use the Iterations section of this page to select an iteration that uses a compact domain, and then select Export.

  2. Select the export format, and then select Export to download the model.

Creating the Edge Module in Python

You can use Azure IoT Edge modules to deploy code that implements your business logic directly to your IoT Edge devices. This tutorial walks you through creating an IoT Edge module that will be edited to use the Custom Vision model exported. In this tutorial, you learn how to:

  • Use Visual Studio Code to create an IoT Edge Python module.
  • Use Visual Studio Code and Docker to create a Docker image and publish it to your registry.

If you don’t have an Azure subscription, create a free account before you begin.


Before beginning this tutorial, you should have gone through the previous tutorial to set up your development environment for Linux container development: Develop IoT Edge modules for Linux devices. By completing either of those tutorials, you should have the following prerequisites in place:

To develop an IoT Edge module in Python, install the following additional prerequisites on your development machine:

  • Python extension for Visual Studio Code.
  • Python.
  • Pip for installing Python packages (typically included with your Python installation).

Create a module project

The following steps create an IoT Edge Python module by using Visual Studio Code and the Azure IoT Tools.

Create a new project

Use the Python package cookiecutter to create a Python solution template that you can build on top of.

  1. In Visual Studio Code, select View > Terminal to open the VS Code integrated terminal.
  2. In the terminal, enter the following command to install (or update) cookiecutter, which you use to create the IoT Edge solution template:
    pip install --upgrade --user cookiecutter
  3. Select View > Command Palette to open the VS Code command palette.
  4. In the command palette, enter and run the command Azure: Sign in and follow the instructions to sign in your Azure account. If you’re already signed in, you can skip this step.

In the command palette, enter and run the command Azure IoT Edge: New IoT Edge solution. Follow the prompts and provide the following information to create your solution:

Field Value
Select folder Choose the location on your development machine for VS Code to create the solution files.
Provide a solution name Enter a descriptive name for your solution or accept the default EdgeSolution.
Select module template Choose Python Module.
Provide a module name Name your module PythonModule.
Provide Docker image repository for the module An image repository includes the name of your container registry and the name of your container image. Your container image is prepopulated from the name you provided in the last step. Replace localhost:5000 with the login server value from your Azure container registry. You can retrieve the login server from the Overview page of your container registry in the Azure portal.

The final image repository looks like <registry name>.azurecr.io/pythonmodule.

Provide Docker image repository

Add your registry credentials

The environment file stores the credentials for your container repository and shares them with the IoT Edge runtime. The runtime needs these credentials to pull your private images onto the IoT Edge device.

  1. In the VS Code explorer, open the .env file.
  2. Update the fields with the username and password values that you copied from your Azure container registry.
  3. Save the .env file.

Select your target architecture

Currently, Visual Studio Code can develop C modules for Linux AMD64 and Linux ARM32v7 devices. You need to select which architecture you’re targeting with each solution, because the container is built and run differently for each architecture type. The default is Linux AMD64.

  1. Open the command palette and search for Azure IoT Edge: Set Default Target Platform for Edge Solution, or select the shortcut icon in the side bar at the bottom of the window.
  2. In the command palette, select the target architecture from the list of options. For this tutorial, we’re using an Ubuntu virtual machine as the IoT Edge device, so will keep the default amd64.

Adding the model and custom code for Custom Vision


Deploy the Module

Build and push your module

In the previous section, you created an IoT Edge solution and added code to the PythonModule that will filter out messages where the reported machine temperature is within the acceptable limits. Now you need to build the solution as a container image and push it to your container registry.

  1. Open the VS Code integrated terminal by selecting View > Terminal.
  2. Sign in to Docker by entering the following command in the terminal. Sign in with the username, password, and login server from your Azure container registry. You can retrieve these values from the Access keys section of your registry in the Azure portal.
    docker login -u <ACR username> -p <ACR password> <ACR login server>
    You may receive a security warning recommending the use of --password-stdin. While that best practice is recommended for production scenarios, it's outside the scope of this tutorial. For more information, see the docker login reference. In the VS Code explorer, right-click the deployment.template.json file and select Build and Push IoT Edge solution.

    The build and push command starts three operations. First, it creates a new folder in the solution called config that holds the full deployment manifest, built out of information in the deployment template and other solution files. Second, it runs docker build to build the container image based on the appropriate dockerfile for your target architecture. Then, it runs docker push to push the image repository to your container registry.

Deploy modules to device

Use the Visual Studio Code explorer and the Azure IoT Tools extension to deploy the module project to your IoT Edge device. You already have a deployment manifest prepared for your scenario, the deployment.json file in the config folder. All you need to do now is select a device to receive the deployment.

Make sure that your IoT Edge device is up and running.

  1. In the Visual Studio Code explorer, expand the Azure IoT Hub Devices section to see your list of IoT devices.
  2. Right-click the name of your IoT Edge device, then select Create Deployment for Single Device.
  3. Select the deployment.json file in the config folder and then click Select Edge Deployment Manifest. Do not use the deployment.template.json file.
  4. Click the refresh button. You should see the new PythonModule running along with the TempSensor module and the $edgeAgent and $edgeHub.




New Pluralsight Courses Released!

My new Pluralsight courses Cleaning and Preparing Data in Microsoft Azure and Architecting Xamarin.Forms Applications for Code Reuse were just released! Here are the synopsis:

Cleaning and Preparing Data in Microsoft Azure


This course targets software developers and data scientists looking to understand the initial steps in a machine learning solution. The content will showcase methods and tools available using Microsoft Azure.


No data science project of merit has ever started with great data ready to plug into an algorithm. In this course, Cleaning and Preparing Data in Microsoft Azure, you’ll learn foundational knowledge of the steps required to utilize data in a machine learning project. First, you’ll discover different types of data and languages. Next, you’ll learn about managing large data sets and handling bad data. Finally, you’ll explore how to utilize Azure Notebooks. When you’re finished with this course, you’ll have the skills and knowledge of preparing data needed for use in Microsoft Azure. Software required: Microsoft Azure.

Architecting Xamarin.Forms Applications for Code Reuse


A well-architected application is flexible to changing business requirements. This course will teach you how to architect Xamarin.Forms applications in a way that promotes reusable patterns.


As business requirements change, so do solution assumptions. In this course, Architecting Xamarin.Forms Applications for Code Reuse, you’ll learn different architectural patterns in Xamarin.Forms. First, you’ll explore project structure and organization. Next, you’ll discover patterns and standards to promote code sharing. Finally, you’ll learn how to utilize dependency injection in Xamarin.Forms. When you’re finished with this course, you’ll have the skills and knowledge of architecting Xamarin.Forms projects needed to optimally promote code reuse.

Azure IoT Hub – OpenSSL – Generate proof of possession

The Azure IoT documentation has guides on setting up certifications for production use. That documentation showcases how to properly setup using certificate authorities to generate proof of possession. For development purposes, you may want to use self signed certificates.

  1. Assuming  the original key and cert were created with the following commands (Azure IoT reports unverified if you upload it):
# Create root key
openssl genrsa -out iotHubRoot.key 2048

# Create root cert
openssl req -new -x509 -key iotHubRoot.key -out iotHubRoot.cer -days 500
  1. Then generate the verification cert (pay attention to fill in common name with verification code):
# Create verification key and csr
openssl genrsa -out verification.key 2048
openssl req -new -key verification.key -out verification.csr

#It will prompt for cert fields. 
#IMPORTANT: The Common Name needs to be your Verification Code (generate and copy that from portal)

# Create verification pem
openssl x509 -req -in -verification.csr -CA iotHubRoot.cer -CAkey iotHubRoot.key -CAcreateserial -out verification.pem -days 500 -sha256
  1. Upload pem file to portal to verify certificate

New Pluralsight Course Released!

My new Pluralsight course Sourcing Data in Microsoft Azure was just released! Here is the synopsis:


This course targets software developers looking to source data from inside and outside of the cloud. The content will also showcase methods and tools available using Microsoft Azure.


The cloud has nearly infinite compute power for processing. In this course, Sourcing Data in Microsoft Azure, you’ll learn foundational knowledge of data types, data policy, and finding data. First, you’ll learn how to register data sources with Azure Data Catalog. Next, you’ll discover how to extract, transform, and load data with Azure Data Factory. Finally, you’ll explore how to set up data processing with Azure HD Insight. When you’re finished with this course, you’ll have the skills and knowledge of the tools and processes needed to source data in Microsoft Azure. Software required: Microsoft Azure portal.

New Pluralsight Course Released!

My new Pluralsight course Deploying and Managing Models in Microsoft Azure was just released! Here is the synopsis:


In this course, you’ll learn about how data science practitioners can utilize tools for managing the models they create. You’ll also see those tools showcased in Microsoft Azure.


One of the most overlooked processes in data science is managing the life cycle of models. In this course, Deploying and Managing Models in Microsoft Azure, you’ll gain foundational knowledge of Azure Machine Learning. First, you’ll discover how to create and utilize Azure Machine Learning. Next, you’ll find out how to integrate with Azure DevOps. Finally, you’ll explore how to utilize them together to automate the deployment and management of models. When you’re finished with this course, you’ll have the skills and knowledge of model life cycle management needed to manage a machine learning project. Software required: Microsoft Azure.

Authoring for Pluralsight – Azure Machine Learning

Off to start another set of courses for Pluralsight:

  • Sourcing Data in Microsoft Azure
  • Deploying and Managing Models in Microsoft Azure
  • Cleaning and Preparing Data in Microsoft Azure

If you would like to check out any of my other courses, visit my author’s profile.

Sourcing Data in Microsoft Azure

This course is for people looking to move into the data sciences. They can have an existing background in development or IT.

This course will show how to find data in Microsoft Azure, how to move and change that data, and finally how to build workflows around that data.

This course assumes the developer has an understanding of basic computer terminology and the azure portal.

Deploying and Managing Models in Microsoft Azure

This course is for people looking to move into the data sciences. They can have an existing background in development or IT.

This course introduces the audience to the different data preparation steps involved with data projects. This course will show how to clean, transform, and wrangle the data needed for a data project.

This course assumes the developer has an understanding of basic computer terminology and the azure portal.

Cleaning and Preparing Data in Microsoft Azure

This course is for data science practitioners who need to learn more about how to utilize tools for managing the models they create.

The audience will be taken through automation and DevOps to learn more about how to manage their workflows. Everything from versioning, automated deployments, automated hyper-parameter tuning, and more will be discussed.

This course assumes the data scientist has an understanding of machine learning and common terminology and integration in machine learning projects. The course also assumes the data scientist has knowledge of Azure and the Azure portal.

Authoring for Pluralsight – Developing Microsoft Azure Intelligent Edge Solutions

Off to start another course for Pluralsight. This time its Developing Microsoft Azure Intelligent Edge Solutions. If you would like to check out any of my other courses, visit my author’s profile. The new course will cover the following topics:

  • Edge
    • IoT Architecture
    • IoT use cases and solutions
    • Edge Architecture
  • Azure IoT Hub
    • Overview of the IoT Ecosystem in Azure
    • IoT Hub message routing
    • Stream processing overview
  • Hot, Warm, and Cold paths
    • Use cases for hot, warm, and cold paths
    • Hot path with event hubs and log app
    • Warm path with Cosmos DB
    • Cold path with Azure Blob Storage
  • Real Time and Batch Processing
    • Overview and Demos of Stream Analytics Service
    • Overview and Demos of Time Series Insights

iotedge: error while loading shared libraries: libssl.so.1.0.2: cannot open shared object file: No such file or directory – Raspberry Pi

After installing Azure IoT Edge using the guide for Linux ARM32, the following error was presented: “iotedge: error while loading shared libraries: libssl.so.1.0.2: cannot open shared object file: No such file or directory“. 

The fix was simple enough, just install the building libssl1.02 using the following command:

sudo apt-get install libssl1.0.2

Test by running the iotedge command:



If that works successfully, restart the iotedge service:

service iotedge edge restart

Verify that it is running by checking the service status:

service iotedge edge status