Secure a Web Server with Azure NSGs

Deploy a Linux VM and lock down network traffic using Azure Network Security Groups.

Introduction

30 Second Summary

Every server connected to the internet gets scanned by automated bots within minutes of going live. Without a firewall controlling which traffic gets in, your server is completely exposed.

In this project, you will deploy a Linux virtual machine in Azure and install a web server on it. Then you will build a Network Security Group from scratch to control exactly which traffic can reach your server.

What You'll Build

You will create a Linux VM running nginx inside an Azure Virtual Network, then configure a Network Security Group with custom inbound rules to allow only SSH and HTTP traffic.

By the end of this project, you'll have:

  • A Resource Group containing all your Azure resources, with a Virtual Network and subnet for network isolation.
  • A Linux VM running an nginx web server that you can access from your browser.
  • A Network Security Group with custom inbound security rules for SSH (port 22) and HTTP (port 80), with tested rule priority evaluation.
  • Secret Mission: Add Application Security Groups to manage security rules by application role instead of IP addresses.

Are there any prerequisites?

You need an Azure account (a free account works perfectly) and a Mac with Terminal for SSH connections. No prior Azure experience is required.

Before We Start

Before We Start...

Create Your Resource Group and Virtual Network

Before you can secure a web server, you need the cloud infrastructure to run it on. Every Azure project starts with a resource group to keep your resources organized.

In this step, you'll create the resource group for this project. You'll also set up a virtual network with a subnet where your VM will live.

In this step, get ready to:
  • Create a resource group to organize your Azure resources.
  • Create a virtual network with a subnet for your VM.
  • Verify everything is set up correctly.
Create a resource group
  • Sign in to the Azure portal at portal.azure.com if you haven't already.
  • Click the search bar at the top of the page.
  • Type Resource groups in the search bar.
  • Select Resource groups from the results.
  • Click + Create.
  • Select your subscription from the Subscription dropdown.
  • Enter nsg-lab-rg in the Resource group field.
  • Select East US 2 from the Region dropdown.
  • Click Review + create.
  • Click Create.

What is a resource group?

A resource group is a container that holds related Azure resources for a project. When you're done with the project, you can delete the entire resource group to clean up all resources at once.

Create a virtual network with a subnet

Your VM needs a network to sit inside. A virtual network is an isolated network in Azure that only your resources can access.

  • Click the search bar at the top of the Azure portal.
  • Type Virtual networks in the search bar.
  • Select Virtual networks from the results.
  • Click + Create.
  • Select nsg-lab-rg from the Resource group dropdown.
  • Enter nsg-lab-vnet in the Virtual network name field.
  • Select East US 2 from the Region dropdown.
  • Click Next until you reach the IP addresses tab.
  • Click on the default subnet that appears in the subnet list.
  • In the Name field, replace the existing name with web-subnet.
  • Keep the Starting address as 10.0.0.0.
  • Keep the Size as /24 (256 addresses).
  • Click Save.
  • Click Review + create.
  • Click Create.

Why a dedicated subnet?

A subnet is a range of IP addresses inside your virtual network. By placing your VM in a specific subnet, you can apply Network Security Group rules to all resources in that subnet at once.

This is exactly how you'll lock down traffic later in this project.

Verify your resources
  • Click the search bar and type Resource groups.
  • Select Resource groups from the results.
  • Click on nsg-lab-rg.
  • Confirm you see nsg-lab-vnet listed in the resource list.
  • Click on nsg-lab-vnet to open it.
  • In the left menu under Settings, click Subnets.
  • Confirm that web-subnet appears with the address range 10.0.0.0/24.

Don't see your subnet?

Make sure you clicked Save after renaming the subnet on the IP addresses tab during virtual network creation.

Confirm that your virtual network and resource group are both set to the East US 2 region. Resources in different regions won't appear together.

Help me find my subnet in Azure.

Your networking foundation is ready. Next up, you'll deploy a Linux VM inside this virtual network and install a web server on it.

Deploy a Linux VM

Your virtual network and subnet are in place. Now you need a resource running inside that network for your security rules to protect.

In this step, you'll deploy a Linux virtual machine into web-subnet and connect to it over SSH. Then you'll install nginx to turn it into a web server.

