Skip to main content

Overview

This guide covers deploying AndanDo to production environments, including configuration, security hardening, and hosting options.
Before deploying to production:
  • Replace all example credentials and API keys
  • Use production-grade SQL Server instance
  • Enable HTTPS with valid SSL certificates
  • Review and harden security settings
  • Test thoroughly in staging environment

Pre-Deployment Checklist

1

Security Review

Credentials

  • Replace default JWT SecretKey
  • Use environment variables for secrets
  • Update SMTP credentials
  • Switch to PayPal live credentials

Configuration

  • Disable DetailedErrors in production
  • Set ASPNETCORE_ENVIRONMENT to Production
  • Enable HSTS and HTTPS redirection
  • Configure proper logging levels
2

Database Preparation

  • Use production SQL Server instance
  • Create database backups and recovery plan
  • Configure connection pooling
  • Set up database monitoring
  • Apply proper user permissions (principle of least privilege)
3

Performance Optimization

  • Enable response compression
  • Configure CDN for static assets
  • Optimize image uploads (compression, resizing)
  • Set up application monitoring (Application Insights, etc.)
4

Testing

  • Load testing for expected traffic
  • Test payment flows with live PayPal
  • Verify email delivery
  • Test all external API integrations
  • Verify database backup/restore procedures

Production Configuration

appsettings.Production.json

Create a production configuration file:
{
  "DetailedErrors": false,
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "andando.com.do,www.andando.com.do",
  "ConnectionStrings": {
    "DefaultConnection": "Server=prod-sql-server.database.windows.net;Database=AndandoDB;User Id=produser;Password=${SQL_PASSWORD};Encrypt=true;TrustServerCertificate=false;"
  },
  "Jwt": {
    "Issuer": "AndanDo",
    "Audience": "AndanDo",
    "SecretKey": "${JWT_SECRET_KEY}",
    "ExpirationMinutes": 120
  },
  "Smtp": {
    "Host": "${SMTP_HOST}",
    "Port": 587,
    "UseSsl": false,
    "UseStartTls": true,
    "User": "${SMTP_USER}",
    "Password": "${SMTP_PASSWORD}",
    "FromEmail": "[email protected]",
    "FromName": "AndanDo"
  },
  "PayPal": {
    "Mode": "live",
    "ClientId": "${PAYPAL_CLIENT_ID}",
    "ClientSecret": "${PAYPAL_CLIENT_SECRET}",
    "BaseUrl": "https://api-m.paypal.com"
  }
}
Variable Substitution: Replace ${VARIABLE_NAME} placeholders with actual values at deployment time, or use environment variables and a configuration provider.

Environment Variables

Store sensitive configuration in environment variables:
# Set system environment variables
[Environment]::SetEnvironmentVariable("SQL_PASSWORD", "YourSecurePassword", "Machine")
[Environment]::SetEnvironmentVariable("JWT_SECRET_KEY", "your-64-character-production-secret-key-here-change-this", "Machine")
[Environment]::SetEnvironmentVariable("SMTP_PASSWORD", "your-smtp-password", "Machine")
[Environment]::SetEnvironmentVariable("PAYPAL_CLIENT_ID", "your-live-client-id", "Machine")
[Environment]::SetEnvironmentVariable("PAYPAL_CLIENT_SECRET", "your-live-secret", "Machine")
[Environment]::SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Production", "Machine")

Build for Production

Publish the Application

1

Clean Previous Builds

dotnet clean --configuration Release
2

Publish Release Build

dotnet publish -c Release -o ./publish
Requires .NET runtime on target server. Smaller deployment size.
3

Verify Output

Check the ./publish folder contains:
  • AndanDo.dll (main assembly)
  • appsettings.json and appsettings.Production.json
  • wwwroot/ directory with static assets
  • All dependency DLLs

Optimize Published Output

Add to AndanDo.csproj for faster startup:
<PropertyGroup>
  <PublishReadyToRun>true</PublishReadyToRun>
  <PublishTrimmed>false</PublishTrimmed>
</PropertyGroup>
Do not enable trimming for Blazor Server apps - it can break reflection-dependent features.
Enable response compression in Program.cs:
builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
});

var app = builder.Build();
app.UseResponseCompression();
Add Kestrel configuration for production in appsettings.Production.json:
{
  "Kestrel": {
    "Limits": {
      "MaxConcurrentConnections": 100,
      "MaxConcurrentUpgradedConnections": 100,
      "MaxRequestBodySize": 52428800,
      "RequestHeadersTimeout": "00:01:00"
    }
  }
}

