Deployment
What a server needs to run the application. Nothing here depends on a particular hosting provider.
Requirements
| Need | Detail |
|---|---|
| Operating system | Linux x64 (the release is published self-contained, so no .NET install is needed; otherwise the .NET 10 runtime) |
| Database | PostgreSQL 17 or later; the exclusion constraint that refuses double room bookings needs PostgreSQL |
| Persistent data directory | Outside the release directory, kept across deploys: attachments/, logs/, keys/ (data-protection key ring). Private to the service user |
| Reverse proxy | TLS termination (the camera and secure cookies need https), WebSocket support (Blazor circuits on /_blazor), forwarded headers, and a request size that lets photo uploads through |
| Process model | One instance. The realtime bus and the caches are in-process; a second instance needs a backplane first |
| Health check | GET /health answers 200 when the app is ready |
Configuration
Environment variables (double underscore for :):
| Key | Purpose |
|---|---|
ConnectionStrings__Default |
PostgreSQL connection string |
ASPNETCORE_ENVIRONMENT |
Production (no demo accounts, HSTS on) |
Seed__AdminPassword |
The first administrator's password, read once on the first start |
Attachments__Path, Logging__Path, DataProtection__Path |
The three folders of the data directory |
AllowedHosts |
The host names the app answers on |
Proxy__Known, Proxy__Hops |
The proxies trusted for forwarded headers |
Proxy__Cdn__Header, Proxy__Cdn__Ranges__N |
Behind a CDN: the header with the client address, and the CDN's ranges |
Email__From, Email__FromName, Email__BaseUrl |
Sender and the public address links in e-mails point to |
Email__Host, Email__Port, Email__User, Email__Password |
SMTP, any provider |
Email__Api=resend (with Email__Password as the API key) |
Send through an HTTPS e-mail API instead of SMTP, where outgoing SMTP is blocked |
Login__Limit |
Login attempts per source per minute |
With no e-mail configured, notifications stay in the app and nothing is kept to send later.
Start-up
- EF Core migrations are applied at start-up, then the seeds and one-time folds run, each guarded by an audit marker so it runs once.
- The startup catalog check refuses to start on a service definition the rules would refuse.
deploy/hangar/start.shis the reference start script: it refuses to start without a data directory, creates the three folders with private permissions, and sets the paths before starting the app.
Releasing
- Run
./verify.shon the exact commit, from a clean checkout (agit worktree), never a working tree with unfinished work. - Publish self-contained for
linux-x64and upload the release. - Switch traffic only after
/healthanswers. - Add the release's line to the changelog (
Changelog.cs), with the build's commit written into the previous release.
Operations
- Logs: Serilog, console and rolling JSON files in
Logging__Path; readable under «سجل النظام» byViewSystemLogs. Slow SQL over 500 ms is logged. - Backups: the database and the data directory together: attachments live on disk, and losing the key ring signs everyone out and breaks open forms.
- Before going live: the repository's
README.mdlists the remaining blockers and sign-off items.