- PowerShell 90.4%
- Shell 4.6%
- Python 4.1%
- HTML 0.7%
- Dockerfile 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .claude | ||
| applications | ||
| assets | ||
| docs | ||
| infrastructure/gotenberg | ||
| scripts | ||
| yeet-deps | ||
| .gitignore | ||
| Add-AuraCustomerCostAllocation.ps1 | ||
| Add-AuraTokenUsageCostComparison.ps1 | ||
| Add-AuraTokenUsageMonthlyShare.ps1 | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| create-app-4-5-db-users.sql | ||
| Create-Or-Update-Certificate.ps1 | ||
| Deploy-Application.ps1 | ||
| env.template | ||
| ExecuteRemoteCommand.ps1 | ||
| FetchRemoteMemoryDump.ps1 | ||
| Get-AuraTokenUsageReport.ps1 | ||
| Get-ServerInfo.ps1 | ||
| grant_aura_permissions.sql | ||
| Initialize-AuraHost.ps1 | ||
| Initialize-Nginx.ps1 | ||
| Initialize-YeetUsers.ps1 | ||
| Install-Dependencies.ps1 | ||
| LinodeUtils.psm1 | ||
| MIGRATION_PLAN_AURA.md | ||
| nginx.md | ||
| README.md | ||
| Repair-NginxConfigs.ps1 | ||
| serverstatus.sh | ||
| Set-LinodeVpcInterface.ps1 | ||
| Setup-YeetDeployment.ps1 | ||
| Upload-Diagnostics.ps1 | ||
| yeet.ps1 | ||
Linode Server Deployment System 🚀
Automatisiertes Deployment-System für .NET Anwendungen auf Linode Servern mit PowerShell und Linux systemd Services.
📖 New here? Read docs/yeet-system.md for a conceptual overview of how the whole Yeet system works (architecture, auth model, deployment lifecycle, networking, data layer). This README is the quick start + app catalog.
Yeet - Das einfache Deployment-Tool 🎯
Yeet ist ein interaktives Terminal-UI (TUI) Tool, das den Deployment-Prozess vereinfacht. Statt komplexe PowerShell-Befehle zu tippen, können Sie Anwendungen über eine benutzerfreundliche Menü-Oberfläche auswählen und deployen.
Was macht Yeet?
- Interaktive Navigation: Durchsucht automatisch den
applications/Ordner und zeigt alle deploybare Anwendungen in einer hierarchischen Menüstruktur - Server-Anzeige: Zeigt den Zielserver für jede App in Klammern an (z.B.
ProdErfalAdminPortal [aturis-app-1]) - ASCII-Art Interface: Stilvolles Terminal-UI mit gelbem "YEET" Banner
- Sound-Effekte: Spielt einen Deployment-Sound beim Start eines Deployments
- Ein-Klick Deployment: Wählen Sie einfach eine Anwendung aus und Yeet kümmert sich um den Rest
Wie benutzt man Yeet?
-
Erstmalige Einrichtung (nur einmal nötig):
.\Install-Dependencies.ps1Dies installiert die benötigten PowerShell-Module und richtet den
yeetAlias ein. -
Einrichtung der SSH-Schlüssel (Kann beliebig oft wiederholt werden):
Das Setup-Skript erstellt automatisch einen SSH-Schlüssel, akzeptiert die Server-Hostschlüssel und richtet den Key auf beiden App-Servern ein. Es sind keine manuellen Schritte nötig:
.\Setup-YeetDeployment.ps1 -
Yeet starten:
yeetOder direkt:
.\yeet.ps1 -
Navigation:
- ↑/↓ - Durch die Liste navigieren
- Enter - Ordner öffnen oder Anwendung deployen
- ESC - Zurück zur vorherigen Ebene
- Q - Beenden
Das Tool führt im Hintergrund Deploy-Application.ps1 mit der ausgewählten Anwendung aus und zeigt den Deployment-Fortschritt in einem separaten Fenster an.
📋 Unterstützte Anwendungen
Das Deployment-System unterstützt alle Mediathek-Anwendungen in Test- und Produktionsumgebungen. Jede Anwendung wird als eigenständiger systemd-Service deployed und nutzt das gemeinsame SSL-Zertifikat.
Architektur
- Testsystem (Ports 9000-9015): Nutzt Datenbank
mediathek_db01✅ VOLLSTÄNDIG DEPLOYED - Produktionssystem (Ports 9100-9115): Nutzt Datenbank
mediathek_db01_prod(bereit für Deployment) - Shared API: Zentrale Datenverwaltung für alle Tenants
- Admin Portals: Datenverwaltung pro Tenant
- Web Apps: Frontend für Endbenutzer pro Tenant
Mediathek
TESTSYSTEM (Ports 9000-9015)
Shared API (zentrale Datenverwaltung)
- Aturis.Mediathek.Shared.Api.csproj → Port 9015, Service:
aturis-mediathek-api-test✅- Deployment:
.\Deploy-Application.ps1 -AppName "TestsystemMediathekApi" - URL: https://api.mediathek.test.aturis.org/swagger
- Deployment:
Demo Tenant
- Aturis.Mediathek.Demo.AdminPortal.csproj → Port 9001, Service:
aturis-demo-adminportal-test✅- Deployment:
.\Deploy-Application.ps1 -AppName "TestsystemDemoAdminPortal" - URL: https://demo.mediathek.test.aturis.org/
- Deployment:
- Aturis.Mediathek.Demo.Web.csproj → Port 9002, Service:
aturis-demo-web-test✅- Deployment:
.\Deploy-Application.ps1 -AppName "TestsystemDemoWeb" - URL: https://webapp.demo.mediathek.test.aturis.org/
- Deployment:
Erfal Tenant
- Aturis.Mediathek.Erfal.AdminPortal.csproj → Port 9000, Service:
aturis-adminportal✅- Deployment:
.\Deploy-Application.ps1 -AppName "TestsystemErfalAdminPortal" - URL: https://erfal.mediathek.test.aturis.org/
- Deployment:
- Aturis.Mediathek.Erfal.Web.csproj → Port 9006, Service:
aturis-erfal-web-test✅- Deployment:
.\Deploy-Application.ps1 -AppName "TestsystemErfalWeb" - URL: https://webapp.erfal.mediathek.test.aturis.org/
- Deployment:
Folgner Tenant
- Aturis.Mediathek.Folgner.AdminPortal.csproj → Port 9008, Service:
aturis-folgner-adminportal-test✅- Deployment:
.\Deploy-Application.ps1 -AppName "TestsystemFolgnerAdminPortal" - URL: https://folgner.mediathek.test.aturis.org/
- Deployment:
Klaiber Tenant
- Aturis.Mediathek.Klaiber.AdminPortal.csproj → Port 9010, Service:
aturis-klaiber-adminportal-test✅- Deployment:
.\Deploy-Application.ps1 -AppName "TestsystemKlaiberAdminPortal" - URL: https://klaiber.mediathek.test.aturis.org/
- Deployment:
Windor Tenant
- Aturis.Mediathek.Windor.AdminPortal.csproj → Port 9012, Service:
aturis-windor-adminportal-test✅- Deployment:
.\Deploy-Application.ps1 -AppName "TestsystemWindorAdminPortal" - URL: https://windor.mediathek.test.aturis.org/
- Deployment:
- Aturis.Mediathek.Windor.Web.csproj → Port 9013, Service:
aturis-windor-web-test✅- Deployment:
.\Deploy-Application.ps1 -AppName "TestsystemWindorWeb" - URL: https://webapp.erfal.mediathek.test.aturis.org/
- Deployment:
PRODUKTIONSSYSTEM (Ports 9100-9115) ✅ VOLLSTÄNDIG DEPLOYED
Shared API (zentrale Datenverwaltung)
- Aturis.Mediathek.Shared.Api.csproj → Port 9115, Service:
aturis-mediathek-api-prod✅- Deployment:
.\Deploy-Application.ps1 -AppName "ProdMediathekApi" - URL: https://api.mediathek.aturis.org/swagger
- Deployment:
Demo Tenant
- Aturis.Mediathek.Demo.AdminPortal.csproj → Port 9101, Service:
aturis-demo-adminportal-prod✅- Deployment:
.\Deploy-Application.ps1 -AppName "ProdDemoAdminPortal" - URL: https://demo.mediathek.aturis.org/
- Deployment:
- Aturis.Mediathek.Demo.Web.csproj → Port 9102, Service:
aturis-demo-web-prod✅- Deployment:
.\Deploy-Application.ps1 -AppName "ProdDemoWeb" - URL: https://webapp.demo.mediathek.aturis.org/
- Deployment:
Erfal Tenant
- Aturis.Mediathek.Erfal.AdminPortal.csproj → Port 9100, Service:
aturis-erfal-adminportal-prod✅- Deployment:
.\Deploy-Application.ps1 -AppName "ProdErfalAdminPortal" - URL: https://erfal.mediathek.aturis.org/
- Deployment:
- Aturis.Mediathek.Erfal.Web.csproj → Port 9106, Service:
aturis-erfal-web-prod✅- Deployment:
.\Deploy-Application.ps1 -AppName "ProdErfalWeb" - URL: https://webapp.erfal.mediathek.aturis.org/
- Deployment:
Folgner Tenant
- Aturis.Mediathek.Folgner.AdminPortal.csproj → Port 9108, Service:
aturis-folgner-adminportal-prod✅- Deployment:
.\Deploy-Application.ps1 -AppName "ProdFolgnerAdminPortal" - URL: https://folgner.mediathek.aturis.org/
- Deployment:
Klaiber Tenant
- Aturis.Mediathek.Klaiber.AdminPortal.csproj → Port 9110, Service:
aturis-klaiber-adminportal-prod✅- Deployment:
.\Deploy-Application.ps1 -AppName "ProdKlaiberAdminPortal" - URL: https://klaiber.mediathek.aturis.org/
- Deployment:
Windor Tenant
- Aturis.Mediathek.Windor.AdminPortal.csproj → Port 9112, Service:
aturis-windor-adminportal-prod✅- Deployment:
.\Deploy-Application.ps1 -AppName "ProdWindorAdminPortal" - URL: https://windor.mediathek.aturis.org/
- Deployment:
- Aturis.Mediathek.Windor.Web.csproj → Port 9113, Service:
aturis-windor-web-prod✅- Deployment:
.\Deploy-Application.ps1 -AppName "ProdWindorWeb" - URL: https://webapp.windor.mediathek.aturis.org/
- Deployment:
MESSENGER SYSTEM (Ports 9020-9025)
Das Messenger-System ist ein separates Chat-System für verschiedene Tenants. Aktuell wird der SHK Tenant im Testsystem unterstützt.
SHK Tenant (Testsystem) ✅ DEPLOYED
- Aturis.Messenger.Api.Shk.csproj → Port 9020, Service:
aturis-shk-messenger-api-test✅- Deployment:
.\Deploy-Application.ps1 -AppName "TestsystemShkMessengerApi" - URL: https://api.shkmessenger.test.aturis.org/swagger
- Database:
messenger_shk_test_db
- Deployment:
- Aturis.Messenger.Admin.Shk.csproj → Port 9021, Service:
aturis-shk-messenger-admin-test✅- Deployment:
.\Deploy-Application.ps1 -AppName "TestsystemShkMessengerAdmin" - URL: https://admin.shkmessenger.test.aturis.org/
- Database:
messenger_shk_test_db
- Deployment:
SHK Webapp (Testsystem) ✅ DEPLOYED
- Aturis.Messenger.Client.Web.Shk → Statisches Web-Frontend (kein Service/Port)
- Deployment:
.\Deploy-Application.ps1 -AppName "TestsystemShkMessengerWebapp" - URL: https://chat.shkmessenger.test.aturis.org/
- Deployment:
WARTUNGSAPPS SYSTEM (Ports 9030-9035)
Das Wartungsapps-System ist ein Multi-Tenant-System für Wartungsverwaltung verschiedener Kunden. Die Anwendungen verwenden Blazor Server-Side Rendering mit MudBlazor-Komponenten.
MHG Tenant (Testsystem)
- Aturis.Wartungsapp.Tenant.MHG.csproj → Port 9030, Service:
aturis-wartungsapp-mhg-test- Deployment:
.\Deploy-Application.ps1 -AppName "TestsystemWartungsappMHG" - Internal URL: https://mhg.wartungsapp.test.aturis.org/
- External URL: https://mhg.test.aturis.org/
- Database:
wartungsapp_mhg_test_db
- Deployment:
LBR Tenant (Testsystem)
- Aturis.Wartungsapp.Tenant.LBR.csproj → Port 9031, Service:
aturis-wartungsapp-lbr-test- Deployment:
.\Deploy-Application.ps1 -AppName "TestsystemWartungsappLBR" - Internal URL: https://lbr.wartungsapp.test.aturis.org/
- External URL: https://liebram.test.aturis.org/
- Database:
wartungsapp_lbr_test_db
- Deployment:
VK Tenant (Testsystem)
- Aturis.Wartungsapp.Tenant.VK.csproj → Port 9032, Service:
aturis-wartungsapp-vk-test- Deployment:
.\Deploy-Application.ps1 -AppName "TestsystemWartungsappVK" - URL: https://vk.wartungsapp.test.aturis.org/
- Database:
wartungsapp_vk_test_db
- Deployment:
Aura - Multi-Tenant AI Platform
IMPORTANT: Aura uses tenant-specific environment variables for AI API keys to support multiple tenants.
Multi-Tenant Configuration System
- Tenant Detection: Automatically extracts tenant name from app name OR config path
- App name pattern:
TestsystemAuraMur→MUR - Config path pattern:
applications/Aura/Prod/MUR/→MUR
- App name pattern:
- Environment Variables: Uses format
{TENANT}_GOOGLE_API_KEY,{TENANT}_OPENAI_API_KEY, etc. - Variable Translation: Deploy script translates
MUR_GOOGLE_API_KEY→GOOGLE_API_KEYin systemd service - Fallback Support: Falls back to non-prefixed variables if tenant-specific ones aren't found
- Documentation: See
applications/Aura/Prod/MUR/README.mdfor detailed setup - Code Reference:
Deploy-Application.ps1:265-320for tenant variable resolution logic
Environment Variable Flow
.env file: MUR_GOOGLE_API_KEY=abc123
↓ (Deploy script reads)
Deploy script: Detects tenant "MUR", loads MUR_GOOGLE_API_KEY
↓ (Translates for service)
Systemd service: Environment=GOOGLE_API_KEY=abc123
↓ (Service starts app)
.NET Application: Reads GOOGLE_API_KEY=abc123
Key Requirements for Aura Deployment
- Directory Permissions:
/var/www/aura/must be owned bywww-data:www-data - Tenant Variables: Each tenant needs
{TENANT}_GOOGLE_API_KEY,{TENANT}_OPENAI_API_KEY,{TENANT}_ANTHROPIC_API_KEYin.env - Config Path: App config must be in
applications/Aura/[Test|Prod]/{TENANT}/structure - Service Isolation: Each tenant gets private environment variables in their systemd service
MUR Tenant (Production) ✅
- Aturis.Aura.Tenant.Mur.csproj → Port 9041, Service:
aturis-aura-mur-prod- Deployment:
.\Deploy-Application.ps1 -AppName "MUR" - URL: https://ki.muetze-raetzel.de/
- Database:
aura - Environment Variables:
MUR_GOOGLE_API_KEY,MUR_OPENAI_API_KEY,MUR_ANTHROPIC_API_KEY - Nginx: Resilient two-file config with Let's Encrypt (auto-renewal)
- Deployment:
DALHOFF Tenant (Production) ✅
- Aturis.Aura.Tenant.Dalhoff.csproj → Port 9042, Service:
aturis-aura-dalhoff-prod- Deployment:
.\Deploy-Application.ps1 -AppName "DALHOFF" - URL: https://ki.dalhoff-bau.de/
- Database:
aura_dalhoff - Environment Variables:
DALHOFF_GOOGLE_API_KEY,DALHOFF_OPENAI_API_KEY,DALHOFF_ANTHROPIC_API_KEY - Nginx: Resilient two-file config with Let's Encrypt (auto-renewal)
- Deployment:
DEMO Tenant (Production)
- Aturis.Aura.Tenant.Demo.csproj → Port 9043, Service:
aturis-aura-demo-prod✅- Deployment:
.\Deploy-Application.ps1 -AppName "DEMO" - URL: https://demo.kilv.de/
- Database:
aura_demo - Environment Variables:
DEMO_GOOGLE_API_KEY,DEMO_OPENAI_API_KEY,DEMO_ANTHROPIC_API_KEY
- Deployment:
GBN Tenant (Production) ✅
- Aturis.Aura.Tenant.Gbn.csproj → Port 9044, Service:
aturis-aura-gbn-prod- Deployment:
.\Deploy-Application.ps1 -AppName "GBN" - URL: https://gbn.kilv.de/
- Database:
aura_gbn - Environment Variables:
GBN_GOOGLE_API_KEY,GBN_OPENAI_API_KEY,GBN_ANTHROPIC_API_KEY - Nginx: Resilient two-file config with Let's Encrypt (auto-renewal)
- Deployment:
WIA Tenant (Production) ✅
- Aturis.Aura.Tenant.Wia.csproj → Port 9045, Service:
aturis-aura-wia-prod- Deployment:
.\Deploy-Application.ps1 -AppName "WIA" - URL: https://wia.kilv.de/
- Database:
aura_wia - Environment Variables:
WIA_GOOGLE_API_KEY,WIA_OPENAI_API_KEY,WIA_ANTHROPIC_API_KEY - Nginx: Resilient two-file config with Let's Encrypt (auto-renewal)
- Deployment:
ATURIS Tenant (Production) ✅
- Aturis.Aura.Tenant.Aturis.csproj → Port 9046, Service:
aturis-aura-aturis-prod- Deployment:
.\Deploy-Application.ps1 -AppName "ATURIS" - URL: https://aura.aturis.com/
- Database:
aura_aturis - Environment Variables:
ATURIS_GOOGLE_API_KEY,ATURIS_OPENAI_API_KEY,ATURIS_ANTHROPIC_API_KEY - Nginx: Resilient two-file config with Let's Encrypt (auto-renewal)
- Deployment:
SUPERTENANT Tenant (Production) ✅
- Aturis.Aura.Tenant.SuperTenant.csproj → Port 9047, Service:
aturis-aura-supertenant-prod- Deployment:
.\Deploy-Application.ps1 -AppName "SUPERTENANT" - URL: https://aurademo.aturis.com/
- Database:
aura_supertenant - Environment Variables:
SUPERTENANT_GOOGLE_API_KEY,SUPERTENANT_OPENAI_API_KEY,SUPERTENANT_ANTHROPIC_API_KEY - Nginx: Resilient two-file config with Let's Encrypt (auto-renewal)
- Deployment:
LANOPROJEKT Tenant (Production) ✅
- Aturis.Aura.Tenant.LanoProjekt.csproj → Port 9048, Service:
aturis-aura-lanoprojekt-prod- Deployment:
.\Deploy-Application.ps1 -AppName "LANOPROJEKT" - URL: https://lano-projekt.kilv.de/
- Database:
aura_lanoprojekt - Environment Variables:
LANOPROJEKT_GOOGLE_API_KEY,LANOPROJEKT_OPENAI_API_KEY,LANOPROJEKT_ANTHROPIC_API_KEY - Nginx: Resilient two-file config with Let's Encrypt (auto-renewal)
- Deployment:
Adding New Aura Tenants
To add a new tenant (e.g., "ABC"):
- Create directory:
applications/Aura/Prod/ABC/(or Test for test systems) - Copy MUR's
app-config.json, update service name/port - Add to
.env:ABC_GOOGLE_API_KEY=...,ABC_OPENAI_API_KEY=...,ABC_ANTHROPIC_API_KEY=... - Deploy:
.\Deploy-Application.ps1 -AppName "ProdAuraABC"(or TestsystemAuraABC for test)
Insgesamt: 32 Anwendungen (18 Mediathek deployed ✅, 3 Messenger deployed ✅, 3 Wartungsapps bereit für Deployment, 8 Aura deployed ✅)
Überblick 📋
Dieses System bietet:
- Einheitliches Deployment-Script gesteuert durch JSON-Konfiguration ⚙️
- Gemeinsame SSL-Zertifikatsverwaltung 🔒
- Automatisiertes Build und Packaging 📦
- Systemd Service-Erstellung und -Verwaltung 🛠️
- Datenbank-Setup und Migrationsskripte 🗄️
- Remote-Server-Diagnose und -Monitoring 📊
Quick Start 🏃♂️
-
Environment Setup
# Kopiere und konfiguriere die Environment-Datei cp env.template .env # Bearbeite .env mit deinen Server-Details -
Anwendung deployen
.\Deploy-Application.ps1 -AppName "TestsystemErfalAdminPortal" -
Status checken
.\Get-ServerInfo.ps1 -
Plesk zu Linode Weiterleitung in Plesk:
- vServer → Applikation → Hosting → nginx config → zusätzliche Einstellungen (z.B. app-config.json von ProdDemoWeb)
- Portnummer auslesen
- Weiterleitung muss zu diesem Port gehen
Tricks und Tipps 💡
Dateien
Hin und her schieben mit WinSCP Übertragungsprotokoll → SFTP Ordner: /var/www/
Für Mediathek:
- mediathek prod = media prod
- mediathek test = shk
- mediathek = media test
was verbraucht Strom:
- htop -> Taskmanager
- F10 zum Beenden
logs lesen einer Applikation:
- JSON-Datei in Linode-Repo finden, z.B. app-config.json von ProdDemoWeb
- Service-Name rauslesen: z.B. aturis-demo-web-prod
- Dann auf SSH: journalctl -u aturis-demo-web-prod
System-Architektur 🏗️
Core Components
- LinodeUtils.psm1: PowerShell-Modul mit gemeinsamen Deployment-Funktionen 🧩
- Deploy-Application.ps1: Einheitliches Deployment-Script 📝
- applications/Mediathek/: Organisierte Anwendungskonfigurationen (Test/Prod) 📁
- build/: Konsolidiertes Build-Artefakte-Verzeichnis 🏭
Anwendungsstruktur
Jede Anwendung in applications/Mediathek/Test/ oder applications/Mediathek/Prod/ enthält:
app-config.json: Deployment-Konfiguration ⚙️config.json: Runtime-Anwendungskonfiguration 🔧README.md: Anwendungsspezifische Dokumentation 📚- Datenbankskripte (falls zutreffend) 🗃️
Konfiguration ⚙️
Environment-Variablen (.env)
# Server-Verbindung
LinodeIP=deine.server.ip
LinodeRootUser=root
LinodeRootPassword=dein_passwort
# SSL-Zertifikat
AspNetCorePfxPassword=dein_pfx_passwort
# Anwendungsspezifische Datenbank-Credentials
ErfalAdminTestDbUser=db_user
ErfalAdminTestDbPassword=db_password
Anwendungskonfiguration (app-config.json)
{
"AppName": "Deine.Anwendung.Name",
"Build": {
"RepoUrl": "https://gitlab.com/dein/repo.git",
"LocalRepoPath": "AturisApplications/repo",
"ProjectPath": "pfad/zu/Project.csproj",
"Runtime": "linux-x64"
},
"Database": {
"Name": "datenbank_name",
"UserEnvVar": "DB_USER_ENV_VAR",
"PasswordEnvVar": "DB_PASS_ENV_VAR"
},
"Deployment": {
"TargetServer": "aturis-app-1",
"UseSharedCertificate": true,
"RemoteBaseDir": "/var/www/deine-app",
"RemoteAppDirName": "AppVerzeichnis",
"RemoteAppPath": "/var/www/deine-app/AppVerzeichnis",
"RemotePublishDir": "/var/www/deine-app/AppVerzeichnis/publish"
},
"Service": {
"Name": "dein-service",
"Port": 9000,
"User": "www-data",
"DllName": "Deine.App.dll",
"UseJemalloc": false
}
}
Service.UseJemalloc aktiviert für dynamische .NET-Dienste den installierten jemalloc-Allocator.
Das Deployment bricht vor einer Serviceänderung ab, wenn das Debian-Paket libjemalloc2 auf dem
Zielserver fehlt. Standardwert ist false.
Deployment-Prozess 🔄
Schritt-für-Schritt Deployment
- Source Control: Git-Repository klonen/updaten 📥
- Build: .NET-Anwendung für Linux kompilieren 🔨
- Package: Deployment-ZIP-Datei erstellen 📦
- Zertifikat: Gemeinsames SSL-Zertifikat deployen (falls konfiguriert) 🔐
- Upload: Anwendung auf Server übertragen ⬆️
- Service: Systemd-Service erstellen/updaten 🔧
- Cleanup: Build-Artefakte entfernen 🧹
Deployment-Optionen
# Standard-Deployment
.\Deploy-Application.ps1 -AppName "DeineApp"
SSL-Zertifikatsverwaltung 🔒
Gemeinsames Zertifikatssystem
Das System verwendet EIN gemeinsames SSL-Zertifikat für ALLE Anwendungen:
/etc/ssl/private/aspnetcore.pfx- Das eine PFX-Zertifikat für alle .NET Apps 🎫
Zertifikatserstellung
Das Zertifikat wird mit dem Create-Or-Update-Certificate.ps1 Script erstellt:
openssl req -x509 -newkey rsa:2048 -nodes -keyout aspnetcore.key -out aspnetcore.crt -subj "/CN=localhost" -days 365
openssl pkcs12 -export -out aspnetcore.pfx -inkey aspnetcore.key -in aspnetcore.crt -password pass:$pfxPass
Nginx Reverse Proxy & Let's Encrypt 🔄🔐
Das Deployment-System unterstützt nginx als Reverse Proxy mit Let's Encrypt SSL-Zertifikaten und automatischer Zertifikatserneuerung ohne manuelle Eingriffe.
Was ist neu?
- Professionelle SSL-Zertifikate - Let's Encrypt pro Domain statt shared self-signed cert
- Domain-basiertes Routing - Apps über eigene Domains erreichbar (z.B.
ki.dalhoff-bau.de) - Sharded Konfiguration - Jede App hat eigene nginx-Config (Fehler isoliert)
- Resiliente Zwei-Datei-Architektur - NEUE FEATURE: Garantierte ACME-Challenge-Verfügbarkeit
- Zero-Intervention Renewals - Zertifikate erneuern sich automatisch, auch wenn sie ablaufen
Architektur
Alt (ohne nginx):
Internet → App:9042 (HTTPS via Kestrel, shared cert)
Neu (mit nginx - Resilient Two-File Approach):
Internet → nginx:80 (HTTP-only config, ACME challenges) → HTTPS redirect
Internet → nginx:443 (HTTPS-only config, Let's Encrypt) → App:9042 (HTTP localhost)
⚡ Resiliente Zwei-Datei-Architektur
Problem: Herkömmliche nginx-Konfigurationen mit kombinierten HTTP/HTTPS-Blöcken können nicht laden, wenn SSL-Zertifikate fehlen oder abgelaufen sind. Dies führt zu einem Henne-Ei-Problem bei der Zertifikatserneuerung.
Lösung: Jede Anwendung erhält ZWEI separate nginx-Konfigurationsdateien:
1. HTTP-Only Config (Port 80)
- Datei:
/etc/nginx/sites-enabled/aturis-{service-name}-http - KEINE SSL-Abhängigkeiten - lädt IMMER erfolgreich
- Behandelt Let's Encrypt ACME-Challenges (
/.well-known/acme-challenge/) - Leitet allen anderen HTTP-Traffic zu HTTPS um (301)
- Garantiert, dass Zertifikatserneuerung funktioniert, selbst wenn Zertifikate abgelaufen sind
2. HTTPS-Only Config (Port 443)
- Datei:
/etc/nginx/sites-enabled/aturis-{service-name}-https - SSL/TLS-Terminierung mit Let's Encrypt-Zertifikaten
- Reverse Proxy zur Anwendung (localhost:PORT)
- Sicherheitsheader und WebSocket-Unterstützung
- Wenn Zertifikate ablaufen, schlägt diese Config fehl ABER...
- ...die HTTP-Config funktioniert weiterhin für ACME-Erneuerungen!
Vorteile:
- ✅ Zero Manual Intervention - System heilt sich selbst, auch nach Zertifikatsablauf
- ✅ ACME Challenges immer verfügbar - HTTP-Config hat keine SSL-Abhängigkeiten
- ✅ Graceful Degradation - Wenn HTTPS-Config fehlschlägt, funktioniert HTTP weiterhin
- ✅ Automatische Erneuerungen - Certbot läuft täglich um 3 Uhr morgens
- ✅ Produktionsbereit - Bereits deployed auf MUR (ki.muetze-raetzel.de) und DALHOFF (ki.dalhoff-bau.de)
Quick Start
-
DNS konfigurieren:
- A-Record für Ihre Domain auf Linode-Server-IP setzen
- Beispiel:
ki.customer.com→172.236.219.21
-
Nginx-Sektion zu app-config.json hinzufügen:
"Nginx": { "UseNginx": true, "DomainName": "ki.customer.com", "LetsEncryptEnabled": true, "AllowHttp": false, "ListenLocalOnly": true } -
Deployen - DAS WAR'S! 🎉
.\Deploy-Application.ps1 -AppName "AppName"
Das Deployment-Script macht automatisch:
- ✅ Nginx-Infrastruktur initialisieren (falls benötigt)
- ✅ HTTP-only Config deployen (für ACME-Challenges)
- ✅ Let's Encrypt-Zertifikat via HTTP-01 Challenge erwerben
- ✅ HTTPS-only Config deployen (SSL/TLS aktivieren)
- ✅ Automatische Erneuerung konfigurieren (täglich 3 Uhr)
Keine manuellen Schritte erforderlich! Die resiliente Zwei-Datei-Architektur garantiert, dass Zertifikate sich automatisch erneuern, selbst wenn sie ablaufen.
Konfigurationsoptionen
- UseNginx:
true= nginx Reverse Proxy,false= direktes HTTPS (legacy) - DomainName: Domain/Subdomain für die App (z.B.
"app.customer.com") - LetsEncryptEnabled:
true= Let's Encrypt Zertifikat,false= kein SSL in nginx - AllowHttp:
false= HTTP→HTTPS redirect (empfohlen),true= HTTP erlaubt
Sharded Configs
Jede App erhält eigene nginx-Konfiguration:
/etc/nginx/sites-available/aturis-{service-name}
/etc/nginx/sites-enabled/aturis-{service-name} → symlink
Vorteil: Fehler in App A brechen nicht App B, C, D.
Systemd Integration
Apps mit nginx haben automatische Abhängigkeiten:
- After=nginx.service - App startet nach nginx
- Wants=nginx.service - App startet nginx mit falls gestoppt
- Bei Server-Reboot: nginx → Apps automatisch gestartet
RSA 4096 Zertifikate (FortiGate-Kompatibilität)
Seit Februar 2026 verwenden alle Let's Encrypt-Zertifikate RSA 4096-Bit Schlüssel statt ECDSA. Hintergrund: Certbot 2.x erzeugt standardmäßig ECDSA-Zertifikate. Bei mindestens zwei Kunden haben Fortinet/FortiGate-Firewalls die SSL Deep Inspection dieser ECDSA-Zertifikate nicht korrekt durchführen können, wodurch unsere Webanwendungen blockiert wurden.
Resultierende Zertifikatskette (reine RSA):
Leaf-Zertifikat (RSA 4096) → R10/R11 Intermediate (RSA) → ISRG Root X1 (RSA)
Bestehende Zertifikate reparieren:
# Vorschau:
.\Repair-NginxConfigs.ps1 -DryRun
# Alle Zertifikate auf RSA 4096 umstellen + nginx-Configs aktualisieren:
.\Repair-NginxConfigs.ps1
# Einzelne App reparieren:
.\Repair-NginxConfigs.ps1 -AppName "DEMO"
Weitere Details: nginx.md - RSA 4096 Zertifikate
Default HTTPS Server (Zertifikat-Leak-Schutz)
server.aturis.com dient als neutraler Default-HTTPS-Server. Ohne diesen würde nginx bei Anfragen ohne SNI (z.B. Port-Scanner) das Zertifikat einer anderen gehosteten Anwendung offenlegen. Der Default-Server zeigt stattdessen nur server.aturis.com -- eine leere, neutrale Seite.
Eingerichtet durch Initialize-Nginx.ps1 oder Repair-NginxConfigs.ps1. Weitere Details: nginx.md - Default HTTPS Server
Weitere Informationen
📖 Detaillierte Dokumentation: nginx.md
Enthält:
- Schritt-für-Schritt Let's Encrypt Setup
- Nginx Konfigurationsdetails
- Migration Guide für bestehende Apps
- Troubleshooting und Diagnostics
- Alle nginx/certbot Befehle
Datenbankverwaltung 🗄️
Datenbank-Setup-Skripte
Anwendungen können Datenbankskripte enthalten:
Initialize-Database.ps1: Datenbankstruktur erstellen 🏗️Import-Database.ps1: Test-/Produktionsdaten importieren 📊
Datenbankkonfiguration
Datenbankverbindungen werden über Environment-Variablen konfiguriert und während des Deployments in die Anwendungskonfiguration injiziert.
Service-Verwaltung 🛠️
Systemd Services
Anwendungen laufen als systemd-Services mit:
- Automatischer Neustart bei Fehlern 🔄
- Ordnungsgemäße Benutzerberechtigungen (www-data) 👤
- Environment-Variable-Konfiguration 🌍
- Logging ins systemd-Journal 📝
Service-Befehle
# Service-Status prüfen
systemctl status dein-service.service
# Logs anzeigen
journalctl -u dein-service.service -f
# Service neustarten
systemctl restart dein-service.service
Administrative Skripte 🔧
Core-Skripte
Deploy-Application.ps1: Haupt-Deployment-Skript 🚀Get-ServerInfo.ps1: Server-Status und -Diagnose 📊ExecuteRemoteCommand.ps1: Befehle auf Server ausführen 💻serverstatus.sh: Server-Gesundheitsprüfung 🏥Create-Or-Update-Certificate.ps1: Erstellt das gemeinsame aspnetcore.pfx Zertifikat 🔐
Diagnose-Tools
# Umfassende Server-Informationen abrufen
.\Get-ServerInfo.ps1
# Benutzerdefinierten Befehl ausführen
.\ExecuteRemoteCommand.ps1 -Command "systemctl status"
# Server-Status prüfen
.\ExecuteRemoteCommand.ps1 -Command "bash serverstatus.sh"
Neue Anwendungen hinzufügen ➕
Schritt 1: Anwendungsverzeichnis erstellen
mkdir applications/Mediathek/Test/DeineNeueApp
# oder für Produktion:
mkdir applications/Mediathek/Prod/DeineNeueApp
Schritt 2: Konfiguration erstellen
Erstelle applications/Mediathek/Test/DeineNeueApp/app-config.json mit deinen Anwendungseinstellungen.
Schritt 3: Environment-Variablen hinzufügen
Füge erforderliche Datenbank-Credentials zur .env-Datei hinzu.
Schritt 4: Dokumentation erstellen
Erstelle applications/Mediathek/Test/DeineNeueApp/README.md mit anwendungsspezifischen Anweisungen.
Schritt 5: Deployen
.\Deploy-Application.ps1 -AppName "DeineNeueApp"
Server Provisioning for Horizontal Scaling
This section documents the complete process for provisioning new, identical Linode servers. Follow these steps whenever adding a new application server.
Current Infrastructure
| Server | Public IP | VPC IP | OS | Role |
|---|---|---|---|---|
| aturis-app-1 | 172.236.219.21 | 10.0.0.2 | Debian 12 | Connectivity server: nginx, Let's Encrypt/certbot, MariaDB, Redis, Docker, and legacy/local apps |
| aturis-app-2 | 172.236.203.80 | 10.0.0.3 | Debian 13 | Application server: Aura apps behind app-1 nginx via VPC |
| aturis-app-3 | 172.238.110.103 | 10.0.0.4 | Debian 12 | Application server: additional Aturis/Aura apps behind app-1 nginx via VPC |
| aturis-app-4 | 172.236.219.51 | 10.0.0.5 | Debian 13 | Application server |
| aturis-app-5 | 172.236.212.9 | 10.0.0.6 | Debian 12 | Application server, including Lano |
| aturis-app-6 | 172.238.119.167 | 10.0.0.7 | Debian 13 | Application server, provisioned |
All servers connected via VPC in Frankfurt datacenter (sub-millisecond latency).
Server Roles
aturis-app-1 is the only connectivity edge for public HTTP(S) traffic. It owns nginx, Let's Encrypt/certbot state, public certificates, MariaDB, Redis, and Docker-based shared services. Public domains terminate on app-1 and are proxied over the VPC to application servers when needed.
aturis-app-2 through aturis-app-6 are application servers. They run yeetApp systemd user services and listen only on the application ports assigned by deployed apps. They do not need nginx, certbot, Redis, Docker, or git for normal deployments. Having no open application ports on a fresh app server is expected until the first app is deployed.
Certificates are stored and renewed on aturis-app-1. Cross-server apps still use Nginx.UseNginx=true, but nginx config and certbot operations happen on app-1 while the app process runs on its TargetServer.
Traffic Monitoring on aturis-app-1
aturis-app-1 runs ntopng for graphical traffic visibility and GeoIP/ASN resolution.
| Component | Location | Notes |
|---|---|---|
| ntopng | Docker container ntopng (ntop/ntopng:latest) |
Captures eth0 and eth1, uses libpcap fallback if PF_RING is not loaded |
| ntopng Redis | Docker container ntopng-redis (redis:7-alpine) |
Bound to 127.0.0.1:6380, data in /opt/ntopng/redis-data |
| ntopng data | /opt/ntopng/ntopng |
Persistent ntopng state |
| Web UI backend | 127.0.0.1:3001 |
Local-only; do not expose this port directly |
| Public URL | https://ntopng.aturis.net |
nginx reverse proxy with Let's Encrypt certificate |
| nginx config | /etc/nginx/sites-available/aturis-ntopng-http and aturis-ntopng-https |
Symlinked in sites-enabled |
| Access restriction | nginx allowlist | ATURIS external IPs only (87.138.204.149, 212.72.184.100) plus localhost |
Operational checks:
.\ExecuteRemoteCommand.ps1 -Server aturis-app-1 -Command "docker ps --filter name=ntopng"
.\ExecuteRemoteCommand.ps1 -Server aturis-app-1 -Command "curl -k -I --resolve ntopng.aturis.net:443:127.0.0.1 https://ntopng.aturis.net/"
.\ExecuteRemoteCommand.ps1 -Server aturis-app-1 -Command "tail -50 /var/log/nginx/ntopng-error.log"
Important: ntopng must use its dedicated Redis on 127.0.0.1:6380. Do not let it fall back to the shared Redis on 127.0.0.1:6379.
The container entrypoint waits for PONG from 127.0.0.1:6380, then executes /usr/bin/ntopng directly with the configured arguments. Do not call the image's /run.sh: it starts an additional Redis on host port 6379 and prevents AURA Redis from publishing that port. Preserve the direct entrypoint when recreating or upgrading the container. The replacement on 2026-09-08 retains the pinned image, mounts, capabilities, logging limits and unless-stopped policy; previous containers have restart disabled.
Repeatable AURA host setup
The authoritative runbook is docs/prepare-new-server.md.
Shared Office/PDF converter updates on app-1: Gotenberg runbook. The package list lives only in scripts/ensure-aura-runtime.sh. It provides .NET9+10 SDKs/runtimes,document/media tools,fonts,Node/npm,Python and deployment utilities. Office dependencies and their sandbox test come from the intended AturisSoftware revision. Debian12/13 retain their distribution-supported package versions; parity means capability,not identical version strings.
# Fresh host after VPC/firewall/.env/host-key preparation:
./Initialize-AuraHost.ps1 -Server aturis-app-6 -Mode NewHost -OfficePrerequisitesPath C:/Repos/messenger/Aura/Scripts/OfficeSandbox/install-prerequisites.sh
# Existing host: dependencies only; no automatic app restart or reboot:
./Initialize-AuraHost.ps1 -Server aturis-app-3 -Mode Dependencies -OfficePrerequisitesPath C:/Repos/messenger/Aura/Scripts/OfficeSandbox/install-prerequisites.sh
# Read-only acceptance:
./Initialize-AuraHost.ps1 -Server aturis-app-6 -Mode Verify
For existing hosts,roll out one host at a time and compare service PIDs/restarts and HTTP health before/after. The runbook covers VPC activation/reboot,4GiB swap verification,team/CI SSH keys,shared credentials, maintenance,backup checks and per-application DB grants. New host provisioning does not move customers. Do not install nginx,certbot,MariaDB server,Redis server or Docker on application hosts for the shared topology.
Deploying Apps to the New Server
-
Set
TargetServerin the app'sapp-config.json:"Deployment": { "TargetServer": "<server-name>" } -
Deploy:
pwsh -NoProfile -Command ".\Deploy-Application.ps1 -AppName '<FolderName>'"
The deployment script handles cross-server nginx proxy configuration, VPC IPs in connection strings, and SSL certificates automatically.
For cross-server deployments, nginx and certbot stay on aturis-app-1. The target app server only needs the app runtime, deployment users, /var/www permissions, VPC connectivity, and the shared credential files required by that app.
Cross-Server Deployment Details
For edge cases and troubleshooting cross-server deployments, see docs/prepare-new-server.md:
- SSL mode for Debian 13 MariaDB clients
- Connection strings pointing to VPC IP
- SSH host key acceptance
- Nginx reverse proxy to apps on other servers via VPC
Troubleshooting 🔍
Häufige Probleme
- Build-Fehler: .NET SDK-Version und Projektabhängigkeiten prüfen ⚠️
- Berechtigungsfehler: Prüfen, ob www-data-Benutzer ordnungsgemäße Berechtigungen hat 🚫
- Zertifikatsprobleme: PFX-Passwort und Dateiberechtigungen prüfen 🔐
- Service-Start: Systemd-Logs für detaillierte Fehlermeldungen überprüfen 📋
Aura-Spezifische Probleme
-
"Required configuration value 'GOOGLE_API_KEY' not found":
- Überprüfen Sie, dass
{TENANT}_GOOGLE_API_KEYin der.env-Datei vorhanden ist - Stellen Sie sicher, dass
/var/www/aura/die richtigen Berechtigungen hat (www-data:www-data) - Führen Sie das Deployment erneut aus, um die Environment-Variablen zu aktualisieren
- Überprüfen Sie, dass
-
File Upload Fehler bei Aura-Deployments:
- Problem:
/var/www/aura/ist oft standardmäßig im Besitz vonroot:root - Lösung:
chown -R www-data:www-data /var/www/aura/
- Problem:
-
Tenant-Detection schlägt fehl:
- Deploy-Script erkennt Aura-Apps über AppName (
*Aura*) oder Config-Pfad (*Aura*) - Debug-Output: "Detected Aura tenant: {TENANT}" muss in den Logs erscheinen
- Deploy-Script erkennt Aura-Apps über AppName (
Debug-Befehle
# Build-Artefakte prüfen
ls build/
# Service-Logs anzeigen
.\ExecuteRemoteCommand.ps1 -Command "journalctl -u dein-service.service --no-pager"
# Zertifikatsberechtigungen prüfen
.\ExecuteRemoteCommand.ps1 -Command "ls -la /etc/ssl/pfx/"
# Service-Konfiguration verifizieren
.\ExecuteRemoteCommand.ps1 -Command "systemctl show dein-service.service"
Sicherheitsüberlegungen 🛡️
- Sensitive Credentials in
.env-Datei speichern (nicht in Versionskontrolle) 🔒 - Starke PFX-Passwörter für SSL-Zertifikate verwenden 💪
- SSH-Zugang nur auf autorisierte Benutzer beschränken 🚪
- Regelmäßig Server-Pakete und Sicherheits-Patches aktualisieren 🔄
- Service-Logs auf verdächtige Aktivitäten überwachen 👀
CAA-Policy für projektbezogene HTTPS-Endpunkte
CAA wird ausschließlich am projektspezifischen FQDN gesetzt, den ATURIS für den
jeweiligen AURA-Endpunkt kontrolliert. Keine Policy ungeprüft auf einer Kunden-Zone
oder deren Apex setzen. Bei Zertifikaten mit AlternateDomains muss jeder einzelne
SAN-Name dieselbe kompatible Policy liefern.
Zielpolicy der ersten Stufe:
TTL 300
CAA 0 issue "letsencrypt.org; validationmethods=http-01"
- TTL 300 Sekunden verwenden; falls der DNS-Provider dies nicht unterstützt, maximal 3600 Sekunden.
- Kein Critical-Flag
128verwenden. - Zunächst keine
accounturibinden. Produktion und Let's-Encrypt-Staging verwenden getrennte ACME-Accounts; eine vorschnelle Bindung blockiertcertbot renew --dry-run. - Änderungen nur montags bis donnerstags zwischen 08:00 und 09:00 Uhr durchführen.
- Nur ändern, wenn alle betroffenen Zertifikate mindestens 30 Tage Restlaufzeit besitzen.
- Vorher und nachher jeden
DomainNameund jedeAlternateDomaingegen autoritative DNS-Server sowie zwei öffentliche Resolver prüfen. - Danach
certbot renew --dry-run, nginx-Konfiguration, SANs, Zertifikatskette und HTTPS-Erreichbarkeit prüfen. - CAA macht vorhandene Zertifikate nicht ungültig. Bei einer Fehlkonfiguration den CAA-Record am konkreten FQDN entfernen oder vorübergehend auf
CAA 0 issue "letsencrypt.org"lockern. - Trotz niedriger DNS-TTL bei einer Korrektur mit bis zu acht Stunden CA-seitiger Wiederverwendung einer früheren CAA-Prüfung rechnen.
Rollout-Reihenfolge:
test.aura.aturis.comals Single-SAN-Canary.- Weitere von ATURIS kontrollierte Single-SAN-Testendpunkte.
- Single-SAN-Produktivendpunkte.
- Multi-SAN-Zertifikate erst nach erfolgreichem Nachweis für jeden beteiligten Namen.
- Der Deploy-Preflight bleibt während des Rollouts bei CAA-Abweichungen warnend. Erst nach vollständiger DNS-Abdeckung darf er in einem separaten Commit fail-closed geschaltet werden.
Eine spätere accounturi-Bindung benötigt vorab einen nachgewiesenen Export und eine
getestete Wiederherstellung der Produktions- und Staging-Account-Keys sowie einen
unabhängig erreichbaren DNS-Break-Glass-Zugang. Produktions- und Staging-Account
werden dann als zwei additive CAA-Records zugelassen, damit der Dry-Run erhalten bleibt.
Anforderungen 📋
Lokale Entwicklungsmaschine
- PowerShell7 (
pwsh) für die aktuellen Provisionierungsbefehle 💻 - .NET SDK 10 für aktuelle AURA-Builds; SDK9 für ältere Anwendungen 🔧
- Git-Client 📥
- PuTTY-Tools (plink.exe, pscp.exe) im PATH 🛠️
Linode Server
- Debian12/13 🐧
- .NET9+10 SDKs/Runtimes und AURA-Abhängigkeiten gemäß
Initialize-AuraHost.ps1⚙️ - MariaDB-Client auf Apphosts; zentraler Datenbankserver auf app-1 🗄️
- OpenSSL für Zertifikatsgenerierung 🔐
- Systemd für Service-Verwaltung 🛠️
Setup Dependencies
Run \Install-Dependencies.ps1 to install/check:
- Posh-SSH module
- Git (via winget if avail, else warn)
- PuTTY (plink/pscp via winget if avail, else warn)
Assumes .NET SDK installed.
Lizenz 📄
Dieses Deployment-System ist proprietäre Software für Aturis-Anwendungen.