Jaap
Jaap

Reputation: 745

Running multiple ASP.NET Core (3.1x/Latest) websites on port 80 with Kestrel

I'm using (ASP).NET Core (3.1x), C#, Blazor and Microsoft Kestrel Web-server and I'm wondering if I can run 2 or 3 different websites (domain names) on one Kestrel instance and on port 80. I would really like to use Kestrel as the only web server and not use a proxy server like nginx in front of it.

I've been googling for an answer for a while now but I can't find an answer to this question. I'm renting colocation server space where I run an Ubuntu 18.04 VPS, and I would really like to run multiple websites on this one VPS, instead of renting multiple VPS's. I am thinking about some sort of routing but I can't figure it out.

Is there any way to use Kestrel and run different websites on port 80?

Update - feb 25th 2020

I've created a Github issue about this, long story short: Use a reverse proxy server like Nginx (for Linux). Only one Kestrel process can run on port 80, and there no good way to host multiple websites with one instance.

Update - May 4th 2021

It is now possible with Microsoft's reverse proxy "YARP", which is a separate Kestrel instance. See my answer below.

Upvotes: 11

Views: 7996

Answers (4)

Glen Jackson
Glen Jackson

Reputation: 1

You can host a URL in Apache and redirect the folders to kestrel using the conf files.

In the conf file (See example below) You can also define environment variables.

#Define APP_CONTEXT Your-Context e.g. Test/Production/Demo
#Define APP_URL Your-URL e.g. http://127.0.0.1
#Define APP_PORT_START Your-Port e.g.  5
#
<VirtualHost *>
<LocationMatch /${APP_CONTEXT}/app1>
    ProxyPreserveHost On
    ProxyPass ${APP_URL}:${APP_PORT_START}001
    ProxyPassReverse ${APP_URL}:${APP_PORT_START}001
</LocationMatch>
<LocationMatch /${APP_CONTEXT}/app2>
    ProxyPreserveHost On
    ProxyPass ${APP_URL}:${APP_PORT_START}002
    ProxyPassReverse ${APP_URL}:${APP_PORT_START}002
</LocationMatch>
<LocationMatch /${APP_CONTEXT}/app3>
    ProxyPreserveHost On
    ProxyPass ${APP_URL}:${APP_PORT_START}003
    ProxyPassReverse ${APP_URL}:${APP_PORT_START}003
</LocationMatch>

Upvotes: 0

Jaap
Jaap

Reputation: 745

To run multiple domains on one server on port 80 and/or 443 with Kestrel you'll need to put a reverse proxy in front of it.

Microsoft has now its own really fast reverse proxy called YARP which is actually another Kestrel instance, see: Getting Started With Yarp

To use it with TLS/HTTPS you'll need Kestrel's SNI feature, see this GitHub discussion for more info

Here's a sample appsettings.Development.json GIST how I did it.

Upvotes: 7

Kalpesh Popat
Kalpesh Popat

Reputation: 1526

Kestrel is best used with proxy server behind nginx or apache or iis, however it is not correct that kestrel do not support multiple apps on a single server.

There are various ways kestrel can be configured to run multiple apps and Microsoft's document describes it in great details. https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/endpoints?view=aspnetcore-5.0

The easiest is to setup the following in your appsettings.json file, change the url to any other port that you desire to support multiple apps, one app can be on port 4000 another on 4100 and so on. Configure according to the available free ports on that server.

{
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://localhost:5000"
      },
      "Https": {
        "Url": "https://localhost:5001",
        "Certificate": {
          "Path": "<path to .pfx file>",
          "Password": "<certificate password>"
        }
      }
    }
  }
}

Upvotes: 0

Anduin Xue
Anduin Xue

Reputation: 3727

There is no virtual host config in Kestrel like there is in IIS, so you can't do it without using IIS or something else in front of Kestrel. The best workaround is to bind another port like 12345 and create a reverse proxy for it.

For example, you can use Caddy server to act as a reverse proxy. In Ubuntu:

Install caddy server

The following script will install caddy. Caddy acts as a reverse proxy server which serves multiple website in the same port.

cat /etc/apt/sources.list.d/caddy-fury.list | grep -q caddy || echo "deb [trusted=yes] https://apt.fury.io/caddy/ /" | tee -a /etc/apt/sources.list.d/caddy-fury.list
apt update
apt install -y caddy

Add new proxy website

The following function adds a new reverse proxy config for caddy.

add_caddy_proxy()
{
    domain_name="$1"
    local_port="$2"
    cat /etc/caddy/Caddyfile | grep -q "an easy way" && echo "" > /etc/caddy/Caddyfile
    echo "
$domain_name {
    reverse_proxy /* 127.0.0.1:$local_port
}" >> /etc/caddy/Caddyfile
    systemctl restart caddy.service
}

Get a valid port

This function will find an empty internal port so your ASP.NET Core app can listen to.

get_port()
{
    while true; 
    do
        local PORT=$(shuf -i 40000-65000 -n 1)
        ss -lpn | grep -q ":$PORT " || echo $PORT && break
    done
}

Register ASP.NET Core web app

And this function helps you register an ASP.NET Core web app as a service and listening for a specific port.

register_service()
{
    service_name="$1" # my.service
    local_port="$2" # 12345
    run_path="$3" # .
    dll="$4" # MyProject.dll
    echo "[Unit]
    Description=$dll Service
    After=network.target
    Wants=network.target
    [Service]
    Type=simple
    ExecStart=/usr/bin/dotnet $run_path/$dll.dll --urls=http://localhost:$local_port/
    WorkingDirectory=$run_path
    Restart=always
    RestartSec=10
    KillSignal=SIGINT
    Environment=\"ASPNETCORE_ENVIRONMENT=Production\"
    Environment=\"DOTNET_PRINT_TELEMETRY_MESSAGE=false\"
    [Install]
    WantedBy=multi-user.target" > /etc/systemd/system/$service_name.service
    systemctl enable $service_name.service
    systemctl start $service_name.service
}

Run your ASP.NET Core app

After executing the previous steps, you can add your ASP.NET Core app behind caddy.

server="www.yourhostname.com"
app_path=/opt/myapp
port=$(get_port)

dotnet publish -c Release -o $app_path ./app.csproj
register_service "myapp" $port $app_path "MyApp"
add_caddy_proxy $server $port

You can do that multiple times so multiple ASP.NET Core app just runs on the same server.

Reference:

https://github.com/EdiWang/Moonglade/blob/master/Deployment/install.sh

Upvotes: 2

Related Questions