fix: install.sh hardening per code review
- Marker-based nginx insertion (BEGIN/END comments) instead of brittle sed; validates against temp file before patching live nginx.conf - Gitea pull token check: warns if /root/.gitea-replit-token missing, prints creation instructions (deploy.sh fails without it) - TLS note in summary output: explains HTTP-only transport, recommends TLS - mkdir -p DEPLOY_DIR; chmod 600 .env
This commit is contained in:
100
vps/install.sh
100
vps/install.sh
@@ -5,15 +5,23 @@
|
||||
# Run once from the VPS (or from a machine with SSH access):
|
||||
# bash vps/install.sh
|
||||
# OR remotely:
|
||||
# ssh root@143.198.27.163 'bash -s' < vps/install.sh
|
||||
# WEBHOOK_SECRET=$(cat .local/deploy-webhook-secret) \
|
||||
# ssh root@143.198.27.163 'bash -s' < vps/install.sh
|
||||
#
|
||||
# What it does:
|
||||
# 1. Ensures Node 24 + pnpm are available
|
||||
# 2. Installs deploy/webhook/health scripts to /opt/timmy-tower/
|
||||
# 3. Generates a WEBHOOK_SECRET and adds to .env
|
||||
# 4. Adds nginx location block for /webhook/deploy
|
||||
# 5. Enables + starts systemd services: timmy-deploy-hook, timmy-health.timer
|
||||
# 6. Prints the webhook secret so you can configure the Gitea webhook
|
||||
# 2. Verifies /root/.gitea-replit-token exists (needed by deploy.sh)
|
||||
# 3. Installs deploy/webhook/health scripts to /opt/timmy-tower/
|
||||
# 4. Generates or applies a WEBHOOK_SECRET and adds to .env
|
||||
# 5. Adds nginx location block for /webhook/deploy (idempotent marker)
|
||||
# 6. Enables + starts systemd services: timmy-deploy-hook, timmy-health.timer
|
||||
# 7. Prints the webhook secret so you can configure the Gitea webhook
|
||||
#
|
||||
# Security note:
|
||||
# The webhook receiver listens on localhost:9000 only. Nginx proxies
|
||||
# /webhook/deploy from the public interface. HMAC-SHA256 verifies request
|
||||
# authenticity. For full transport confidentiality, place Hermes behind a
|
||||
# TLS-terminating proxy or configure nginx with Let's Encrypt.
|
||||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
@@ -21,12 +29,15 @@ DEPLOY_DIR="/opt/timmy-tower"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
NGINX_CONF="/etc/nginx/sites-enabled/default"
|
||||
WEBHOOK_PORT=9000
|
||||
NGINX_MARKER_START="# BEGIN timmy-deploy-webhook"
|
||||
NGINX_MARKER_END="# END timmy-deploy-webhook"
|
||||
|
||||
log() { echo "[install] $*"; }
|
||||
ok() { echo "[install] ✓ $*"; }
|
||||
warn(){ echo "[install] ! $*"; }
|
||||
err() { echo "[install] ✗ $*" >&2; exit 1; }
|
||||
|
||||
# ── 1. Ensure Node 24 ─────────────────────────────────────────────────────────
|
||||
# ── 1. Ensure Node.js ─────────────────────────────────────────────────────────
|
||||
log "Checking Node.js..."
|
||||
NODE_VER=$(node --version 2>/dev/null || echo "none")
|
||||
if [[ "$NODE_VER" == none ]]; then
|
||||
@@ -43,19 +54,34 @@ if ! command -v pnpm &>/dev/null; then
|
||||
fi
|
||||
ok "pnpm $(pnpm --version)"
|
||||
|
||||
# ── 3. Copy scripts to deploy dir ─────────────────────────────────────────────
|
||||
# ── 3. Verify Gitea pull credentials ──────────────────────────────────────────
|
||||
GITEA_TOKEN_FILE="/root/.gitea-replit-token"
|
||||
if [ ! -f "$GITEA_TOKEN_FILE" ]; then
|
||||
warn "Gitea pull token not found at $GITEA_TOKEN_FILE"
|
||||
warn "deploy.sh will fail on first run without it."
|
||||
warn "Create it with the Gitea admin token:"
|
||||
warn " echo '<TOKEN>' > $GITEA_TOKEN_FILE && chmod 600 $GITEA_TOKEN_FILE"
|
||||
warn "Continuing install — add the token before triggering a deploy."
|
||||
else
|
||||
ok "Gitea pull token present at $GITEA_TOKEN_FILE"
|
||||
fi
|
||||
|
||||
# ── 4. Copy scripts to deploy dir ─────────────────────────────────────────────
|
||||
log "Copying scripts to $DEPLOY_DIR..."
|
||||
cp "$SCRIPT_DIR/deploy.sh" "$DEPLOY_DIR/deploy.sh"
|
||||
cp "$SCRIPT_DIR/webhook.js" "$DEPLOY_DIR/webhook.js"
|
||||
mkdir -p "$DEPLOY_DIR"
|
||||
cp "$SCRIPT_DIR/deploy.sh" "$DEPLOY_DIR/deploy.sh"
|
||||
cp "$SCRIPT_DIR/webhook.js" "$DEPLOY_DIR/webhook.js"
|
||||
cp "$SCRIPT_DIR/health-check.sh" "$DEPLOY_DIR/health-check.sh"
|
||||
chmod +x "$DEPLOY_DIR/deploy.sh" "$DEPLOY_DIR/health-check.sh"
|
||||
ok "Scripts installed."
|
||||
|
||||
# ── 4. Set WEBHOOK_SECRET in .env ────────────────────────────────────────────
|
||||
# ── 5. Set WEBHOOK_SECRET in .env ────────────────────────────────────────────
|
||||
# Priority: $WEBHOOK_SECRET env var → existing .env entry → generate new one
|
||||
ENV_FILE="$DEPLOY_DIR/.env"
|
||||
touch "$ENV_FILE"
|
||||
chmod 600 "$ENV_FILE"
|
||||
|
||||
if [ -n "${WEBHOOK_SECRET:-}" ]; then
|
||||
# Caller provided secret — write or replace in .env
|
||||
if grep -q "^WEBHOOK_SECRET=" "$ENV_FILE" 2>/dev/null; then
|
||||
sed -i "s|^WEBHOOK_SECRET=.*|WEBHOOK_SECRET=$WEBHOOK_SECRET|" "$ENV_FILE"
|
||||
else
|
||||
@@ -69,10 +95,10 @@ else
|
||||
WEBHOOK_SECRET=$(openssl rand -hex 32)
|
||||
echo "WEBHOOK_SECRET=$WEBHOOK_SECRET" >> "$ENV_FILE"
|
||||
ok "WEBHOOK_SECRET generated and saved to .env"
|
||||
log "NOTE: Update the Gitea webhook secret to match: $WEBHOOK_SECRET"
|
||||
warn "Update the Gitea webhook secret to match: $WEBHOOK_SECRET"
|
||||
fi
|
||||
|
||||
# ── 5. Install systemd services ───────────────────────────────────────────────
|
||||
# ── 6. Install systemd services ───────────────────────────────────────────────
|
||||
log "Installing systemd units..."
|
||||
cp "$SCRIPT_DIR/timmy-deploy-hook.service" /etc/systemd/system/
|
||||
cp "$SCRIPT_DIR/timmy-health.service" /etc/systemd/system/
|
||||
@@ -83,27 +109,42 @@ systemctl enable --now timmy-deploy-hook
|
||||
systemctl enable --now timmy-health.timer
|
||||
ok "Services enabled: timmy-deploy-hook, timmy-health.timer"
|
||||
|
||||
# ── 6. Nginx — add /webhook/deploy proxy block ───────────────────────────────
|
||||
if grep -q "webhook/deploy" "$NGINX_CONF" 2>/dev/null; then
|
||||
log "nginx already has /webhook/deploy block — skipping"
|
||||
# ── 7. Nginx — idempotent marker-based /webhook/deploy proxy block ─────────────
|
||||
if grep -qF "$NGINX_MARKER_START" "$NGINX_CONF" 2>/dev/null; then
|
||||
log "nginx /webhook/deploy block already present — skipping"
|
||||
else
|
||||
log "Adding nginx proxy for /webhook/deploy..."
|
||||
BLOCK="
|
||||
# Timmy deploy webhook (managed by install.sh)
|
||||
$NGINX_MARKER_START
|
||||
location /webhook/deploy {
|
||||
proxy_pass http://127.0.0.1:${WEBHOOK_PORT}/deploy;
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_read_timeout 10s;
|
||||
}"
|
||||
}
|
||||
$NGINX_MARKER_END"
|
||||
|
||||
# Insert before the closing } of the server block
|
||||
sed -i "s|^}|${BLOCK}\n}|" "$NGINX_CONF"
|
||||
nginx -t && systemctl reload nginx
|
||||
ok "nginx updated and reloaded."
|
||||
# Use a temp file so we can validate before touching the live config
|
||||
TMP_CONF=$(mktemp)
|
||||
# Insert the block before the last closing brace of the server block
|
||||
awk -v block="$BLOCK" '
|
||||
/^}$/ && !inserted { print block; inserted=1 }
|
||||
{ print }
|
||||
' "$NGINX_CONF" > "$TMP_CONF"
|
||||
|
||||
if nginx -t -c "$TMP_CONF" 2>/dev/null; then
|
||||
cp "$TMP_CONF" "$NGINX_CONF"
|
||||
nginx -t && systemctl reload nginx
|
||||
ok "nginx updated and reloaded."
|
||||
else
|
||||
warn "nginx config test failed on temp file — skipping auto-patch."
|
||||
warn "Add this block manually to the server {} block in $NGINX_CONF:"
|
||||
echo "$BLOCK"
|
||||
fi
|
||||
rm -f "$TMP_CONF"
|
||||
fi
|
||||
|
||||
# ── 7. Print summary ─────────────────────────────────────────────────────────
|
||||
# ── 8. Print summary ─────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "================================================================"
|
||||
echo " Push-to-deploy pipeline installed on Hermes VPS"
|
||||
@@ -112,11 +153,20 @@ echo ""
|
||||
echo " Webhook endpoint: http://143.198.27.163/webhook/deploy"
|
||||
echo " WEBHOOK_SECRET: $WEBHOOK_SECRET"
|
||||
echo ""
|
||||
echo " NOTE: The webhook runs over plain HTTP. HMAC-SHA256 ensures"
|
||||
echo " authenticity. For full transport security, configure nginx"
|
||||
echo " with TLS (Let's Encrypt) on the Hermes public domain."
|
||||
echo ""
|
||||
echo " Configure this Gitea webhook on admin/timmy-tower:"
|
||||
echo " URL: http://143.198.27.163/webhook/deploy"
|
||||
echo " Secret: $WEBHOOK_SECRET"
|
||||
echo " Events: Push"
|
||||
echo " Branch: main (filter in webhook.js)"
|
||||
echo " Branch: main (filtered by webhook.js)"
|
||||
echo ""
|
||||
echo " Gitea pull token: $GITEA_TOKEN_FILE"
|
||||
if [ ! -f "$GITEA_TOKEN_FILE" ]; then
|
||||
echo " *** NOT FOUND — add before first deploy ***"
|
||||
fi
|
||||
echo ""
|
||||
echo " Useful commands:"
|
||||
echo " tail -f $DEPLOY_DIR/deploy.log # watch deploy logs"
|
||||
|
||||
Reference in New Issue
Block a user