.NET Web Application Linux Deployment Guide: From Environment Setup to Production Launch

Introduction

Background and Advantages

<span>ASP.NET Core</span> has supported cross-platform deployment since <span>.NET Core 1.0</span> (2016), and deploying on <span>Linux</span> offers the following advantages:

  • • High Performance: <span>Linux</span> servers (such as <span>Ubuntu</span>) have low resource consumption, suitable for high concurrency.
  • • Cost-Effective: Open-source operating system reduces server costs.
  • • Ecosystem Support: Supports <span>MySQL, Docker, Nginx</span>, compatible with microservices and cloud-native.
  • • Active Community: <span>Linux</span> is the preferred choice for cloud deployments (such as <span>AWS, Azure</span>).

Deployment Methods

<span>ASP.NET Core Web</span> projects have the following main deployment methods on <span>Linux</span>:

  • • Self-contained Deployment:
    • • Package the application and <span>.NET</span> runtime to run independently.
    • • Suitable for <span>Linux</span> servers without the <span>.NET</span> runtime.
  • • Framework-dependent Deployment:
    • • Only package the application, relying on the server-installed <span>.NET SDK</span>/runtime.
    • • Suitable for servers with a configured <span>.NET</span> environment.
  • • Docker Container Deployment:
    • • Use <span>Docker</span> containers to encapsulate the application and dependencies.
    • • Suitable for microservices, cloud-native, and <span>CI/CD</span>.
  • • Cloud Platform Deployment:
    • • Use cloud services (such as <span>Azure App Service, AWS Elastic Beanstalk</span>).
    • • Suitable for rapid deployment and scaling.

Prerequisites

Target Machine

  • • Distribution (<span>Ubuntu, CentOS, Debian, Alpine</span>, etc.)
  • • Installed <span>.NET</span> runtime or <span>SDK</span> (recommended at least <span>.NET 6 LTS</span> or higher)

<span>.NET</span> Installation

# Install .NET 6 runtime on Ubuntu as an example
wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt update
sudo apt install -y aspnetcore-runtime-6.0

Firewall and Ports

Ensure that the ports used by the hosted application (such as <span>5000</span> or <span>80/443</span>) are open in the firewall/security group.

Publishing and Running (Self-Contained vs Framework-Dependent)

<span>Framework-Dependent</span> Deployment

Depends on the target host having the <span>.NET</span> runtime installed, resulting in a smaller publish package.

dotnet publish -c Release -o ./publish

<span>Self-Contained</span> Deployment

Includes the runtime, no need for pre-installed <span>.NET</span>, but larger in size.

dotnet publish -c Release -r linux-x64 --self-contained true -o ./publish
  • <span>-c Release</span>: Publish optimized version.
  • <span>-o ./publish</span>: Output to <span>publish</span> directory.
  • <span>--self-contained true</span>: Include <span>.NET</span> runtime.
  • <span>-r linux-x64</span>: Target runtime (<span>Linux 64</span> bit).

Run: <span>./publish/YourApp</span>

Deploy Application

Transfer Files

  • • Use <span>scp</span> or <span>rsync</span> to upload the <span>publish</span> directory to the <span>Linux</span> server:
scp -r ./publish user@server:/var/www/yourapp

Set Permissions

sudo chown -R www-data:www-data /var/www/yourapp
sudo chmod -R 755 /var/www/yourapp

Run Directly (Kestrel Self-Hosted)

Start Application

cd yourapp
dotnet YourApp.dll        # Framework-Dependent
# or ./YourApp             # Self-Contained

Listen on All Interfaces

Configure in <span>appsettings.json</span> or environment variables:

"Kestrel": {
  "Endpoints": {
    "Http": { "Url": "http://0.0.0.0:5000" }
  }
}

Or:

export ASPNETCORE_URLS="http://0.0.0.0:5000"
dotnet YourApp.dll
  • • Advantages: Simple deployment;
  • • Disadvantages: Lacks load balancing, <span>TLS</span> termination, logging management, and other enterprise features.

Using systemd Daemon

Run the application as a service in the background and start it with the system.

Create <span>systemd Unit</span> file <span>/etc/systemd/system/kestrel-yourapp.service</span>:

[Unit]
Description=YourApp ASP.NET Core Service
After=network.target

[Service]
WorkingDirectory=/var/www/yourapp
ExecStart=/usr/bin/dotnet /var/www/yourapp/YourApp.dll
Restart=always
RestartSec=10
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=ASPNETCORE_URLS=http://0.0.0.0:5000

[Install]
WantedBy=multi-user.target

Start and Enable

sudo systemctl daemon-reload
sudo systemctl start kestrel-yourapp
sudo systemctl enable kestrel-yourapp
sudo journalctl -fu kestrel-yourapp

Reverse Proxy (Nginx/Apache) + Kestrel

It is recommended to use a reverse proxy in production environments to achieve static file caching, <span>TLS</span> termination, path rewriting, etc.

Install Nginx

sudo apt install -y nginx

Configure Nginx

In <span>/etc/nginx/sites-available/yourapp</span>:

