487 lines
13 KiB
Markdown
487 lines
13 KiB
Markdown
# 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**:
|
|
```json
|
|
{
|
|
"ConnectionStrings": {
|
|
"DefaultConnection": "Server=.\\SQLEXPRESS;Database=PowderCoatingDb;Trusted_Connection=true;MultipleActiveResultSets=true;TrustServerCertificate=true"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Production** (Windows Server with SQL Server):
|
|
```bash
|
|
# Environment Variable
|
|
set ConnectionStrings__DefaultConnection="Server=PROD_SERVER;Database=PowderCoatingDb;User Id=app_user;Password=SecurePassword123!;MultipleActiveResultSets=true;Encrypt=true"
|
|
```
|
|
|
|
**Production** (Linux/Docker):
|
|
```bash
|
|
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**:
|
|
```json
|
|
{
|
|
"JwtSettings": {
|
|
"SecretKey": "DEV-ONLY-SecretKey-MinimumLength32CharactersRequired!@#$",
|
|
"Issuer": "PowderCoatingAPI",
|
|
"Audience": "PowderCoatingMobileApp",
|
|
"ExpirationMinutes": 15,
|
|
"RefreshTokenExpirationDays": 7
|
|
}
|
|
}
|
|
```
|
|
|
|
**Production**:
|
|
|
|
Generate a strong secret key (minimum 32 characters):
|
|
```powershell
|
|
# PowerShell - Generate random secret
|
|
-join ((48..57) + (65..90) + (97..122) | Get-Random -Count 64 | ForEach-Object {[char]$_})
|
|
```
|
|
|
|
```bash
|
|
# Linux - Generate random secret
|
|
openssl rand -base64 64
|
|
```
|
|
|
|
Set as environment variable:
|
|
```bash
|
|
# 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**:
|
|
```json
|
|
{
|
|
"CorsSettings": {
|
|
"AllowedOrigins": [
|
|
"http://localhost:3000",
|
|
"http://localhost:5173",
|
|
"http://localhost:58461",
|
|
"https://localhost:58461"
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
**Production**:
|
|
```json
|
|
{
|
|
"CorsSettings": {
|
|
"AllowedOrigins": [
|
|
"https://yourapp.com",
|
|
"https://www.yourapp.com",
|
|
"https://app.yourdomain.com"
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
⚠️ **NEVER use `*` (wildcard) in production!**
|
|
|
|
---
|
|
|
|
### 4. Allowed Hosts
|
|
|
|
**Development**:
|
|
```json
|
|
{
|
|
"AllowedHosts": "localhost;127.0.0.1"
|
|
}
|
|
```
|
|
|
|
**Production**:
|
|
```json
|
|
{
|
|
"AllowedHosts": "yourapp.com;www.yourapp.com;app.yourdomain.com"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 5. Logging Configuration
|
|
|
|
**Development** (detailed logging):
|
|
```json
|
|
{
|
|
"Logging": {
|
|
"LogLevel": {
|
|
"Default": "Debug",
|
|
"Microsoft.AspNetCore": "Information",
|
|
"Microsoft.EntityFrameworkCore": "Information"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Production** (reduced logging):
|
|
```json
|
|
{
|
|
"Logging": {
|
|
"LogLevel": {
|
|
"Default": "Information",
|
|
"Microsoft.AspNetCore": "Warning",
|
|
"Microsoft.EntityFrameworkCore": "Warning"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Security Checklist
|
|
|
|
### ✅ Development Environment
|
|
|
|
- [x] Use `appsettings.Development.json` for local development
|
|
- [x] Development secrets can be simple (e.g., "Dev123!")
|
|
- [x] CORS can allow `localhost` origins
|
|
- [x] Detailed logging enabled for debugging
|
|
- [x] 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
|
|
|
|
### Method 1: Environment Variables (Recommended for Production)
|
|
|
|
**Advantages**:
|
|
- Secure (not stored in files)
|
|
- Easy to manage in cloud platforms
|
|
- Platform-agnostic
|
|
|
|
**Windows**:
|
|
```powershell
|
|
# 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**:
|
|
```bash
|
|
# Add to ~/.bashrc or /etc/environment
|
|
export ConnectionStrings__DefaultConnection="Server=...;Database=...;User Id=...;Password=..."
|
|
export JwtSettings__SecretKey="YourSecretKey"
|
|
```
|
|
|
|
**Docker**:
|
|
```yaml
|
|
# 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**:
|
|
```bash
|
|
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**:
|
|
```bash
|
|
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`):
|
|
```csharp
|
|
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:
|
|
```bash
|
|
cd src/PowderCoating.Web
|
|
dotnet ef database update --project ../PowderCoating.Infrastructure
|
|
```
|
|
5. Run application:
|
|
```bash
|
|
dotnet run
|
|
```
|
|
|
|
---
|
|
|
|
### Production Deployment (Windows Server/IIS)
|
|
|
|
1. **Publish Application**:
|
|
```bash
|
|
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**:
|
|
```bash
|
|
# 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**:
|
|
```bash
|
|
# 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 (`__`):
|
|
```bash
|
|
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.
|