In this step, get ready to:
  • Deploy a Linux VM into your virtual network.
  • Connect to the VM using SSH from your Mac.
  • Install and verify the nginx web server.
Create the VM in the Azure portal

Azure Virtual Machines let you run a full operating system in the cloud. You'll create an Ubuntu Linux VM that will become your web server.

  • Type Virtual machines in the Azure portal search bar and select Virtual machines from the results.
  • Click + Create, then select Azure virtual machine.
  • On the Basics tab, select nsg-lab-rg as the Resource group.
  • Enter web-server-vm as the Virtual machine name.
  • Set Region to (US) East US 2.
  • Under Availability options, select No infrastructure redundancy required.
  • Set Security type to Standard.
  • For Image, select Ubuntu Server 22.04 LTS - x64 Gen2.
  • For Size, click See all sizes and select Standard_B1s.

Don't see Standard_B1s?

Some regions don't offer B1s. Select Standard_B2ats_v2 instead. Both are covered by the Azure free tier.

  • Under Administrator account, select SSH public key as the Authentication type.
  • Set Username to azureuser.
  • For SSH public key source, select Generate new key pair.
  • Enter web-server-key as the Key pair name.
  • Under Inbound port rules, set Public inbound ports to Allow selected ports.
  • Select SSH (22) from the Select inbound ports dropdown.
  • Click Next : Disks > at the bottom of the page.
  • Click Next : Networking > to skip past the Disks tab.
  • On the Networking tab, select nsg-lab-vnet as the Virtual network.
  • Select web-subnet as the Subnet.
  • Leave Public IP set to the default. Azure creates a new public IP address for you automatically.
  • Set NIC network security group to None.

Why set NIC network security group to None?

Azure can attach a Network Security Group directly to the VM's network interface (NIC). Setting this to None means the VM starts with no firewall rules at all. Every port is open to the internet.

This is intentional. In the next step, you'll build your own NSG from scratch and attach it at the subnet level. That way you'll see the full before-and-after of locking down your VM yourself.

  • Click Review + create.
  • Click Create.
  • A Generate new key pair dialog appears. Click Download private key and create resource.
  • The .pem file downloads to your ~/Downloads folder. You'll use this file to connect to your VM in the next substep.
  • Wait for the deployment to complete. Click Go to resource when it finishes.

You should see the web-server-vm overview page showing a Status of Running and a public IP address listed on the right side.

Deployment failed?

If you see a quota or size error, your region may not have Standard_B1s available. Go back and select Standard_B2ats_v2 as the VM size instead.

Make sure the region is set to East US 2 and the resource group is nsg-lab-rg.

help me troubleshoot my Azure VM deployment failure

Connect to your VM using SSH

SSH is a protocol that lets you securely access a remote machine's command line. You'll use it to connect from your Mac's Terminal to the Ubuntu VM running in Azure.

  • On the web-server-vm overview page, find the Public IP address field on the right side and copy the value.
  • Press Cmd+Space to open your search bar.
  • Type Terminal and press Enter to open it.
  • Set the key file permissions and connect to your VM by running these commands:
chmod 400 ~/Downloads/web-server-key.pem
ssh -i ~/Downloads/web-server-key.pem azureuser@[[VM_PUBLIC_IP="your VM public IP address"]]

What do these commands do?

  • chmod 400 restricts the key file so only you can read it. SSH refuses to use a key file that other users on your machine could access.
  • ssh -i tells SSH to use the specified private key file to authenticate. azureuser is the username you set during VM creation.
  • Type yes when prompted to accept the host fingerprint and press Enter.

You should see the Ubuntu welcome message with system information displayed in your Terminal. You are now connected to your Azure VM.

Connection timed out or permission denied?

  • If you see Permission denied, make sure you ran the chmod 400 command first and that the .pem file is in your ~/Downloads folder.
  • If the connection times out, double check that you pasted the correct public IP address from the VM overview page.
  • Make sure the VM status shows Running in the Azure portal. If it shows Stopped, click Start and wait for it to boot.

help me troubleshoot my SSH connection to an Azure VM

Install nginx on your VM

