aspnetcore: DOTNET_URLS ignored by Kestrel on macOS / .NET Core 3.1 + .NET 5 Preview 8

On macOS with both .NET Core 3.1 + .NET 5 Preview 8, Kestrel ignores the DOTNET_URLS environment variable.

Funnily, using the URLS environment variable does work, but this shouldn’t be the case because the host configuration environment variables use the DOTNET_ prefix by default. My ASP.NET Core knowledge is quite limited, but after playing around with ConfigureHostConfiguration and ConfigureAppConfiguration, it seems that Kestrel reads the URLs from the app configuration instead of the host configuration.

Steps to reproduce

  • Go into a new empty directory (macOS! Haven’t tried Windows.)
  • dotnet new web
  • Verify SDK version with dotnet --info (5.0.0-preview.8.20407.11)
  • DOTNET_URLS=http://localhost:4567 dotnet run

Output:

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://localhost:5000

Commands that do work:

  • URLS=http://localhost:4567 dotnet run
  • dotnet run --urls http://localhost:4567

Output:

info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://localhost:4567

Code generated by “dotnet new web” in the steps to reproduce

Nothing special.

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });
}

Further technical details

.NET SDK (reflecting any global.json):
 Version:   5.0.100-preview.8.20417.9
 Commit:    fc62663a35

Runtime Environment:
 OS Name:     Mac OS X
 OS Version:  10.15
 OS Platform: Darwin
 RID:         osx.10.15-x64
 Base Path:   /usr/local/share/dotnet/sdk/5.0.100-preview.8.20417.9/

Host (useful for support):
  Version: 5.0.0-preview.8.20407.11
  Commit:  bf456654f9

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Comments: 16 (9 by maintainers)

Most upvoted comments

I don’t know if this is related but launchSettings.json appear to be ignored on MacOS if using Host.CreateDefaultBuilder. This code will start localhost:5000, ignoring the launchSettings.json

        private static IHostBuilder CreateHostBuilder(string[] args)
        {
            return Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    //Disable default startup messages so we don't mess up console based structured logging
                    services.Configure<ConsoleLifetimeOptions>(opt => opt.SuppressStatusMessages = false);
                })
                .ConfigureWebHostDefaults(c => { c.UseStartup<Startup>(); })
                .ConfigureLogging(c => { c.SetMinimumLevel(LogLevel.Trace); })
                .UseNLog();
        }

whereas this “legacy code” will correctly pick up launchSettings.json

        private static IWebHostBuilder CreateHostBuilder(string[] args)
        {
            return WebHost
                .CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .ConfigureLogging(c =>
                {
                    c.SetMinimumLevel(LogLevel.Trace);
                })
                .UseNLog();
        }

Running in Rider but no other changes between the two debug runs except to swap these methods.

.NET Core 3.1.3

+1 for addressing this. When running .NET core in a Docker container, ENV variable for URLs are completely ignored and the default http://localhost:5000 is always used. Seemingly the only way to change this behavior is by setting Kestrel:Endpoints:Http:Url value in appsettings.json.

If you don’t need all the extra features configuring endpoints directly in Kestrel gives you (like specifying TLS certs or HTTP protocol versions), you can set the key Urls (or URLS or urls because it’s case insensitive) to http://*:8080. This should work with all versions of ASP.NET Core using either ConfigureWebHostDefaults (The generic host) or WebApplicationBuilder (new in .NET 6).

Urls can be defined via the command line (--urls "http://*:8080"), non-prefixed environment variables (Just URLS. DOTNET_URLS or ASPNETCORE_URLS get overridden by URLS) which includes any defined in launchsettings.json or in appsettings.json or any other configuration source. If Urls is defined in more than one place, it is taken from the highest priority configuration source which is the last one added to the IConfigurationBuilder. By default, the command line has the highest priority closely followed by non-prefixed environment variables (from launchsettings.json or otherwise) and then appsettings.json.

The recently updated doc https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-6.0#default-application-configuration-sources goes into a lot more detail about all of this. As noted in those docs:

URLS is one of the many common host settings that is not a bootstrap setting. Like every other host setting not in the previous list, URLS is read later from application config. Host config is a fallback for application config, so host config can be used to set URLS, but it will be overridden by any configuration source in application config like appsettings.json.

In an earlier triage we suggested the following:

Triage: We can look at adding info logs stating “<value> from <location> was overridden by <value> from <location>” or something similar.

Unfortunately, this is not possible because we cannot determine if config was overridden using IConfiguration. I’m going to move this out of the backlog to discuss in triage again, but now that the documentation is updated, I think we should close this issue. While the current behavior is unfortunately quite complicated, any simplification would be a pretty major breaking change.

Can confirm that only (i’m setting this via kubernetes) @kmjungersen approach worked with my case, ie. I set the key: Kestrel__Endpoints__Http__Url to http://*:8080 (what I need for my kubernetes service). Thanks.

Also experienced this issue, running in the context of a Docker container.

Triage: We can look at adding info logs stating "<value> from <location> was overridden by <value> from <location>" or something similar.

I’m removing the labels because I want to discuss this next triage. This experience does seem pretty surprising and hard-to-diagnose, and I want to make sure there isn’t something more we can do to improve this before marking it at resolved.