Skip to main content

Overview

The Happy Habitat backend is a .NET 8 API that provides RESTful endpoints for the condominium management system. This guide covers production deployment for IIS, Azure App Service, and Docker environments.

Prerequisites

Building for Production

Solution Structure

The backend is organized as a .NET 8 solution with clean architecture (see HappyHabitat.sln):
  • HappyHabitat.API - Web API project with controllers and startup configuration
  • HappyHabitat.Application - Application services and interfaces
  • HappyHabitat.Domain - Domain entities and business logic
  • HappyHabitat.Infrastructure - Data access, migrations, and external services
  • HappyHabitat.Infrastructure.Tests - Unit tests

Build the API

From the backend directory:
cd ~/workspace/source/happy-habitat-backend
dotnet build --configuration Release
Or build just the API project:
cd ~/workspace/source/happy-habitat-backend/HappyHabitat.API
dotnet build --configuration Release

Publish the Application

Create a self-contained deployment:
dotnet publish --configuration Release --output ./publish --self-contained false
For a self-contained deployment (includes runtime):
dotnet publish --configuration Release --output ./publish --self-contained true --runtime linux-x64
Available runtimes:
  • linux-x64 - Linux (Ubuntu, Debian, CentOS, etc.)
  • win-x64 - Windows 64-bit
  • osx-x64 - macOS

Production Configuration

Critical Settings

The application validates critical settings on startup. The following must be configured in production:
Security RequirementsThe application will fail to start in production if:
  • Jwt:Key is not set or uses the default value
  • Cors:Origins is not configured
  • Database:RecreateOnStartup is set to true

Configuration Files

Create appsettings.Production.json:
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=your-sql-server;Database=HappyHabitat;User Id=your-user;Password=your-password;TrustServerCertificate=True;"
  },
  "Database": {
    "RecreateOnStartup": false
  },
  "Jwt": {
    "Key": "YOUR_SECURE_KEY_AT_LEAST_32_CHARACTERS_LONG",
    "Issuer": "HappyHabitat",
    "Audience": "HappyHabitatUsers"
  },
  "Cors": {
    "Origins": "https://app.happyhabitat.com;https://www.happyhabitat.com"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.EntityFrameworkCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

Environment Variables

Alternatively, use environment variables (recommended for containers):
ConnectionStrings__DefaultConnection="Server=..."
Database__RecreateOnStartup=false
Jwt__Key="YOUR_SECURE_KEY"
Jwt__Issuer="HappyHabitat"
Jwt__Audience="HappyHabitatUsers"
Cors__Origins="https://app.happyhabitat.com"
ASPNETCORE_ENVIRONMENT=Production

Deployment Options

Option 1: IIS (Windows Server)

  1. Install Prerequisites:
    • IIS with ASP.NET Core Hosting Bundle
    • .NET 8 Runtime or SDK
  2. Configure IIS:
    • Create a new Application Pool (.NET CLR Version: No Managed Code)
    • Create a new website pointing to the publish directory
    • Set Application Pool identity with database access
  3. Configure 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="dotnet" 
                  arguments=".\HappyHabitat.API.dll" 
                  stdoutLogEnabled="false" 
                  stdoutLogFile=".\logs\stdout" 
                  hostingModel="inprocess">
        <environmentVariables>
          <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" />
        </environmentVariables>
      </aspNetCore>
    </system.webServer>
  </location>
</configuration>
  1. File Permissions:
    • Grant IIS_IUSRS read access to the publish directory
    • Grant write access to uploads directory for file uploads

Option 2: Azure App Service

  1. Create App Service:
az webapp create --name happyhabitat-api \
  --resource-group happyhabitat-rg \
  --plan happyhabitat-plan \
  --runtime "DOTNET|8.0"
  1. Configure Settings:
az webapp config appsettings set --name happyhabitat-api \
  --resource-group happyhabitat-rg \
  --settings \
  Jwt__Key="YOUR_SECURE_KEY" \
  Cors__Origins="https://app.happyhabitat.com" \
  Database__RecreateOnStartup=false
  1. Configure Connection String:
az webapp config connection-string set --name happyhabitat-api \
  --resource-group happyhabitat-rg \
  --connection-string-type SQLAzure \
  --settings DefaultConnection="Server=..."
  1. Deploy:
dotnet publish --configuration Release
cd bin/Release/net8.0/publish
zip -r deploy.zip .
az webapp deployment source config-zip --name happyhabitat-api \
  --resource-group happyhabitat-rg \
  --src deploy.zip

Option 3: Docker

  1. Create Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["HappyHabitat.API/HappyHabitat.API.csproj", "HappyHabitat.API/"]
COPY ["HappyHabitat.Application/HappyHabitat.Application.csproj", "HappyHabitat.Application/"]
COPY ["HappyHabitat.Domain/HappyHabitat.Domain.csproj", "HappyHabitat.Domain/"]
COPY ["HappyHabitat.Infrastructure/HappyHabitat.Infrastructure.csproj", "HappyHabitat.Infrastructure/"]
RUN dotnet restore "HappyHabitat.API/HappyHabitat.API.csproj"
COPY . .
WORKDIR "/src/HappyHabitat.API"
RUN dotnet build "HappyHabitat.API.csproj" -c Release -o /app/build

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

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "HappyHabitat.API.dll"]
  1. Build and Run:
