This commit is contained in:
56
.gitea/workflows/deploy.yml
Normal file
56
.gitea/workflows/deploy.yml
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
name: Deploy SingleChat
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
env:
|
||||||
|
SSH_HOST: ${{ vars.PROD_HOST }}
|
||||||
|
SSH_PORT: ${{ vars.PROD_PORT }}
|
||||||
|
SSH_USER: ${{ vars.PROD_USER }}
|
||||||
|
DEPLOY_SCRIPT: ${{ vars.PROD_DEPLOY_SCRIPT }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Show resolved non-secret config
|
||||||
|
run: |
|
||||||
|
echo "SSH_HOST=$SSH_HOST"
|
||||||
|
echo "SSH_PORT=$SSH_PORT"
|
||||||
|
echo "SSH_USER=$SSH_USER"
|
||||||
|
echo "DEPLOY_SCRIPT=${DEPLOY_SCRIPT:-/usr/local/bin/actualize-singlechat.sh}"
|
||||||
|
|
||||||
|
- name: Prepare SSH
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
printf '%s' "${{ secrets.PROD_SSH_KEY_B64 }}" | base64 -d > ~/.ssh/id_deploy
|
||||||
|
chmod 600 ~/.ssh/id_deploy
|
||||||
|
ssh-keygen -l -f ~/.ssh/id_deploy
|
||||||
|
ssh-keyscan -p "$SSH_PORT" "$SSH_HOST" >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
- name: Test SSH connection
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
ssh -i ~/.ssh/id_deploy \
|
||||||
|
-o StrictHostKeyChecking=no \
|
||||||
|
-o BatchMode=yes \
|
||||||
|
-o ConnectTimeout=10 \
|
||||||
|
-p "$SSH_PORT" \
|
||||||
|
"$SSH_USER@$SSH_HOST" \
|
||||||
|
"echo SSH OK"
|
||||||
|
|
||||||
|
- name: Run deployment script
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
script="${DEPLOY_SCRIPT:-/usr/local/bin/actualize-singlechat.sh}"
|
||||||
|
ssh -i ~/.ssh/id_deploy \
|
||||||
|
-o StrictHostKeyChecking=no \
|
||||||
|
-o BatchMode=yes \
|
||||||
|
-o ConnectTimeout=10 \
|
||||||
|
-p "$SSH_PORT" \
|
||||||
|
"$SSH_USER@$SSH_HOST" \
|
||||||
|
"$script"
|
||||||
@@ -53,6 +53,24 @@ sudo journalctl -u ypchat -f
|
|||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
## Auto-Rollout mit Gitea
|
||||||
|
|
||||||
|
Der Workflow `.gitea/workflows/deploy.yml` startet bei Push auf `main` per SSH das Server-Skript `/usr/local/bin/actualize-singlechat.sh`.
|
||||||
|
|
||||||
|
Gitea-Konfiguration:
|
||||||
|
|
||||||
|
- Variables: `PROD_HOST`, `PROD_PORT`, `PROD_USER`
|
||||||
|
- Optional: `PROD_DEPLOY_SCRIPT`, falls der Skriptpfad abweicht
|
||||||
|
- Secret: `PROD_SSH_KEY_B64` mit dem base64-kodierten privaten Deploy-Key
|
||||||
|
|
||||||
|
Server-Skript installieren:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo install -m 755 scripts/actualize-singlechat.sh /usr/local/bin/actualize-singlechat.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Das Skript aktualisiert `/opt/ypchat`, baut den Client neu und startet `ypchat` per systemd neu.
|
||||||
|
|
||||||
### Service startet nicht
|
### Service startet nicht
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -86,4 +104,3 @@ cd /opt/ypchat
|
|||||||
sudo -u www-data npm run build
|
sudo -u www-data npm run build
|
||||||
sudo -u www-data cp -r client/dist docroot/
|
sudo -u www-data cp -r client/dist docroot/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,28 @@ sudo systemctl stop singlechat
|
|||||||
|
|
||||||
## Updates
|
## Updates
|
||||||
|
|
||||||
|
### Automatisch per Gitea Actions
|
||||||
|
|
||||||
|
Der Workflow `.gitea/workflows/deploy.yml` deployt bei jedem Push auf `main` per SSH auf den Produktionsserver und startet dort das Rollout-Skript.
|
||||||
|
|
||||||
|
In Gitea müssen dafür gesetzt sein:
|
||||||
|
|
||||||
|
- Repository Variables:
|
||||||
|
- `PROD_HOST`: Produktionsserver, z.B. `tsschulz.de`
|
||||||
|
- `PROD_PORT`: SSH-Port, z.B. `2222`
|
||||||
|
- `PROD_USER`: SSH-User für den Deploy
|
||||||
|
- `PROD_DEPLOY_SCRIPT`: optional, Standard ist `/usr/local/bin/actualize-singlechat.sh`
|
||||||
|
- Repository Secret:
|
||||||
|
- `PROD_SSH_KEY_B64`: privater SSH-Key base64-kodiert
|
||||||
|
|
||||||
|
Auf dem Produktionsserver das Rollout-Skript installieren:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo install -m 755 scripts/actualize-singlechat.sh /usr/local/bin/actualize-singlechat.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Das Skript aktualisiert `/opt/ypchat` aus `ssh://git@tsschulz.de:2222/torsten/singlechat`, installiert Dependencies mit `npm ci`, baut den Client, aktualisiert `docroot/dist` und startet `ypchat` neu. Bei Bedarf können `APP_DIR`, `REPO_URL`, `BRANCH` und `SERVICE_NAME` als Environment-Variablen überschrieben werden.
|
||||||
|
|
||||||
Nach Code-Änderungen:
|
Nach Code-Änderungen:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -159,4 +181,3 @@ Die folgenden Umgebungsvariablen können in `.env` gesetzt werden:
|
|||||||
- **HTTPS**: Stelle sicher, dass SSL/TLS korrekt konfiguriert ist
|
- **HTTPS**: Stelle sicher, dass SSL/TLS korrekt konfiguriert ist
|
||||||
- **Firewall**: Port 4000 sollte nur von localhost erreichbar sein
|
- **Firewall**: Port 4000 sollte nur von localhost erreichbar sein
|
||||||
- **Updates**: Halte Node.js und alle Dependencies aktuell
|
- **Updates**: Halte Node.js und alle Dependencies aktuell
|
||||||
|
|
||||||
|
|||||||
149
scripts/actualize-singlechat.sh
Executable file
149
scripts/actualize-singlechat.sh
Executable file
@@ -0,0 +1,149 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
APP_DIR="${APP_DIR:-/opt/ypchat}"
|
||||||
|
REPO_URL="${REPO_URL:-ssh://git@tsschulz.de:2222/torsten/singlechat}"
|
||||||
|
BRANCH="${BRANCH:-main}"
|
||||||
|
SERVICE_NAME="${SERVICE_NAME:-ypchat}"
|
||||||
|
RUN_USER="${RUN_USER:-www-data}"
|
||||||
|
RUN_GROUP="${RUN_GROUP:-www-data}"
|
||||||
|
LOCK_FILE="${LOCK_FILE:-/tmp/actualize-singlechat.lock}"
|
||||||
|
NPM_CACHE_DIR="${NPM_CACHE_DIR:-$APP_DIR/.npm-cache}"
|
||||||
|
|
||||||
|
log() {
|
||||||
|
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_as_app_user() {
|
||||||
|
if [ "$(id -u)" -eq 0 ]; then
|
||||||
|
sudo -u "$RUN_USER" env HOME="$APP_DIR" npm_config_cache="$NPM_CACHE_DIR" "$@"
|
||||||
|
else
|
||||||
|
env HOME="$APP_DIR" npm_config_cache="$NPM_CACHE_DIR" "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
need_cmd() {
|
||||||
|
if ! command -v "$1" >/dev/null 2>&1; then
|
||||||
|
echo "FEHLER: $1 ist nicht installiert." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
need_cmd git
|
||||||
|
need_cmd npm
|
||||||
|
need_cmd node
|
||||||
|
need_cmd rsync
|
||||||
|
need_cmd flock
|
||||||
|
need_cmd openssl
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
need_cmd sudo
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec 9>"$LOCK_FILE"
|
||||||
|
if ! flock -n 9; then
|
||||||
|
echo "Deployment laeuft bereits: $LOCK_FILE" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Starte SingleChat Rollout"
|
||||||
|
log "APP_DIR=$APP_DIR"
|
||||||
|
log "REPO_URL=$REPO_URL"
|
||||||
|
log "BRANCH=$BRANCH"
|
||||||
|
log "SERVICE_NAME=$SERVICE_NAME"
|
||||||
|
|
||||||
|
mkdir -p "$APP_DIR" "$NPM_CACHE_DIR"
|
||||||
|
|
||||||
|
if [ ! -d "$APP_DIR/.git" ]; then
|
||||||
|
log "Erstelle initialen Git-Checkout fuer $APP_DIR"
|
||||||
|
tmp_checkout="$(mktemp -d)"
|
||||||
|
git clone --branch "$BRANCH" --single-branch "$REPO_URL" "$tmp_checkout"
|
||||||
|
rsync -a --delete \
|
||||||
|
--exclude '.env' \
|
||||||
|
--exclude '.npm-cache/' \
|
||||||
|
--exclude 'logs/' \
|
||||||
|
--exclude 'tmp/' \
|
||||||
|
"$tmp_checkout/" "$APP_DIR/"
|
||||||
|
rm -rf "$tmp_checkout"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$(id -u)" -eq 0 ]; then
|
||||||
|
chown -R "$RUN_USER:$RUN_GROUP" "$APP_DIR" "$NPM_CACHE_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "$APP_DIR"
|
||||||
|
|
||||||
|
if ! git remote get-url origin >/dev/null 2>&1; then
|
||||||
|
git remote add origin "$REPO_URL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
current_origin="$(git remote get-url origin)"
|
||||||
|
if [ "$current_origin" != "$REPO_URL" ]; then
|
||||||
|
log "Setze Git-Origin von $current_origin auf $REPO_URL"
|
||||||
|
git remote set-url origin "$REPO_URL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Hole neuesten Stand"
|
||||||
|
git fetch --prune origin "$BRANCH"
|
||||||
|
git reset --hard "origin/$BRANCH"
|
||||||
|
git clean -fd \
|
||||||
|
-e .env \
|
||||||
|
-e .npm-cache/ \
|
||||||
|
-e logs/ \
|
||||||
|
-e tmp/ \
|
||||||
|
-e docroot/dist/
|
||||||
|
|
||||||
|
if [ "$(id -u)" -eq 0 ]; then
|
||||||
|
chown -R "$RUN_USER:$RUN_GROUP" "$APP_DIR" "$NPM_CACHE_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Installiere Root-Dependencies"
|
||||||
|
run_as_app_user npm ci
|
||||||
|
|
||||||
|
log "Installiere Client-Dependencies"
|
||||||
|
run_as_app_user npm --prefix client ci
|
||||||
|
|
||||||
|
if [ ! -f "$APP_DIR/.env" ]; then
|
||||||
|
log "Erstelle .env"
|
||||||
|
session_secret="$(openssl rand -hex 32)"
|
||||||
|
cat > "$APP_DIR/.env" <<EOF
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=4000
|
||||||
|
SESSION_SECRET=$session_secret
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$(id -u)" -eq 0 ]; then
|
||||||
|
chown "$RUN_USER:$RUN_GROUP" "$APP_DIR/.env"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Baue Client"
|
||||||
|
run_as_app_user npm run build
|
||||||
|
|
||||||
|
log "Aktualisiere docroot/dist"
|
||||||
|
rm -rf "$APP_DIR/docroot/dist"
|
||||||
|
cp -r "$APP_DIR/client/dist" "$APP_DIR/docroot/dist"
|
||||||
|
|
||||||
|
mkdir -p "$APP_DIR/logs" "$APP_DIR/tmp"
|
||||||
|
if [ "$(id -u)" -eq 0 ]; then
|
||||||
|
chown -R "$RUN_USER:$RUN_GROUP" "$APP_DIR/docroot/dist" "$APP_DIR/logs" "$APP_DIR/tmp"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Pruefe Server-Syntax"
|
||||||
|
node --check "$APP_DIR/server/index.js"
|
||||||
|
node --check "$APP_DIR/server/routes-seo.js"
|
||||||
|
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
log "Starte Service neu: $SERVICE_NAME"
|
||||||
|
if [ "$(id -u)" -eq 0 ]; then
|
||||||
|
systemctl restart "$SERVICE_NAME"
|
||||||
|
systemctl --no-pager --lines=20 status "$SERVICE_NAME"
|
||||||
|
else
|
||||||
|
sudo systemctl restart "$SERVICE_NAME"
|
||||||
|
sudo systemctl --no-pager --lines=20 status "$SERVICE_NAME"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log "systemctl nicht gefunden, Service-Neustart uebersprungen"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "SingleChat Rollout abgeschlossen"
|
||||||
Reference in New Issue
Block a user