dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.33k stars 9.97k forks source link

Hosting multiple Blazor Server Side websites with Kestrel #18816

Closed JeepNL closed 4 years ago

JeepNL commented 4 years ago

I'm using (ASP).NET core 3.1x, latest (preview) versions / Blazor

I would like to host multiple (2 or 3) domains (different Blazor websites) on one Kestrel Instance (example1.com & example2.com) on port 80. I'm running Kestrel as the only web server on my Ubuntu 18.04 VPS, so without a proxy server and I would like to keep using this configuration.

In Microsoft Docs there's a paragraph about SNI, it says "Server Name Indication (SNI) can be used to host multiple domains on the same IP address and port. "

What I don't understand is how to route them in Blazor to different paths. Is that possible with SNI? If not, is there any solution for this?

Tratcher commented 4 years ago

SNI is a TLS extension, it only applies to HTTPs request that normally use port 443.

Serving HTTP request for multiple domains on port 80 doesn't need any special setup in Kestrel, each request indicates its domain preference in the Host header.

The more interesting question is if you can set up blazor to serve multiple sites based on the domain? Rerouting this to those folks.

JeepNL commented 4 years ago

@Tratcher Oh, sorry didn't know that about SNI. But yes, 'the more interesting question' is exactly what I mean. I would like run 2 or 3 sites (domain names) on port 80 with Kestrel.

I've found something in Github issues (from Ryan Nowak) but that's for Razor Pages (Areas). I would like to use different domain names for Blazor sites (for example) : SiteOne.com & SiteTwo.net

Update Oh wait, I'm sorry, I forgot I'm using Let's Encrypt HTTPS Certificates as well for my Blazor Sites. So not only port 80, but with redirect to 443. Here's a site I'm using for testing Kestrel/Blazor (It has an A+ rating at Qualys SSL Labs) beta.ictz.net

So port 80 and 443. (I'm using Blazor Server Side)

Tratcher commented 4 years ago

@rynowak

javiercn commented 4 years ago

I'm not entirely sure if its possible, but in theory you can call endpoints.MapBlazorHub() multiple times and differentiate them via host maching as described here

JeepNL commented 4 years ago

@javiercn Earlier I've posted a question at StackOverflow about this and yes there was a suggestion about using MapGet but using this would make it hard to maintain, @rynowak told me the same on Twitter and suggested to me opening an issue here.

At this moment I'm renting 2 Linux Ubuntu 18.04 VPSs at a Dutch hosting provider for 2 Blazor (Server Side) websites, so It would be great if I can use 1 VPS for this.

javiercn commented 4 years ago

@JeepNL sorry if I was not clear, I meant you can try and do

endpoints.MapBlazorHub().RequireHost("host1");
endpoints.MapBlazorHub().RequireHost("host2");

Then you can decide what app/component to render based on the host?

JeepNL commented 4 years ago

@javiercn I sure can try that, but could you please provide me with some more info/code, if it's not too much work? How do I 'route' this to different apps/components. The page you've mentioned at Docs returns different views, but I'm using Server Side Blazor.

rynowak commented 4 years ago

@javiercn Earlier I've posted a question at StackOverflow about this and yes there was a suggestion about using MapGet but using this would make it hard to maintain, @rynowak told me the same on Twitter and suggested to me opening an issue here

To be really clear about one point - in ASP.NET Core there's one "app" because there's one definition of the service provider. If you're OK with this, then you can have multiple entry point components just fine. If you really want to treat these as separate apps that don't interact with each other, dealing with the service provider and the need to have multiple service providers is the hard part.

mkArtakMSFT commented 4 years ago

Closing as there are no more actions pending here for us.

JeepNL commented 4 years ago

@mkArtakMSFT I'm sorry, I can't get it to work. @rynowak FYI: I don't want the two websites to interact with each other, I just want to host multiple websites with Kestrel on one server. At StackOverflow they don't know how to do this, and here your words "is the hard part" stand out to me. I can't figure out why this basic (in my opinion) webserver functionality would be 'hard'. I'm in no hurry, and I'm sure more people want to host multiple Blazor websites with Kestrel, so I'll wait until more sample code becomes available.

javiercn commented 4 years ago

@JeepNL I would suggest that you host them in separate processes and configure kestrel appropriately to handle it?

@halter73 @Tratcher This should be doable with 3.1, isn't it? You would set kestrel to listen to host1 in process1 and host2 in process2 and at that point they are completely separate apps. They should both be able to listen on 80 and 443 with the right registrations?

If I'm wrong, can you assist here, as this is about how to host multiple kestrel instances in the same server.

JeepNL commented 4 years ago

@javiercn I thought I can't start 2 instances of Kestrel sharing the same port(s) (80/443) on my Ubuntu VPS (sharing violation?) . This makes sense to me, but I'm by far no Linux expert, But if this is possible I'll start asking questions at an Ubuntu forum, because I think that would be a solution. And because Kestrel is so light weight and fast my Ubuntu VPS wouldn't have a problem with serving two Kestrel instances. It's pretty awesome developing these days with .NET Core / Kestrel and multi platform. But a couple of (again, in my opinion) basic setups could be better (or simpler for me 😉) documented.

javiercn commented 4 years ago

I'm no expert in Linux/Kestrel hosting, that's why I looped in the right folks.

javiercn commented 4 years ago

@JeepNL just to be clear, from what I understand you want 2 separate applications (processes) running on the same machine, and not the same application (same process) serving two different apps. (With no isolation whatsoever between the two apps, (both apps share memory and other resources)).

Is that right?

JeepNL commented 4 years ago

I'm no expert in Linux/Kestrel hosting, that's why I looped in the right folks.

@javiercn Thank you for that, and thank you for your reply.

2 separate applications (processes) running on the same machine

For me, I can work with both scenarios, because I only want to run 2 or 3 different websites. A) One Kestrel process and putting different websites in different directories in the same App/(Visual Studio Solution/Project), which would mean they will be sharing resources, and work from there with some kind of routing.

