Convert to Bicep templates and update Ubuntu image support - #5
Conversation
Brings the stalled Ubuntu/Bicep work (Bicep sources, osVersion parameter, optional public IP) into the Ubuntu support branch. Resolves the linuxrouter.sh conflict by dropping the unfinished raw-nft path and unifying on iptables, which is nftables-backed on Ubuntu 20.04 and later.
Sync with upstream; brings linuxrouterv2.sh.
The UbuntuLTS alias was removed from the Azure CLI. Also match the Ubuntu image offer case-insensitively in deploylinuxnvabgpnp.azcli, since new deployments use the 0001-com-ubuntu-server-jammy offer.
- NSG rule used a comma-separated sourceAddressPrefix string, which is invalid; use sourceAddressPrefixes. Protocol * instead of TCP so the router also handles UDP/ICMP traffic. - Subnet was created as '<name>-vnet' instead of the given subnet name - scriptUri default pointed to LinuxRouter.sh (wrong case)
Canonical no longer publishes Ubuntu 18.04 images in the Azure Marketplace, so the templates were not deployable anymore. Both templates now take an osVersion parameter offering 22.04 (jammy, Gen2) and 24.04 (noble), defaulting to 24.04 LTS. linuxrouter.sh needs no version branching: from Ubuntu 20.04 on, iptables is backed by nftables (iptables-nft), so the same commands work unchanged - verified on 22.04 and 24.04.
Basic SKU public IPs were retired in Azure (September 2025), which made new deployments fail. Also bump the 2015-2022 resource API versions to current ones, express the optional public IP as a proper conditional object, name the OS disk explicitly in the newsubnet template, and drop the completed roadmap item from the README.
There was a problem hiding this comment.
Pull request overview
This PR modernizes the Linux router deployment assets by introducing Bicep sources (and regenerated ARM JSON) and updating Ubuntu image selection to support Ubuntu 22.04/24.04, along with more flexible networking/public IP options.
Changes:
- Added new Bicep templates for Linux router deployments (existing subnet vs. new subnet) and regenerated the corresponding ARM templates.
- Updated VM image selection to support Ubuntu 22.04 and 24.04, and refreshed API versions across resources.
- Made public IP deployment optional and adjusted scripts/docs for newer Ubuntu images and tooling.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Updates Linux router template description to reflect Ubuntu 24.04 default + Bicep source-of-truth. |
| notes.txt | Updates example az vm create image to Ubuntu 22.04. |
| linuxrouterv2.sh | Removes stray trailing markdown backticks. |
| linuxrouter.sh | Updates install steps for persistence packages and adds Ubuntu version context. |
| LinuxRouter.json | Regenerated ARM template with new parameters (osVersion, optional public IP), updated API versions, and imageReference mapping. |
| LinuxRouter.bicep | New Bicep template (existing subnet) with parameterization and Ubuntu 22.04/24.04 image selection. |
| LinuxRouter-newsubnet.json | Regenerated ARM template (new subnet) with NSG/subnet creation, updated APIs, imageReference mapping, and optional public IP. |
| LinuxRouter-newsubnet.bicep | New Bicep template (new subnet) adding NSG/subnet creation plus VM/NIC/PIP resources. |
| deploylinuxnvabgpnp.azcli | Updates Ubuntu VM selection filter for applying a tooling extension. |
| deploylinuxnvabgp.azcli | Updates az vm create image to Ubuntu 22.04. |
| deploylinuxnva.azcli | Updates az vm create image to Ubuntu 22.04. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| @secure() | ||
| param adminPassword string | ||
|
|
||
| @description('Existing Virtual Nework Name') |
| @secure() | ||
| param adminPassword string | ||
|
|
||
| @description('Existing Virtual Nework Name') |
| var extensionName = 'CustomScript' | ||
| var nicName = '${virtualMachineName}-nic' | ||
| var publicIPAddressName = '${virtualMachineName}-PublicIP' |
| "extensionName": "CustomScript", | ||
| "NIC": "[concat(parameters('virtualMachineName'),'-NIC')]", | ||
| "publicIPAddressName": "[concat(parameters('virtualMachineName'),'-PublicIP')]", | ||
| "subnet1Ref": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('existingVirtualNetworkName'), parameters('subnetName'))]", | ||
| "location": "[resourceGroup().location]" | ||
| "nicName": "[format('{0}-nic', parameters('virtualMachineName'))]", | ||
| "publicIPAddressName": "[format('{0}-PublicIP', parameters('virtualMachineName'))]", | ||
| "osVersionDefinitions": { |
| @description('Deploy Public IP Address') | ||
| param deployPublicIpAdress bool = true |
| @description('Deploy Public IP Address') | ||
| param deployPublicIpAdress bool = true |
| export DEBIAN_FRONTEND=noninteractive | ||
|
|
||
| echo "Updating repositories" | ||
| sudo apt-get update -y --fix-missing |
| echo Installing tools for networking connectivity validation such as traceroute, tcptraceroute, iperf and others | ||
| nettoolsuri="https://raw.githubusercontent.com/dmauser/azure-vm-net-tools/main/script/nettools.sh" | ||
| for vm in `az vm list -g $rg --query "[?storageProfile.imageReference.offer=='UbuntuServer'].name" -o tsv` | ||
| for vm in `az vm list -g $rg --query "[?contains(storageProfile.imageReference.offer, 'ubuntu')].name" -o tsv` |
- Fix 'Nework' typo in parameter descriptions - Restore '-NIC' name casing in the newsubnet template so redeploys into existing resource groups keep the same NIC resource name - Rename deployPublicIpAdress -> deployPublicIpAddress (new parameter in this PR, so no compatibility impact) - linuxrouter.sh: drop sudo - the script already requires root and runs as root via the Custom Script Extension; this also makes DEBIAN_FRONTEND=noninteractive actually reach apt-get (sudo env_reset would strip it). Re-verified on 22.04/24.04. - Match both 'ubuntu' and 'Ubuntu' image offers in the VM filter
Standard SKU public IPs block inbound Internet traffic until an NSG allows it, while outbound stays available through the attached public IP as an explicit outbound method. Also documents the outbound requirements when deploying without a public IP, now that Azure has retired default outbound access for new deployments.
|
Thanks for this — reviewed it in depth and validated it by actually deploying to Azure. This is good work and I'm merging it. Beyond the Ubuntu 24.04 support, it quietly fixes several real latent bugs that were breaking the templates:
I also confirmed the checked-in ARM JSON is byte-identical to One pre-existing bug worth folding in: a CSE / cloud-init raceWhile validating I deployed both templates. CSE exited 2. To be clear: this is not caused by your PR — Root cause. The Custom Script Extension can start while cloud-init is still rewriting Diagnostic signature on a failed VM: $ apt-cache policy netfilter-persistent # empty output
$ grep -r . /etc/apt/sources.list # azure.archive.ubuntu.com
$ ls /var/lib/apt/lists/ # archive.ubuntu.com_* filesRe-running the identical commands by hand after Fix — guard the apt work at the top of # The Custom Script Extension can start before cloud-init has finished setting
# up the apt sources. Installing then fails with "Unable to locate package"
# because the package indexes on disk belong to the superseded mirror.
echo "Waiting for cloud-init to complete"
cloud-init status --wait >/dev/null 2>&1 || trueNo deadlock risk: waagent runs extensions independently of cloud-init, so cloud-init never waits on the extension. The I've already applied this to Validation resultsEverything below was run against a live subscription and has since been torn down.
One heads-up on Standard SKU public IPsNow that Basic SKU public IPs are retired, new public IPs are Standard, which is deny-by-default for inbound. Thanks again for the contribution. |
This pull request introduces two new Bicep templates (
LinuxRouter.bicepandLinuxRouter-newsubnet.bicep) for deploying a Linux router VM in Azure, and updates their corresponding ARM templates (LinuxRouter.jsonandLinuxRouter-newsubnet.json). The main improvements include support for Ubuntu 22.04 and 24.04, parameterization of key deployment options, modernization of API versions, and enhanced flexibility for network and public IP configuration.The most important changes are:
Template Modernization and Flexibility
LinuxRouter.bicep,LinuxRouter-newsubnet.bicep) with improved parameterization for VM size, OS version, disk type, admin credentials, and public IP deployment, making deployments more flexible and maintainable. [1] [2]Operating System and Disk Options
Network and Security Enhancements
deployPublicIpAddressparameter, with conditional resource creation and NIC attachment logic. [1] [2] [3] [4]Template Metadata and Minor Fixes
Fixed issues
Fixes #3 — Ubuntu 18.04 LTS is out of support: Canonical has meanwhile removed the 18.04 images from the Azure Marketplace entirely, so the templates were no longer deployable. They now offer Ubuntu 22.04 (jammy, Gen2) and 24.04 (noble) via the new
osVersionparameter, defaulting to 24.04 LTS.Fixes #1 — Deployment of Linux VM fails, package
iptables-persistentcannot be found:linuxrouter.shnow runsapt-get updatebefore installing packages (which also ensures/etc/iptablesexists once the package is installed). The script was verified end-to-end on Ubuntu 22.04 and 24.04: package installation, NAT rules, and persistence in/etc/iptables/rules.v4.