Names the deployed instance slpsoftware, not the software itself

SlpModularCms is the product; slpsoftware.nl is the customer running
it - the first one, and a fine stand-in for what a real deployment
looks like. Renamed the directories, systemd units, and backup paths
accordingly. Left the backup script's own filename alone since the
already-committed deploy-scp.yaml calls it by that exact name.
This commit is contained in:
2026-07-28 22:16:04 +02:00
parent 843253888e
commit 97f18d00e5
3 changed files with 47 additions and 30 deletions
@@ -4,6 +4,12 @@
directory, `systemd --user` unit, and local port. Domains: `test.slpsoftware.nl` (test),
`slpsoftware.nl` (production).
**Naming note**: directories, systemd units and the website-upload path below are named
`slpsoftware` — the **customer/instance** running SlpModularCms (this repo's software), not the
software itself. SlpModularCms can host multiple customers; `slpsoftware` is this one — the first,
and the owner's own site. A future second customer on the same Pi would get its own instance name
throughout, following the same pattern.
---
## 1. One-Time Host Setup
@@ -35,7 +41,7 @@ sudo useradd -m -s /bin/bash gitea-workflow
sudo passwd gitea-workflow
```
Each project deploying through this account gets its own subdirectory under its home (§ 1.4 already
namespaces by project: `~/apps/slpmodularcms/<env>/`), so one generic account can serve multiple
namespaces by project: `~/apps/slpsoftware/<env>/`), so one generic account can serve multiple
projects without their release trees colliding.
**Fallback, only if no SSH-capable account exists at all and creating one genuinely isn't feasible**
@@ -66,25 +72,25 @@ for the CMS's own release/current/shared structure to live anywhere near the oth
which directly avoids interfering with them (as you asked in Q2):
```bash
mkdir -p ~/apps/slpmodularcms/<env>/releases
mkdir -p ~/apps/slpsoftware/<env>/releases
```
`current` is created by the first deploy itself (`ln -sfn`) — don't pre-create it.
**`shared/wwwroot-web` is the one exception** — it must resolve to wherever `webadmin` actually
uploads *this* customer's website via FileZilla, e.g. `/mnt/storage1/www/html/slpmodularcms/<env>/`
uploads *this* customer's website via FileZilla, e.g. `/mnt/storage1/www/html/slpsoftware/<env>/`
(adjust the exact folder name to whatever convention the other sites under `html/` already use, if
one exists). Rather than a plain directory, make it a symlink across accounts:
```bash
mkdir -p ~/apps/slpmodularcms/<env>
ln -s /mnt/storage1/www/html/slpmodularcms/<env> ~/apps/slpmodularcms/<env>/shared/wwwroot-web
mkdir -p ~/apps/slpsoftware/<env>
ln -s /mnt/storage1/www/html/slpsoftware/<env> ~/apps/slpsoftware/<env>/shared/wwwroot-web
```
`deploy-scp.yaml`'s existing logic (`releases/{ts}/wwwroot/web -> ../../../shared/wwwroot-web`)
needs no changes for this — it only ever resolves the symlink chain, it doesn't care how many hops
that chain has. What **does** need attention: `gitea-workflow` needs read + traverse permission on
`/mnt/storage1/www/html/slpmodularcms/<env>/` and its parent directories, which `webadmin` owns.
`/mnt/storage1/www/html/slpsoftware/<env>/` and its parent directories, which `webadmin` owns.
Simplest fix: put both accounts in a shared group (e.g. `webshared`), `chgrp -R webshared` that
folder, and make sure webadmin's FTP server creates new uploads group-readable (`g+rx`, not just
owner-readable) — a one-time permission setup, not something either pipeline touches per deploy.
@@ -92,15 +98,15 @@ owner-readable) — a one-time permission setup, not something either pipeline t
### 1.5 Runtime Configuration File
One file per environment, **outside** the release directory so it survives every switch:
```bash
touch ~/apps/slpmodularcms/<env>/shared/env
chmod 600 ~/apps/slpmodularcms/<env>/shared/env
touch ~/apps/slpsoftware/<env>/shared/env
chmod 600 ~/apps/slpsoftware/<env>/shared/env
```
Contents (fill in real values — this file is never read by the workflow, only by the systemd unit
below):
```ini
ASPNETCORE_ENVIRONMENT=Production
ASPNETCORE_URLS=http://localhost:<port>
ConnectionStrings__DefaultConnection=Server=127.0.0.1,1433;User ID=<user>;Password=<password>;Database=SlpModularCms<Env>;TrustServerCertificate=True
ConnectionStrings__DefaultConnection=Server=127.0.0.1,1433;User ID=<user>;Password=<password>;Database=SlpSoftware<Env>;TrustServerCertificate=True
JwtSettings__Secret=<secure-long-random-secret>
JwtSettings__Issuer=SlpModularCms
JwtSettings__Audience=SlpModularCmsPortal
@@ -120,16 +126,16 @@ gate only catches drift between the frontend build and that Gitea variable; it c
so keeping the two in sync is a manual discipline, not something enforced automatically.
### 1.6 systemd User Units
Create `~/.config/systemd/user/slpmodularcms-test.service`:
Create `~/.config/systemd/user/slpsoftware-test.service`:
```ini
[Unit]
Description=SlpModularCms API (test)
After=network.target
[Service]
WorkingDirectory=%h/apps/slpmodularcms/test/current
ExecStart=/usr/bin/dotnet %h/apps/slpmodularcms/test/current/SlpModularCms.Api.dll
EnvironmentFile=%h/apps/slpmodularcms/test/shared/env
WorkingDirectory=%h/apps/slpsoftware/test/current
ExecStart=/usr/bin/dotnet %h/apps/slpsoftware/test/current/SlpModularCms.Api.dll
EnvironmentFile=%h/apps/slpsoftware/test/shared/env
Restart=on-failure
RestartSec=5
KillSignal=SIGINT
@@ -138,14 +144,14 @@ TimeoutStopSec=20
[Install]
WantedBy=default.target
```
And `~/.config/systemd/user/slpmodularcms-production.service` — identical, with `test` replaced by
And `~/.config/systemd/user/slpsoftware-production.service` — identical, with `test` replaced by
`production` throughout (including the port inside `shared/env`).
Enable both (does not start them yet — nothing is deployed there until the first CI run):
```bash
systemctl --user daemon-reload
systemctl --user enable slpmodularcms-test.service
systemctl --user enable slpmodularcms-production.service
systemctl --user enable slpsoftware-test.service
systemctl --user enable slpsoftware-production.service
```
### 1.7 nginx Routing
@@ -177,12 +183,12 @@ feature — assumed already handled the same way the reference project's domains
### 1.8 Database Backup Credentials (§ 4 depends on this)
```bash
touch ~/.config/slpmodularcms-db-backup.env
chmod 600 ~/.config/slpmodularcms-db-backup.env
touch ~/.config/slpsoftware-db-backup.env
chmod 600 ~/.config/slpsoftware-db-backup.env
```
```ini
DB_SERVER=127.0.0.1,1433
DB_NAME=SlpModularCmsProduction
DB_NAME=SlpSoftwareProduction
DB_USER=<a-login-with-backup-database-permission>
DB_PASSWORD=<password>
```
@@ -202,10 +208,10 @@ change:
| `PI_MAIN_PORT` | secret | SSH port |
| `PI_MAIN_USERNAME` | secret | `gitea-workflow` — the generic, host-wide deploy account (§ 1.2), **not** `webadmin`; reuse the reference project's if it already has one |
| `PI_MAIN_PASSWORD` | secret | `gitea-workflow`'s password |
| `DEPLOY_PATH_TEST` | variable | `/home/gitea-workflow/apps/slpmodularcms/test` |
| `DEPLOY_PATH_PRODUCTION` | variable | `/home/gitea-workflow/apps/slpmodularcms/production` |
| `SERVICE_NAME_TEST` | variable | `slpmodularcms-test.service` |
| `SERVICE_NAME_PRODUCTION` | variable | `slpmodularcms-production.service` |
| `DEPLOY_PATH_TEST` | variable | `/home/gitea-workflow/apps/slpsoftware/test` |
| `DEPLOY_PATH_PRODUCTION` | variable | `/home/gitea-workflow/apps/slpsoftware/production` |
| `SERVICE_NAME_TEST` | variable | `slpsoftware-test.service` |
| `SERVICE_NAME_PRODUCTION` | variable | `slpsoftware-production.service` |
| `HEALTH_CHECK_URL_TEST` | variable | `https://test.slpsoftware.nl/health` |
| `HEALTH_CHECK_URL_PRODUCTION` | variable | `https://slpsoftware.nl/health` |
| `VITE_SENTRY_DSN` | variable | Sentry DSN (shared, not sensitive — safe in the client bundle) |
@@ -223,7 +229,7 @@ Already built (U5/U6) — this is the read-only walkthrough for whoever operates
2. `publish-test` runs (and `publish-production`, only if `workflow_dispatch` with the flag)
3. `deploy-test` (always, if gates pass) calls `deploy-scp.yaml`, which uploads into a new
`releases/{timestamp}/`, links `shared/wwwroot-web` in, switches `current`, restarts
`slpmodularcms-test.service`, verifies `https://test.slpsoftware.nl/health`, then prunes old
`slpsoftware-test.service`, verifies `https://test.slpsoftware.nl/health`, then prunes old
releases (only test — `run_db_backup: false`)
4. `deploy-production` (only with the flag) does the same, plus a database backup first
(`run_db_backup: true`) — see § 4
@@ -246,7 +252,7 @@ part of this repository, so no DB credential ever reaches Gitea):
set -euo pipefail
ENVIRONMENT="${1:?Usage: backup-slpmodularcms-db.sh <environment>}"
CREDENTIALS_FILE="$HOME/.config/slpmodularcms-db-backup.env"
CREDENTIALS_FILE="$HOME/.config/slpsoftware-db-backup.env"
if [[ ! -f "$CREDENTIALS_FILE" ]]; then
echo "Missing $CREDENTIALS_FILE — see deployment-instructions.md § 1.8" >&2
@@ -256,7 +262,7 @@ fi
source "$CREDENTIALS_FILE"
: "${DB_SERVER:?}" "${DB_NAME:?}" "${DB_USER:?}" "${DB_PASSWORD:?}"
BACKUP_DIR="$HOME/backups/slpmodularcms/${ENVIRONMENT}"
BACKUP_DIR="$HOME/backups/slpsoftware/${ENVIRONMENT}"
mkdir -p "$BACKUP_DIR"
TIMESTAMP=$(date -u +%Y%m%d%H%M%S)
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}-${TIMESTAMP}.bak"
@@ -278,7 +284,7 @@ chmod +x ~/scripts/backup-slpmodularcms-db.sh
```bash
~/scripts/backup-slpmodularcms-db.sh production
```
Confirm a `.bak` file appears under `~/backups/slpmodularcms/production/` and that `sqlcmd` didn't
Confirm a `.bak` file appears under `~/backups/slpsoftware/production/` and that `sqlcmd` didn't
silently fail (the script uses `set -euo pipefail`, so a real SQL error does propagate as a non-zero
exit — which fails the calling `deploy-scp.yaml` step, correctly blocking the deploy).