Skip to main content

Deployment Overview

This guide covers deploying the DonaSF API built with ASP.NET Core .NET 10.0 to production environments including Windows Server, Linux servers, and cloud platforms.

Pre-Deployment Checklist

Before deploying to production, ensure you have:
Database server configured and accessible
SQL scripts executed and database initialized
Production Conf.txt with secure credentials
Strong JWT key configured (min 32 characters)
Email addresses configured
SSL/TLS certificate ready (for HTTPS)
Firewall rules configured
Backup strategy in place

Build for Production

Clean and Build

1

Clean Previous Builds

Remove any previous build artifacts:
dotnet clean PaqueteriaWS.sln --configuration Release
2

Restore Dependencies

Ensure all NuGet packages are restored:
dotnet restore PaqueteriaWS.sln
3

Build in Release Mode

Build the solution with optimizations:
dotnet build PaqueteriaWS.sln --configuration Release
This creates optimized binaries with:
  • Code optimizations enabled
  • Debug symbols removed
  • Smaller assembly size

Publishing the Application

Self-Contained Deployment

Create a self-contained deployment that includes the .NET runtime:
dotnet publish ServiciosConsolaCentralizada/ServiciosConsolaCentralizada.csproj \
  --configuration Release \
  --runtime win-x64 \
  --self-contained true \
  --output ./publish/win-x64

Framework-Dependent Deployment

Smaller deployment that requires .NET 10.0 runtime on the server:
dotnet publish ServiciosConsolaCentralizada/ServiciosConsolaCentralizada.csproj \
  --configuration Release \
  --output ./publish/framework-dependent
Framework-dependent deployments are smaller but require .NET 10.0 runtime installed on the target server

Single File Deployment

Bundle everything into a single executable:
dotnet publish ServiciosConsolaCentralizada/ServiciosConsolaCentralizada.csproj \
  --configuration Release \
  --runtime win-x64 \
  --self-contained true \
  --output ./publish/single-file \
  -p:PublishSingleFile=true \
  -p:IncludeNativeLibrariesForSelfExtract=true

Configuration for Production

Create Production Configuration

Create appsettings.Production.json in the publish directory:
appsettings.Production.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "yourdomain.com;api.yourdomain.com",
  "Jwt": {
    "Key": "your-production-jwt-key-min-32-chars-long-use-env-vars",
    "Expires": 3600
  },
  "CorreosElectronicos": {
    "Correo1": "[email protected]",
    "Correo2": "[email protected]",
    "Correo3": "[email protected]"
  }
}

Create Production Conf.txt

Create a secure Conf.txt file with production database credentials:
Conf.txt
production-server.database.windows.net:WSDonaciones:produser:SecureProductionPassword123!
Security Best Practice: Use environment variables or Azure Key Vault for sensitive data instead of storing in configuration files

Environment Variables

Override configuration using environment variables:
export ASPNETCORE_ENVIRONMENT=Production
export Jwt__Key="your-secure-production-jwt-key-here"
export Jwt__Expires="3600"
export CorreosElectronicos__Correo1="[email protected]"

Deployment Scenarios

Windows Server with IIS

1

Install Prerequisites

Install required components on Windows Server:
  • .NET 10.0 Hosting Bundle (for framework-dependent deployment)
  • IIS with ASP.NET Core Module
  • URL Rewrite Module (optional)
Download from: https://dotnet.microsoft.com/download/dotnet/10.0
2

Create IIS Application

  1. Open IIS Manager
  2. Create a new Application Pool:
    • Name: DonaSF-API
    • .NET CLR Version: No Managed Code
    • Managed Pipeline Mode: Integrated
  3. Create a new Website or Application:
    • Physical path: C:\inetpub\DonaSF-API
    • Application Pool: DonaSF-API
    • Binding: HTTP port 80 or HTTPS port 443
3

Deploy Files

Copy published files to IIS directory:
Copy-Item -Path .\publish\win-x64\* -Destination C:\inetpub\DonaSF-API -Recurse
Ensure Conf.txt and appsettings.Production.json are in the root directory.
4

Configure Permissions

Grant IIS user access to the application directory:
icacls "C:\inetpub\DonaSF-API" /grant "IIS AppPool\DonaSF-API:(OI)(CI)F" /T
5

Configure web.config

Create or update web.config for IIS:
web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath=".\ServiciosConsolaCentralizada.exe" 
                  arguments="" 
                  stdoutLogEnabled="true" 
                  stdoutLogFile=".\logs\stdout" 
                  hostingModel="inprocess">
        <environmentVariables>
          <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" />
        </environmentVariables>
      </aspNetCore>
    </system.webServer>
  </location>
