Search code examples
.net-coresystemd

Using systemd sockets with .NET Core


I have installed a .NET Core application on my Ubuntu server, and it is running fine both when I run it manually and when I set it up as a systemd service. However, since the application is being run through an nginx web server, and I would like to only start the application when a user accesses it, I tried setting it up with a systemd socket so that the corresponding service only starts when the socket receives a notification from nginx. In this scenario, the application is not working and giving an error when it happens. Is there a way to set up socket-based activiation for .NET Core applications in Linux? I want to emphasize that the same service works fine when it's not activated by the socket. Below is the error I'm receiving, and the systemd units.

Microsoft.AspNetCore.DataProtection.Repositories.EphemeralXmlRepository[50]
Using an in-memory repository. Keys will not be persisted to storage.
Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[59]
Neither user profile nor HKLM registry available. Using an ephemeral key repository. Protected data will be unavailable when application exits.
Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
No XML encryptor configured. Key {1c6b8e72-67bd-4653-b656-76f9dd136ee3} may be persisted to storage in unencrypted form.

ercot.service
[Unit]
Description=ERCOT trade uploader daemon
Requires=ercot.socket
After=network.target

[Service]
Type=notify
# the specific user that our service will run as
User=www-data
Group=www-data
# another option for an even more restricted service is
# DynamicUser=yes
# see http://0pointer.net/blog/dynamic-users-with-systemd.html
RuntimeDirectory=ercot
WorkingDirectory=/srv/netcore/ercot
ExecStart=/srv/netcore/ercot/DashboardWebServer
# ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true

[Install]
WantedBy=multi-user.target

[Unit]
Description=ERCOT trade uploader socket

ercot.socket
[Socket]
ListenStream=/run/ercot.sock
# Our service won't need permissions for the socket, since it
# inherits the file descriptor by socket activation
# only the nginx daemon will need access to the socket
SocketUser=www-data
SocketGroup=www-data
# Optionally restrict the socket permissions even more.
# SocketMode=600

[Install]
WantedBy=sockets.target

Relevant Google searches bring up this error with IIS but that is obviously not relevant for this situation. Thanks!

https://www.puresourcecode.com/dotnet/net-core/using-an-in-memory-repository-keys-will-not-be-persisted-to-storage-asp-net-core-under-iis/


Solution

  • So it turns out my question was sort of incorrect. The application does not support socket activation so that's why it wasn't working. Instead the solution I came up with uses a socket proxy to achieve this with systemd-socket-proxyd being the app to use. Here are the three systemd units I made.

    ercot-proxy.socket
    [Unit]
    Description=ERCOT trade uploader proxy socket
    
    [Socket]
    ListenStream=/run/ercot-proxy.sock
    SocketUser=www-data
    SocketGroup=www-data
    
    [Install]
    WantedBy=sockets.target
    

    ercot-proxy.service
    [Unit]
    Description=ERCOT trade uploader proxy service
    
    BindsTo=ercot-proxy.socket
    After=ercot-proxy.socket
    
    Wants=ercot.service
    
    [Service]
    ExecStart=/lib/systemd/systemd-socket-proxyd 127.0.0.1:42222
    

    ercot.service
    [Unit]
    Description=ERCOT trade uploader daemon
    BindsTo=ercot-proxy.service
    
    [Service]
    WorkingDirectory=/srv/netcore/ercot
    ExecStart=/srv/netcore/ercot/DashboardWebServer