Set up automated deployment and configuration for SkillGuard
Some checks failed
Deploy to Production / deploy (push) Failing after 0s
Some checks failed
Deploy to Production / deploy (push) Failing after 0s
Configure deployment workflows, SSH settings, and environment variables for the SkillGuard project. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 0d01f99a-ea6a-447d-82fd-311715434a39 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: f938974b-4b4e-47df-8a70-53fbb1c1de6e Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/e32d2b99-1721-47dd-833c-98b372f48008/0d01f99a-ea6a-447d-82fd-311715434a39/b33cDqP Replit-Helium-Checkpoint-Created: true
This commit is contained in:
parent
dc6f01dd74
commit
86e9fb57ab
12 changed files with 623 additions and 0 deletions
24
.forgejo/workflows/deploy.yml
Normal file
24
.forgejo/workflows/deploy.yml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
name: Deploy to Production
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- name: Code aktualisieren
|
||||
run: |
|
||||
git -C /opt/skillguard fetch /opt/forgejo/data/git/repositories/avameo/skillguard.git main
|
||||
git -C /opt/skillguard reset --hard FETCH_HEAD
|
||||
|
||||
- name: Dependencies installieren
|
||||
run: npm ci --prefix /opt/skillguard
|
||||
|
||||
- name: Build ausführen
|
||||
run: npm run build --prefix /opt/skillguard
|
||||
|
||||
- name: Service neu starten
|
||||
run: sudo systemctl restart skillguard.service
|
||||
14
.ssh/config
Normal file
14
.ssh/config
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# >>> ANPASSEN: frei wählbarer Alias, mit dem du dich verbindest (z. B. ssh forgejo)
|
||||
Host <HOST_ALIAS_ANPASSEN>
|
||||
# >>> ANPASSEN: echte Server-Adresse oder IP
|
||||
HostName <HOSTNAME_ANPASSEN>
|
||||
Port 2222
|
||||
User git
|
||||
IdentityFile /home/runner/workspace/.ssh/id_ed25519_forgejo
|
||||
StrictHostKeyChecking no
|
||||
Host forgejo-skillguard.a42i.de
|
||||
HostName forgejo-skillguard.a42i.de
|
||||
Port 2222
|
||||
User git
|
||||
IdentityFile /home/runner/workspace/.ssh/id_ed25519_forgejo
|
||||
StrictHostKeyChecking no
|
||||
8
.ssh/id_ed25519_forgejo
Normal file
8
.ssh/id_ed25519_forgejo
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBJBy+0Tw
|
||||
MdthFIWzIa1SA8AAAAGAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIPLnSbMdI67Xkv2A
|
||||
AXxQsYExQAvd1/jdNd3u4LNJuVjvAAAAoGwXDrTwGpuHYYp2xFfb2YJ32C6fDGThaX6T/M
|
||||
U3HHNHi7nFip1UnOGrFJbVllGCKAxfNliyMiC712Pubu/utd3JXx5xe1xx9arv8t6B8hDm
|
||||
zWZoGnesrkgyf5IoaEBO4U8I9IwqI725LGQp1DpJozauzjf1NUvVc25VoCbQxrVoiih5OD
|
||||
fmdlsJKpWIVE2vvfXwBw2Eu3hdiXacPgbT/Qc=
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
0
hetzner-deployment/.gitkeep
Normal file
0
hetzner-deployment/.gitkeep
Normal file
104
hetzner-deployment/deploy-database-dump.sh
Executable file
104
hetzner-deployment/deploy-database-dump.sh
Executable file
|
|
@ -0,0 +1,104 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# =============================================================================
|
||||
# deploy-database-dump.sh
|
||||
# Erstellt einen PostgreSQL-Dump und uebertraegt ihn per SFTP auf die
|
||||
# Zielinstanz innerhalb der Hetzner-Infrastruktur.
|
||||
#
|
||||
# Verwendung: ./deploy-database-dump.sh <target>
|
||||
# Beispiel: ./deploy-database-dump.sh pilot1
|
||||
# =============================================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# --- Kontext laden ---
|
||||
source "${SCRIPT_DIR}/ssh_context.sh" "$@"
|
||||
|
||||
# --- SSH (Key wird geladen, Passphrase einmalig abgefragt) ---
|
||||
setup_ssh
|
||||
|
||||
# --- Datenbank-URL pruefen ---
|
||||
if [ -z "${DATABASE_URL:-}" ]; then
|
||||
echo "FEHLER: DATABASE_URL ist nicht gesetzt."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Dump erstellen ---
|
||||
BACKUP_DIR="/home/runner/workspace/backups"
|
||||
TIMESTAMP=$(node -e "const d=new Date();console.log(d.toISOString().replace(/[-:]/g,'').replace('T','_').slice(0,15))")
|
||||
DUMP_FILE="${BACKUP_DIR}/datadump_${TARGET}_${TIMESTAMP}.dump"
|
||||
SFTP_TARGET="/uploads/datadump.dump"
|
||||
|
||||
mkdir -p "${BACKUP_DIR}"
|
||||
|
||||
echo ""
|
||||
echo "=== Datenbank-Export ==="
|
||||
echo "Target: ${TARGET} (${DOMAIN})"
|
||||
echo "DB: ${DB_NAME}"
|
||||
echo "Ziel: ${DUMP_FILE}"
|
||||
echo ""
|
||||
|
||||
echo "Starte Datenbank-Export..."
|
||||
|
||||
pg_dump -Fc -d "$DATABASE_URL" -f "$DUMP_FILE" &
|
||||
DUMP_PID=$!
|
||||
|
||||
while kill -0 "$DUMP_PID" 2>/dev/null; do
|
||||
if [ -f "$DUMP_FILE" ]; then
|
||||
SIZE=$(du -h "$DUMP_FILE" 2>/dev/null | cut -f1)
|
||||
printf "\r Exportiert: %s ..." "$SIZE"
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
|
||||
wait "$DUMP_PID"
|
||||
DUMP_EXIT=$?
|
||||
|
||||
echo ""
|
||||
|
||||
if [ $DUMP_EXIT -ne 0 ] || [ ! -f "$DUMP_FILE" ]; then
|
||||
echo "FEHLER: Datenbank-Export fehlgeschlagen."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SIZE=$(du -h "$DUMP_FILE" | cut -f1)
|
||||
echo "Export fertig: ${DUMP_FILE} (${SIZE})"
|
||||
|
||||
sync
|
||||
|
||||
# --- SFTP-Transfer ---
|
||||
echo ""
|
||||
echo "=== SFTP-Upload ==="
|
||||
echo "Ziel: ${SFTP_HOST}:${SFTP_TARGET}"
|
||||
echo ""
|
||||
|
||||
sftp -P "${SFTP_PORT}" -i "${KEY_PATH}" "replit-user@${SFTP_HOST}" <<EOF
|
||||
put ${DUMP_FILE} ${SFTP_TARGET}
|
||||
bye
|
||||
EOF
|
||||
|
||||
SFTP_EXIT=$?
|
||||
|
||||
if [ $SFTP_EXIT -ne 0 ]; then
|
||||
echo "FEHLER: SFTP-Upload fehlgeschlagen (Exit-Code: ${SFTP_EXIT})."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Verifikation ---
|
||||
echo "Pruefe Upload..."
|
||||
REMOTE_CHECK=$(sftp -P "${SFTP_PORT}" -i "${KEY_PATH}" "replit-user@${SFTP_HOST}" <<EOF
|
||||
ls -l ${SFTP_TARGET}
|
||||
bye
|
||||
EOF
|
||||
2>&1)
|
||||
|
||||
if echo "$REMOTE_CHECK" | grep -q "datadump.dump"; then
|
||||
echo "Upload erfolgreich: Datei auf dem Server vorhanden."
|
||||
else
|
||||
echo "FEHLER: Datei wurde nicht auf dem Server gefunden."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Datenbank-Deployment fuer '${TARGET}' abgeschlossen ==="
|
||||
130
hetzner-deployment/deploy-full-release.sh
Executable file
130
hetzner-deployment/deploy-full-release.sh
Executable file
|
|
@ -0,0 +1,130 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# =============================================================================
|
||||
# deploy-full-release.sh
|
||||
# Fuehrt ein vollstaendiges Release durch: Datenbank-Dump + Code-Push.
|
||||
# Die Passwort-Abfrage erfolgt einmalig zu Beginn.
|
||||
#
|
||||
# Verwendung: ./deploy-full-release.sh <target>
|
||||
# Beispiel: ./deploy-full-release.sh pilot1
|
||||
# =============================================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# --- Kontext laden ---
|
||||
source "${SCRIPT_DIR}/ssh_context.sh" "$@"
|
||||
|
||||
# --- SSH (Key wird geladen, Passphrase einmalig abgefragt) ---
|
||||
setup_ssh
|
||||
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo " Full Release: ${TARGET} (${DOMAIN})"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
|
||||
# --- Phase 1: Datenbank ---
|
||||
echo "--- Phase 1/2: Datenbank-Deployment ---"
|
||||
echo ""
|
||||
|
||||
if [ -z "${DATABASE_URL:-}" ]; then
|
||||
echo "FEHLER: DATABASE_URL ist nicht gesetzt."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BACKUP_DIR="/home/runner/workspace/backups"
|
||||
TIMESTAMP=$(node -e "const d=new Date();console.log(d.toISOString().replace(/[-:]/g,'').replace('T','_').slice(0,15))")
|
||||
DUMP_FILE="${BACKUP_DIR}/datadump_${TARGET}_${TIMESTAMP}.dump"
|
||||
SFTP_TARGET="/uploads/datadump.dump"
|
||||
|
||||
mkdir -p "${BACKUP_DIR}"
|
||||
|
||||
echo "Starte Datenbank-Export..."
|
||||
echo "Ziel: ${DUMP_FILE}"
|
||||
|
||||
pg_dump -Fc -d "$DATABASE_URL" -f "$DUMP_FILE" &
|
||||
DUMP_PID=$!
|
||||
|
||||
while kill -0 "$DUMP_PID" 2>/dev/null; do
|
||||
if [ -f "$DUMP_FILE" ]; then
|
||||
SIZE=$(du -h "$DUMP_FILE" 2>/dev/null | cut -f1)
|
||||
printf "\r Exportiert: %s ..." "$SIZE"
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
|
||||
wait "$DUMP_PID"
|
||||
DUMP_EXIT=$?
|
||||
|
||||
echo ""
|
||||
|
||||
if [ $DUMP_EXIT -ne 0 ] || [ ! -f "$DUMP_FILE" ]; then
|
||||
echo "FEHLER: Datenbank-Export fehlgeschlagen."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SIZE=$(du -h "$DUMP_FILE" | cut -f1)
|
||||
echo "Export fertig: ${DUMP_FILE} (${SIZE})"
|
||||
|
||||
sync
|
||||
|
||||
echo "Uebertrage nach ${SFTP_HOST}:${SFTP_TARGET}..."
|
||||
|
||||
sftp -P "${SFTP_PORT}" -i "${KEY_PATH}" "replit-user@${SFTP_HOST}" <<EOF
|
||||
put ${DUMP_FILE} ${SFTP_TARGET}
|
||||
bye
|
||||
EOF
|
||||
|
||||
SFTP_EXIT=$?
|
||||
|
||||
if [ $SFTP_EXIT -ne 0 ]; then
|
||||
echo "FEHLER: SFTP-Upload fehlgeschlagen (Exit-Code: ${SFTP_EXIT})."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Pruefe Upload..."
|
||||
REMOTE_CHECK=$(sftp -P "${SFTP_PORT}" -i "${KEY_PATH}" "replit-user@${SFTP_HOST}" <<EOF
|
||||
ls -l ${SFTP_TARGET}
|
||||
bye
|
||||
EOF
|
||||
2>&1)
|
||||
|
||||
if echo "$REMOTE_CHECK" | grep -q "datadump.dump"; then
|
||||
echo "Upload erfolgreich."
|
||||
else
|
||||
echo "FEHLER: Datei wurde nicht auf dem Server gefunden."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "--- Phase 1/2: Datenbank-Deployment abgeschlossen ---"
|
||||
echo ""
|
||||
|
||||
# --- Phase 2: Code ---
|
||||
echo "--- Phase 2/2: Code-Deployment ---"
|
||||
echo ""
|
||||
|
||||
echo "Pruefe Git-Remote '${GIT_REMOTE}'..."
|
||||
if ! git remote get-url "${GIT_REMOTE}" &>/dev/null; then
|
||||
echo "FEHLER: Git-Remote '${GIT_REMOTE}' existiert nicht."
|
||||
git remote -v
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Starte Push: main -> ${GIT_REMOTE}..."
|
||||
git push "${GIT_REMOTE}" main --force
|
||||
|
||||
PUSH_EXIT=$?
|
||||
|
||||
if [ $PUSH_EXIT -ne 0 ]; then
|
||||
echo "FEHLER: Git-Push fehlgeschlagen (Exit-Code: ${PUSH_EXIT})."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "--- Phase 2/2: Code-Deployment abgeschlossen ---"
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo " Full Release fuer '${TARGET}' fertig"
|
||||
echo "========================================="
|
||||
46
hetzner-deployment/deploy-github-push.sh
Executable file
46
hetzner-deployment/deploy-github-push.sh
Executable file
|
|
@ -0,0 +1,46 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# =============================================================================
|
||||
# deploy-github-push.sh
|
||||
# Pusht den aktuellen main-Branch an das Forgejo-Remote der Zielinstanz.
|
||||
#
|
||||
# Verwendung: ./deploy-github-push.sh <target>
|
||||
# Beispiel: ./deploy-github-push.sh audit
|
||||
# =============================================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# --- Kontext laden ---
|
||||
source "${SCRIPT_DIR}/ssh_context.sh" "$@"
|
||||
|
||||
# --- SSH (Key wird geladen, Passphrase einmalig abgefragt) ---
|
||||
setup_ssh
|
||||
|
||||
# --- Git-Push ---
|
||||
echo ""
|
||||
echo "=== Code-Deployment ==="
|
||||
echo "Target: ${TARGET} (${DOMAIN})"
|
||||
echo "Remote: ${GIT_REMOTE}"
|
||||
echo ""
|
||||
|
||||
echo "Pruefe Git-Remote '${GIT_REMOTE}'..."
|
||||
if ! git remote get-url "${GIT_REMOTE}" &>/dev/null; then
|
||||
echo "FEHLER: Git-Remote '${GIT_REMOTE}' existiert nicht."
|
||||
echo "Verfuegbare Remotes:"
|
||||
git remote -v
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Starte Push: main -> ${GIT_REMOTE}..."
|
||||
git push "${GIT_REMOTE}" main --force
|
||||
|
||||
PUSH_EXIT=$?
|
||||
|
||||
if [ $PUSH_EXIT -ne 0 ]; then
|
||||
echo "FEHLER: Git-Push fehlgeschlagen (Exit-Code: ${PUSH_EXIT})."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Code-Deployment fuer '${TARGET}' abgeschlossen ==="
|
||||
106
hetzner-deployment/init.sh
Executable file
106
hetzner-deployment/init.sh
Executable file
|
|
@ -0,0 +1,106 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# =============================================================================
|
||||
# init.sh
|
||||
# Interaktive Einrichtung eines Deployment-Targets.
|
||||
# Fragt alle relevanten Werte ab (jeweils mit Beispiel) und speichert sie unter
|
||||
# targets/<target>.env. Danach koennen die Deploy-Scripts mit dem Target-Namen
|
||||
# aufgerufen werden (z. B. ./deploy-full-release.sh <target>).
|
||||
# =============================================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
TARGETS_DIR="${SCRIPT_DIR}/targets"
|
||||
|
||||
echo "==================================================="
|
||||
echo " Hetzner-Deployment: Target einrichten (init.sh)"
|
||||
echo "==================================================="
|
||||
echo ""
|
||||
echo "Die Eingaben werden gespeichert unter:"
|
||||
echo " ${TARGETS_DIR}/<target>.env"
|
||||
echo ""
|
||||
|
||||
if [ ! -t 0 ]; then
|
||||
echo "FEHLER: Kein interaktives Terminal. init.sh muss manuell ausgefuehrt werden."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Hilfsfunktionen ---
|
||||
|
||||
# Leerzeichen am Anfang/Ende entfernen.
|
||||
trim() {
|
||||
printf '%s' "$1" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'
|
||||
}
|
||||
|
||||
# Wert fuer sicheres Schreiben in single-quotes escapen: jedes ' wird zu '\''.
|
||||
# So kann der spaeter via 'source' geladene Wert keine Shell-Befehle ausloesen.
|
||||
esc() {
|
||||
printf "%s" "$1" | sed "s/'/'\\\\''/g"
|
||||
}
|
||||
|
||||
# Pflichtfeld abfragen (mit Beispiel im Prompt); leere Eingaben werden abgelehnt.
|
||||
# $1 = Beschreibung, $2 = Beispiel, $3 = Name der Zielvariablen.
|
||||
ask() {
|
||||
local prompt="$1" example="$2" __out="$3" value=""
|
||||
while true; do
|
||||
read -r -p "${prompt} (z. B. ${example}): " value
|
||||
value="$(trim "$value")"
|
||||
if [ -n "$value" ]; then
|
||||
printf -v "$__out" '%s' "$value"
|
||||
break
|
||||
fi
|
||||
echo " -> Eingabe darf nicht leer sein."
|
||||
done
|
||||
}
|
||||
|
||||
mkdir -p "${TARGETS_DIR}"
|
||||
|
||||
# --- Target-Name ---
|
||||
ask "Target-Name" "kwali8-landingpage" TARGET_NAME
|
||||
if ! printf '%s' "$TARGET_NAME" | grep -Eq '^[A-Za-z0-9._-]+$'; then
|
||||
echo "FEHLER: Target-Name darf nur Buchstaben, Zahlen sowie '.', '_' und '-' enthalten."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TARGET_FILE="${TARGETS_DIR}/${TARGET_NAME}.env"
|
||||
if [ -f "${TARGET_FILE}" ]; then
|
||||
echo ""
|
||||
echo "Hinweis: Target '${TARGET_NAME}' existiert bereits (${TARGET_FILE})."
|
||||
read -r -p "Ueberschreiben? [j/N]: " answer
|
||||
case "$(printf '%s' "$answer" | tr '[:upper:]' '[:lower:]')" in
|
||||
j|ja|y|yes) ;;
|
||||
*) echo "Abgebrochen. Es wurde nichts geaendert."; exit 0 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# --- Restliche Werte ---
|
||||
ask "SSH-Host (Forgejo-Server)" "forgejo-landing.kwali8.de" SSH_HOST
|
||||
ask "SFTP-Host (Zielserver)" "forgejo-landing.kwali8.de" SFTP_HOST
|
||||
ask "Datenbank-Name" "helium" DB_NAME
|
||||
ask "Git-Remote-Name" "kwali8-landingpage" GIT_REMOTE
|
||||
ask "Domain (Zielserver)" "kwali8.de" DOMAIN
|
||||
|
||||
# --- Speichern ---
|
||||
# Werte single-quoted und escaped schreiben, damit das spaetere 'source'
|
||||
# in ssh_context.sh keine Command-Substitution o. ae. ausfuehren kann.
|
||||
umask 077
|
||||
cat > "${TARGET_FILE}" <<EOF
|
||||
# Target-Konfiguration fuer '$(esc "$TARGET_NAME")'.
|
||||
# Erstellt von init.sh am $(date '+%Y-%m-%d %H:%M:%S').
|
||||
SSH_HOST='$(esc "$SSH_HOST")'
|
||||
SFTP_HOST='$(esc "$SFTP_HOST")'
|
||||
DB_NAME='$(esc "$DB_NAME")'
|
||||
GIT_REMOTE='$(esc "$GIT_REMOTE")'
|
||||
DOMAIN='$(esc "$DOMAIN")'
|
||||
EOF
|
||||
|
||||
echo ""
|
||||
echo "Gespeichert: ${TARGET_FILE}"
|
||||
echo ""
|
||||
echo "Naechste Schritte:"
|
||||
echo " - Git-Remote '${GIT_REMOTE}' anlegen, falls noch nicht vorhanden."
|
||||
echo " - Deployment starten, z. B.:"
|
||||
echo " ./deploy-full-release.sh ${TARGET_NAME}"
|
||||
echo ""
|
||||
163
hetzner-deployment/ssh_context.sh
Executable file
163
hetzner-deployment/ssh_context.sh
Executable file
|
|
@ -0,0 +1,163 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# =============================================================================
|
||||
# ssh_context.sh
|
||||
# Wird von den Deploy-Skripten gesourced.
|
||||
# Stellt Target-Aufloesung und SSH-Setup bereit.
|
||||
#
|
||||
# Targets werden NICHT mehr hartkodiert, sondern aus Konfigurationsdateien unter
|
||||
# targets/<target>.env geladen. Neue Targets legt man interaktiv mit ./init.sh an.
|
||||
#
|
||||
# Der SSH-Key (id_ed25519_forgejo) ist mit einer Passphrase verschluesselt.
|
||||
# setup_ssh() laedt ihn in einen temporaeren ssh-agent; dabei wird die
|
||||
# Passphrase einmalig abgefragt (Quelle: VaultWarden). Eine falsche Passphrase
|
||||
# kann den Key nicht entschluesseln -> Abbruch, keine SSH/SFTP-Verbindung.
|
||||
# Ein separates Passwort-Secret ist dadurch nicht mehr noetig.
|
||||
# =============================================================================
|
||||
|
||||
# --- Pfade ---
|
||||
CONTEXT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
TARGETS_DIR="${CONTEXT_DIR}/targets"
|
||||
|
||||
# --- Hilfsfunktion: verfuegbare Targets auflisten ---
|
||||
# Eine einzige Quelle fuer die Target-Liste (keine duplizierten Strings mehr).
|
||||
list_targets() {
|
||||
local found=""
|
||||
local f name
|
||||
if [ -d "${TARGETS_DIR}" ]; then
|
||||
for f in "${TARGETS_DIR}"/*.env; do
|
||||
[ -e "$f" ] || continue
|
||||
name="$(basename "$f" .env)"
|
||||
# 'example' ist nur eine Vorlage und kein echtes Target.
|
||||
[ "$name" = "example" ] && continue
|
||||
found="${found:+${found}, }${name}"
|
||||
done
|
||||
fi
|
||||
if [ -n "$found" ]; then
|
||||
echo "Verfuegbare Targets: ${found}"
|
||||
else
|
||||
echo "Keine Targets konfiguriert. Lege eines mit ./init.sh an."
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Target-Validierung ---
|
||||
TARGET="${1:-}"
|
||||
|
||||
if [ -z "$TARGET" ]; then
|
||||
echo "FEHLER: Target ist erforderlich."
|
||||
echo "Verwendung: $0 <target>"
|
||||
list_targets
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Target-Name auf sichere Zeichen beschraenken, bevor daraus ein Pfad gebaut
|
||||
# wird (verhindert Path-Traversal wie '../' und das Laden beliebiger Dateien).
|
||||
if ! printf '%s' "$TARGET" | grep -Eq '^[A-Za-z0-9._-]+$'; then
|
||||
echo "FEHLER: Ungueltiger Target-Name '${TARGET}'."
|
||||
echo "Erlaubt sind nur Buchstaben, Zahlen sowie '.', '_' und '-'."
|
||||
list_targets
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Target-Aufloesung (Config aus targets/<target>.env laden) ---
|
||||
TARGET_FILE="${TARGETS_DIR}/${TARGET}.env"
|
||||
|
||||
if [ ! -f "${TARGET_FILE}" ]; then
|
||||
echo "FEHLER: Unbekanntes Target '${TARGET}'."
|
||||
list_targets
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
source "${TARGET_FILE}"
|
||||
|
||||
# Pflichtfelder pruefen, damit kaputte Configs frueh auffallen.
|
||||
for _var in SSH_HOST SFTP_HOST DB_NAME GIT_REMOTE DOMAIN; do
|
||||
if [ -z "${!_var:-}" ]; then
|
||||
echo "FEHLER: '${_var}' fehlt oder ist leer in ${TARGET_FILE}."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
unset _var
|
||||
|
||||
export TARGET SSH_HOST SFTP_HOST DB_NAME GIT_REMOTE DOMAIN
|
||||
|
||||
echo "Target: ${TARGET} (${DOMAIN})"
|
||||
|
||||
# --- SSH-Setup ---
|
||||
setup_ssh() {
|
||||
WORKSPACE_SSH_DIR="/home/runner/workspace/.ssh"
|
||||
KEY_PATH="${WORKSPACE_SSH_DIR}/id_ed25519_forgejo"
|
||||
local FORGEJO_SSH_PORT="2222"
|
||||
SFTP_PORT="2022"
|
||||
|
||||
mkdir -p "${WORKSPACE_SSH_DIR}"
|
||||
|
||||
# SSH-Config fuer den aktuellen Host erstellen/aktualisieren
|
||||
local TEMP_CONFIG
|
||||
TEMP_CONFIG=$(mktemp)
|
||||
|
||||
if [ -f "${WORKSPACE_SSH_DIR}/config" ]; then
|
||||
# Bestehende Eintraege fuer diesen Host entfernen
|
||||
awk -v host="${SSH_HOST}" '
|
||||
/^Host / { skip = ($2 == host); }
|
||||
!skip { print; }
|
||||
' "${WORKSPACE_SSH_DIR}/config" > "${TEMP_CONFIG}"
|
||||
else
|
||||
touch "${TEMP_CONFIG}"
|
||||
fi
|
||||
|
||||
cat >> "${TEMP_CONFIG}" <<EOF
|
||||
Host ${SSH_HOST}
|
||||
HostName ${SSH_HOST}
|
||||
Port ${FORGEJO_SSH_PORT}
|
||||
User git
|
||||
IdentityFile ${KEY_PATH}
|
||||
StrictHostKeyChecking no
|
||||
EOF
|
||||
|
||||
mv "${TEMP_CONFIG}" "${WORKSPACE_SSH_DIR}/config"
|
||||
# Git speichert keine 0600-Rechte -> nach Checkout/Reset liegt der Key auf 0644,
|
||||
# was ssh-add ablehnt. Rechte hier korrigieren und Fehler sichtbar machen.
|
||||
if ! chmod 600 "${KEY_PATH}"; then
|
||||
echo "FEHLER: Konnte Rechte auf ${KEY_PATH} nicht auf 600 setzen."
|
||||
exit 1
|
||||
fi
|
||||
chmod 644 "${WORKSPACE_SSH_DIR}/config"
|
||||
|
||||
# Symlinks ins Home-Verzeichnis
|
||||
mkdir -p ~/.ssh
|
||||
ln -sf "${WORKSPACE_SSH_DIR}/config" ~/.ssh/config
|
||||
ln -sf "${KEY_PATH}" ~/.ssh/id_ed25519_forgejo
|
||||
ln -sf "${KEY_PATH}.pub" ~/.ssh/id_ed25519_forgejo.pub
|
||||
|
||||
# --- Verschluesselten Key in ssh-agent laden (Passphrase-Abfrage) ---
|
||||
if [ ! -f "${KEY_PATH}" ]; then
|
||||
echo "FEHLER: SSH-Key nicht gefunden: ${KEY_PATH}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ssh-add fragt die Passphrase ueber das Terminal ab.
|
||||
if [ ! -t 0 ]; then
|
||||
echo "FEHLER: Kein interaktives Terminal. Skript muss manuell ausgefuehrt werden."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Frischen ssh-agent starten und beim Script-Ende automatisch beenden,
|
||||
# damit der entschluesselte Key nur waehrend der Laufzeit im Speicher liegt.
|
||||
eval "$(ssh-agent -s)" >/dev/null
|
||||
trap 'ssh-agent -k >/dev/null 2>&1 || true' EXIT
|
||||
|
||||
echo "Lade SSH-Key in den Agent (Passphrase erforderlich; siehe VaultWarden)..."
|
||||
if ! ssh-add "${KEY_PATH}"; then
|
||||
echo "FEHLER: SSH-Key konnte nicht geladen werden (falsche Passphrase?)."
|
||||
exit 1
|
||||
fi
|
||||
echo "SSH-Key geladen."
|
||||
|
||||
echo "SSH-Setup fuer ${SSH_HOST} abgeschlossen."
|
||||
|
||||
# Exportiere Pfade fuer andere Skripte
|
||||
export WORKSPACE_SSH_DIR KEY_PATH SFTP_PORT
|
||||
}
|
||||
14
hetzner-deployment/targets/example.env
Normal file
14
hetzner-deployment/targets/example.env
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Beispiel-Target-Konfiguration (Vorlage / Referenz).
|
||||
#
|
||||
# Diese Datei wird von ssh_context.sh bei der Target-Liste IGNORIERT
|
||||
# (Dateiname 'example.env'). Sie dient nur als Vorlage.
|
||||
#
|
||||
# Ein echtes Target legst du am einfachsten interaktiv an:
|
||||
# ./init.sh
|
||||
# Alternativ diese Datei nach targets/<target>.env kopieren und anpassen.
|
||||
|
||||
SSH_HOST="forgejo-landing.kwali8.de"
|
||||
SFTP_HOST="forgejo-landing.kwali8.de"
|
||||
DB_NAME="helium"
|
||||
GIT_REMOTE="kwali8-landingpage"
|
||||
DOMAIN="kwali8.de"
|
||||
7
hetzner-deployment/targets/kwali8-landingpage.env
Normal file
7
hetzner-deployment/targets/kwali8-landingpage.env
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# Target-Konfiguration fuer 'kwali8-landingpage' (Beispiel-Target / Referenz).
|
||||
# Erstellt von init.sh oder manuell. Wird von ssh_context.sh geladen.
|
||||
SSH_HOST="forgejo-landing.kwali8.de"
|
||||
SFTP_HOST="forgejo-landing.kwali8.de"
|
||||
DB_NAME="helium"
|
||||
GIT_REMOTE="kwali8-landingpage"
|
||||
DOMAIN="kwali8.de"
|
||||
7
hetzner-deployment/targets/skillguard.env
Normal file
7
hetzner-deployment/targets/skillguard.env
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# Target-Konfiguration fuer 'skillguard'.
|
||||
# Erstellt von init.sh am 2026-06-18 15:10:32.
|
||||
SSH_HOST='forgejo-skillguard.a42i.de'
|
||||
SFTP_HOST='forgejo-skillguard.a42i.de'
|
||||
DB_NAME='helium'
|
||||
GIT_REMOTE='skillguard'
|
||||
DOMAIN='a42i.de'
|
||||
Loading…
Add table
Reference in a new issue