Nginx is a lightweight web server. Installing it gives your VM something to serve over HTTP, which you'll use later to test whether your security rules are allowing or blocking traffic.

  • While still connected to your VM via SSH, update the package list and install nginx by running these commands:
sudo apt-get -y update
sudo apt-get -y install nginx

What do these commands do?

  • sudo apt-get -y update refreshes the list of available packages so Ubuntu knows what's available to install.
  • sudo apt-get -y install nginx downloads and installs the nginx web server. The -y flag automatically confirms the installation so you don't have to type "yes" at a prompt.
  • Verify nginx is running by running this command:
sudo systemctl status nginx

You should see active (running) in green text. This confirms nginx started successfully and is ready to serve web pages.

  • Press q to exit the status view.
  • Type exit and press Enter to close the SSH session.

Nginx not showing as active?

  • If the status shows inactive or failed, try starting it manually with sudo systemctl start nginx and then check the status again.
  • If the install command failed, make sure you ran sudo apt-get -y update first. The package list needs to be refreshed before installing.

help me troubleshoot nginx not running on my Azure VM

Your VM is up, nginx is running, and every port is wide open. Next up, you'll build a Network Security Group from scratch to lock down exactly which traffic gets through.

Create and Configure a Network Security Group

Your VM is running and nginx is serving web pages. There is just one problem.

Right now, your VM has no firewall controlling which network traffic can reach it. Anyone on the internet can connect to any port. In this step, you will create a Network Security Group and attach it to your subnet to lock down all inbound internet traffic by default.

In this step, get ready to:
  • Create a Network Security Group in the Azure portal.
  • Explore the default security rules that Azure generates automatically.
  • Associate the NSG with your subnet to activate traffic filtering.
Create the Network Security Group
  • In the Azure portal, type Network security group in the top search bar.
  • Select Network security groups from the results.

Watch out for the classic version

You may see "Network security groups (classic)" in the results. Do not select that one. Choose the option without "(classic)" in the name.

  • Click + Create.
  • Set Subscription to your subscription.
  • Set Resource group to nsg-lab-rg.
  • Set Name to web-nsg.
  • Set Region to East US 2.
  • Click Review + create, then click Create.
  • Once deployment completes, click Go to resource.

You should now see the overview page for web-nsg. It has no custom rules yet.

What is a Network Security Group?

A Network Security Group (NSG) is an Azure resource that filters network traffic to and from other Azure resources. Think of it as a list of rules that Azure checks every time traffic tries to enter or leave your resources.

Each rule specifies a source, destination, port, protocol, and whether to allow or deny the traffic. Azure evaluates rules in priority order, and the first matching rule wins.

Don't see web-nsg after deployment?

Make sure you selected nsg-lab-rg as the resource group and East US 2 as the region. If you accidentally used a different resource group, the NSG will not appear alongside your other resources.

Help me troubleshoot my NSG creation in Azure.

Explore the default rules

Every NSG comes with a set of default security rules that Azure creates automatically. These defaults define the baseline behavior for traffic filtering before you add any custom rules.

  • In the Settings section of web-nsg, click Inbound security rules.
  • Click Default rules to expand the hidden default rules.

You should see three default inbound rules:

  • AllowVnetInBound (priority 65000). Allows traffic between resources within the same Virtual Network.
  • AllowAzureLoadBalancerInBound (priority 65001). Allows health probes from the Azure load balancer.
  • DenyAllInBound (priority 65500). Denies all other inbound traffic that did not match an earlier rule.
  • Now click Outbound security rules in the Settings section.
  • Click Default rules to expand the outbound defaults.

You should see three default outbound rules: AllowVnetOutBound (65000), AllowInternetOutBound (65001), and DenyAllOutBound (65500).

What do the default rules mean?

The key rule to notice is DenyAllInBound at priority 65500. It blocks all inbound traffic from the internet unless an earlier rule (with a lower priority number) explicitly allows it.

Priority numbers range from 100 to 4096 for custom rules. Lower numbers are evaluated first. The default rules use very high numbers (65000+) so your custom rules always take precedence.

Associate the NSG with your subnet

