-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathdeploy.sh
More file actions
executable file
·170 lines (154 loc) · 7.91 KB
/
Copy pathdeploy.sh
File metadata and controls
executable file
·170 lines (154 loc) · 7.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#!/usr/bin/env bash
#
# deploy.sh — Sync & deploy AMRouter (frontend + backend) ke VPS
#
# Penggunaan:
# ./deploy.sh # build frontend + sync + restart
# ./deploy.sh --no-build # sync + restart saja (skip build frontend)
# ./deploy.sh --sync-only
# ./deploy.sh --restart-only
# ./deploy.sh --help
#
# Config ada di .deploy.env (gitignored). Contoh lihat .deploy.env.example.
#
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# ── Load config ───────────────────────────────────────────────────────────────
ENV_FILE="$SCRIPT_DIR/.deploy.env"
if [ -f "$ENV_FILE" ]; then
# shellcheck disable=SC1090
set -a; . "$ENV_FILE"; set +a
fi
: "${VPS_HOST:=43.156.183.7}"
: "${VPS_USER:=root}"
: "${VPS_PATH:=/opt/amrouter}"
: "${VPS_SERVICE:=amrouter.service}"
: "${VPS_FRONTEND_PORT:=8080}"
: "${VPS_BACKEND_PORT:=3011}"
if [ -z "${VPS_PASS:-}" ]; then
echo "ERROR: VPS_PASS belum diset. Isi di .deploy.env (lihat .deploy.env.example)." >&2
exit 1
fi
command -v sshpass >/dev/null 2>&1 || { echo "ERROR: sshpass belum terinstall (sudo apt install sshpass)."; exit 1; }
command -v rsync >/dev/null 2>&1 || { echo "ERROR: rsync belum terinstall (sudo apt install rsync)."; exit 1; }
export SSHPASS="$VPS_PASS"
SSH="sshpass -e ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
RSYNC="rsync -az --info=stats2 -e \"$SSH\""
REMOTE="$VPS_USER@$VPS_HOST"
# ── Flags ─────────────────────────────────────────────────────────────────────
DO_BUILD=1; DO_SYNC=1; DO_RESTART=1
for arg in "$@"; do
case "$arg" in
--no-build) DO_BUILD=0 ;;
--sync-only) DO_BUILD=0; DO_RESTART=0 ;;
--restart-only) DO_BUILD=0; DO_SYNC=0 ;;
--help|-h)
sed -n '3,12p' "$0"; exit 0 ;;
*) echo "Arg tidak dikenal: $arg (coba --help)"; exit 1 ;;
esac
done
# ── 1. Build frontend ──────────────────────────────────────────────────────────
if [ "$DO_BUILD" = 1 ]; then
echo "▸ [1/4] Build frontend…"
npm run build --workspace=frontend
fi
# ── 2. Sync ke VPS ─────────────────────────────────────────────────────────────
if [ "$DO_SYNC" = 1 ]; then
echo "▸ [2/4] rsync ke $VPS_HOST:$VPS_PATH …"
# Frontend dist (dengan --delete supaya asset hash lama bersih)
eval "$RSYNC --delete" "$SCRIPT_DIR/frontend/dist/" "$REMOTE:$VPS_PATH/frontend/dist/"
# Backend source (tanpa --delete, jangan hapus profile/dump/db lokal di VPS)
eval "$RSYNC" \
--exclude=node_modules --exclude=.venv --exclude=profiles \
--exclude='*.db' --exclude='*.db-shm' --exclude='*.db-wal' \
--exclude='*.png' --exclude='*.html' --exclude='*_debug.log' \
"$SCRIPT_DIR/backend/src/" "$REMOTE:$VPS_PATH/backend/src/"
eval "$RSYNC" --exclude=node_modules \
"$SCRIPT_DIR/backend/open-sse/" "$REMOTE:$VPS_PATH/backend/open-sse/"
# backend/tests + package.json: the diagnose/repair scripts are only reachable
# through their npm run entries, and DB-repair runs have to happen on the VPS's
# own /root/.amrouter DB — it is never synced (see the *.db excludes above).
eval "$RSYNC" --exclude=node_modules \
"$SCRIPT_DIR/backend/tests/" "$REMOTE:$VPS_PATH/backend/tests/"
eval "$RSYNC" "$SCRIPT_DIR/backend/package.json" "$REMOTE:$VPS_PATH/backend/package.json"
fi
# ── 2b. Provisioning: curl-impersonate ────────────────────────────────────────
# genspark.ai duduk di belakang Cloudflare bot management, yang men-skor TLS
# ClientHello (JA3/JA4) + HTTP/2 SETTINGS. Stock curl punya fingerprint yang
# khas non-browser, jadi setiap request genspark dapat 403 "Just a moment".
# Diukur 2026-08-03, satu request per varian setelah cooldown supaya rate-limit
# Cloudflare tidak mengaburkan hasil:
# stock curl 7.81 → 403 + challenge HTML
# curl-impersonate → lolos Cloudflare (jawaban aplikasi genspark)
#
# Ini TIDAK ikut di git, jadi tanpa langkah ini setiap VPS baru akan 403 lagi.
# Idempoten: kalau versi yang sama sudah ada, tidak mengunduh ulang. Tidak
# menyentuh curl bawaan sistem — dipasang berdampingan di /usr/local/bin.
if [ "$DO_SYNC" = 1 ]; then
echo "▸ [2b/4] Pastikan curl-impersonate terpasang…"
$SSH "$REMOTE" '
set -e
WANT='"${CURL_IMPERSONATE_VERSION:-v2.0.0}"'
BIN=/usr/local/bin/curl-impersonate
WRAP=/usr/local/bin/curl-impersonate-chrome
CHROME='"${CURL_IMPERSONATE_TARGET:-chrome146}"'
if [ -x "$BIN" ] && "$BIN" --version 2>/dev/null | grep -qi impersonate; then
echo " curl-impersonate sudah ada: $("$BIN" --version | head -1 | cut -d" " -f2)"
else
# Nama asset upstream memakai triple Rust, bukan uname -m mentah.
case "$(uname -m)" in
x86_64) TRIPLE=x86_64-linux-gnu ;;
aarch64) TRIPLE=aarch64-linux-gnu ;;
armv7l) TRIPLE=arm-linux-gnueabihf ;;
*) echo " WARN: arch $(uname -m) tidak didukung — genspark akan kena 403 Cloudflare"; exit 0 ;;
esac
URL="https://github.com/lexiforest/curl-impersonate/releases/download/${WANT}/curl-impersonate-${WANT}.${TRIPLE}.tar.gz"
echo " unduh ${WANT} (${TRIPLE})…"
TMP=$(mktemp -d); trap "rm -rf $TMP" EXIT
if ! curl -sSL -m 300 -o "$TMP/ci.tar.gz" "$URL"; then
echo " WARN: unduh gagal — genspark akan kena 403 Cloudflare"; exit 0
fi
tar xzf "$TMP/ci.tar.gz" -C "$TMP"
install -m755 "$TMP/curl-impersonate" "$BIN"
echo " terpasang: $("$BIN" --version | head -1 | cut -d" " -f2)"
fi
# Binary telanjang TIDAK meniru apa pun tanpa --impersonate (diukur: 403).
# Wrapper inilah yang menyematkan flag-nya; auto-detect di curlFetch.js
# mencari nama ini lebih dulu.
printf "%s\n" "#!/bin/sh" "exec $BIN --impersonate $CHROME \"\$@\"" > "$WRAP"
chmod 755 "$WRAP"
mkdir -p /etc/systemd/system/'"$VPS_SERVICE"'.d
printf "%s\n" "[Service]" "Environment=CURL_IMPERSONATE_BIN=$WRAP" \
> /etc/systemd/system/'"$VPS_SERVICE"'.d/override.conf
systemctl daemon-reload
'
fi
# ── 3. Restart service + reload nginx ──────────────────────────────────────────
if [ "$DO_RESTART" = 1 ]; then
echo "▸ [3/4] Reload nginx & restart $VPS_SERVICE …"
$SSH "$REMOTE" '
set -e
nginx -t 2>&1 && systemctl reload nginx || echo "WARN: reload nginx dilewati"
systemctl restart '"$VPS_SERVICE"'
sleep 4
'
fi
# ── 4. Verifikasi ──────────────────────────────────────────────────────────────
if [ "$DO_RESTART" = 1 ]; then
echo "▸ [4/4] Verifikasi…"
$SSH "$REMOTE" '
echo "service : $(systemctl is-active '"$VPS_SERVICE"')"
echo "backend : $(curl -s -m10 -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:'"$VPS_BACKEND_PORT"'/api/health)"
echo "frontend: $(curl -s -m10 -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:'"$VPS_FRONTEND_PORT"'/)"
# Tanpa ini genspark dapat 403 Cloudflare di setiap request, dan itu baru
# ketahuan saat model dipakai — bukan saat deploy.
if [ -x /usr/local/bin/curl-impersonate-chrome ]; then
echo "tls-imp : aktif ($(/usr/local/bin/curl-impersonate --version 2>/dev/null | head -1 | cut -d" " -f2))"
else
echo "tls-imp : TIDAK AKTIF — genspark akan 403 Cloudflare"
fi
echo "uptime : $(systemctl show '"$VPS_SERVICE"' -p ActiveEnterTimestamp --value)"
'
fi
echo "✓ Deploy selesai."