Files
PowderCoatingLogix/DEPLOYMENT_CONFIGURATION.md
2026-04-23 21:38:24 -04:00

13 KiB

Deployment Configuration Guide

This guide explains how to configure the Powder Coating App for different environments (Development, Staging, Production).

Overview

The application uses environment-specific configuration files and supports multiple secure configuration methods:

  • Development: appsettings.Development.json (included in repo)
  • Production: Environment variables, User Secrets, or Azure Key Vault

Configuration Files

Development Environment

File: src/PowderCoating.Web/appsettings.Development.json

  • Contains actual development values
  • Safe to commit to source control (dev-only credentials)
  • Used automatically when ASPNETCORE_ENVIRONMENT=Development

File: src/PowderCoating.Api/appsettings.Development.json

  • API-specific development settings
  • Contains dev JWT secret and CORS origins

Production Environment

File: src/PowderCoating.Web/appsettings.json

  • Contains placeholders only (USE_USER_SECRETS_OR_ENVIRONMENT_VARIABLE)
  • NEVER contains actual secrets
  • Safe to commit to source control

File: src/PowderCoating.Api/appsettings.json

  • Same approach - placeholders only
  • Production secrets configured via environment variables or Key Vault

Required Configuration Values

1. Database Connection String

Development:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=.\\SQLEXPRESS;Database=PowderCoatingDb;Trusted_Connection=true;MultipleActiveResultSets=true;TrustServerCertificate=true"
  }
}

Production (Windows Server with SQL Server):

# Environment Variable
set ConnectionStrings__DefaultConnection="Server=PROD_SERVER;Database=PowderCoatingDb;User Id=app_user;Password=SecurePassword123!;MultipleActiveResultSets=true;Encrypt=true"

Production (Linux/Docker):

export ConnectionStrings__DefaultConnection="Server=PROD_SERVER;Database=PowderCoatingDb;User Id=app_user;Password=SecurePassword123!;MultipleActiveResultSets=true;Encrypt=true"

Production (Azure Web App):

  • Navigate to: Configuration > Connection strings
  • Name: DefaultConnection
  • Value: Your production connection string
  • Type: SQLServer

2. JWT Settings (API Only)

Development:

{
  "JwtSettings": {
    "SecretKey": "DEV-ONLY-SecretKey-MinimumLength32CharactersRequired!@#$",
    "Issuer": "PowderCoatingAPI",
    "Audience": "PowderCoatingMobileApp",
    "ExpirationMinutes": 15,
    "RefreshTokenExpirationDays": 7
  }
}

Production:

Generate a strong secret key (minimum 32 characters):

# PowerShell - Generate random secret
-join ((48..57) + (65..90) + (97..122) | Get-Random -Count 64 | ForEach-Object {[char]$_})
# Linux - Generate random secret
openssl rand -base64 64

Set as environment variable:

# Windows
set JwtSettings__SecretKey="YOUR_GENERATED_SECRET_HERE"

# Linux
export JwtSettings__SecretKey="YOUR_GENERATED_SECRET_HERE"

# Azure Web App - Application Settings
JwtSettings__SecretKey = YOUR_GENERATED_SECRET_HERE

3. CORS Origins (API Only)

Development:

{
  "CorsSettings": {
    "AllowedOrigins": [
      "http://localhost:3000",
      "http://localhost:5173",
      "http://localhost:58461",
      "https://localhost:58461"
    ]
  }
}

Production:

{
  "CorsSettings": {
    "AllowedOrigins": [
      "https://yourapp.com",
      "https://www.yourapp.com",
      "https://app.yourdomain.com"
    ]
  }
}

⚠️ NEVER use * (wildcard) in production!


4. Allowed Hosts

Development:

{
  "AllowedHosts": "localhost;127.0.0.1"
}

Production:

{
  "AllowedHosts": "yourapp.com;www.yourapp.com;app.yourdomain.com"
}

5. Logging Configuration

Development (detailed logging):

{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "Microsoft.AspNetCore": "Information",
      "Microsoft.EntityFrameworkCore": "Information"
    }
  }
}

Production (reduced logging):

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.EntityFrameworkCore": "Warning"
    }
  }
}