Deployment Options

Option 1: Windows Server with IIS

1

Install Prerequisites

On Windows Server:
  1. Install IIS via Server Manager
  2. Install .NET 10.0 Hosting Bundle from dotnet.microsoft.com
  3. Restart IIS: net stop was /y && net start w3svc
2

Create IIS Site

In IIS Manager:
  1. Create new Application Pool:
    • Name: AndanDoAppPool
    • .NET CLR version: No Managed Code
    • Managed pipeline mode: Integrated
  2. Create new Website:
    • Site name: AndanDo
    • Application pool: AndanDoAppPool
    • Physical path: C:\inetpub\andando
    • Binding: HTTPS on port 443 with SSL certificate
3

Deploy Files

Copy published files to C:\inetpub\andando:
xcopy /E /I /Y .\publish\* C:\inetpub\andando\
4

Configure web.config

IIS requires a web.config file (auto-generated during publish):
<?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="dotnet" 
                  arguments=".\AndanDo.dll" 
                  stdoutLogEnabled="false" 
                  stdoutLogFile=".\logs\stdout" 
                  hostingModel="inprocess">
        <environmentVariables>
          <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" />
        </environmentVariables>
      </aspNetCore>
    </system.webServer>
  </location>
</configuration>
5

Configure SSL Certificate

In IIS Manager:
  1. Select the AndanDo site
  2. Bindings > Add > HTTPS (port 443)
  3. Select your SSL certificate (e.g., from Let’s Encrypt or commercial CA)
  4. Save and restart the site
6

Set Permissions

Grant IIS_IUSRS permissions to:
  • Application folder: Read & Execute
  • wwwroot/uploads: Modify (for file uploads)
icacls C:\inetpub\andando /grant "IIS_IUSRS:(OI)(CI)(RX)"
icacls C:\inetpub\andando\wwwroot\uploads /grant "IIS_IUSRS:(OI)(CI)(M)"
Application Insights: Consider adding Application Insights for monitoring in production:
dotnet add package Microsoft.ApplicationInsights.AspNetCore
Then configure in appsettings.Production.json.

Option 2: Azure App Service

1

Create App Service

Via Azure Portal:
  1. Create new Web App
  2. Runtime: .NET 10
  3. Operating System: Windows or Linux
  4. Region: Choose closest to users
  5. App Service Plan: At least B1 (Basic) for production
2

Configure Application Settings

In App Service > Configuration:
  • Add all environment variables (SQL_PASSWORD, JWT_SECRET_KEY, etc.)
  • Set ASPNETCORE_ENVIRONMENT to Production
  • Configure connection strings
3

Deploy Application

  1. Right-click project > Publish
  2. Select Azure > Azure App Service
  3. Choose your App Service
  4. Click Publish
4

Configure Custom Domain and SSL

  1. App Service > Custom domains > Add custom domain
  2. Add DNS records at your domain registrar
  3. App Service > TLS/SSL settings
  4. Upload certificate or use free App Service Managed Certificate
  5. Add TLS/SSL binding for your domain
Azure SQL Database: Consider using Azure SQL Database for managed database hosting with automatic backups, scaling, and monitoring.

Option 3: Docker Container

1

Create Dockerfile

Create Dockerfile in the solution root:
# Build stage
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src

COPY ["AndanDo/AndanDo.csproj", "AndanDo/"]
RUN dotnet restore "AndanDo/AndanDo.csproj"

COPY . .
WORKDIR "/src/AndanDo"
RUN dotnet build "AndanDo.csproj" -c Release -o /app/build

# Publish stage
FROM build AS publish
RUN dotnet publish "AndanDo.csproj" -c Release -o /app/publish

# Runtime stage
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS final
WORKDIR /app

# Create uploads directory
RUN mkdir -p /app/wwwroot/uploads

COPY --from=publish /app/publish .

# Environment variables
ENV ASPNETCORE_URLS=http://+:80 \
    ASPNETCORE_ENVIRONMENT=Production

EXPOSE 80
ENTRYPOINT ["dotnet", "AndanDo.dll"]
2

Create .dockerignore

