Last night I was writing my previous article about anchor links in Blazor applications. I got a few comments on it that triggered my interest to dig a bit deeper into the subject. Thanks Chris 😉
Previously, I had only been running Blazor applications on the root of a site. This made me completely miss the point of the
<base href="/" /> element, which is added by default to Blazor applications. That element isn’t required until you run your application in a subdirectory of your site.
That is why I started to look into GitHub Pages. GitHub Pages allows you to host static content on GitHub. You can publish any GitHub repository to a project site in GitHub Pages. A project site will be published to a subdirectory under your account. An example of that is the sample application I wrote for this article, which you can find running at mikaberglund.github.io/hosting-blazor-apps-on-github-pages. The application is published in the
/docs folder in the master branch of the repository.
Considerations for GitHub Pages
Blazor is a SPA Framework, which typically only has one physical page that acts as the starting point for the application. The application provides a routing mechanism that loads the view associated with the current route (the path in the browser’s address bar).
This is all good as long as the Blazor application with its routing engine is loaded. But what if you reload the browser window? Or if you copy the address in your browser, and send it off to a friend? Then the request will go all the way to the server. Since there is no corresponding folder or file that would match the request, the server returns a 404 Not Found error message.
ASP.NET Core handles this by loading the application’s startup page, if no better matching resource or route is available.
But since GitHub Pages only hosts static content, no server-side processing is possible. One solution to this is to leverage custom 404 (not found) pages in GitHub Pages. The basic idea in this solution is that the custom 404 page will store the current route (URL) in the browser’s history, and redirect the browser to
index.html (the application’s startup page) with the original route as parameters.
index.html will then rewrite the URL so that Blazor’s routing engine will understand it. Read more about this solution on the Microsoft Docs site.
If you publish your application on a project site, you need to modify the
<base /> element in your
index.html file. My sample app associated with this article runs in the /hosting-blazor-apps-on-github-pages folder. This means that I need to change the element as shown below.
<base href="/hosting-blazor-apps-on-github-pages/" />
A Simplified Solution
The solution described above is pretty cool. You can probably apply that to any kind of SPA Framework hosted on any kind of service that supports static content with customizable 404 pages.
However, this got me thinking whether the solution could be simplified. If the custom 404 page “catches” any incoming request that does not have a corresponding physical file, why could that 404 page not be the application’s startup page too? Why would you need to modify the incoming request and redirect to
index.html when you could serve the application directly from
So I published the sample application to the
/docs folder, renamed
404.html, and pushed my changes to the remote repository. As you can see in the
/docs folder, there is no
404.html. Still, the application works just fine.
There is one downside to this though. When you load your application, GitHub Pages will return the HTTP status 404 (not found), even if your application loads completely fine. So, if this becomes an issue for you, then you need to do it the way it is described on the Microsoft Docs site.
Running the application directly from the
404.html page instead of doing some tweaking and redirecting to the
index.html is obviously a more simple solution. However, so far I have only tested it with the sample Blazor application I wrote for this article. That sample application is pretty simple, so I’m going to add more advanced routing scenarios to it later on to be more certain. And, as I said, you will get a 404 response status to every request to your application.
I already published the Blazor Bootstrap Showroom application on GitHub Pages. You can find it here. I wrote about the Blazor Bootstrap component library a while ago here on my blog. If you want to learn more about this project and how you can use it in your Blazor application, have a look at the Blazor Bootstrap Wiki.
If you manage to publish your SPA application directly from the custom 404 page on GitHub Pages, I’d be happy to hear about it. Feel free to leave a comment below and let me know.
Mike · December 30, 2019 at 18:21
Can you host multiple blazor apps in one storage account? Meaning root/app1 and root/app2?
Mika Berglund · December 30, 2019 at 20:49
Do you mean an Azure storage account? Yes, you can. You just follow the same principles as you would when prepping the app to run in a GitHub Pages project site, like the sample app for this article. You find that at https://mikaberglund.github.io/hosting-blazor-apps-on-github-pages/
Similarly, you can enable the static website feature on an Azure storage account, which will give you a $web blob container in that storage account, which represents the root of the static website for your storage account. In that container, you can create whatever folder structure you like. Just remember to make sure your application is set up to run in the folder you specify.
roustan thierry · April 23, 2020 at 09:25
404.html is a good idea. But is incompatible with pwa app who need http 200 for offline page no?
Mika Berglund · April 25, 2020 at 08:14
I’m not quite sure what it does to PWAs. But you definitely need 404.html to make routing work without server logic.
foo · September 6, 2020 at 21:06
unfortunately, there are caching issues with the 404.html page. Github seems to cache everything but the index.html. Optimally your index.html/404.html should embed scripts with filename+hash so you don’t have to worry about the old .js file being cached. However, since the 404.html is cached (unlike the index.html), your users may get an old index.html and thus the page won’t load (or get an old .js filename).
So, is the solution for the 404.html page to embed a fullscreen iframe of the index.html? Or is there a better way?
Mika Berglund · September 7, 2020 at 13:49
I have noticed that GitHub Pages cache files. Haven’t noticed that index.html would be treated any differently though. However, the duration for the cache to get updated does not seem that long though (only a couple of minutes), so personally I don’t see any reason to try and come up with cludges to work around that.
Shaun Curtis · March 5, 2021 at 21:44
Any inside line on when we’ll get Net 5.0 on Github? I can’t find anything. I’ve tried the template with 5.0 and it doesn’t seem to work. Maybe idiot mistake???
Mika Berglund · March 7, 2021 at 15:03
Since GitHub Pages is just a static hosting provider that just hosts your files, you don’t need to have .NET 5 support on GitHub or GitHub Pages. Having said that, I’ve noticed that the publish process in Visual Studio for Blazor WebAssembly apps is a little different from what it was. Maybe this is the cause.
Well, anyway. I’m planning on writing a blog article on how to write a Microsoft Teams application as a Blazor WebAssembly application using Blazorade Teams, and how to host that on GitHub Pages, so stay tuned. Since such an application would be written in .NET 5, it would also cover your scenario.