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)
-
Install Prerequisites:
- IIS with ASP.NET Core Hosting Bundle
- .NET 8 Runtime or SDK
-
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
-
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>
- 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
- Create App Service:
az webapp create --name happyhabitat-api \
--resource-group happyhabitat-rg \
--plan happyhabitat-plan \
--runtime "DOTNET|8.0"
- 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
- Configure Connection String:
az webapp config connection-string set --name happyhabitat-api \
--resource-group happyhabitat-rg \
--connection-string-type SQLAzure \
--settings DefaultConnection="Server=..."
- 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
- 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"]
- 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)
- Copy Published Files:
sudo mkdir -p /var/www/happyhabitat-api
sudo cp -r ./publish/* /var/www/happyhabitat-api/
- 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
- 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):
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
- Check logs for startup validation errors
- Verify all required configuration is set
- Ensure database connection string is correct
- Verify SQL Server is accessible
CORS Errors
- Confirm
Cors:Origins includes your frontend URL
- Verify no trailing slashes in origins
- Check that frontend uses correct API URL
Database Connection Fails
- Verify connection string format
- Check SQL Server allows remote connections
- Verify firewall rules
- Test connection with
sqlcmd or SQL Management Studio
File Upload Issues
- Verify
uploads directory exists
- Check write permissions
- Review request size limits
Next Steps