An NSG does nothing until you attach it to a subnet or a network interface. Once attached, Azure enforces its rules on all traffic flowing through that subnet.

  • In the Settings section of web-nsg, click Subnets.
  • Click + Associate.
  • Select nsg-lab-vnet as the Virtual network.
  • Select web-subnet as the Subnet.
  • Click OK.

You should see web-subnet listed under the Subnets page for web-nsg. Your NSG is now filtering all traffic to and from resources in that subnet.

Why associate with the subnet instead of the NIC?

You can attach an NSG to a subnet or to an individual network interface (NIC). Microsoft recommends associating NSGs to subnets rather than individual NICs for easier administration.

When attached to a subnet, the rules apply to every resource in that subnet automatically. If you add another VM to web-subnet later, it inherits the same security rules without any extra configuration.

What changed for your VM?

Before this step, your VM had no NSG at all. Azure allows all traffic when no NSG is associated with a network interface or subnet. That is why SSH worked freely in the previous step.

Now that web-nsg is in place, the DenyAllInBound default rule blocks all inbound internet traffic. SSH, HTTP, and everything else from outside the Virtual Network is denied until you add custom allow rules.

Can't find the Subnets option?

Make sure you are on the web-nsg resource page, not the Virtual Network page. The Subnets option is in the Settings section of the NSG's left navigation menu.

Help me find the subnet association option for my NSG.

Your NSG is now protecting your subnet with a default deny-all posture. Next up, you will add custom inbound rules to selectively open the ports you need.

Add Inbound Security Rules and Test Connectivity

In the last step, you created a Network Security Group and attached it to your subnet. Right now, every inbound request from the internet hits the default DenyAllInBound rule and gets dropped.

In this step, you'll punch through that wall by creating custom inbound rules. You'll open port 22 for SSH and port 80 for HTTP, testing each change as you go.

In this step, get ready to:
  • Confirm that the default NSG rules block all inbound traffic to your VM.
  • Add custom inbound rules to allow SSH and HTTP traffic.
  • Test a priority conflict to see how Azure evaluates rules in order.
Test that all inbound traffic is blocked

Before you add any custom rules, confirm that the NSG is doing its job. Both SSH and HTTP traffic should be completely blocked right now.

  • Open a new browser tab and navigate to the following URL:
http://[[VM_PUBLIC_IP="your VM public IP address"]]
  • Wait 15-20 seconds. The page should time out or fail to load.
  • Open Terminal on your Mac by pressing Cmd+Space, typing Terminal, and pressing Enter.
  • Try connecting via SSH by running this command:
ssh -i ~/Downloads/web-server-key.pem azureuser@[[VM_PUBLIC_IP="your VM public IP address"]]
  • This should also hang or time out. Press Ctrl+C to cancel the connection attempt.

Why is everything blocked now?

Before you created web-nsg, your VM had no NSG at all. Azure allows all traffic when no NSG is associated with a network interface or subnet.

Now that web-nsg is attached to web-subnet, the default DenyAllInBound rule (priority 65500) blocks all inbound internet traffic. The only way through is to add a higher-priority rule that explicitly allows it.

SSH still connecting successfully?

If SSH connects instead of timing out, your NSG may not be properly associated with the subnet.

  • Go back to web-nsg in the Azure portal.
  • Click Subnets under Settings and confirm web-subnet is listed.
  • If it's not listed, re-associate the NSG by clicking + Associate and selecting nsg-lab-vnet and web-subnet.

Why is my VM still reachable after associating the NSG?

Add inbound rules for SSH and HTTP

Your NSG is blocking everything. Now you'll selectively open exactly the ports you need. First up is port 22 for SSH, so you can manage your VM remotely.

  • In the Azure portal, search for web-nsg in the top search bar and select it.
  • Click Inbound security rules under Settings.
  • Click + Add.
  • Set Source to Any.
  • Set Source port ranges to *.
  • Set Destination to Any.
  • Set Service to Custom.
  • Set Destination port ranges to 22.
  • Set Protocol to TCP.
  • Set Action to Allow.
  • Set Priority to 100.
  • Set Name to Allow-SSH.
  • Click Add.

Why priority 100?

Azure evaluates NSG rules from the lowest priority number to the highest. The valid range is 100 to 4096, and the first matching rule wins.