server {
    listen 80;
    server_name your.domain.com;

    # Redirect HTTP to HTTPS (optional)
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name your.domain.com;

    ssl_certificate     /etc/ssl/certs/your.crt;
    ssl_certificate_key /etc/ssl/private/your.key;

    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;
    }

    # Optional: Direct connection for static files
    location /static/ {
        root /var/www/yourapp/wwwroot;
        expires 30d;
    }
}

Enable the configuration and restart <span>Nginx</span>:

sudo ln -s /etc/nginx/sites-available/yourapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

Containerized Deployment (Docker)

Use <span>Docker</span> to achieve environment consistency and portability.

Dockerfile Example

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["YourApp.csproj", "./"]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "YourApp.dll"]

Build and Run

docker build -t yourapp:1.0 .
docker run -d -p 80:80 --name yourapp -e ASPNETCORE_ENVIRONMENT=Production yourapp:1.0

Using Docker Compose

version: '3.8'
services:
  web:
    image: yourapp:latest
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:80"
    environment:
      - ASPNETCORE_ENVIRONMENT=Production
    depends_on:
      - mysql
    networks:
      - app-network

  mysql:
    image: mysql:8.0
    environment:
      - MYSQL_ROOT_PASSWORD=password
    volumes:
      - mysql-data:/var/lib/mysql
    ports:
      - "3306:3306"
    networks:
      - app-network
  nginx:
    image: nginx:latest
    ports:
        - "80:80"
    volumes:
        - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
        - web
    networks:
        - app-network  

networks:
  app-network:
    driver: bridge

volumes:
  mysql-data:

<span>Nginx</span> Configuration (<span>nginx.conf</span>):

events {}
http {
    server {
        listen 80;
        location / {
            proxy_pass http://web:80;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

PaaS Platform Deployment

If you do not want to manage the server yourself, you can choose cloud vendors’ <span>PaaS</span>:

  • • Azure App Service for Linux
  • • AWS Elastic Beanstalk (Docker/.NET Core platform)
  • • Google Cloud Run (containerized)
  • • Heroku (using Docker buildpacks)

These platforms typically only require pushing code or images, automatically completing building, running, load balancing, and <span>TLS</span>.

Operations and Monitoring

  • • Centralized Logging

Use <span>Microsoft.Extensions.Logging</span> to output to files, <span>Syslog</span>, <span>ELK/EFK</span>, or <span>Prometheus</span>.

  • • Health Checks

Configure health check endpoints in <span>Startup</span> with <span>app.MapHealthChecks("/health")</span>, and let the load balancer probe the health.

  • • Automatic Restart

<span>systemd</span> with <span>Restart=always</span> or <span>Kubernetes</span> with <span>livenessProbe</span>.

  • • Performance Analysis

Utilize <span>dotnet-counters, dotnet-trace, Application Insights, Prometheus + Grafana</span>, etc.

# Install dotnet-counters
dotnet tool install -g dotnet-counters

# Monitor application performance
dotnet-counters monitor -n your-app --counters System.Runtime,Microsoft.AspNetCore.Http

# Install dotnet-trace
dotnet tool install -g dotnet-trace

# Collect performance traces
dotnet-trace collect -n your-app --format Speedscope

Key Diagnostic Commands

# Check port listening
sudo ss -tulpn | grep ':5000\|:5001'

# View application logs
journalctl -u your-app --since "10 minutes ago" -f

# Test database connection
psql -h localhost -U your_app_user -d your_app_db -c "SELECT 1"

# Network connectivity test
curl -v http://localhost:5000/health

# Analyze memory usage
top -p $(pgrep -f YourApp)

Best Practices Checklist

Environment Standardization:

  • • Use the same version of <span>OS</span> and <span>.NET</span> runtime
  • • Configure unified environment variable management

Security First:

  • • Principle of least privilege (run as non-<span>root</span> user)
  • • Regularly update security patches
  • • Enforce <span>HTTPS</span> connections

Reliable Deployment:

  • • Use <span>CI/CD</span> pipelines for automated deployment
  • • Implement blue-green deployment or canary releases
  • • Retain rollback capability for the previous version

Performance Optimization:

  • • Enable <span>ReadyToRun</span> compilation
  • • Configure response compression
  • • Use load balancing and horizontal scaling

Monitoring and Alerts:

  • • Implement comprehensive health checks
  • • Integrate <span>APM</span> tools (such as <span>Application Insights</span>)
  • • Set alerts for key metrics (CPU, memory, error rate)

Disaster Recovery:

  • • Regularly back up databases and application configurations
  • • Develop and test recovery plans
  • • Deploy critical applications across multiple regions

Conclusion

Method Advantages Disadvantages
Direct Run (Kestrel) Most straightforward, zero dependencies Lacks TLS, load balancing
systemd Management Stable restart, auto-start on boot No reverse proxy, certificate management requires additional effort
Nginx/Apache Reverse Proxy + systemd TLS termination, path rewriting, static caching Configuration is slightly complex
Docker Containerization Environment isolation, portability, high consistency Learning curve, image management
Cloud PaaS Minimal operations, automatic scaling Platform dependency, relatively high costs

Resources and Documentation

Official Documentation:

  • <span>ASP.NET Core on Linux</span>: https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx
  • <span>Docker with ASP.NET Core</span>: https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/docker

Leave a Comment