From dcd5bb2aad74d969a98c12c6a607e3b23eb0466a43a4bc516acb6dffd6a52bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= <93217193+Daniel-Garmig@users.noreply.github.com> Date: Wed, 9 Sep 2026 13:34:38 +0200 Subject: [PATCH] Deploy configuration - Added tasks for publishing as container image. - Improvements for deployment: Db migrations on startup, reverse-proxy forward headers, and DataProtect management. - Added deploy example using docker-compose. --- .vscode/settings.json | 9 +++ .vscode/tasks.json | 36 ++++++++++ Deploy/README.md | 23 +++++++ Deploy/docker-compose.yaml | 66 +++++++++++++++++++ src/Somnia.GuestLog/Program.cs | 29 ++++++++ src/Somnia.GuestLog/Somnia.GuestLog.csproj | 5 ++ .../appsettings.Development.json | 5 +- src/Somnia.GuestLog/appsettings.json | 2 + 8 files changed, 173 insertions(+), 2 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 Deploy/README.md create mode 100644 Deploy/docker-compose.yaml diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c8a74c4 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "files.associations": { + "appsettings*.json": "jsonc", + "*_config.json": "jsonc", + "*_config.json.sample": "jsonc" + }, + "editor.formatOnSave": true, + "editor.formatOnSaveMode": "modificationsIfAvailable", +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..e02f0cc --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,36 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "type": "dotnet", + "task": "build", + "group": "build", + "problemMatcher": [], + "label": "Build Somnia.GuestLog" + }, + { + "label": "Publish Container Image", + "type": "shell", + "command": "dotnet", + "args": [ + "publish", + "-c", + "Release", + "--os", + "linux", + "--arch", + "x64", + "-p:PublishProfile=DefaultContainer" + ], + "options": { + "cwd": "${workspaceFolder}/src/Somnia.GuestLog" + }, + "group": "build", + "presentation": { + "reveal": "always" + } + }, + ] +} \ No newline at end of file diff --git a/Deploy/README.md b/Deploy/README.md new file mode 100644 index 0000000..e2384a2 --- /dev/null +++ b/Deploy/README.md @@ -0,0 +1,23 @@ +# Somnia.GuestLog Deployment + +## Deploy using docker-compose + +Use [docker-compose file](docker-compose.yaml) as example. Configure required enviroment variables. + +Notes: +- By default, HTTP-only is deploy. Uncomment required sections to enable HTTPS (and mount required certs). +- Reverse-proxies should work? + +[To-Be-Improved] + +## Manually update registry + +Container images are built by CI/CD pipelines and uploaded to the registry (**not yet!**). + +If required, a image can be manually built and uploaded to the registry (for testing or development purposes): +```sh +podman push [IMAGE_ID] [REGISTRY]/somnia/somnia-guestlog:[TAG] + +# Example: +podman push localhost/somnia-guestlog:latest gitea.uberelectronnetwork.cc/somnia/somnia-guestlog:devbuild +``` diff --git a/Deploy/docker-compose.yaml b/Deploy/docker-compose.yaml new file mode 100644 index 0000000..2360b01 --- /dev/null +++ b/Deploy/docker-compose.yaml @@ -0,0 +1,66 @@ +services: + database: + environment: + POSTGRES_DB: ${POSTGRES_DB:-SomniaGuestLog} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-NotAStrongPassword} + POSTGRES_USER: ${POSTGRES_USER:-somnia} + healthcheck: + retries: 5 + start_period: 60s + test: + - CMD + - pg_isready + timeout: 5s + image: postgres:18-alpine + volumes: + - somniaguestlog_database_data:/var/lib/postgresql:rw + somnia-guestlog: + depends_on: + - database + environment: + SOMNIA_ConnectionStrings__DbSomniaGuestLog: Host=database;Port=5432;Username=${POSTGRES_USER:-somnia};Password=${POSTGRES_PASSWORD:-NotAStrongPassword};Database=${POSTGRES_DB:-SomniaGuestLog} + # Configure path for data protection keys. This path must persists between container restarts (use a mount or a volume). + SOMNIA_DataProtectionDir: /SomniaGuestLog/dataprotection + ASPNETCORE_URLS: "http://+:8080" + # Somnia AddressQuery Service - START + SOMNIA_AddressQuery__Provider: "Nominatim" + # Override if required. + # SOMNIA_AddressQuery__ServiceURL: "" + # SOMNIA_AddressQuery__ApiKey: "" + SOMNIA_AddressQuery__UserAgent: Somnia-GuestLog-Dev-Container + SOMNIA_AddressQuery__ResultLang: es + # Somnia AddressQuery Service - END + SOMNIA_StayExport__ExportStorageConnectionString: disk://path=/SomniaGuestLog/StayExportFiles + # Somnia StayExport - SpainParteViajeros Provider - START + # Override vars if required + # SOMNIA_StayExportSpainParteViajeros__InternetAvailable: true + # SOMNIA_StayExportSpainParteViajeros__CodigoEstablecimiento: 123123123 + # Somnia StayExport - SpainParteViajeros Provider - END + + # Enable for HTTPS - START + # ASPNETCORE_URLS: "https://+:8090;http://+:8080" + # ASPNETCORE_HTTPS_PORTS: 8090 + # ASPNETCORE_Kestrel__Certificates__Default__Password: ${CERTIFICATE_CREDENTIAL:-} + # ASPNETCORE_Kestrel__Certificates__Default__Path: /https/aspnetapp.pfx + # Enable for HTTPS - END + + image: localhost/somnia-guestlog:latest + # image: gitea.uberelectronnetwork.cc/somnia/somnia-guestlog:devbuild + + ports: + - protocol: tcp + published: 8080 + target: 8080 + # Enable for HTTPS + # - protocol: tcp + # published: 8090 + # target: 8090 + restart: unless-stopped + volumes: + - somniaguestlog_app_data:/SomniaGuestLog + # Enable for HTTPS and configure path to your certificate. + # - ${HOME}/.aspnet/https:/https/ + +volumes: + somniaguestlog_database_data: Null + somniaguestlog_app_data: Null diff --git a/src/Somnia.GuestLog/Program.cs b/src/Somnia.GuestLog/Program.cs index ffa5bc6..fb7b13a 100644 --- a/src/Somnia.GuestLog/Program.cs +++ b/src/Somnia.GuestLog/Program.cs @@ -1,5 +1,7 @@ using FluentStorage; using FluentValidation; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.Localization; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; @@ -23,6 +25,7 @@ var builder = WebApplication.CreateBuilder(args); //Load config files. builder.Configuration.AddJsonFile("Config/log_Config.json", optional: false, reloadOnChange: false); +builder.Configuration.AddEnvironmentVariables("SOMNIA_"); //Create and configure Logger (Serilog) var serilog = new LoggerConfiguration() @@ -34,6 +37,19 @@ var logger = new SerilogLoggerFactory(serilog).CreateLogger(); logger.LogInformation("\n\n\n -------------- Starting {appName} {appVersion} --------------", AppSettings.AppName, AppSettings.AppVersion); +if (!builder.Environment.IsDevelopment()) +{ + string dataProtectionPath = builder.Configuration.GetValue("DataProtectionDir", defaultValue: "/SomniaGuestLog/dataprotection"); + builder.Services.AddDataProtection() + .PersistKeysToFileSystem(new DirectoryInfo(dataProtectionPath)) + .SetApplicationName("SomniaGuestLog"); +} + +builder.Services.Configure(options => +{ + options.ForwardedHeaders = + ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost; +}); var connectionStringGuestLog = builder.Configuration.GetConnectionString("DbSomniaGuestLog") ?? throw new InvalidOperationException("Connection string 'DbSomniaGuestLog' not found."); @@ -102,6 +118,8 @@ builder.Services.AddOptions() var app = builder.Build(); +app.UseForwardedHeaders(); + // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { @@ -136,4 +154,15 @@ app.MapRazorComponents() //Activate S3 storage. AwsS3Storage.Use(); +//Run database migrations +bool runMigrationsOnStartup = builder.Configuration.GetValue("RunDatabaseMigrationOnStartup", defaultValue: true); +if (runMigrationsOnStartup) +{ + logger.LogInformation("Running database migrations..."); + using var scope = app.Services.CreateScope(); + var db = scope.ServiceProvider.GetRequiredService(); + await db.Database.MigrateAsync(); + logger.LogInformation("Database migrations OK"); +} + app.Run(); diff --git a/src/Somnia.GuestLog/Somnia.GuestLog.csproj b/src/Somnia.GuestLog/Somnia.GuestLog.csproj index c789cb9..0335040 100644 --- a/src/Somnia.GuestLog/Somnia.GuestLog.csproj +++ b/src/Somnia.GuestLog/Somnia.GuestLog.csproj @@ -7,6 +7,11 @@ true + + DefaultContainer + OCI + + diff --git a/src/Somnia.GuestLog/appsettings.Development.json b/src/Somnia.GuestLog/appsettings.Development.json index 2d6cd3d..2a64ad4 100644 --- a/src/Somnia.GuestLog/appsettings.Development.json +++ b/src/Somnia.GuestLog/appsettings.Development.json @@ -4,5 +4,6 @@ "Default": "Information", "Microsoft.AspNetCore": "Warning" } - } -} + }, + "RunDatabaseMigrationOnStartup": false +} \ No newline at end of file diff --git a/src/Somnia.GuestLog/appsettings.json b/src/Somnia.GuestLog/appsettings.json index 90c1da5..7ab3c4e 100644 --- a/src/Somnia.GuestLog/appsettings.json +++ b/src/Somnia.GuestLog/appsettings.json @@ -2,6 +2,8 @@ "ConnectionStrings": { "DbSomniaGuestLog": "Host=localhost;Port=5432;Username=postgres;Password=P@ssw0rd;Database=SomniaGuestLog" }, + "RunDatabaseMigrationOnStartup": true, + "DataProtectionDir": "/SomniaGuestLog/dataprotection", "AllowedHosts": "*", "AddressQuery": { "EnableAddressQuery": true,