By setting Allow-SSH to 100, you ensure it gets checked well before the default DenyAllInBound at 65500. Any SSH traffic matches this rule first and gets allowed through.

Wait a few seconds for the rule to take effect, then test it.

  • Test your SSH connection by running this command in Terminal:
ssh -i ~/Downloads/web-server-key.pem azureuser@[[VM_PUBLIC_IP="your VM public IP address"]]
  • Type yes if prompted to accept the host fingerprint.

You should see the Ubuntu welcome message. Your Allow-SSH rule is working.

  • Type exit to close the SSH session.

SSH still timing out?

  • Wait 30-60 seconds for the rule to propagate, then try again.
  • Double check that Protocol is set to TCP and Destination port ranges is 22.
  • Confirm the rule's Action is Allow, not Deny.

Help me troubleshoot my Allow-SSH rule.

Now add a second rule for HTTP traffic on port 80 so your nginx web page is accessible from a browser.

  • Go back to web-nsg in the Azure portal.
  • Click Inbound security rules under Settings.
  • Click + Add.
  • Set Source to Any.
  • Set Source port ranges to *.
  • Set Destination to Any.
  • Set Service to Custom.
  • Set Destination port ranges to 80.
  • Set Protocol to TCP.
  • Set Action to Allow.
  • Set Priority to 200.
  • Set Name to Allow-HTTP.
  • Click Add.

Wait a few seconds, then test it.

  • Refresh your browser tab that was pointing to http:// followed by your VM's public IP address.

You should see the nginx welcome page. Your Allow-HTTP rule is working.

  • Now try navigating to https:// followed by the same IP address (note the s in https).

This should fail to load.

Why does HTTPS fail?

HTTPS uses port 443. Your NSG only has custom rules for port 22 (SSH) and port 80 (HTTP). Since no rule allows port 443, the default DenyAllInBound blocks it.

This proves that NSG rules are specific. Opening one port does not open others.

Test a priority conflict

Azure always evaluates rules from the lowest priority number to the highest. The first matching rule wins. Let's prove this by creating a Deny rule for port 80 that has a lower priority number than your existing Allow-HTTP rule.

  • Go back to web-nsg in the Azure portal.
  • Click Inbound security rules under Settings.
  • Click + Add.
  • Set Source to Any.
  • Set Source port ranges to *.
  • Set Destination to Any.
  • Set Destination port ranges to 80.
  • Set Protocol to TCP.
  • Set Action to Deny.
  • Set Priority to 150.
  • Set Name to Deny-HTTP-Test.
  • Click Add.
  • Refresh your browser tab pointing to http:// followed by your VM's public IP.

The page should time out or fail to load. Even though Allow-HTTP (priority 200) still exists, Deny-HTTP-Test (priority 150) has a lower number and gets evaluated first. The Deny wins.

How does rule evaluation work?

When traffic arrives, Azure checks rules in order starting from the lowest priority number. For your port 80 traffic, Deny-HTTP-Test (150) is checked before Allow-HTTP (200).

The first matching rule wins. Since Deny-HTTP-Test matches and says Deny, the traffic is dropped immediately. Azure never reaches Allow-HTTP. This is why priority numbers matter so much when designing your security rules.

Now clean up the test rule to restore HTTP access.

  • In the Inbound security rules list, find the Deny-HTTP-Test rule.
  • Click the three dots (...) on the right side of the rule.
  • Select Delete and confirm the deletion.
  • Refresh your browser tab. The nginx welcome page should load again.

Page still not loading after deleting the rule?

  • Wait 30-60 seconds for the rule deletion to propagate.
  • Confirm that Deny-HTTP-Test no longer appears in the Inbound security rules list.
  • Make sure you are using http:// (not https://) in the browser address bar.

Help me figure out why HTTP is still blocked after deleting my Deny rule.

Your NSG now has two custom rules filtering traffic exactly the way you want. Next up, you'll use Azure's Effective Security Rules view to see the full picture of how all your rules combine.

Diagnose with Effective Security Rules

Your Network Security Group is live and filtering traffic. SSH and HTTP both work, and everything else is blocked.

But how do you confirm that your rules are actually doing what you think they're doing? Azure has a built-in diagnostic view called Effective Security Rules that shows the full, aggregated picture of every rule applied to a network interface. In this step, you'll use it to verify your security posture and then deliberately break things to prove you understand how rule priority works.

In this step, get ready to:
  • View the Effective Security Rules for your VM's network interface.
  • Understand how Azure evaluates rules by priority number.
  • Test a priority conflict to prove that rule order determines what traffic gets through.
View effective security rules

Right now you know which rules you added to web-nsg. The Effective Security Rules view goes further. It shows every rule that applies to a specific network interface, including your custom rules and all default rules, sorted by priority.

  • In the Azure portal, search for Virtual machines and select web-server-vm.
  • In the left pane, expand Networking.
  • Select Network settings.

You'll see the inbound and outbound rules listed for your VM's network interface. This is a summary view, but you need the full diagnostic view.

  • Click the network interface name. It looks like web-server-vm followed by some numbers.
  • In the network interface view, expand Help in the left pane.
  • Select Effective security rules.

You should see your Allow-SSH (priority 100) and Allow-HTTP (priority 200) rules alongside the three default inbound rules: AllowVnetInBound (65000), AllowAzureLoadBalancerInBound (65001), and DenyAllInBound (65500).

What are Effective Security Rules?

When you look at an NSG directly, you only see the rules you added to that specific NSG. The Effective Security Rules view combines rules from every NSG that applies to a network interface and shows them in priority order.

This is the view you use in production when you need to diagnose why traffic is or isn't reaching a VM. It shows you the complete picture in one place.

Don't see the Effective security rules option?

Make sure you clicked the network interface name (not the NSG name) on the Network settings page. The Effective security rules option is under Help in the network interface view, not in the VM's left pane directly.

If you're still stuck, help me find the Effective Security Rules view for my VM.

Understand rule evaluation order

The Effective Security Rules view isn't just a list of rules. It's sorted by priority number, which is the exact order Azure uses to evaluate incoming traffic.

  • Look at the priority numbers in the view. Notice that your rules are listed from lowest number (100) to highest (65500).

How does Azure evaluate security rules?

When traffic arrives at your VM, Azure checks rules starting from the lowest priority number. The first rule that matches the traffic wins. No further rules are checked after a match.

For example, when SSH traffic arrives on port 22, Azure checks Allow-SSH (priority 100) first. It matches, so the traffic is allowed. Azure never reaches DenyAllInBound (priority 65500).

If someone tries to reach port 443 (HTTPS), none of your custom rules match. Azure keeps checking until it hits DenyAllInBound, which blocks the traffic. This is why only the ports you explicitly allow are open.

Test a priority conflict

Understanding priority order in theory is one thing. Seeing it break real traffic makes it stick. You'll add a deny rule for port 80 with a lower priority number than your existing Allow-HTTP rule, which means Azure will evaluate the deny rule first.

  • Navigate back to your NSG. Search for Network security groups in the portal and select web-nsg.
  • Click Inbound security rules under Settings.
  • Click + Add.
  • Set Source to Any.
  • Set Source port ranges to *.
  • Set Destination to Any.
  • Set Service to Custom.
  • Set Destination port ranges to 80.
  • Set Protocol to TCP.
  • Set Action to Deny.
  • Set Priority to 150.
  • Set Name to Deny-HTTP-Test.
  • Click Add.

You now have two rules targeting port 80. Allow-HTTP has priority 200 and Deny-HTTP-Test has priority 150. Since 150 is a lower number than 200, Azure evaluates the deny rule first.

  • Open a new browser tab and navigate to http:// followed by your VM's public IP address.

The page should time out or fail to load. Even though Allow-HTTP (priority 200) still exists, Azure never reaches it. The Deny-HTTP-Test rule (priority 150) matches the traffic first and blocks it.

Why does the deny rule win?

Azure evaluates rules from the lowest priority number to the highest. When HTTP traffic arrives on port 80, Azure checks priority 100 (Allow-SSH). That doesn't match port 80, so Azure moves on.

Next it checks priority 150 (Deny-HTTP-Test). This matches port 80, so Azure denies the traffic immediately. It never checks priority 200 (Allow-HTTP). The first matching rule always wins.