or B) starting multiple instances of kestrel sharing the same port(s).

I think, for the future, Kestrel hosting multiple websites with isolation would be best. But I can work without. I'm sorry, English is not my first language, I hope this makes sense.

javiercn commented 4 years ago

I think, for the future, Kestrel hosting multiple websites with isolation would be best. But I can work without. I'm sorry, English is not my first language, I hope this makes sense.

I don't think we'll ever go in this direction. For us, the process is the unit of isolation.

For your case, you can do with something like this

In _Host.cshtml

@if(context.Request.Host == "host1"){
   <component type="typeof(App1)" render-mode="ServerPrerendered" />
}
@if(context.Request.Host == "host2"){
   <component type="typeof(App2)" render-mode="ServerPrerendered" />
}

I don't even think that you would need to map multiple BlazorHubs on startup. The code that I've given you should be enough, provided that you get kestrel to listen on both endpoints.

Tratcher commented 4 years ago

@halter73 @Tratcher This should be doable with 3.1, isn't it? You would set kestrel to listen to host1 in process1 and host2 in process2 and at that point they are completely separate apps. They should both be able to listen on 80 and 443 with the right registrations?

No, Kestrel can't share ports with another process, you'd need a reverse proxy for that. IIS/Http.Sys have a built in proxy to enable port sharing but only with other IIS/Http.Sys sites.

See my earlier comments about not needing any kestrel server config to host multiple domains. It's a matter of routing at the application layer.

JeepNL commented 4 years ago

@javiercn Thank you for your code example (@if(context...) in _Host.cshtml, it seems pretty easy to implement and if I can use that, it would make me very happy, I'll try to get it working this weekend. @Tratcher, yes that's what I thought. If I can host multiple websites with the code example above from Javier it would be great. Having just one Kestrel process, and I'd really like to use Kestrel only (it does its job so good), no proxy servers.

And FYI "y'all": I think it's almost magic (provided by Microsoft) that I can compile my C#/Blazor code 1:1 from my Windows desktop to an Ubuntu VPS into a single executable.

JeepNL commented 4 years ago

@javiercn @Tratcher Yes, by reading the host header in _Host.cshtml I can use multiple domain names in a project, but it's not easy to set it up to serve different websites with (for example) separate identity logins / databases. It's like using Duct Tape to hold things together. It can be done, somehow, but pretty soon you can't see the wood through the trees anymore. But maybe I'm still doing something wrong.

Tratcher commented 4 years ago

separate identity logins / databases.

Correct, this is a non-goal for us. Supporting full multi-tenant scenarios like that would add significant complexity at all levels of the framework. Our guidance is to host separate apps (in the same process or different processes, or move to something like Orchard which as built the multi-tenant functionality on top of the framework.

JeepNL commented 4 years ago

@Tratcher Okay, thank you for your reply. So probably using a reverse proxy server in front of Kestrel to host multiple apps/websites is the best way forward. I'm looking into that (Linux with Nginx) now.