**/.dockerignore
**/.git
**/.vs
**/.vscode
**/bin
**/obj
**/out
**/publish
**/*.user
3

Build Docker Image

docker build -t andando:latest .
4

Run Container

docker run -d \
  --name andando \
  -p 80:80 \
  -e SQL_PASSWORD="YourPassword" \
  -e JWT_SECRET_KEY="your-secret-key" \
  -e SMTP_PASSWORD="smtp-pass" \
  -e PAYPAL_CLIENT_ID="client-id" \
  -e PAYPAL_CLIENT_SECRET="secret" \
  -v /var/andando/uploads:/app/wwwroot/uploads \
  andando:latest
5

Deploy to Container Registry

# Login to ACR
az acr login --name andandoacr

# Tag image
docker tag andando:latest andandoacr.azurecr.io/andando:latest

# Push image
docker push andandoacr.azurecr.io/andando:latest

# Deploy to Azure Container Instances
az container create \
  --resource-group AndanDoRG \
  --name andando-container \
  --image andandoacr.azurecr.io/andando:latest \
  --cpu 2 --memory 4 \
  --registry-username <username> \
  --registry-password <password> \
  --dns-name-label andando \
  --ports 80

Option 4: Linux Server (Systemd)

1

Install .NET Runtime

On Ubuntu/Debian:
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-get update
sudo apt-get install -y aspnetcore-runtime-10.0
2

Deploy Application

# Create application directory
sudo mkdir -p /var/www/andando

# Copy published files
sudo cp -r ./publish/* /var/www/andando/

# Create uploads directory
sudo mkdir -p /var/www/andando/wwwroot/uploads
sudo chown -R www-data:www-data /var/www/andando/wwwroot/uploads
3

Create Systemd Service

Create /etc/systemd/system/andando.service:
[Unit]
Description=AndanDo Tour Marketplace
After=network.target

[Service]
Type=notify
WorkingDirectory=/var/www/andando
ExecStart=/usr/bin/dotnet /var/www/andando/AndanDo.dll
Restart=always
RestartSec=10
KillSignal=SIGINT
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target
4

Configure Nginx Reverse Proxy

Create /etc/nginx/sites-available/andando:
server {
    listen 80;
    server_name andando.com.do www.andando.com.do;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name andando.com.do www.andando.com.do;
    
    ssl_certificate /etc/letsencrypt/live/andando.com.do/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/andando.com.do/privkey.pem;
    
    location / {
        proxy_pass http://localhost:5000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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;
    }
    
    # Static files caching
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)$ {
        proxy_pass http://localhost:5000;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}
Enable site and reload Nginx:
sudo ln -s /etc/nginx/sites-available/andando /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
5

Start Application Service

sudo systemctl daemon-reload
sudo systemctl enable andando
sudo systemctl start andando
sudo systemctl status andando
Let’s Encrypt SSL: Get free SSL certificates:
sudo apt-get install certbot python3-certbot-nginx
sudo certbot --nginx -d andando.com.do -d www.andando.com.do

Post-Deployment Tasks

1

Verify Application Health

  • Test homepage loads correctly
  • Verify database connectivity
  • Test user registration and login
  • Create test tour and booking
  • Verify email delivery
  • Test PayPal payment flow
2

Configure Monitoring

Application Monitoring

  • Set up Application Insights or similar APM
  • Configure alerts for errors and performance
  • Track custom metrics (bookings, revenue)

Infrastructure Monitoring

  • Monitor CPU, memory, disk usage
  • Set up database performance monitoring
  • Configure uptime monitoring
3

Set Up Backups

Database Backups:
-- Schedule daily automated backups
BACKUP DATABASE AndandoDB 
TO DISK = '/backups/AndandoDB_$(date +%Y%m%d).bak'
WITH FORMAT, COMPRESSION;
File Backups:
  • Backup wwwroot/uploads directory daily
  • Store backups in separate location or cloud storage
4

Configure Logging

Update appsettings.Production.json for production logging:
{
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "Microsoft": "Warning",
      "Microsoft.AspNetCore.SignalR": "Information",
      "Microsoft.AspNetCore.Http.Connections": "Information"
    },
    "EventLog": {
      "LogLevel": {
        "Default": "Warning"
      }
    }
  }
}

Security Best Practices

Critical Security Checklist
  • ✅ Use strong, unique JWT secret key (64+ characters)
  • ✅ Store secrets in environment variables or Azure Key Vault
  • ✅ Disable detailed errors in production (DetailedErrors: false)
  • ✅ Use HTTPS everywhere with valid SSL certificates
  • ✅ Enable HSTS (configured in Program.cs)
  • ✅ Set AllowedHosts to specific domains only
  • ✅ Use least-privilege database accounts
  • ✅ Enable SQL Server encryption (TDE)
  • ✅ Regular security patches and updates
  • ✅ Firewall rules: Allow only app server IPs
  • ✅ Enable audit logging for sensitive operations
  • ✅ Keep .NET runtime and packages updated
  • ✅ Validate and sanitize all user inputs
  • ✅ Use parameterized queries (already using stored procedures)
  • ✅ Implement rate limiting for API endpoints
  • ✅ Enable anti-forgery tokens (configured via UseAntiforgery())
  • ✅ Validate file types and sizes
  • ✅ Scan uploads for malware
  • ✅ Store uploads outside webroot or use CDN
  • ✅ Use unique filenames to prevent overwriting
  • ✅ Set proper file permissions (read-only for web server)

Performance Tuning

Blazor Server

  • Configure SignalR message size limits
  • Enable circuit activity tracking
  • Set appropriate reconnection settings
  • Optimize component rendering

Database

  • Index frequently queried columns
  • Optimize stored procedures
  • Enable query execution plans
  • Configure connection pooling

Caching

  • Implement response caching for static content
  • Use distributed cache for session data
  • Cache database query results where appropriate
  • Configure CDN for static assets

Resource Limits

  • Set Kestrel connection limits
  • Configure max request body size
  • Set timeout values appropriately
  • Monitor and adjust based on load

Troubleshooting Production Issues

Check:
  1. Environment variable ASPNETCORE_ENVIRONMENT is set to Production
  2. All required dependencies are in publish folder
  3. .NET runtime is installed (for framework-dependent deployments)
  4. Ports 80/443 are not blocked by firewall
  5. Check application logs in Event Viewer (Windows) or journalctl (Linux)
Check:
  1. Connection string is correct in production config
  2. SQL Server is running and accessible
  3. Firewall allows traffic on SQL Server port (1433)
  4. Database user has proper permissions
  5. Test connection with sqlcmd or SQL Server Management Studio
Check:
  1. WebSocket support is enabled in IIS/web server
  2. Load balancer supports WebSocket sticky sessions
  3. Firewall allows WebSocket connections
  4. Browser console for connection errors
  5. SignalR fallback to long polling if WebSocket fails
Check:
  1. wwwroot/uploads directory exists
  2. Application has write permissions to uploads folder
  3. Disk space is available
  4. Max request body size is sufficient
  5. Request timeout is not too short for large files

Scaling Considerations

Blazor Server maintains persistent connections, requiring careful scaling strategies.

Vertical Scaling

  • Increase server CPU and RAM
  • Upgrade to higher-tier App Service plan
  • Use faster SSD storage

Horizontal Scaling (Multiple Instances)

Blazor Server requires sticky sessions when scaling horizontally.
Requirements:
  1. Sticky Sessions: Configure load balancer for session affinity (ARR Affinity in Azure)
  2. Shared Storage: Use Azure Blob Storage or network share for wwwroot/uploads
  3. Distributed Cache: Implement Redis for shared session state
  4. Database Scaling: Use read replicas or Azure SQL elastic pools
Load Balancer Configuration (Nginx):
upstream andando_servers {
    ip_hash;  # Enables sticky sessions
    server 10.0.0.1:5000;
    server 10.0.0.2:5000;
    server 10.0.0.3:5000;
}

Maintenance and Updates

1

Regular Updates

  • Apply .NET security patches monthly
  • Update NuGet packages regularly
  • Review dependency vulnerabilities
  • Test updates in staging before production
2

Database Maintenance

  • Weekly index maintenance
  • Regular statistics updates
  • Periodic backup testing
  • Monitor database size and growth
3

Monitoring and Alerts

  • Review application logs daily
  • Set up alerts for critical errors
  • Monitor performance metrics
  • Track user experience metrics

Rollback Plan

Always have a rollback strategy before deploying updates.
  1. Keep Previous Version: Maintain previous deployment in separate directory
  2. Database Backups: Always backup database before schema changes
  3. Quick Rollback: Swap deployment folders or restore previous Docker image
  4. Test Rollback: Periodically test rollback procedures

Need Help?

If you encounter issues during deployment, check the application logs, verify configuration settings, and ensure all prerequisites are met. For development setup questions, refer back to Development Setup.

Build docs developers (and LLMs) love