Microsoft’s .NET 8 runtime and SDK are available for RHEL 8 directly from Red Hat’s AppStream and Microsoft’s package feed, making it straightforward to run modern ASP.NET Core applications on enterprise Linux. This tutorial covers installing the .NET 8 SDK, scaffolding a minimal Web API project, running it for local testing, publishing a self-contained Release build, creating a dedicated system user and systemd service, and placing Nginx in front of the application as a reverse proxy. Following production best practices throughout — including a non-privileged service account and environment variable injection via the unit file — results in a deployment that is both secure and easy to maintain.

Prerequisites

  • A RHEL 8 server with a non-root sudo user
  • EPEL 8 repository enabled (dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm)
  • Nginx available: sudo dnf install nginx
  • Port 80 and an internal port (5000) reachable — adjust firewall-cmd as needed
  • At least 1 GB of free disk space under /opt

Step 1 — Install the .NET 8 SDK

Red Hat distributes the .NET packages through the AppStream module stream. Installing the SDK includes the runtime, so you do not need a separate runtime package.

sudo dnf install dotnet-sdk-8.0 -y

dotnet --version
# Expected: 8.0.x

dotnet --list-sdks
dotnet --list-runtimes

Step 2 — Create and Run a Minimal Web API Project

The webapi template generates a minimal ASP.NET Core project with a sample weather-forecast endpoint that you can test immediately.

cd ~
dotnet new webapi -n MyApi --no-openapi
cd MyApi

# Run for local testing — binds to all interfaces on port 5000
dotnet run --urls=http://0.0.0.0:5000 &

# Test the default endpoint from another terminal
curl -s http://localhost:5000/weatherforecast | python3 -m json.tool

# Stop the background process
kill %1

Step 3 — Publish a Release Build

The dotnet publish command compiles the project in Release mode and writes a self-contained, ready-to-deploy output directory to /opt/myapi.

dotnet publish -c Release -o /tmp/myapi_publish

# Deploy to the final location
sudo mkdir -p /opt/myapi
sudo cp -r /tmp/myapi_publish/. /opt/myapi/

# Confirm the published binary and DLLs are present
ls /opt/myapi/

Step 4 — Create a Dedicated Service User

Running .NET applications as root is a security risk. Create a locked-down system account that owns the application directory.

sudo useradd --system --no-create-home --shell /sbin/nologin dotnetapp

# Grant the service user ownership of the app directory
sudo chown -R dotnetapp:dotnetapp /opt/myapi
sudo chmod -R 0750 /opt/myapi

# Verify
ls -la /opt/myapi/ | head -5

Step 5 — Create and Enable a systemd Service Unit

A systemd unit starts and supervises the application automatically. ASP.NET Core reads connection strings and other configuration from environment variables, which are set securely in the unit file rather than baked into the application binary.

sudo tee /etc/systemd/system/myapi.service << 'EOF'
[Unit]
Description=My ASP.NET Core 8 Web API
After=network.target

[Service]
User=dotnetapp
WorkingDirectory=/opt/myapi
ExecStart=/usr/bin/dotnet /opt/myapi/MyApi.dll
Restart=always
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=myapi

# ASP.NET Core environment configuration
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=ASPNETCORE_URLS=http://127.0.0.1:5000
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now myapi.service
sudo systemctl status myapi.service

Step 6 — Configure Nginx as a Reverse Proxy

Nginx terminates HTTP connections and forwards requests to the .NET application listening on 127.0.0.1:5000. This allows Nginx to handle TLS termination and static asset serving while .NET handles application logic.

sudo tee /etc/nginx/conf.d/myapi.conf << 'EOF'
server {
    listen 80;
    server_name _;

    location / {
        proxy_pass         http://127.0.0.1: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;
    }
}
EOF

sudo nginx -t
sudo systemctl enable --now nginx
curl -s http://localhost/weatherforecast | python3 -m json.tool

Conclusion

You have installed the .NET 8 SDK on RHEL 8, created a minimal ASP.NET Core Web API, published a Release build to /opt/myapi, secured the application under a dedicated dotnetapp system account, configured a systemd unit with explicit ASPNETCORE_* environment variables, and placed Nginx in front of the application as a reverse proxy. The result is a production-grade deployment that starts automatically on boot, restarts on failure, and exposes no privileged processes to the network.

Next steps: How to Add TLS to an Nginx Reverse Proxy with Let’s Encrypt on RHEL 8, How to Connect an ASP.NET Core Application to PostgreSQL on RHEL 8, and How to Containerise a .NET Application with Podman on RHEL 8.