Update deployment script to ensure persistent data management, enhance backup and restore processes, and improve error handling. Modify .gitignore to exclude sensitive production data and update deployment documentation to reflect changes. Add environment variable loading for production secrets in configuration files.
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 48s

This commit is contained in:
Torsten Schulz (local)
2026-01-07 17:42:04 +01:00
parent 371fef25d7
commit 225e930e4c
6 changed files with 127 additions and 33 deletions

11
.gitignore vendored
View File

@@ -149,11 +149,8 @@ gitleaks
gitleaks.tar.gz gitleaks.tar.gz
osv-scanner osv-scanner
# Sensitive data (DO NOT commit production sessions!) # Sensitive / production data (DO NOT commit!)
# server/data/sessions.json - uncomment for production server/data/**
public/uploads
public/uploads/*
# Server data files (all data files to prevent overwriting)
server/data/
!server/data/.gitkeep !server/data/.gitkeep
public/data/**
public/uploads/**

View File

@@ -119,7 +119,7 @@ pm2 save
## Notizen ## Notizen
- **`.output/` ist NICHT im Git** (steht in `.gitignore`) - **`.output/` ist NICHT im Git** (steht in `.gitignore`)
- **Produktivdaten SIND im Git** (werden versioniert) - **Produktivdaten SOLLEN NICHT im Git sein** (werden per `.gitignore` ausgeschlossen und in Produktion außerhalb des Repos persistiert, z.B. unter `/var/lib/harheimertc`)
- **Bei Deployment:** Immer Backup → Build → Restore - **Bei Deployment:** Immer Backup → Build → Restore
- **Bei Problemen:** Script verwenden oder manuell Daten sichern - **Bei Problemen:** Script verwenden oder manuell Daten sichern

View File

@@ -1,10 +1,55 @@
#!/bin/bash #!/bin/bash
set -euo pipefail
# Immer im Repo-Verzeichnis arbeiten (wichtig für Backup/Restore mit relativen Pfaden)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# Deployment Script für Harheimer TC Website # Deployment Script für Harheimer TC Website
# Sichert Produktivdaten vor dem Build und stellt sie danach wieder her # Sichert Produktivdaten vor dem Build und stellt sie danach wieder her
echo "=== Harheimer TC Deployment ===" echo "=== Harheimer TC Deployment ==="
echo "" echo ""
echo "Working directory: $(pwd)"
echo ""
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
echo "ERROR: Dieses Script muss im Git-Repository ausgeführt werden (kein .git gefunden)."
exit 1
fi
# Optional (empfohlen): Persistente Daten außerhalb des Git-Repos halten und per Symlink einbinden.
# Das verhindert zuverlässig, dass Git jemals Produktivdaten überschreibt.
DATA_ROOT="${DATA_ROOT:-/var/lib/harheimertc}"
mkdir -p "$DATA_ROOT"
ensure_symlink_dir() {
local src="$1" # z.B. server/data
local target="$2" # z.B. /var/lib/harheimertc/server-data
mkdir -p "$(dirname "$src")"
mkdir -p "$target"
if [ -L "$src" ]; then
return 0
fi
if [ -d "$src" ]; then
echo " Moving $src -> $target (first-time migration)"
# Merge existing content into target
cp -a "$src/." "$target/" || true
rm -rf "$src"
fi
ln -s "$target" "$src"
echo " Linked $src -> $target"
}
echo "0. Ensuring persistent data directories (recommended)..."
ensure_symlink_dir "server/data" "$DATA_ROOT/server-data"
ensure_symlink_dir "public/data" "$DATA_ROOT/public-data"
ensure_symlink_dir "public/uploads" "$DATA_ROOT/public-uploads"
echo ""
# 1. BACKUP: Laufende Produktivdaten VOR allen Git-Operationen sichern # 1. BACKUP: Laufende Produktivdaten VOR allen Git-Operationen sichern
echo "1. Backing up current production data (pre-git)..." echo "1. Backing up current production data (pre-git)..."
@@ -14,9 +59,21 @@ rm -rf .backup
mkdir -p .backup mkdir -p .backup
# Backup server data (JSON) und CSVs immer vom Dateisystem, nicht aus 'stash' # Backup server data (JSON) und CSVs immer vom Dateisystem, nicht aus 'stash'
cp -a server/data .backup/data_backup 2>/dev/null || echo " No server/data to backup" if [ -d server/data ]; then
cp -a server/data .backup/data_backup
echo " Backed up server/data -> .backup/data_backup"
else
echo "ERROR: server/data existiert nicht. Abbruch, damit wir keine Repo-Defaults ausrollen."
exit 1
fi
mkdir -p .backup/public_data mkdir -p .backup/public_data
cp -a public/data/*.csv .backup/public_data/ 2>/dev/null || echo " No public CSVs to backup" if ls public/data/*.csv >/dev/null 2>&1; then
cp -a public/data/*.csv .backup/public_data/
echo " Backed up public/data/*.csv -> .backup/public_data/"
else
echo " No public CSVs to backup (public/data/*.csv not found)"
fi
# 2. Handle local changes and Git Pull # 2. Handle local changes and Git Pull
echo "2. Handling local changes and pulling latest from git..." echo "2. Handling local changes and pulling latest from git..."
@@ -29,15 +86,11 @@ fi
# Stash any local changes (including production data) # Stash any local changes (including production data)
echo " Stashing local changes..." echo " Stashing local changes..."
git stash push -m "Production deployment stash $(date)" git stash push -m "Production deployment stash $(date)" || true
# Pull latest changes # Pull latest changes
echo " Pulling latest changes..." echo " Pulling latest changes..."
git pull git pull
if [ $? -ne 0 ]; then
echo "ERROR: Git pull failed!"
exit 1
fi
# Reset any accidental changes from stash restore (should be none now) # Reset any accidental changes from stash restore (should be none now)
git reset --hard HEAD >/dev/null 2>&1 git reset --hard HEAD >/dev/null 2>&1
@@ -46,10 +99,6 @@ git reset --hard HEAD >/dev/null 2>&1
echo "" echo ""
echo "3. Installing dependencies..." echo "3. Installing dependencies..."
npm install npm install
if [ $? -ne 0 ]; then
echo "ERROR: npm install failed!"
exit 1
fi
# 4. Remove old build (but keep data!) # 4. Remove old build (but keep data!)
echo "" echo ""
@@ -60,31 +109,36 @@ rm -rf .output
echo "" echo ""
echo "5. Building application..." echo "5. Building application..."
npm run build npm run build
if [ $? -ne 0 ]; then
echo "ERROR: Build failed!"
exit 1
fi
# 6. Restore Production Data (überschreibe Repo-Defaults mit Backup) # 6. Restore Production Data (überschreibe Repo-Defaults mit Backup)
echo "" echo ""
echo "6. Restoring production data..." echo "6. Restoring production data..."
# Stelle server/data vollständig wieder her (inkl. config.json, users.json, news.json, sessions.json, members.json, membership-applications) # Stelle server/data vollständig wieder her (inkl. config.json, users.json, news.json, sessions.json, members.json, membership-applications)
if [ -d .backup/data_backup ]; then if [ ! -d .backup/data_backup ]; then
mkdir -p server/data echo "ERROR: Backup-Verzeichnis .backup/data_backup fehlt. Abbruch."
cp -a .backup/data_backup/. server/data/ exit 1
else
echo "No server/data to restore"
fi fi
mkdir -p server/data
cp -a .backup/data_backup/. server/data/
echo " Restored server/data from backup."
# Stelle alle CSVs wieder her # Stelle alle CSVs wieder her
if ls .backup/public_data/*.csv >/dev/null 2>&1; then if ls .backup/public_data/*.csv >/dev/null 2>&1; then
mkdir -p public/data mkdir -p public/data
cp -a .backup/public_data/*.csv public/data/ cp -a .backup/public_data/*.csv public/data/
echo " Restored public/data/*.csv from backup."
else else
echo "No public CSVs to restore" echo "No public CSVs to restore"
fi fi
# Sanity Check: users.json muss existieren und darf nicht leer sein
if [ ! -s server/data/users.json ]; then
echo "ERROR: server/data/users.json fehlt oder ist leer nach Restore. Abbruch."
exit 1
fi
# 7. Cleanup backup and stash # 7. Cleanup backup and stash
echo "" echo ""
echo "7. Cleaning up backup and stash..." echo "7. Cleaning up backup and stash..."

View File

@@ -1,3 +1,11 @@
// Load environment variables from .env (production secrets)
try {
// eslint-disable-next-line global-require
require('dotenv').config({ path: '/var/www/harheimertc/.env' })
} catch (_e) {
// If dotenv isn't available or .env missing, continue (process.env may be set elsewhere)
}
module.exports = { module.exports = {
apps: [{ apps: [{
name: 'harheimertc', name: 'harheimertc',
@@ -10,7 +18,32 @@ module.exports = {
max_memory_restart: '1G', max_memory_restart: '1G',
env: { env: {
NODE_ENV: 'production', NODE_ENV: 'production',
PORT: 3100 PORT: 3100,
// Secrets/Config (loaded from .env above, if present)
ENCRYPTION_KEY: process.env.ENCRYPTION_KEY,
JWT_SECRET: process.env.JWT_SECRET,
SMTP_HOST: process.env.SMTP_HOST,
SMTP_PORT: process.env.SMTP_PORT,
SMTP_USER: process.env.SMTP_USER,
SMTP_PASS: process.env.SMTP_PASS,
SMTP_FROM: process.env.SMTP_FROM,
SMTP_ADMIN: process.env.SMTP_ADMIN,
NUXT_PUBLIC_BASE_URL: process.env.NUXT_PUBLIC_BASE_URL,
COOKIE_SECURE: process.env.COOKIE_SECURE,
COOKIE_SAMESITE: process.env.COOKIE_SAMESITE,
CSP_ENABLED: process.env.CSP_ENABLED,
CSP_REPORT_ONLY: process.env.CSP_REPORT_ONLY,
CSP_VALUE: process.env.CSP_VALUE,
HIBP_ENABLED: process.env.HIBP_ENABLED,
HIBP_USER_AGENT: process.env.HIBP_USER_AGENT,
HIBP_TIMEOUT_MS: process.env.HIBP_TIMEOUT_MS,
HIBP_CACHE_TTL_MS: process.env.HIBP_CACHE_TTL_MS,
HIBP_FAIL_CLOSED: process.env.HIBP_FAIL_CLOSED,
AUDIT_LOG_ENABLED: process.env.AUDIT_LOG_ENABLED,
WEBAUTHN_ORIGIN: process.env.WEBAUTHN_ORIGIN,
WEBAUTHN_RP_ID: process.env.WEBAUTHN_RP_ID,
WEBAUTHN_RP_NAME: process.env.WEBAUTHN_RP_NAME,
WEBAUTHN_REQUIRE_UV: process.env.WEBAUTHN_REQUIRE_UV
}, },
error_file: '/var/log/pm2/harheimertc-error.log', error_file: '/var/log/pm2/harheimertc-error.log',
out_file: '/var/log/pm2/harheimertc-out.log', out_file: '/var/log/pm2/harheimertc-out.log',

View File

@@ -1,3 +1,11 @@
// Load environment variables from .env (production secrets)
try {
// eslint-disable-next-line global-require
require('dotenv').config({ path: '/var/www/harheimertc/.env' })
} catch (_e) {
// ignore
}
module.exports = { module.exports = {
apps: [{ apps: [{
name: 'harheimertc', name: 'harheimertc',
@@ -9,7 +17,9 @@ module.exports = {
max_memory_restart: '1G', max_memory_restart: '1G',
env: { env: {
NODE_ENV: 'production', NODE_ENV: 'production',
PORT: 3100 PORT: 3100,
ENCRYPTION_KEY: process.env.ENCRYPTION_KEY,
JWT_SECRET: process.env.JWT_SECRET
} }
}] }]
} }

6
package-lock.json generated
View File

@@ -11374,9 +11374,9 @@
} }
}, },
"node_modules/qs": { "node_modules/qs": {
"version": "6.14.0", "version": "6.14.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
"dev": true, "dev": true,
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {