Debugging an IIS-Hosted ASP.NET Core API on Azure VM: A Real-World Walkthrough

Overview

This article walks through a real-world debugging scenario involving an ASP.NET Core API deployed on an Azure VM behind IIS. The issue initially appeared to be a connectivity or deployment problem but ultimately turned out to be related to IIS hostname bindings and SNI (Server Name Indication).

The goal was to validate API availability directly on the VM and isolate issues between Azure routing, IIS configuration, and application behavior.


Step 1: Initial Problem

The API endpoint:

https://foo-vm.example.com/service/ProcessRequest

was returning:

404 Not Found

This raised several possible concerns:

  • Deployment failure
  • IIS misconfiguration
  • Routing issues
  • Network or SSL problems

Step 2: SSL / Certificate Validation

While testing direct HTTPS calls, the following error appeared:

Could not establish trust relationship for the SSL/TLS secure channel

Action Taken

  • Exported the server certificate (.cer)
  • Installed it on the local machine (Trusted Root / Intermediate store)
  • Alternatively, used curl with -k to bypass SSL validation:
curl -k https://foo-vm.example.com

Outcome

  • SSL issues were eliminated as a blocker
  • Able to reach the server over HTTPS

Step 3: Direct API Testing with curl

Multiple endpoints were tested:

curl -k https://foo-vm.example.com/
curl -k https://foo-vm.example.com/service/health
curl -k https://foo-vm.example.com/api/health

Result

All returned:

404 Not Found (Microsoft-IIS/10.0)

Insight

  • Requests were reaching IIS
  • But no matching route/application was found

Step 4: Validate Application Deployment

A simple health check endpoint was introduced:

/service/health

Expected response:

Healthy

However, even this endpoint returned 404 when accessed via the VM hostname.


Step 5: IIS Investigation

Upon inspecting IIS:

  • The API was not hosted under Default Web Site
  • Instead, it was hosted under a separate site:
Foo.ApiSvc

Key Finding

Requests to:

https://foo-vm.example.com

were hitting:

Default Web Site ❌

—not the actual API site.


Step 6: Binding and SNI Discovery (Root Cause)

IIS bindings for the API site showed:

Host Name: foo.example.com  
Port: 443
SNI: Enabled

Critical Insight

With SNI enabled, IIS routes requests based on the Host header.

So:

https://foo-vm.example.com  → Default Web Site → 404  
https://foo.example.com → Foo.ApiSvc → API

Step 7: Validate Using Host Header Override

Since DNS for foo.example.com was not directly usable from the VM, the Host header was manually injected:

curl -k https://foo-vm.example.com/service/health \
-H "Host: foo.example.com"

Result

Healthy

Conclusion

  • API was functioning correctly
  • IIS routing was working as designed
  • Issue was purely hostname-based routing

Step 8: Azure Layer Insight

The /service/... route seen earlier was part of the Azure routing layer, not IIS.

Architecture:

Azure Front Door / Gateway

foo.example.com

Azure VM (IIS with SNI)

ASP.NET Core API

Key Takeaway:

When bypassing Azure and hitting the VM directly, you must:

  • Use the correct hostname
    OR
  • Override the Host header

Application Pool Configuration Update

The IIS application pool was updated from .NET CLR v4.0 to No Managed Code to align with ASP.NET Core hosting best practices.

ASP.NET Core applications run on the CoreCLR in a separate process and do not depend on the IIS-managed CLR. While the previous setting did not prevent the application from running, updating it improves clarity and avoids confusion in future maintenance.


Step 9: Final Resolution

✅ Correct endpoint:

https://foo.example.com/service/health

✅ Or direct VM access with Host override:

curl -k https://foo-vm.example.com/service/health \
-H "Host: foo.example.com"

Key Learnings

1. IIS with SNI routes based on hostname, not IP

Incorrect hostname results in routing to the wrong site and returns 404.


2. Default Web Site is not always your application

Always verify IIS site bindings and application mapping.


3. Azure routing can mask backend behavior

The /service path was part of the Azure layer, not IIS configuration.


4. curl is a powerful debugging tool

  • -k bypasses SSL issues
  • -v shows detailed request/response
  • -H allows header injection

5. ASP.NET Core hosting configuration

  • App pool should be set to No Managed Code
  • Runtime and hosting bundle were already functioning correctly

Final Summary

What initially appeared to be a deployment or API issue was ultimately traced to a hostname binding mismatch caused by IIS SNI configuration.

Once the correct hostname was used—or injected via the Host header—the API routed correctly and responded as expected.

Root cause: Incorrect Host header when bypassing Azure routing
Resolution: Use the correct hostname or override the Host header

FavoriteLoadingAdd to favorites

Author: Shahzad Khan

Software Developer / Architect

Leave a Reply