Self-hosted gRPC applications
Tip
This content is an excerpt from the eBook, gRPC for WCF developers, available on .NET Docs or as a free downloadable PDF that can be read offline.
Although ASP.NET Core 7.0 applications can be hosted in IIS on Windows Server, currently it isn't possible to host a gRPC application in IIS because some of the HTTP/2 functionality isn't supported. This functionality is a goal for a future update to Windows Server.
You can run your application as a Windows service. Or you can run it as a Linux service controlled by systemd, because of features introduced in the .NET 6 hosting extensions.
Run your app as a Windows service
To configure your ASP.NET Core application to run as a Windows service, install the Microsoft.Extensions.Hosting.WindowsServices package from NuGet. Then add a call to UseWindowsService
to the CreateHostBuilder
method in Program.cs
.
Host.CreateDefaultBuilder(args)
.UseWindowsService()
...
Note
If the application isn't running as a Windows service, the UseWindowsService
method doesn't do anything.
Now publish your application by using one of these methods:
- From Visual Studio by right-clicking the project and selecting Publish on the shortcut menu.
- From the .NET CLI.
When you publish a .NET application, you can choose to create a framework-dependent deployment or a self-contained deployment. Framework-dependent deployments require the .NET Shared Runtime to be installed on the host where they're run. Self-contained deployments are published with a complete copy of the .NET runtime and framework and can be run on any host. For more information, including the advantages and disadvantages of each approach, see the .NET application deployment documentation.
To publish a self-contained build of the application that doesn't require the .NET 5 runtime to be installed on the host, specify the runtime to be included with the application. Use the -r
(or --runtime
) flag.
dotnet publish -c Release -r win-x64 -o ./publish
To publish a framework-dependent build, omit the -r
flag.
dotnet publish -c Release -o ./publish
Copy the complete contents of the publish
directory to an installation folder. Then, use the sc tool to create a Windows service for the executable file.
sc create MyService binPath=C:\MyService\MyService.exe
Log to the Windows event log
The UseWindowsService
method automatically adds a logging provider that writes log messages to the Windows event log. You can configure logging for this provider by adding an EventLog
entry to the Logging
section of appsettings.json
or another configuration source.
You can override the source name used in the event log by setting a SourceName
property in these settings. If you don't specify a name, the default application name (normally the executable assembly name) will be used.
More information on logging is at the end of this chapter.
Run your app as a Linux service with systemd
To configure your ASP.NET Core application to run as a Linux service (or daemon in Linux parlance), install the Microsoft.Extensions.Hosting.Systemd package from NuGet. Then add a call to UseSystemd
to the CreateHostBuilder
method in Program.cs
.
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSystemd() // Enable running as a Systemd service
.ConfigureServices((hostContext, services) =>
{
...
});
Note
If the application isn't running as a Linux service, the UseSystemd
method doesn't do anything.
Now publish your application. The application can be either framework dependent or self-contained for the relevant Linux runtime (for example, linux-x64
). You can publish by using one of these methods:
From Visual Studio by right-clicking the project and selecting Publish on the shortcut menu.
From the .NET CLI, by using the following command:
dotnet publish -c Release -r linux-x64 -o ./publish
Copy the complete contents of the publish
directory to an installation folder on the Linux host. Registering the service requires a special file, called a unit file, to be added to the /etc/systemd/system
directory. You'll need root permission to create a file in this folder. Name the file with the identifier that you want systemd
to use and the .service
extension. For example, use /etc/systemd/system/myapp.service
.
The service file uses INI format, as shown in this example:
[Unit]
Description=My gRPC Application
[Service]
Type=notify
ExecStart=/usr/sbin/myapp
[Install]
WantedBy=multi-user.target
The Type=notify
property tells systemd
that the application will notify it on startup and shutdown. The WantedBy=multi-user.target
setting will cause the service to start when the Linux system reaches "runlevel 2," which means a nongraphical, multi-user shell is active.
Before systemd
will recognize the service, it needs to reload its configuration. You control systemd
by using the systemctl
command. After reloading, use the status
subcommand to confirm that the application has registered successfully.
sudo systemctl daemon-reload
sudo systemctl status myapp
If you've configured the service correctly, you'll get the following output:
myapp.service - My gRPC Application
Loaded: loaded (/etc/systemd/system/myapp.service; disabled; vendor preset: enabled)
Active: inactive (dead)
Use the start
command to start the service.
sudo systemctl start myapp.service
Tip
The .service
extension is optional when you're using systemctl start
.
To tell systemd
to start the service automatically on system startup, use the enable
command.
sudo systemctl enable myapp
Log to journald
The Linux equivalent of the Windows event log is journald
, a structured logging system service that's part of systemd
. Log messages written to the standard output by a Linux daemon are automatically written to journald
. To configure logging levels, use the Console
section of the logging configuration. The UseSystemd
host builder method automatically configures the console output format to suit the journal.
Because journald
is the standard for Linux logs, a variety of tools integrate with it. You can easily route logs from journald
to an external logging system. Working locally on the host, you can use the journalctl
command to view logs from the command line.
sudo journalctl -u myapp
Tip
If you have a GUI environment available on your host, a few graphical log viewers are available for Linux, such as QJournalctl and gnome-logs.
To learn more about querying the systemd
journal from the command line by using journalctl
, see the manpages.
HTTPS certificates for self-hosted applications
When you're running a gRPC application in production, you should use a TLS certificate from a trusted certificate authority (CA). This CA might be a public CA, or an internal one for your organization.
On Windows hosts, you can load the certificate from a secure certificate store by using the X509Store class. You can also use the X509Store
class with the OpenSSL key store on some Linux hosts.
You can also create certificates by using one of the X509Certificate2 constructors, from either:
- A file, such as a
.pfx
file protected by a strong password - Binary data retrieved from a secure storage service such as Azure Key Vault
You can configure Kestrel to use a certificate in two ways: from configuration or in code.
Set HTTPS certificates by using configuration
The configuration approach requires setting the password and path to the certificate .pfx
file in the Kestrel configuration section. In appsettings.json
, that looks like this:
{
"Kestrel": {
"Certificates": {
"Default": {
"Path": "cert.pfx",
"Password": "DO NOT STORE PLAINTEXT PASSWORDS IN APPSETTINGS FILES"
}
}
}
}
Provide the password by using a secure configuration source such as Azure Key Vault or Hashicorp Vault.
Important
Don't store unencrypted passwords in configuration files.
Set HTTPS certificates in code
To configure HTTPS on Kestrel in code, use the ConfigureKestrel
method on IWebHostBuilder
in the Program
class.
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureKestrel(kestrel =>
{
kestrel.ConfigureHttpsDefaults(https =>
{
https.ServerCertificate = new X509Certificate2("mycert.pfx", "password");
});
});
});
Again, be sure to store the password for the .pfx
file in, and retrieve it from, a secure configuration source.
Feedback
Submit and view feedback for