Build & Deploy ASP.NET MVC Core web server to a Raspberry Pi

Listen for external connections

Want want to listen on port 80 for HTTP and port 443 for HTTPS, but only root can listen on these ports, so we’re going to listen on 8800 and 44433 and redirect traffic to 80 and 443 to these ports so we don’t have to run our app as root.

Enable Kestrel

In your CreateHostBuilder method:

webBuilder.UseKestrel(options =>
{
    options.Listen(IPAddress.Any, 8800);
    options.Listen(IPAddress.Any, 44433);
});

Forward ports

sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8800
sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports 44433

Override forwarding to 44433

If you configure .NET to use port 44433 for HTTPS then it will try to redirect HTTP traffic to this port. But you want it to go to 443 still. In your ConfigureServices method:

services.AddHttpsRedirection(options =>
{
    options.RedirectStatusCode = StatusCodes.Status307TemporaryRedirect;
    options.HttpsPort = 443;
});

Build & copy to Raspberry Pi

dotnet publish [project name] --configuration Release --runtime linux-arm
cd [project name]\bin\Release\[dotnet core version]\linux-arm\publish
scp -r * pi@[pi ip address]:/var/www/[project name]
cd ..\..\..\..\..\..

Run in Raspberry Pi

cd /var/www/[project name]
dotnet [project name].dll

Create certificates

Install certbot & generate certificates (source)

Note this will listen on port 80 as a verification step so won’t work if the server is currently running and/or the port forwarding is enabled. A reboot will fix both.

sudo apt-get install certbot
sudo certbot certonly --standalone

Combine certificate+key into pfx

sudo openssl pkcs12 -export -out certificate.pfx -inkey /etc/letsencrypt/live/[your domain]/privkey.pem -in /etc/letsencrypt/live/[your domain]/fullchain.pem
sudo chmod 755 certificate.pfx

Renew certificate

sudo certbot renew

Then repeat step above.

Update Kestrel config to use certificate

webBuilder.UseKestrel(options =>
{
    options.Listen(IPAddress.Any, 8800);
    options.Listen(IPAddress.Any, 44433, listenOptions =>
    {
        listenOptions.UseHttps("certificate.pfx", "password chosen in previous step");
    });
});