Security Checklist

Development Environment

  • Use appsettings.Development.json for local development
  • Development secrets can be simple (e.g., "Dev123!")
  • CORS can allow localhost origins
  • Detailed logging enabled for debugging
  • Database uses Trusted Connection (Windows Auth) or simple password

Production Environment

  • CRITICAL: Never use development secrets in production
  • CRITICAL: Use strong, randomly generated secrets (64+ characters)
  • CRITICAL: Store secrets in environment variables, User Secrets, or Azure Key Vault
  • CRITICAL: Enable HTTPS with valid SSL certificate
  • CRITICAL: Configure CORS with specific allowed origins (NO wildcards)
  • Configure AllowedHosts with actual production domain(s)
  • Use encrypted database connection with strong password
  • Reduce logging verbosity (Warning/Error only)
  • Set ASPNETCORE_ENVIRONMENT=Production
  • Enable HSTS (Strict-Transport-Security headers)
  • Configure rate limiting and DDoS protection
  • Set up monitoring and alerting
  • Regular security patches and updates

Configuration Methods by Environment

Advantages:

  • Secure (not stored in files)
  • Easy to manage in cloud platforms
  • Platform-agnostic

Windows:

# Set for current session
$env:ConnectionStrings__DefaultConnection="Server=...;Database=...;User Id=...;Password=..."
$env:JwtSettings__SecretKey="YourSecretKey"

# Set permanently (System-wide)
[Environment]::SetEnvironmentVariable("ConnectionStrings__DefaultConnection", "Server=...;", "Machine")

Linux:

# Add to ~/.bashrc or /etc/environment
export ConnectionStrings__DefaultConnection="Server=...;Database=...;User Id=...;Password=..."
export JwtSettings__SecretKey="YourSecretKey"

Docker:

# docker-compose.yml
services:
  powdercoating-web:
    environment:
      - ConnectionStrings__DefaultConnection=Server=db;Database=PowderCoatingDb;User Id=sa;Password=YourPassword
      - ASPNETCORE_ENVIRONMENT=Production

Method 2: User Secrets (Development Only)

Setup:

cd src/PowderCoating.Web
dotnet user-secrets init
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Server=...;Database=...;"
dotnet user-secrets set "JwtSettings:SecretKey" "YourSecretKey"

View secrets:

dotnet user-secrets list

⚠️ User Secrets are for development only - they are stored locally on your machine and won't deploy to production.


Method 3: Azure Key Vault (Production)

Setup:

  1. Create Azure Key Vault
  2. Add secrets to Key Vault:
    • ConnectionStrings--DefaultConnection
    • JwtSettings--SecretKey
  3. Grant App Service Managed Identity access to Key Vault

Code (add to Program.cs):

if (builder.Environment.IsProduction())
{
    var keyVaultUri = new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/");
    builder.Configuration.AddAzureKeyVault(keyVaultUri, new DefaultAzureCredential());
}

Deployment Steps

Local Development

  1. Clone repository
  2. Ensure ASPNETCORE_ENVIRONMENT=Development
  3. Verify appsettings.Development.json has correct local SQL Server connection
  4. Run migrations:
    cd src/PowderCoating.Web
    dotnet ef database update --project ../PowderCoating.Infrastructure
    
  5. Run application:
    dotnet run
    

Production Deployment (Windows Server/IIS)

  1. Publish Application:

    cd src/PowderCoating.Web
    dotnet publish -c Release -o C:\Publish\PowderCoatingApp
    
  2. Configure Environment Variables (IIS):

    • Open IIS Manager
    • Select Application Pool > Advanced Settings
    • Under Environment Variables, add:
      • ASPNETCORE_ENVIRONMENT = Production
      • ConnectionStrings__DefaultConnection = <your connection string>
  3. Install SQL Server Database:

    # Run migrations on production database
    dotnet ef database update --project ../PowderCoating.Infrastructure --configuration Release
    
  4. Configure IIS:

    • Enable HTTPS binding with valid SSL certificate
    • Set Application Pool to "No Managed Code"
    • Install ASP.NET Core Hosting Bundle
  5. Security Hardening:

    • Disable directory browsing
    • Remove unnecessary HTTP headers
    • Configure IP restrictions if needed
    • Enable request filtering

