.NET Core 3.1 IHostBuilder Apache 托管与 Kestrel Program.cs 设置
.NET Core 3.1 IHostBuilder Apache Hosting With Kestrel Program.cs Setup
我在 CentOS 7 上有一个 Web 应用程序 运行,Apache 服务器用作 Kestrel 的代理。在我的 Program.cs 文件中,我使用的是以下内容,它似乎工作正常:
public static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.Build();
var host = new WebHostBuilder()
.UseKestrel()
.UseConfiguration(config)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseUrls("http://localhost:5555")
.Build();
host.Run();
}
但看起来 .NET Core 的东西最近更新了,我正在尝试以与下面相同的方式使用 IHostBuilder,这似乎在本地工作正常,但在生产服务器上我收到错误“代理错误 502:代理服务器从上游服务器收到无效响应”。
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel();
webBuilder.UseContentRoot(Directory.GetCurrentDirectory());
webBuilder.UseConfiguration(new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddCommandLine(args).Build());
webBuilder.UseUrls("https://localhost:5555");
webBuilder.UseStartup<Startup>();
});
我不确定这是否与我服务器上的域配置有任何关系 - 使用上面的第一个示例再次正常工作 - 或者我是否需要在 Program.cs 或 Startup.cs 将使用 IHostBuilder 解决此问题。
与此同时,我将继续使用我拥有的东西,因为它工作得很好。
提前感谢任何可以帮助阐明这一点的人。如果有任何其他信息可以提供帮助,请告诉我。
可能是本地主机绑定或 SSL 安全导致了问题。
确保您在项目中使用的 HTTPS 证书可以被代理信任,或者禁用在 apache 中的检查。
从 .Net 的角度来看,尝试将以下内容添加到您的项目中
public class ConfigHelper
{
/// <summary>
/// This method is used in the service startup to read hosting configuration options from the applications settings
/// The following section can be included in your appsettings.json file to specify the binding, ports and certificate information.
/// The certificate should be self-signed in .pfx format
///
/// "Hosting": {
/// "HTTPBinding": "DISABLED",
/// "HTTPPort": 0,
/// "HTTPSBinding": "ANY",
/// "HTTPSPort": 5555,
/// "SSLCert": "PathToCert"
/// }
/// </summary>
/// <param name="configuration">The configuration option loaded from a local config file</param>
/// <param name="options">The KestrelServerOptions from WebHost.CreateDefaultBuilder(args).UseKestrel(options => ConfigHelper.SetupHostingOptions(configuration, options);)</param>
public static void SetupHostingOptions(IConfigurationRoot configuration, KestrelServerOptions options)
{
IPAddress httpBinding = ConfigHelper.GetAddressFromSetting(configuration.GetValue<string>("Hosting:HTTPBinding"));
IPAddress httpsBinding = ConfigHelper.GetAddressFromSetting(configuration.GetValue<string>("Hosting:HTTPSBinding"));
if (httpBinding != null && httpBinding != IPAddress.None)
{
if (configuration.GetValue<int?>("Hosting:HTTPPort") != null)
options.Listen(httpBinding, configuration.GetValue<int>("Hosting:HTTPPort"));
}
if (httpsBinding != null && httpsBinding != IPAddress.None)
{
int httpsPort = configuration.GetValue<int?>("Hosting:HTTPSPort") ?? 443;
string sslCert = configuration.GetValue<string>("Hosting:SSLCert");
string sslCertPassword = configuration.GetValue<string>("Hosting:SSLCertPassword");
if (sslCert != null)
{
if (sslCertPassword != null)
options.Listen(httpsBinding, httpsPort, listenOptions => { listenOptions.UseHttps(sslCert, sslCertPassword); });
else
options.Listen(httpsBinding, httpsPort, listenOptions => { listenOptions.UseHttps(sslCert); });
}
}
}
/// <summary>
/// Gets the IP address from the configuration setting
/// </summary>
/// <param name="httpBinding"></param>
/// <returns></returns>
public static IPAddress GetAddressFromSetting(string httpBinding)
{
if (string.IsNullOrWhiteSpace(httpBinding) || httpBinding.ToUpper() == "DISABLED")
return null;
else
httpBinding = httpBinding.ToUpper();
IPAddress bindingIp = null;
switch (httpBinding.ToUpper())
{
case "DISABLED":
bindingIp = null;
break;
case "ANY":
bindingIp = IPAddress.Any;
break;
case "IPV6ANY":
bindingIp = IPAddress.IPv6Any;
break;
case "IPV6LOOPBACK":
bindingIp = IPAddress.IPv6Loopback;
break;
case "IPV6NONE":
bindingIp = IPAddress.IPv6None;
break;
case "LOOPBACK":
bindingIp = IPAddress.Loopback;
break;
case "NONE":
bindingIp = IPAddress.None;
break;
default:
bool ipParsed = false;
try
{
bindingIp = IPAddress.Parse(httpBinding);
ipParsed = true;
}
catch(System.Exception)
{
}
if(!ipParsed)
{
IPHostEntry hostEntry = Dns.GetHostEntry(httpBinding);
if (hostEntry.AddressList.Length > 0)
{
bindingIp = hostEntry.AddressList[0];
ipParsed = true;
}
}
if (!ipParsed)
{
throw new System.Exception("Failed to parse IP address from '" + httpBinding + "'");
}
break;
}
return bindingIp;
}
}
然后在你的 main
public static void Main(string[] args)
{
// Start the application
CreateHostBuilder(args).Build().Run();
}
/// <summary>
/// Create the service objects
/// </summary>
/// <param name="args">Command line arguments</param>
/// <returns>The configured host builder object</returns>
public static IHostBuilder CreateHostBuilder(string[] args)
{
// Load the configuration object
var configuration = new ConfigurationBuilder()
.AddCommandLine(args)
.SetBasePath(Environment.CurrentDirectory)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true)
.AddEnvironmentVariables()
.Build();
// Create the host builder object
return Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseStartup<Startup>()
.UseConfiguration(configuration)
.UseKestrel(options => { ConfigHelper.SetupHostingOptions(configuration, options); });
});
}
那么你appsettings.json应该有一个像
这样的部分
"Hosting": {
"HTTPBinding": "DISABLED",
"HTTPPort": 0,
"HTTPSBinding": "ANY",
"HTTPSPort": 5555,
"SSLCert": "sslcert.pfx",
"SSLCertPassword": "sslcertpasswordhere"
}
如果您在同一个 centos 实例上从 apache 代理到 kestrel 服务,那么您可以考虑 运行 外部世界在 HTTPS 中的 apache 并在两者之间使用 http(或者只是跳过使用一起代理)
哇...这是因为服务 运行 我的网络应用程序在 http 上 运行 但强制重定向到 https。问题出在这一行:
webBuilder.UseUrls("https://localhost:5555");
需要这样:
webBuilder.UseUrls("http://localhost:5555");
我还测试了 Xavier 的解决方案,它也有效。所以感谢您提供解决方案。
我在 CentOS 7 上有一个 Web 应用程序 运行,Apache 服务器用作 Kestrel 的代理。在我的 Program.cs 文件中,我使用的是以下内容,它似乎工作正常:
public static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.Build();
var host = new WebHostBuilder()
.UseKestrel()
.UseConfiguration(config)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseUrls("http://localhost:5555")
.Build();
host.Run();
}
但看起来 .NET Core 的东西最近更新了,我正在尝试以与下面相同的方式使用 IHostBuilder,这似乎在本地工作正常,但在生产服务器上我收到错误“代理错误 502:代理服务器从上游服务器收到无效响应”。
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel();
webBuilder.UseContentRoot(Directory.GetCurrentDirectory());
webBuilder.UseConfiguration(new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddCommandLine(args).Build());
webBuilder.UseUrls("https://localhost:5555");
webBuilder.UseStartup<Startup>();
});
我不确定这是否与我服务器上的域配置有任何关系 - 使用上面的第一个示例再次正常工作 - 或者我是否需要在 Program.cs 或 Startup.cs 将使用 IHostBuilder 解决此问题。
与此同时,我将继续使用我拥有的东西,因为它工作得很好。
提前感谢任何可以帮助阐明这一点的人。如果有任何其他信息可以提供帮助,请告诉我。
可能是本地主机绑定或 SSL 安全导致了问题。
确保您在项目中使用的 HTTPS 证书可以被代理信任,或者禁用在 apache 中的检查。
从 .Net 的角度来看,尝试将以下内容添加到您的项目中
public class ConfigHelper
{
/// <summary>
/// This method is used in the service startup to read hosting configuration options from the applications settings
/// The following section can be included in your appsettings.json file to specify the binding, ports and certificate information.
/// The certificate should be self-signed in .pfx format
///
/// "Hosting": {
/// "HTTPBinding": "DISABLED",
/// "HTTPPort": 0,
/// "HTTPSBinding": "ANY",
/// "HTTPSPort": 5555,
/// "SSLCert": "PathToCert"
/// }
/// </summary>
/// <param name="configuration">The configuration option loaded from a local config file</param>
/// <param name="options">The KestrelServerOptions from WebHost.CreateDefaultBuilder(args).UseKestrel(options => ConfigHelper.SetupHostingOptions(configuration, options);)</param>
public static void SetupHostingOptions(IConfigurationRoot configuration, KestrelServerOptions options)
{
IPAddress httpBinding = ConfigHelper.GetAddressFromSetting(configuration.GetValue<string>("Hosting:HTTPBinding"));
IPAddress httpsBinding = ConfigHelper.GetAddressFromSetting(configuration.GetValue<string>("Hosting:HTTPSBinding"));
if (httpBinding != null && httpBinding != IPAddress.None)
{
if (configuration.GetValue<int?>("Hosting:HTTPPort") != null)
options.Listen(httpBinding, configuration.GetValue<int>("Hosting:HTTPPort"));
}
if (httpsBinding != null && httpsBinding != IPAddress.None)
{
int httpsPort = configuration.GetValue<int?>("Hosting:HTTPSPort") ?? 443;
string sslCert = configuration.GetValue<string>("Hosting:SSLCert");
string sslCertPassword = configuration.GetValue<string>("Hosting:SSLCertPassword");
if (sslCert != null)
{
if (sslCertPassword != null)
options.Listen(httpsBinding, httpsPort, listenOptions => { listenOptions.UseHttps(sslCert, sslCertPassword); });
else
options.Listen(httpsBinding, httpsPort, listenOptions => { listenOptions.UseHttps(sslCert); });
}
}
}
/// <summary>
/// Gets the IP address from the configuration setting
/// </summary>
/// <param name="httpBinding"></param>
/// <returns></returns>
public static IPAddress GetAddressFromSetting(string httpBinding)
{
if (string.IsNullOrWhiteSpace(httpBinding) || httpBinding.ToUpper() == "DISABLED")
return null;
else
httpBinding = httpBinding.ToUpper();
IPAddress bindingIp = null;
switch (httpBinding.ToUpper())
{
case "DISABLED":
bindingIp = null;
break;
case "ANY":
bindingIp = IPAddress.Any;
break;
case "IPV6ANY":
bindingIp = IPAddress.IPv6Any;
break;
case "IPV6LOOPBACK":
bindingIp = IPAddress.IPv6Loopback;
break;
case "IPV6NONE":
bindingIp = IPAddress.IPv6None;
break;
case "LOOPBACK":
bindingIp = IPAddress.Loopback;
break;
case "NONE":
bindingIp = IPAddress.None;
break;
default:
bool ipParsed = false;
try
{
bindingIp = IPAddress.Parse(httpBinding);
ipParsed = true;
}
catch(System.Exception)
{
}
if(!ipParsed)
{
IPHostEntry hostEntry = Dns.GetHostEntry(httpBinding);
if (hostEntry.AddressList.Length > 0)
{
bindingIp = hostEntry.AddressList[0];
ipParsed = true;
}
}
if (!ipParsed)
{
throw new System.Exception("Failed to parse IP address from '" + httpBinding + "'");
}
break;
}
return bindingIp;
}
}
然后在你的 main
public static void Main(string[] args)
{
// Start the application
CreateHostBuilder(args).Build().Run();
}
/// <summary>
/// Create the service objects
/// </summary>
/// <param name="args">Command line arguments</param>
/// <returns>The configured host builder object</returns>
public static IHostBuilder CreateHostBuilder(string[] args)
{
// Load the configuration object
var configuration = new ConfigurationBuilder()
.AddCommandLine(args)
.SetBasePath(Environment.CurrentDirectory)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true)
.AddEnvironmentVariables()
.Build();
// Create the host builder object
return Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseStartup<Startup>()
.UseConfiguration(configuration)
.UseKestrel(options => { ConfigHelper.SetupHostingOptions(configuration, options); });
});
}
那么你appsettings.json应该有一个像
这样的部分 "Hosting": {
"HTTPBinding": "DISABLED",
"HTTPPort": 0,
"HTTPSBinding": "ANY",
"HTTPSPort": 5555,
"SSLCert": "sslcert.pfx",
"SSLCertPassword": "sslcertpasswordhere"
}
如果您在同一个 centos 实例上从 apache 代理到 kestrel 服务,那么您可以考虑 运行 外部世界在 HTTPS 中的 apache 并在两者之间使用 http(或者只是跳过使用一起代理)
哇...这是因为服务 运行 我的网络应用程序在 http 上 运行 但强制重定向到 https。问题出在这一行:
webBuilder.UseUrls("https://localhost:5555");
需要这样:
webBuilder.UseUrls("http://localhost:5555");
我还测试了 Xavier 的解决方案,它也有效。所以感谢您提供解决方案。