I recently bought a Raspberry Pi 4 with 4GB RAM and have official OS "Raspbian" installed. I've managed to run an ASP.NET Core 3.0 application on this Raspberry Pi 4. 

ARM32 or ARM64?

To be clear, you can't run ARM64 version of .NET Core runtime or SDK on a Raspberry Pi 4 today. Although Raspberry Pi 4's CPU supports 64 bit, its official operating system "Raspbian" isn't 64 bit. And other third party operating systems aren't updated to support Raspberry Pi 4 yet. So, if you are trying .NET Core 3.0 today on a Raspberry Pi 4, the only architecture you can use is ARM32.

Prepare

Required: An Internet connection for downloading .NET Core 3.0 SDK and Runtime.

Optional: Visual Studio Code / Visual Studio on your desktop machine to create a sample project

Update your Raspbian:

sudo apt-get update
sudo apt-get upgrade

I also suggest using a monitor for your Raspberry Pi or a VNC connection, so that you can test your ASP.NET Core websites at the final step without messing up port and network settings.

Download .NET Core 3.0 SDK and Runtime

On your desktop machine, open https://dotnet.microsoft.com/download/dotnet-core/3.0

Find Linux distributions for ARM32 SDK and Runtime, click into it, you will have a Direct Link. These 2 links are what we use in Raspbian to download the latest SDK and Runtime.

Currently, those links are:

.NET Core 3.0 SDK (Linux/ARM32)

https://download.visualstudio.microsoft.com/download/pr/8ddb8193-f88c-4c4b-82a3-39fcced27e91/b8e0b9bf4cf77dff09ff86cc1a73960b/dotnet-sdk-3.0.100-linux-arm.tar.gz

ASP.NET Core 3.0 Runtime (Linux/ARM32)

https://download.visualstudio.microsoft.com/download/pr/e9d4b012-a877-443c-8344-72ef910c86dd/b5e729b532d7b3b5488c97764bd0fb8e/aspnetcore-runtime-3.0.0-linux-arm.tar.gz

Use wget on your Raspbian to download these files:

wget https://download.visualstudio.microsoft.com/download/pr/8ddb8193-f88c-4c4b-82a3-39fcced27e91/b8e0b9bf4cf77dff09ff86cc1a73960b/dotnet-sdk-3.0.100-linux-arm.tar.gz
wget https://download.visualstudio.microsoft.com/download/pr/e9d4b012-a877-443c-8344-72ef910c86dd/b5e729b532d7b3b5488c97764bd0fb8e/aspnetcore-runtime-3.0.0-linux-arm.tar.gz

Please always check for updated URLs for a newer version of SDK and Runtime.

Install .NET Core 3.0 SDK and Runtime

Create a folder named for example "dotnet-arm32" and unzip them into it. 

mkdir dotnet-arm32
tar zxf aspnetcore-runtime-3.0.0-linux-arm.tar.gz -C $HOME/dotnet-arm32
tar zxf dotnet-sdk-3.0.100-linux-arm.tar.gz -C $HOME/dotnet-arm32

So far you can only run .NET Core commands inside the dotnet-arm32 folder. To make "dotnet" command can be run everywhere, you have to make something like environment variables, which will link dotnet-arm32 folder to system level.

export DOTNET_ROOT=$HOME/dotnet-arm32
export PATH=$PATH:$HOME/dotnet-arm32

Now, you can run dotnet --info to have a quick test:

Create .NET Core Applications in Raspbian

Now that we have the SDK, we don't have to use another machine to develop and publish the App. We can just do it directly on our Raspberry Pi. 

mkdir hello-netcore3
cd hello-netcore3/
dotnet new console

After the project files are created and NuGet restore completes. You can run the project using "dotnet run" command.

You can even use nano as a basic code editor.

sudo nano Program.cs

Deploy and Run ASP.NET Core Applications

In a more real-world scenario. You just can't develop complex .NET Core applications without an IDE on Raspbain. We usually develop and test our App on desktop machines first and then publish it to Raspberry Pi to run it.

To run an ASP.NET Core application. You need to first publish it. For example, from Visual Studio 2019. What I have is an empty ASP.NET Core application with a little more output information in Startup.cs

await context.Response.WriteAsync($"Empower every person and every organization on the planet to achieve more{Environment.NewLine}" +
                                  $".NET Core {Environment.Version}{Environment.NewLine}" +
                                  $"Environment.OSVersion: {Environment.OSVersion}{Environment.NewLine}" +
                                  $"Environment.Is64BitOperatingSystem: {Environment.Is64BitOperatingSystem}{Environment.NewLine}" +
                                  $"Environment.Is64BitProcess: {Environment.Is64BitProcess}", Encoding.UTF8);

Publish it using Framework-Dependent (FDD) and Portable. Because we have the native runtime on Raspberry Pi. We DON'T have to build it into linux-arm RID! Portable will run just fine!

Copy the published directory to Raspberry Pi.

Now you can use "dotnet <Your DLL Name>.dll" to run your ASP.NET Core application.

"Auto Start" .NET Core Environment

Every time you restart your Raspberry Pi, you'll have to re-configure the DOTNET_ROOT and PATH environment variables or .NET CLI won't work. To make them auto start with the system, we can modify the ".profile".

sudo nano .profile

Add those lines at the end of this file

# set .NET Core SDK and Runtime path
export DOTNET_ROOT=$HOME/dotnet-arm32
export PATH=$PATH:$HOME/dotnet-arm32

Looks like this

Save the file and restart your Raspbian system. Now you can run "dotnet --info" directly without manually setting the environment variables again.

Access ASP.NET Core Website from LAN

So far your ASP.NET Core application can only be visited on Raspberry Pi itself using "localhost". It would be much more useful if we expose it to LAN. There are two ways to do that.

Host by Kestrel itself

Just give dotnet command a --urls parameter, it would listen on the domain and port you provided. I don't want to limit to any domain name, so I use * instead.

dotnet Empower.dll --urls "http://*:8080"

Now you will be able to access your Raspberry Pi via LAN.

But this hosting model has its disadvantages, for example, when you have an exception in your code, the dotnet process will end and you have to manually restart it. Let's check out a more real-world hosting model.

Host by Nginx with auto-restart capability

First, install and start Nginx:

sudo apt-get install nginx
sudo /etc/init.d/nginx start

Open Nginx config file:

sudo nano /etc/nginx/sites-available/default

Replace its content with:

server {
    listen        80 default_server;
    server_name   _;
    location / {
        proxy_pass         http://localhost:5000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

server_name is set to _; means I don't limit domain names, just accept any hostnames. proxy_pass is the default Kestrel HTTP endpoint, which runs our ASP.NET Core website.

Check and apply the config file:

sudo nginx -t
sudo nginx -s reload

Now, start your ASP.NET Core website, you will be able to access your Raspberry Pi using port 80.

dotnet Empower.dll

Now we have one last step to go, make dotnet process auto-restart in case your code accidentally blow up. To do that, we will create a systemd service.

sudo nano /etc/systemd/system/kestrel-empowerapp.service

With the following content:

[Unit]
Description=ASP.NET Core 3.0 App - Empower

[Service]
WorkingDirectory=/home/pi/dotnet-playground/empower/portable-fdd
ExecStart=/home/pi/dotnet-arm32/dotnet /home/pi/dotnet-playground/empower/portable-fdd/Empower.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-empower
User=pi
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target

Note, we can only use absolute path in systemd configuation. 

Register and start the service:

sudo systemctl enable kestrel-empowerapp.service
sudo systemctl start kestrel-empowerapp.service
sudo systemctl status kestrel-empowerapp.service

Now, you have the auto start and failure restart capability for your ASP.NET Core 3.0 application running on Raspberry Pi 4. Try to reboot your Raspberry Pi, your website will auto start! It is a web server now!

For more configuration details, you can refer to Microsoft official document here.

Want Docker?

There are Microsoft official docker images supporting ARM32 on Raspberry Pi 4, if you managed to install docker on your Raspberry Pi 4, have fun :)

Reference: https://www.hanselman.com/blog/InstallingTheNETCore2xSDKOnARaspberryPiAndBlinkingAnLEDWithSystemDeviceGpio.aspx