How to Setup URLs for Your ASP.NET Core Apps

There are many ways that you can use to set URLs that ASP.NET Core binds to on startup. In this article, we will give you 8 ways to set the URLs for your ASP.NET Apps. Here we go.

What URLs can you use?

I list the “URLs” you can bind to in this post, but you can’t use any old URL. You can bind three different classes of URLs in essence:

  • The “loopback” hostname for IPv4 and IPv6 (e.g. http://localhost:5000http://127.0.0.1:5000, or http://[::1]:5000), in the format: {scheme}://{loopbackAddress}:{port}
  • A specific IP address available on your machine (e.g. http://192.168.8.31:5005), in the format {scheme}://{IPAddress}:{port}
  • “Any” IP address for a given port (e.g. http://*:6264), in the format {scheme}://*:{port}

The port in the above patterns is also optional – if you omit it, the default port for the given scheme is used instead (port 80 for http, port 443 for https).

In addition to TCP, which I’ll cover in another post, you can listen to requests on named pipes and Unix sockets in.NET 8.

The pattern you select will vary depending on your deployment method. For example, you might need to set an explicit IPAddress if you’re running several applications on a “bare metal” system. You can typically use “any” IP address when hosting in a container.

Be wary of the “any” IP address format; anything that isn’t an IP address or the loopback address, such as localhost, can be used instead of the required *.That means you can use http://*http://+http://mydomain, or http://example.org. When configuring Kestrel, all of these operate in the same way and allow listening on any IP address.

You must inform your application of the URLs you need to listen on once you are aware of them. I outline eight potential methods to accomplish that in this post.

UseUrls()

Using UseUrls() to configure the WebApplicationBuilder and hardcoding the binding URLs is the simplest and first option. An extension method available on the WebHost property is the UseUrls() function:

var builder = WebApplication.CreateBuilder(args);
// Configure the URLs 👇
builder.WebHost.UseUrls("http://localhost:5003", "https://localhost:5004");

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

Although the UseUrls() method has been present in ASP.NET Core since version 1.0, a more recent method that uses WebApplication directly has been available since.NET 6.

WebApplication.Urls and WebApplication.Run()

WebApplication exposes a Urls property for configuring which URLs the application should listen to:

var builder = WebApplication.CreateBuilder(args);

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Urls.Add("http://*:5003"); // 👈 Add the URL
app.Run();

IServerAddressFeature is exposed by the Urls property behind the scenes. You are directly adding the addresses there, under Addresses collection:

public ICollection<string> Urls => ServerFeatures.GetRequiredFeature<IServerAddressesFeature>().Addresses;

A similar, related way to set the URL is to provide it in the call to app.Run(). The URL you pass here is added to the IServerAddressesFeature collection just before the application is started.

var builder = WebApplication.CreateBuilder(args);

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run("http://*:5003"); // 👈 Use the provided URL when running the application

Note that you can only provide a single URL when using the app.Run() approach, so you need to use one of the other approaches if you want to set multiple URLs.

You won’t use this approach generally because hard-coding the URLs never feels like a particularly clean or extensible solution. Fortunately, environment variables, command line arguments, and configuration files can also be used to load the URLs.

Environment variables for the URL

A sophisticated, expandable configuration system built into ASP.NET Core allows it to load values from several different configuration sources. When using ConfigurationManager in.NET 8, values are loaded by default from the following locations:

  • appsettings.json JSON file
  • Optional environment-specific JSON file, appsettings.ENVIRONMENT.json
  • User Secrets
  • Environment variables
  • Command-line arguments

These are the default providers added, but you can add more to load from different locations. This system is used by ASP.NET Core to configure its internals, but you can also use it to load settings and customize your application.

The configuration system gains all of the following features from ASP.NET Core:

  • Every environment variable is immediately added to the configuration.
  • Prefix DOTNET_ is eliminated from environment variables and their values are added to the collection.
  • Environment variables with the prefix ASPNETCORE_ for ASP.NET Core applications are added to the collection after the prefix has been removed. If you are using HostApplicationBuilder to create a generic-host-based worker service, these are not added.

If you don’t override them manually with UseUrls(), then ASP.NET Core will use the value of the URLS key from the configuration system. Based on the description above you can set the URLS using any of the following environment variables (casing doesn’t matter):

  • URLS
  • ASPNETCORE_URLS
  • DOTNET_URLS

If you set all of these environment variables in the order described above, URLS will have the highest precedence.

Depending on your environment, you can set environment variables in the standard manner. Using the command line, for instance:

setx ASPNETCORE_URLS "http://localhost:5001"

using powershell

$Env:ASPNETCORE_URLS="http://localhost:5001"

or using bash:

export ASPNETCORE_URLS="http://localhost:5001;https://localhost:5002"

As you can see above, by using a semicolon to separate the addresses, you can also pass multiple addresses to listen on (using HTTP or HTTPS).

Environment variables for the ports

The URLs can be set using the formats displayed at the beginning of this post by using the ASPNETCORE_URLS and related environment variables, for instance:

  • ASPNETCORE_URLS="http://localhost:5001"—listen to port 5001 on the loopback (localhost address).
  • ASPNETCORE_URLS="http://192.168.8.31:5001"—listen to port 5001 on the specified IP address.
  • ASPNETCORE_URLS="http://*:5001"—listen to port 5001 on any IP address

One thing that’s always bugged me a little is the name of this variable. It implies (to me) that you can use things like http://example.com:5000 and your app will listen on that DNS name. That’s not the case. The above URL is treated exactly the same as http://*:5000, i.e. it configures the app to listen to port 5000 on any IP address.

.NET 8 added new configuration keys to be more explicit about this. Instead of specifying “URLs” you specify HTTP_PORTS and HTTPS_PORTS, and these are used to bind any IP address. You can specify multiple ports using a semicolon separator. For example, if you set the following environment variables:

  • ASPNETCORE_HTTP_PORTS=5001;5002
  • ASPNETCORE_HTTPS_PORTS=5003

The aforementioned URLs are expanded to include:

  • http://*:5001
  • http://*:5002
  • https://*:5003

As with other configuration keys, the values can be specified using ASPNETCORE_, DOTNET_, or “no prefix”:

  • HTTP_PORTS (and HTTPS_PORTS)
  • ASPNETCORE_HTTP_PORTS (and ASPNETCORE_HTTPS_PORTS)
  • DOTNET_HTTP_PORTS (or DOTNET_HTTPS_PORTS)

Keep in mind that if you specify ASPNETCORE_URLS (for example) along with one of these, the ASPNETCORE_URLS value takes precedence, and the following warning is logged to the output:

warn: Microsoft.AspNetCore.Hosting.Diagnostics[15]
      Overriding HTTP_PORTS '5002' and HTTPS_PORTS ''. Binding to values defined by URLS instead 'http://*:5003'.

The ASPNETCORE_HTTP_PORTS variable in.NET 8 docker images has a default value of 8080 (ASPNETCORE_URLS was set in previous version docker images). Setting ASPNETCORE_HTTP_PORTS or ASPNETCORE_URLS will override this default value, among other methods.

Command line arguments are an additional means of adding values to configuration, in addition to environment variables.

Command line arguments

Using the command line is an additional method of adding values to the ASP.NET Core configuration system. If environment variables are set, the values are overridden by command line arguments. To run the application, just pass the “un-prefixed” environment variable as an argument and prefix with --. As an illustration:

dotnet run -- --urls "http://localhost:5100"

As previously, you can pass multiple URLs to listen on by semicolons separating them:

dotnet run -- --urls "http://*:5100;http://localhost:5101"

This also functions with the dotnet runtime version, in which dotnet is called with the path of the compiled dll rather than dotnet run:

dotnet ./WebApplication1.dll --urls "http://*:5100;http://localhost:5101"

You can also use --http_ports and --https_ports:

dotnet run -- --http_ports "5100;5101" --https_ports "5003;5004"

It should be noted that the additional -- in the dotnet run command is not a typo; rather, it serves to confirm that the arguments are understood as arguments for configuration rather than as arguments for the run command.

Although you can use any provider, environment variables and command line arguments are popular ways to add values to an ASP.NET Core configuration. The appsettings.json file is one of the most widely used methods (found in all default templates) for adding values to configuration.

appsettings.json

appsettings.json, and the environment-specific appsettings.Development.json files are included in virtually every modern .NET app template, and provide an easy way to add values to the ASP.NET Core configuration system.

Hopefully it’s no surprise that you can use these files to specify the URLs your app listens on using the same urlshttp_ports and https_ports keys you’ve seen already. The following adds the urls key to the default template:

{
  "urls": "http://*:5003", // 👈 Specify the URL
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

This version adds the http_ports and https_ports keys:

{
  "http_ports": "5001;5002", // 👈 Expands to http://*:5001 and http://*:5002
  "https_ports": "5003", // 👈 Expands to http2://*:5003
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

You can use the appsettings.json file for production and the appsettings to use different ports for development and production.For development, use Development.json. or whichever pattern suits you best.

As an alternative, launchSettings.json is a distinct JSON file that you can depend on.

launchSettings.json

Most.NET project templates include a launchSettings.json file in the Properties folder in addition to the appsettings.json file. This file contains multiple profiles for using dotnet run to launch your ASP.NET Core application in development, rather than adding anything directly to your configuration.

Typically, a file has one definition for using IIS Express to launch the profile and one or more definitions for launching the profile directly from the command line. This file controls Visual Studio’s Debug drop-down menu:

launchSettings.json provides an easy way to set the application URLs via the applicationUrl property – you can see one under the iisSettings for IIS express, and one under each of the http and https profiles:

{
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:49412", // 👈 URL to use with IIS Express profile
      "sslPort": 44381
    }
  },
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "http://localhost:5005", // 👈 HTTP-only profile
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://localhost:7045;http://localhost:5005", // 👈 HTTP & HTTPS profile
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

You don’t need to do anything special to use this file—dotnet run will pick it up automatically.

launchSettings.json also provides an easy way to set additional environment variables using the environmentVariables, as you can see from the file above.

When you run your app from the command line with dotnet run, your app will use the applicationUrl properties in the “Project” command: http://localhost:5005 in the http profile above. When you run the app using the “IISExpress” command, your app will use the applicationUrl from the iisSettings.iisExpress node: http://localhost:49412.

When developing locally, this file offers the simplest method for configuring your environment. Actually, you have to take special care to avoid using the launchSettings.JSON:

dotnet run --no-launch-profile

The launchSettings.json file will be ignored in favor of using configuration to find the URLs.

You can set the Kestrel URLs directly, but all of the methods that have been demonstrated thus far set them indirectly.

KestrelServerOptions.Listen()

In the majority of ASP.NET Core applications, Kestrel is set by default. Instead of using the higher-level configuration provided by ASPNETCORE_URLS et al., you can choose to manually configure the Kestrel endpoints or to configure KestrelServerOptions using the IConfiguration system.

When you run behind IIS out-of-process or self-host your application, Kestrel is used by default. You use an IIS HTTP Server when you run in-process. You can also use the HTTP.sys kernel driver on Windows.

Configuring HTTPS certificates, SSL/TLS protocols and cipher suites, and Server Name Indications (SNI) configurations will probably require you to use the Kestrel Listen() functions. Since there are many configuration options, I recommend consulting the documentation the majority of the time. The Listen() functions made available by KestrelServerOptions can be used, for instance, in the following ways:

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(opts =>
{
    opts.Listen(IPAddress.Loopback, port: 5002); // listen on http://localhost:5002
    opts.ListenAnyIP(5003); // listen on http://*:5003
    opts.ListenLocalhost(5004, listenOptions => listenOptions.UseHttps());  // listen on https://localhost:5004
    opts.ListenAnyIP(5005, listenOptions => // listen on https://*:5005
    {
        listenOptions.UseHttps("testCert.pfx", "testPassword");
    });
});

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

Kestrel is configured to listen on multiple addresses. If you set the URLS configuration value using one of the other mechanisms, like environment variables, it gets overwritten when you set the URLs for Kestrel in this manner. If that occurs, a warning will appear in the logs:

warn: Microsoft.AspNetCore.Server.Kestrel[0]
      Overriding address(es) 'http://localhost:5165'. Binding to endpoints defined via IConfiguration and/or UseKestrel() instead.
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://127.0.0.1:5002
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://[::]:5003
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://localhost:5004
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://[::]:5005

Unlike how you can bind to urls or http_ports, you can use IConfiguration to bind the Kestrel configuration instead of having to hardcode it, as was the case in the example above. For instance, appsettings.json could be used to configure the Kestrel configuration mentioned above:

{
  "Kestrel": {
    "Endpoints": {
      "HttpLoopback": {
        "Url": "http://localhost:5002"
      },
      "HttpAny": {
        "Url": "http://*:5003"
      },
      "HttpsDefaultCert": {
        "Url": "https://localhost:5004"
      },
      "HttpsInlineCertFile": {
        "Url": "https://*:5005",
        "Certificate": {
          "Path": "testCert.pfx",
          "Password": "testPassword"
        }
      }
    }
  }
}

One nice thing about this is that you can configure your app’s binding and HTTPS certificate completely from the IConfiguration. This implies that you can store your certificates and certificate passwords using safe secret storage solutions like Key Vault. You won’t even need to call ConfigureKestrel() if you use the configuration from appsettings.json mentioned above.

Summary

I demonstrated eight different methods in this post for configuring the URLs that your application listens on. use WebApplication and UseUrls().The simplest are urls, but they are typically not appropriate for use in production workloads by themselves. For setting the values in production, the ASPNETCORE_/DOTNET_ environment variables and the command line arguments --urls, --http_ports, and --https_ports are most helpful. Setting up URLs in a development environment is made very easy with the help of the launchSettings.json file. You can use Kestrel’s Listen* options directly if you require more precise configuration control. Additionally, these can be loaded from configuration for simple use in development and production scenarios.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *