diff --git a/AGENTS.md b/AGENTS.md index e0ad73d..5a3d3a5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -32,7 +32,7 @@ Privates Portfolio von „eldov" (Jan Wagner), Domain `eldov.win`. Gegenstück z - **i18n:** DE als Default (ohne Prefix), EN unter `/en`. Routing über `proxy.ts` analog `w-make-com`. - **DB:** SQLite unter `DB_PATH` (Default `data/eldov.db`). Schema in `src/lib/schema.sql`, Seed in `src/lib/seed.ts`. Wird beim ersten Request automatisch initialisiert. - **Auth:** Single-User-Admin via `ADMIN_PASSWORD` + `SESSION_SECRET` (HMAC-signiertes HttpOnly-Cookie). `proxy.ts` schützt `/admin/*` und `/api/admin/*` (außer `/admin/login`, `/api/admin/login`). -- **Deploy:** `deploy-vps.sh` synct in Container `/opt/containers/eldov-portfolio` auf `free-warez.top`, 9router-Eintrag `eldov.win` → Container. +- **Deploy:** `./deploy.sh` (oder `./deploy-vps.sh`) synct in Container `/opt/containers/eldov-portfolio` auf `free-warez.win`, Traefik routet `eldov.win` und `www.eldov.win` → Container-Port 3000. ## Konventionen diff --git a/README.md b/README.md index a56dc08..c9072f6 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Beim ersten Request ohne DB wird automatisch migriert und mit dem Seed aus `src/ ## Deployment -`./deploy-vps.sh` synct nach `free-warez.top:/opt/containers/eldov-portfolio`. Build und Restart des Containers passieren dort. 9router-Eintrag `eldov.win` → Container-Internes `3000`. +`./deploy.sh` (oder `./deploy-vps.sh`) synct nach `free-warez.win:/opt/containers/eldov-portfolio`. Build und Restart des Containers passieren dort. Traefik routet `eldov.win` & `www.eldov.win` per Docker-Labels → Container-Internes 3000. ## DSGVO-Hinweis diff --git a/deploy-vps.sh b/deploy-vps.sh index 933ff4e..b756865 100755 --- a/deploy-vps.sh +++ b/deploy-vps.sh @@ -15,8 +15,23 @@ set -euo pipefail VPS_HOST="${VPS_HOST:-free-warez.win}" VPS_DIR="${VPS_DIR:-/opt/containers/eldov-portfolio}" +# 1. Check SSH connection echo "→ Prüfe SSH-Verbindung zu $VPS_HOST..." -ssh -o BatchMode=yes -o ConnectTimeout=10 "$VPS_HOST" "echo OK" >/dev/null +if ! ssh -q -o BatchMode=yes -o ConnectTimeout=10 "$VPS_HOST" exit; then + echo "❌ Keine SSH-Verbindung zu $VPS_HOST möglich." + exit 1 +fi + +# 2. Push git commits if in git repo +LOCAL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +if [ -d "$LOCAL_DIR/.git" ]; then + echo "→ Prüfe Git-Status..." + if ! git -C "$LOCAL_DIR" diff-index --quiet HEAD -- 2>/dev/null; then + echo "⚠️ Lokale uncommitted Änderungen vorhanden." + fi + echo "→ Pushe Commits nach Gitea..." + git -C "$LOCAL_DIR" push origin main 2>/dev/null || echo "ℹ️ Git push übersprungen oder bereits aktuell." +fi echo "→ Synchronisiere Quelldateien nach $VPS_HOST:$VPS_DIR" rsync -avz --delete \ @@ -35,6 +50,17 @@ ssh "$VPS_HOST" "cd '$VPS_DIR' && \ docker compose up -d app && \ docker image prune -f" -echo "✓ Deploy abgeschlossen. Healthcheck in 10 s…" -sleep 10 -ssh "$VPS_HOST" "docker inspect --format='{{.State.Health.Status}}' eldov-portfolio || echo 'no healthcheck yet'" +echo "✓ Deploy abgeschlossen. Healthcheck in 5 s…" +sleep 5 +echo -n " Docker Health: " +ssh "$VPS_HOST" "docker inspect --format='{{if .State.Health}}{{.State.Health.Status}}{{else}}no healthcheck{{end}}' eldov-portfolio" + +echo -n " Public URL (https://eldov.win): " +if curl -fs -o /dev/null --resolve eldov.win:443:217.160.217.196 -m 5 "https://eldov.win/"; then + echo "✅ 200 OK" +else + echo "⚠️ Nicht erreichbar" +fi + +echo "✨ Deployment erfolgreich beendet!" + diff --git a/deploy.sh b/deploy.sh new file mode 120000 index 0000000..709470a --- /dev/null +++ b/deploy.sh @@ -0,0 +1 @@ +deploy-vps.sh \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 3699cdc..ce7b3a1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,7 +14,7 @@ services: dockerfile: Dockerfile args: NEXT_PUBLIC_SITE_URL: ${NEXT_PUBLIC_SITE_URL:-https://eldov.win} - image: eldov-portfolio:latest + image: eldov-portfolio:1.0.0 container_name: eldov-portfolio mem_limit: 512m restart: unless-stopped @@ -49,9 +49,10 @@ services: - "traefik.http.routers.eldov-win.entrypoints=websecure" - "traefik.http.routers.eldov-win.tls=true" - "traefik.http.routers.eldov-win.tls.certresolver=http_resolver" - - "traefik.http.routers.eldov-win.middlewares=default@file,crowdsec-bouncer-plugin@file" + - "traefik.http.routers.eldov-win.middlewares=my-get-real-ip@file,default@file,crowdsec-bouncer-plugin@file" - "traefik.http.routers.eldov-win.service=eldov-win" - "traefik.http.services.eldov-win.loadbalancer.server.port=3000" + - "com.centurylinklabs.watchtower.enable=false" # HTTP→HTTPS-Redirect für die unverschlüsselte Variante (Traefik # bringt dafür eine eingebaute redirectScheme-Middleware mit). - "traefik.http.routers.eldov-win-http.rule=Host(`eldov.win`) || Host(`www.eldov.win`)" diff --git a/package.json b/package.json index 305170b..e92897c 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "start": "next start", "lint": "eslint", "test": "node --experimental-strip-types --test src/i18n/routes.test.ts src/lib/auth/session.test.ts", - "test:db": "node --experimental-strip-types src/lib/db/smoke.ts", + "test:db": "bash -c 'node --experimental-strip-types src/lib/db/smoke.ts'", "seed": "node --experimental-strip-types src/lib/db/seed-cli.ts" }, "dependencies": { diff --git a/src/lib/db/smoke.ts b/src/lib/db/smoke.ts index dde4c95..1aa5bc5 100644 --- a/src/lib/db/smoke.ts +++ b/src/lib/db/smoke.ts @@ -90,7 +90,7 @@ console.log("\n[2] Lesen + Schreiben"); } // Cleanup -__resetDbForTest(); +// __resetDbForTest(); try { rmSync(dir, { recursive: true, force: true }); } catch { @@ -102,4 +102,7 @@ console.log(`\n${failures === 0 ? "✓ smoke ok" : `✗ ${failures} failure(s)`} // Hinweis: Auf manchen Node-Versionen segfaultet better-sqlite3 beim // nativen Handle-Cleanup nach process.exit. Das ist kosmetisch — die Tests // oben sind alle grün. In Produktion (Docker, Node 22.13) tritt das nicht auf. -process.exit(failures === 0 ? 0 : 1); +if (failures > 0) { + process.exit(1); +} +