docker build -t happyhabitat-api:latest .
docker run -d -p 80:80 \
  -e ConnectionStrings__DefaultConnection="Server=..." \
  -e Jwt__Key="YOUR_SECURE_KEY" \
  -e Cors__Origins="https://app.happyhabitat.com" \
  -e Database__RecreateOnStartup=false \
  -e ASPNETCORE_ENVIRONMENT=Production \
  -v /app/uploads:/app/uploads \
  happyhabitat-api:latest

Option 4: Linux Service (systemd)

  1. Copy Published Files:
sudo mkdir -p /var/www/happyhabitat-api
sudo cp -r ./publish/* /var/www/happyhabitat-api/
  1. Create Service File (/etc/systemd/system/happyhabitat-api.service):
[Unit]
Description=Happy Habitat API
After=network.target

[Service]
Type=notify
User=www-data
WorkingDirectory=/var/www/happyhabitat-api
ExecStart=/usr/bin/dotnet /var/www/happyhabitat-api/HappyHabitat.API.dll
Restart=always
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=happyhabitat-api
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=Jwt__Key=YOUR_SECURE_KEY
Environment=Cors__Origins=https://app.happyhabitat.com
Environment=Database__RecreateOnStartup=false

[Install]
WantedBy=multi-user.target
  1. Start Service:
sudo systemctl enable happyhabitat-api
sudo systemctl start happyhabitat-api
sudo systemctl status happyhabitat-api

Database Migrations

The application automatically applies pending migrations on startup (see Program.cs:262). To run migrations manually:
dotnet ef database update --project HappyHabitat.Infrastructure --startup-project HappyHabitat.API
Never set Database:RecreateOnStartup to true in production. The application will fail to start to prevent data loss.

File Uploads

The API serves uploaded documents from the uploads directory (see Program.cs:226-233):
  • Path structure: uploads/{communityId}/{categoria}/{residentId}/{filename}
  • Accessible via: https://api.example.com/uploads/{path}
  • Ensure write permissions for the application user
  • Consider using cloud storage (Azure Blob, S3) for scalability

Security Considerations

JWT Configuration

Generate a secure key (minimum 32 characters):
openssl rand -base64 32

CORS Configuration

Multiple origins are separated by semicolons:
Cors:Origins=https://app.example.com;https://admin.example.com

HTTPS

Production deployments should:
  • Use HTTPS (enabled by default in production mode - see Program.cs:220-223)
  • Configure SSL certificates
  • Use HSTS headers

Request Size Limits

The API has a global 10MB request body limit (Program.cs:18-21). Individual endpoints can set lower limits using [RequestSizeLimit].

Health Checks

Monitor application health:
# Check if API is responding
curl https://api.example.com/api/health

# View logs (systemd)
sudo journalctl -u happyhabitat-api -f

Troubleshooting

Application Won’t Start

  1. Check logs for startup validation errors
  2. Verify all required configuration is set
  3. Ensure database connection string is correct
  4. Verify SQL Server is accessible

CORS Errors

  1. Confirm Cors:Origins includes your frontend URL
  2. Verify no trailing slashes in origins
  3. Check that frontend uses correct API URL

Database Connection Fails

  1. Verify connection string format
  2. Check SQL Server allows remote connections
  3. Verify firewall rules
  4. Test connection with sqlcmd or SQL Management Studio

File Upload Issues

  1. Verify uploads directory exists
  2. Check write permissions
  3. Review request size limits

Next Steps

Build docs developers (and LLMs) love