Now confirm this is visible in the diagnostic view.

  • Navigate back to the Effective Security Rules view. Go to web-server-vm, expand Networking, select Network settings, click the network interface name, expand Help, and select Effective security rules.

You should see both Deny-HTTP-Test (priority 150) and Allow-HTTP (priority 200) listed. This confirms that both rules exist, but the deny rule is evaluated first because of its lower priority number.

Now clean up the test rule so your web server is accessible again.

  • Navigate back to web-nsg. Search for Network security groups and select it.
  • Click Inbound security rules under Settings.
  • Find the Deny-HTTP-Test rule and click the three dots (or the delete icon) on the right side of the rule.
  • Click Delete, then confirm the deletion.
  • Go back to your browser tab and refresh http:// followed by your VM's public IP address.

The nginx welcome page should load again. With the deny rule deleted, Allow-HTTP (priority 200) is once again the first rule that matches port 80 traffic.

Still seeing a timeout after deleting the rule?

Azure rule changes can take a few seconds to propagate. Wait 30 seconds and try refreshing the page again.

If the page still doesn't load, go back to web-nsg and check Inbound security rules to confirm that Deny-HTTP-Test is gone and Allow-HTTP (priority 200) is still present.

If you're still stuck, help me restore HTTP access to my Azure VM after deleting a deny rule.

Secret mission

Add Application Security Groups

So far, your NSG rules use "Any" as the destination. That works for one VM, but production environments run dozens of servers. In this secret mission, you will use Application Security Groups to organize your VM by role and apply security rules based on application function instead of IP addresses.

Before you go

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. The VM you created is free-tier eligible, but the public IP address may incur a small charge if left running beyond the free tier allocation.

Cost warning

Azure free accounts include 750 hours/month of B-series burstable VMs for 12 months. If you exceed that limit or your free trial expires, the VM and public IP will start incurring charges.

If you are not planning to continue experimenting right away, choose Pause or Delete below to avoid unexpected costs.

Resources you used:

  • 1 Resource Group (nsg-lab-rg).
  • 1 Virtual Network (nsg-lab-vnet) with a subnet (web-subnet).
  • 1 Linux VM (web-server-vm) with an OS disk, network interface, and public IP address.
  • 1 Network Security Group (web-nsg).
  • 1 SSH key file (web-server-key.pem) saved to your local ~/Downloads folder.

Keep everything running

No action needed. Choose this if you are still actively experimenting with your NSG rules and VM.

  • Set up Auto-shutdown to avoid unnecessary charges. Navigate to your VM (web-server-vm) in the Azure portal.
  • In the left pane, expand Operations and select Auto-shutdown.
  • Toggle it On, set a time that works for you, and click Save.

Pause - I'll come back to this later

Stop (deallocate) the VM to stop compute charges while keeping all your resources intact.

  • Navigate to your VM (web-server-vm) in the Azure portal.
  • On the VM overview page, click Stop.
  • Confirm the deallocation when prompted.
  • You will not be charged for compute while the VM is stopped. The public IP and disk storage may still incur minimal charges.

Delete - I don't want to use this again

Remove all project resources and stop all charges by deleting the resource group.

  • In the Azure portal, search for Resource groups and select it.
  • Select nsg-lab-rg.
  • Click Delete resource group.
  • Type nsg-lab-rg to confirm, then click Delete.
  • Delete the SSH key file from your local machine by opening Terminal and running:
rm ~/Downloads/web-server-key.pem

Mission accomplished

That's a Wrap!

Nice work! You just secured a live Azure VM from scratch using Network Security Groups. That is a real cloud security skill you can talk about in any interview.

You've learned how to:

  • Deploy a Linux VM running an nginx web server inside an Azure Virtual Network, and build a Network Security Group from scratch with custom inbound rules for SSH (port 22) and HTTP (port 80).
  • Test a priority conflict to prove you understand how Azure evaluates security rules in order from lowest priority number to highest.
  • Diagnose your full security posture using the Effective Security Rules view, verifying exactly which traffic reaches your VM and why.
  • Secret Mission: Added Application Security Groups to manage security rules by application role instead of IP address.

Ready to quiz yourself?