The Azure App Service default hostname problem (and the web.config fix)
You added a custom domain, pointed everyone at the login page, and shipped. Then someone pastes the old *.azurewebsites.net URL into a chat and lands straight on the raw app you thought you'd hidden. The default hostname never left — and it's still a front door.
New to cloud? CAMPUX is a free, build-first course. Start here →
This one bites Windows App Service teams running a classic ASP.NET Framework app — the kind with a web.config at the root. You stand up the App Service, it comes with a public address like yourappname.azurewebsites.net, you add your real domain, and you wire your links and DNS to the domain. Job done, you think. But the platform-issued default hostname is still live, still public, and still routes to the exact same app. Anyone who has that URL — an old bookmark, a cached search result, a screenshot — reaches your app on it and skips whatever front door your custom domain was supposed to enforce.
Why the "obvious" fixes are dead ends
Before the real fix, two roads that look right and aren't — so you don't spend an afternoon on them:
- "I'll just delete the default hostname." You can't. The
*.azurewebsites.netaddress is assigned by the platform and can't be removed. Custom domains are additive; the default is permanent for the life of the app. - "I'll make the App Service private." Locking public access down (access restrictions, private endpoint) does hide the default hostname — but it hides everything, including your custom domain, because they front the same app. You take the whole site down to close one door.
Both dead ends share a root cause: the default hostname and your custom domain are two labels on one app. You can't remove one label, and you can't block traffic to one without blocking the other. So you stop trying to close the default door and instead make it send people through the right one.
The fix: redirect the default hostname in web.config
Because this is a classic ASP.NET app on Windows App Service, IIS is already in the request path — and it ships the URL Rewrite module. That's all you need. Add one rule that inspects the incoming {HTTP_HOST}, and when it sees the default hostname, redirects to your custom domain. Here's the canonical rule — swap in your own app name, custom domain, and (if you want) login path:
<rule name="Redirect Azure default domain" stopProcessing="true"> <match url="(.*)" /> <conditions> <add input="{HTTP_HOST}" pattern="yourappname.azurewebsites.net" /> </conditions> <action type="Redirect" url="https://your-custom-domain.com/{R:0}" redirectType="Permanent" appendQueryString="false" /> </rule>
Lives inside <system.webServer><rewrite><rules> in your root web.config
A few things worth knowing about that rule:
{R:0}is the whole matched path from<match url="(.*)">, so a visitor hitting/pricing?ref=xlands onyour-custom-domain.com/pricing— the path carries through. If you'd rather funnel everyone to one place regardless of where they came in, drop{R:0}and hardcode the route:url="https://your-custom-domain.com/login".stopProcessing="true"plus placement matters. Put this rule where it won't fight your existing rules, and let it short-circuit the pipeline once it fires. If you already have canonicalization or HTTPS rules, order them deliberately.- Hostnames aren't case-sensitive, so you don't need to worry about
YourAppNamevsyourappnamein the condition.
Where to edit it — no redeploy required
You don't need a pipeline run to change one config file. Edit it in place through Kudu:
- Portal → your App Service → Advanced Tools → Go (that's Kudu).
- Debug console → CMD, then browse to
site/wwwroot. - Open
web.configwith the pencil icon, add the rule inside<system.webServer><rewrite><rules>, and save.
Saving web.config recycles the app automatically — the change is live within seconds, no build, no deploy. That also makes it a fast, low-risk place to iterate while you get the rule right.
The gotcha that will waste your afternoon: patternSyntax
This is the real teaching moment, and it fails silently — the rule saves fine, the app recycles fine, and nothing redirects. The culprit is the patternSyntax of the surrounding <rules> block. URL Rewrite conditions can be matched as ECMAScript regex (the default) or as Wildcard. If your rules block is set to Wildcard — which plenty of scaffolded configs are — then a regex-style pattern with escaped dots never matches, because in Wildcard mode the dot is already a literal character and \ is just a stray backslash.
<!-- WRONG in Wildcard mode: escaped dots never match --> <add input="{HTTP_HOST}" pattern="printscan\.azurewebsites\.net" /> <!-- RIGHT in Wildcard mode: the dot is already literal --> <add input="{HTTP_HOST}" pattern="printscan.azurewebsites.net" />
Same intent, opposite outcome — the difference is one patternSyntax setting
So before you touch the pattern, check the opening tag of the rules block. If it reads <rules patternSyntax="Wildcard">, drop the backslashes. If there's no patternSyntax attribute or it says ECMAScript, escaped dots are correct. The canonical rule above uses an unescaped host precisely so it's safe under Wildcard; if your block is regex, either escape the dots or leave them — a literal . still matches a real dot, it just also matches any character, which for a fixed hostname you control is harmless.
The rule that "does nothing" is almost never wrong logic. It's the pattern being read in a dialect you didn't know the block was speaking.
Testing it without hard-caching a mistake
A 301 is permanent, and browsers cache permanent redirects aggressively — get it wrong and you'll be fighting your own cache. So test in stages:
- Test in a private / incognito window every time, so you're never reading a cached response.
- While iterating, set
redirectType="Found"(a 302, temporary). If the rule is wrong, nothing gets stuck in a cache you can't clear. - Once the default hostname redirects cleanly to the right place, switch back to
redirectType="Permanent"(301) for the SEO and correctness win. - Finally, load your custom domain directly and confirm it still serves normally — the whole point is that the rule fires only on the default hostname and leaves real traffic alone.
Redirecting the default hostname is the classic-ASP.NET flavour of "App Service isn't behaving." Its ASP.NET Core cousin looks nothing like it but shows up just as often: Decoding HTTP 500.30 — the ASP.NET Core startup failure. Two common App Service faceplants, different app classes — worth knowing both on sight.
Questions people also ask
Can I delete or disable the azurewebsites.net default domain?
No. The platform assigns this hostname to every App Service and it stays live for the life of the app; there is no portal option or API call that removes it. Custom domains are additive, not a replacement. If you want traffic off it, redirect it with a URL Rewrite rule instead of trying to delete it.
Why does my site still load on azurewebsites.net after adding a custom domain?
Because the default hostname and your custom domain are two labels pointing at the same app. Adding a custom domain does not remove the old one — it just gives visitors a second way in. Anyone with the old link, a bookmark, or a cached search result still reaches the app directly unless you add a redirect rule.
How do I redirect azurewebsites.net to my custom domain?
On a classic ASP.NET app on Windows App Service, add an IIS URL Rewrite rule to web.config that matches {HTTP_HOST} against your default hostname and redirects to your custom domain. Edit the file live through Kudu's Debug console under site/wwwroot — saving it recycles the app in seconds, no redeploy needed.
Why isn't my URL Rewrite rule in web.config redirecting anything?
Check the patternSyntax of the surrounding rules block. If it's set to Wildcard, a dot is already a literal character, so an escaped pattern like printscan\.azurewebsites\.net never matches and the rule fails silently. Drop the backslashes for Wildcard mode, or leave them only if the block uses ECMAScript regex.
Can Azure App Service run on a private endpoint without breaking my custom domain?
No, not if the goal is hiding only the default hostname. A private endpoint or access restriction blocks public traffic to the whole app, and the default hostname and your custom domain front the same app — you can't shut off one without shutting off the other. Use a redirect rule instead of going private.