Host a static site and an API on one IIS site with sub applications
If you want a static site frontend and an API at the same domain, you can do it with IIS.
Just IIS Things:
IIS has Sites, Applications, and Virtual Directories.
- Sites
- Each one has a different host name.
- You can use this if you don’t mind having a different subdomain for your API, e.g.
contoso.com
andapi.contoso.com
- Applications
- One site can have many Applications.
- Two applications may each use different app pools (if you want).
- Importantly, they can execute code.
- Virtual Directory
- One Application can have many Virtual Directories
- It seems to me that Virtual Dirs cannot execute code, CGIs, managed or otherwise. They just map folders.
The docs for hosting and deploying ASP.Net mention:
IIS Virtual Directories aren’t supported with ASP.NET Core apps. An app can be hosted as a sub-application.
Where to set it up
You can set it up in the IIS GUI, but the source of truth is actually the global IIS config in applicationHost.config
, which by default lives in C:\Windows\System32\inetsrv\config\applicationHost.config
(If you have set up IIS shared config then you probably already know where your config lives instead).
Take this snippet:
<site name="dinosaurs.local" id="5">
<application path="/" applicationPool="dinosaurs.local">
<virtualDirectory path="/" physicalPath="C:\inetpub\wwwroot\dinosaurs.local" />
</application>
<application path="/api" applicationPool="dinosaurs.local">
<virtualDirectory path="/" physicalPath="C:\inetpub\wwwroot\dinosaurs.local\api" />
</application>
<bindings>
<binding protocol="http" bindingInformation="*:80:dinosaurs.local" />
</bindings>
</site>
Here we have a site called dinosaurs.local
, containing two Applications: one at the root path, one at the /api
path. Each app contains just one virtual directory (the root) which points to the folder on disk.
What can you do with it?
You can deploy static site files, like an index.htm
to wwwroot\dinosaurs.local
, and deploy an ASP.Net (±Core) site to the wwwroot\dinosaurs.local\api
dir, and you will be able to call the /api
route from your frontend code with no mess, no fuss, no octopus.
If you have a SPA which requires a “redirect all” kind of rule, you will need to tune it to exclude /api/*
routes! Exercise left to the reader.
Why
The big reason to deploy this way is to eliminate problems with CORS and cross-site cookies. Safari on iOS is really stingy about so-called “third party cookies”, which are blocked by default; it’s even caused me mysterious problems with two sites with different subdomains on the same host. Beware!
Architecturally, if you’re doing a backend for frontend, it’s nice to keep it at the same host so you can do samesite cookies and stuff.
Okay, that’s the post. Later, nerds! 📬🏓