Production Deployment (Azure App Service)

  1. Create Azure Resources:

    • Azure SQL Database
    • Azure App Service (Windows or Linux)
    • Azure Key Vault (optional, but recommended)
  2. Configure App Service:

    • Configuration > General Settings:

      • Stack: .NET 8
      • Platform: 64-bit
      • HTTPS Only: On
    • Configuration > Application Settings:

      ASPNETCORE_ENVIRONMENT = Production
      JwtSettings__SecretKey = <your secret>
      JwtSettings__ExpirationMinutes = 15
      CorsSettings__AllowedOrigins__0 = https://yourapp.com
      AllowedHosts = yourapp.com;www.yourapp.com
      
    • Configuration > Connection Strings:

      Name: DefaultConnection
      Value: Server=tcp:yourserver.database.windows.net,1433;Database=PowderCoatingDb;User ID=sqladmin;Password=...;Encrypt=True;
      Type: SQLServer
      
  3. Deploy Code:

    # Via Azure CLI
    az webapp deployment source config-zip --resource-group YourRG --name YourAppName --src publish.zip
    
  4. Run Database Migrations:

    • Option 1: Use Azure Cloud Shell or local machine with connection to Azure SQL
    • Option 2: Enable migrations on startup (NOT recommended for production)

Password Requirements

Development: Minimum 8 characters

Production (enforced by application):

  • Minimum 12 characters
  • At least 1 uppercase letter
  • At least 1 lowercase letter
  • At least 1 digit
  • At least 1 special character (!@#$%^&*)
  • At least 4 unique characters
  • Account lockout after 5 failed attempts (15-minute lockout)

Security Headers (Automatically Applied)

The application automatically adds these security headers in production:

  • X-Frame-Options: DENY - Prevent clickjacking
  • X-Content-Type-Options: nosniff - Prevent MIME sniffing
  • X-XSS-Protection: 1; mode=block - XSS protection
  • Strict-Transport-Security: max-age=31536000; includeSubDomains - Force HTTPS
  • Content-Security-Policy - Restrict resource loading
  • Referrer-Policy: strict-origin-when-cross-origin - Control referrer info
  • Permissions-Policy - Disable unnecessary browser features

Troubleshooting

Issue: "Connection string not found"

Solution: Ensure environment variable is set with double underscores (__):

ConnectionStrings__DefaultConnection  # Correct
ConnectionStrings:DefaultConnection   # Wrong (this is for User Secrets only)

Issue: "JWT secret key is too short"

Solution: Generate a new secret with minimum 32 characters (64+ recommended)

Issue: "CORS policy blocked"

Solution: Add your frontend domain to CorsSettings:AllowedOrigins array

Issue: "Cookies not working"

Solution:

  • Ensure HTTPS is enabled in production
  • Check that CookieSecurePolicy.Always is compatible with your hosting
  • For development over HTTP, set SecurePolicy = CookieSecurePolicy.SameAsRequest

Monitoring and Logs

Development:

  • Console output
  • Files in /logs/ directory
    • powdercoating-{date}.txt - All logs
    • errors-{date}.txt - Errors only

Production:

  • Configure Azure Application Insights (recommended)
  • Or use Serilog sinks (Seq, Elasticsearch, etc.)
  • Set up alerts for errors and performance issues

Summary

Configuration Development Production
Secrets appsettings.Development.json Environment Variables / Key Vault
HTTPS Optional Required
CORS localhost:* Specific domains only
Logging Debug/Information Warning/Error
AllowedHosts localhost;127.0.0.1 yourdomain.com
JWT Expiration 15 minutes 15 minutes
Password Policy Strong (12 chars) Strong (12 chars)
Session Cookies Secure, HttpOnly, SameSite=Strict Same + SecurePolicy=Always

Questions?

If you encounter any issues with deployment or configuration, check:

  1. This guide
  2. Application logs (Diagnostics > View Logs in the app)
  3. Environment-specific appsettings files
  4. Environment variables are correctly set

Security Tip: Regularly rotate secrets (JWT keys, database passwords) every 90 days in production.