</configuration>

Linux Server with systemd

1

Install .NET Runtime

Install .NET 10.0 runtime (for framework-dependent) or skip for self-contained:
wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt-get update
sudo apt-get install -y aspnetcore-runtime-10.0
2

Create Application User

Create a dedicated user for running the application:
sudo useradd -r -s /bin/false donasf-api
3

Deploy Application Files

Copy files to /var/www/donasf-api:
sudo mkdir -p /var/www/donasf-api
sudo cp -r ./publish/linux-x64/* /var/www/donasf-api/
sudo chown -R donasf-api:donasf-api /var/www/donasf-api
sudo chmod +x /var/www/donasf-api/ServiciosConsolaCentralizada
4

Create systemd Service

Create /etc/systemd/system/donasf-api.service:
donasf-api.service
[Unit]
Description=DonaSF API Service
After=network.target

[Service]
Type=notify
User=donasf-api
WorkingDirectory=/var/www/donasf-api
ExecStart=/var/www/donasf-api/ServiciosConsolaCentralizada
Restart=always
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=donasf-api
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target
Enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable donasf-api
sudo systemctl start donasf-api
sudo systemctl status donasf-api
5

Configure Nginx Reverse Proxy

Create /etc/nginx/sites-available/donasf-api:
server {
    listen 80;
    server_name api.yourdomain.com;

    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;
    }
}
Enable the site:
sudo ln -s /etc/nginx/sites-available/donasf-api /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Docker Container

1

Create Dockerfile

Create a Dockerfile in the solution root:
Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY ["ServiciosConsolaCentralizada/ServiciosConsolaCentralizada.csproj", "ServiciosConsolaCentralizada/"]
COPY ["BussinesRuls/BussinesRuls.csproj", "BussinesRuls/"]
COPY ["DataManagment/DataManagment.csproj", "DataManagment/"]
COPY ["Objects/Objects.csproj", "Objects/"]
RUN dotnet restore "ServiciosConsolaCentralizada/ServiciosConsolaCentralizada.csproj"
COPY . .
WORKDIR "/src/ServiciosConsolaCentralizada"
RUN dotnet build "ServiciosConsolaCentralizada.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "ServiciosConsolaCentralizada.csproj" -c Release -o /app/publish

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

Build Docker Image

docker build -t donasf-api:latest .
3

Create docker-compose.yml

docker-compose.yml
version: '3.8'

services:
  api:
    image: donasf-api:latest
    ports:
      - "5000:80"
    environment:
      - ASPNETCORE_ENVIRONMENT=Production
      - Jwt__Key=${JWT_KEY}
      - Jwt__Expires=3600
    volumes:
      - ./Conf.txt:/app/Conf.txt:ro
      - ./appsettings.Production.json:/app/appsettings.Production.json:ro
    restart: unless-stopped
    depends_on:
      - sqlserver

  sqlserver:
    image: mcr.microsoft.com/mssql/server:2022-latest
    environment:
      - ACCEPT_EULA=Y
      - SA_PASSWORD=YourStrong@Password123
    ports:
      - "1433:1433"
    volumes:
      - sqldata:/var/opt/mssql
    restart: unless-stopped

volumes:
  sqldata:
4

Run with Docker Compose

docker-compose up -d

Database Deployment

SQL Server Deployment Considerations

Execute the database scripts on your production SQL Server:
# Connect to production SQL Server
sqlcmd -S production-server -U sa -P password

# Execute database scripts
:r ServiciosConsolaCentralizada/Database/Script/BDPaqueteria.sql
:r ServiciosConsolaCentralizada/Database/ScriptDonaciones/Donaciones.sql
GO
Best Practices:
  • Use SQL Server authentication with strong passwords
  • Create dedicated database user with minimal permissions
  • Enable encrypted connections (TLS 1.2+)
  • Restrict network access with firewall rules
  • Regular security audits and updates
Create dedicated user:
USE [WSDonaciones];
GO

CREATE LOGIN [donasf_api_user] WITH PASSWORD = 'StrongPassword123!';
CREATE USER [donasf_api_user] FOR LOGIN [donasf_api_user];

-- Grant minimum required permissions
ALTER ROLE db_datareader ADD MEMBER [donasf_api_user];
ALTER ROLE db_datawriter ADD MEMBER [donasf_api_user];
GRANT EXECUTE TO [donasf_api_user];
GO
Implement regular database backups:
-- Full backup daily
BACKUP DATABASE [WSDonaciones] 
TO DISK = 'C:\Backups\WSDonaciones_Full.bak'
WITH FORMAT, INIT, COMPRESSION;

-- Transaction log backup hourly
BACKUP LOG [WSDonaciones] 
TO DISK = 'C:\Backups\WSDonaciones_Log.trn'
WITH COMPRESSION;
Set up automated backup schedules using SQL Server Agent or Azure Backup.
Index Optimization:
  • Review and create indexes for frequently queried columns
  • Monitor index fragmentation and rebuild regularly
  • Use execution plans to identify slow queries
Connection Pooling: The application uses Microsoft.Data.SqlClient which automatically enables connection pooling.Monitoring:
-- Check active connections
SELECT 
    DB_NAME(dbid) as DatabaseName,
    COUNT(dbid) as NumberOfConnections,
    loginame as LoginName
FROM sys.sysprocesses
WHERE dbid > 0
GROUP BY dbid, loginame;

SSL/TLS Configuration

Enable HTTPS in Production

Modify Program.cs to enable HTTPS redirection:
if (!app.Environment.IsDevelopment())
{
    app.UseHttpsRedirection();
}

Configure Kestrel for HTTPS

Add to appsettings.Production.json:
{
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://0.0.0.0:5000"
      },
      "Https": {
        "Url": "https://0.0.0.0:5001",
        "Certificate": {
          "Path": "/path/to/certificate.pfx",
          "Password": "certificate-password"
        }
      }
    }
  }
}
Never store certificate passwords in configuration files. Use Azure Key Vault or environment variables.

Monitoring and Logging

Application Logging

Configure file logging for production:
  1. Add Serilog package:
dotnet add package Serilog.AspNetCore
dotnet add package Serilog.Sinks.File
  1. Configure in Program.cs:
using Serilog;

Log.Logger = new LoggerConfiguration()
    .WriteTo.File("logs/donasf-.txt", rollingInterval: RollingInterval.Day)
    .CreateLogger();

builder.Host.UseSerilog();

Health Checks

Monitor application health:
curl http://localhost:5000/health

Performance Monitoring

  • Use Application Insights for Azure deployments
  • Monitor CPU, memory, and disk usage
  • Track API response times
  • Monitor database connection pool
  • Set up alerts for errors and slow responses

Deployment Verification

1

Test API Endpoints

Verify the API is responding:
curl http://your-domain/health
curl http://your-domain/swagger
2

Test Database Connection

Verify database connectivity by calling an endpoint that queries the database.
3

Test Authentication

Verify JWT token generation and validation:
curl -X POST http://your-domain/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"test","password":"test"}'
4

Monitor Logs

Check application logs for errors:
# Linux systemd
sudo journalctl -u donasf-api -f

# Docker
docker logs -f donasf-api

# Windows Event Viewer
# Check Application logs
5

Load Testing

Perform load testing to ensure the application can handle expected traffic:
# Using Apache Bench
ab -n 1000 -c 10 http://your-domain/api/endpoint

Troubleshooting

Check:
  • Conf.txt exists and has correct format
  • Database server is accessible
  • .NET runtime is installed (for framework-dependent)
  • Port is not already in use
  • Sufficient permissions on application directory
View logs:
# Linux
sudo journalctl -u donasf-api -n 100

# Docker
docker logs donasf-api
Verify:
  • SQL Server is running and accessible
  • Firewall allows connection on port 1433
  • Credentials in Conf.txt are correct
  • TrustServerCertificate setting is configured
Test connection:
sqlcmd -S server -U user -P password -d database
Common issues:
  • JWT Key is less than 32 characters
  • Token has expired (check Expires setting)
  • Clock skew between client and server
Verify configuration:
echo $Jwt__Key | wc -c  # Should be >= 32
Check:
  • Database query performance
  • Connection pool exhaustion
  • Memory leaks
  • Disk I/O bottlenecks
Monitor resources:
# Linux
htop
iotop

# Check application memory
ps aux | grep ServiciosConsolaCentralizada

Security Hardening

Remove Development Features

  • Disable Swagger UI in production
  • Remove development exception pages
  • Disable detailed error messages
  • Remove test accounts

Secure Configuration

  • Use environment variables for secrets
  • Rotate JWT keys regularly
  • Implement rate limiting
  • Enable CORS restrictions

Network Security

  • Use HTTPS only
  • Configure firewall rules
  • Restrict database access
  • Use VPN for administrative access

Monitoring & Auditing

  • Enable security logs
  • Monitor failed login attempts
  • Track API usage patterns
  • Set up security alerts

Next Steps

Setup Guide

Return to development setup

Configuration

Review configuration options

API Reference

Explore API endpoints

Architecture

Learn about the system architecture

Build docs developers (and LLMs) love