5 ways to set the URLs for an ASP.NET Core app
Tags: aspnetcore, netcore30, configuration, hosting
Published: 2020-05-03 17:48:55

---
title: 5 ways to set the URLs for an ASP.NET Core app
published: true
date: 2020-04-07 10:00:00 UTC
tags: ASP.NET Core,.NET Core 3.0,Configuration,Hosting
canonical_url: https://andrewlock.net/5-ways-to-set-the-urls-for-an-aspnetcore-app/
---

 ![5 ways to set the URLs for an ASP.NET Core app](https://andrewlock.net/content/images/2016/07/banner.jpg)

By default, ASP.NET Core apps listen on the following URLs:

- [http://localhost:5000](http://localhost:5000)
- [https://localhost:5001](https://localhost:5001)

In this post I show 5 different ways to change which URLs your app listens on.

There are multiple ways to set the URLs that ASP.NET Core binds to on startup. I have [an old post](https://andrewlock.net/configuring-urls-with-kestrel-iis-and-iis-express-with-asp-net-core/) about the various options available to you that applies to ASP.NET Core 1.0, but the options available in ASP.NET Core 3.x are much the same:

- `UseUrls()` - Set the URLs to use statically in _Program.cs_.
- Environment variables - Set the URLs using `DOTNET_URLS` or `ASPNETCORE_URLS`.
- Command line arguments - Set the URLs with the `--urls` parameter when running from the command line.
- Using _launchSettings.json_ - Set the URLs using the `applicationUrl` property.
- `KestrelServerOptions.Listen()` - Configure addresses for Kestrel server manually using `Listen()`.

We'll look at each of these options in more detail below.

## What URLs can you use?

In this post I describe the "URLs" you can bind to, but you can't use just any URL. There are essentially 3 classes of URLs that you can bind:

- The "loopback" hostname for IPv4 and IPv6 (e.g. `http://localhost: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`).

Which of these pattern you choose will depend on your deployment mechanism. For example, if you're hosting multiple applications on a "bare metal" machine, you may well need to set an explicit IPAddress. If you're hosting in a container, then you can generally use a `localhost` address.

> Watch out for the "any" IP address format - you don't have to use `*`, you can use anything that's not an IP Address and is not `localhost`. That means you can use `http://*`, `http://+`, `http://mydomain`, or `http://example.org`. All of these behave identically, and listen on any IP address. If you only want to handle requests from a single hostname, you need to configure [host filtering](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-3.1#host-filtering) in addition.

Once you know the URLs you need to listen on, you need to tell your application about them. In this post I show 5 possible ways of doing that.

## UseUrls()

The first, and easiest, option to set the binding URLs is to hard code them when configuring the `IWebHostBuilder` using `UseUrls()`:

```csharp
public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
                webBuilder.UseUrls("http://localhost:5003", "https://localhost:5004");
            });
}
```

Hard-coding the URLs never feels like a particularly clean or extensible solution, so this option isn't really useful for anything more than demos.

Luckily, you can also load the URLs from an external configuration file, from environment variables, or from command line arguments.

## Environment variables

.NET Core uses two _types_ of configuration:

- **App configuration** is the configuration you typically use in your application, and is loaded from _appSettings.json_ and environment variables, among other places.

- **Host configuration** is used to configure basic things about your application, like the [hosting environment](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-3.1) and the host URLs to use.

The _host configuration_ is the one we're interested in when considering how to set the URLs for our application. By default, host configuration values are loaded from three different sources:

- Environment variables that have the prefix `DOTNET_`. The environment variables have the prefix removed and are added to the collection.
- Command line arguments.
- Environment variables that have the prefix `ASPNETCORE_`. For ASP.NET Core apps only, these environment variables are also added. These aren't added if you are creating a generic-host-based worker service.

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 either of the following environment variables:

- `DOTNET_URLS`
- `ASPNETCORE_URLS`

> If you set both of these environment variables, the `ASPNETCORE_URLS` parameter takes precedence.

You can set environment variables in the usual way based on your environment. For example, using the command line:

```bash
setx ASPNETCORE_URLS "http://localhost:5001"
```

using powershell

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

or using bash:

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

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

## Command line arguments

The other way to set host configuration values is to use the command line. Command line arguments override the value of the environment variables if they're set. Simply use the `--urls` parameter:

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

As before, you can pass multiple URLs to listen on by separating them with a semicolon:

```bash
dotnet run --urls "http://localhost:5100;https://localhost:5101"
```

Environment variables and command line arguments are probably the most common way to set URLs for an application in production, but they're a bit cumbersome for local development. It's often easier to using _launchSettings.json_ instead.

## launchSettings.json

Most .NET project templates include a _launchSettings.json_ file in the _Properties_ folder. This file contains various profiles for launching your ASP.NET Core application. A typical file contains one definition for launching the profile directly from the command line and one definition for launching the profile using IIS Express. This file drives the Debug drop-down in Visual Studio:

![The launchsettings.json drives the Visual Studio Debug view](https://andrewlock.net/content/images/2020/launchsettings.png)

_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 `TestApp` (the name of the application for this file).

```json
{
  "iisSettings": {
    "windowsAuthentication": false, 
    "anonymousAuthentication": true, 
    "iisExpress": {
      "applicationUrl": "http://localhost:38327",
      "sslPort": 44310
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "TestApp": {
      "commandName": "Project",
      "launchBrowser": true,
      "applicationUrl": "https://localhost:5001;http://localhost:5000",
      "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: `https://localhost:5001;http://localhost:5000` in the file above. When you run the app using the "IISExpress" command, your app will use the `applicationUrl` from the `iisSettings.iisExpress` node: `http://localhost:38327`

This file is the easiest way to configure your environment when developing locally. In fact, you have to go out of your way to _not_ use the _launchSettings.json_:

```bash
dotnet run --no-launch-profile
```

This will skip over the _launchSettings.json_ file and fall back to the machine environment variables to determine the URLs instead.

All of the approaches shown so far set the URLs for Kestrel indirectly, but you can also set them _directly_.

## KestrelServerOptions.Listen()

[Kestrel](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-3.1) is configured by default in almost all ASP.NET Core apps. If you wish, you can configure the endpoints for Kestrel manually, or via configuring `KestrelServerOptions` using the `IConfiguration` system.

I've never found myself actually needing to do this, and there's a _lot_ of configuration options available, so for the most part I suggest [referring to the documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-3.1#endpoint-configuration). As an example, you can use the `Listen()` functions exposed by `KestrelServerOptions`:

```csharp
public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
                webBuilder.UseKestrel(opts =>
                {
                    // Bind directly to a socket handle or Unix socket
                    // opts.ListenHandle(123554);
                    // opts.ListenUnixSocket("/tmp/kestrel-test.sock");
                    opts.Listen(IPAddress.Loopback, port: 5002);
                    opts.ListenAnyIP(5003);
                    opts.ListenLocalhost(5004, opts => opts.UseHttps());
                    opts.ListenLocalhost(5005, opts => opts.UseHttps());
                });

            });
}
```

This configuration sets Kestrel listening on multiple addresses. It's hard-coded in the example above, but it doesn't have to be — you can bind to an `IConfiguration` instead. When you set the URLs for kestrel in this way, it overrides the `URLS` configuration value if you've set it through one of the other mechanisms as well, such as environment variables. You'll see a warning in the logs if that happens:

```bash
warn: Microsoft.AspNetCore.Server.Kestrel[0]
      Overriding address(es) 'http://localhost:5007'. Binding to endpoints defined in UseKestrel() instead.
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://127.0.0.1:5002 
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://[::]:5003
```

Personally I haven't found a need to set the listening endpoints in Kestrel this way, but it's good to be aware that you can get complete control of Kestrel like this if you need it.

## Summary

In this post I showed five different ways you can set the URLs that your application listens on. `UseUrls()` is one of the simplest, but generally isn't suitable for production workloads. The `--urls` command line argument and `ASPNETCORE_`/`DOTNET_` environment variables are most useful for setting the values in production. The _launchSettings.json_ file is very useful for setting the URLs in a development environment. If you need fine-grained control over your configuration, you can use Kestrel's `Listen*` options directly. These can also be loaded from configuration for easy use in both production and development.