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-cmdas 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.