From f2c57c1ad19568235b4e7245b046436d70f316ef Mon Sep 17 00:00:00 2001 From: Zareian Date: Sat, 17 Oct 2026 20:18:40 +0330 Subject: [PATCH] docs: step-by-step cut-over to 216 with rollback, what waits on others, after-cut-over list Co-Authored-By: Claude Opus 5.5 --- docs/operations.md | 50 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/docs/operations.md b/docs/operations.md index 6a5ce73..8656c45 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -409,16 +409,48 @@ the servers»): خروج و باطل شدنِ توکن. کاوه‌نگار و GapGPT از IPِ خروجیِ این سرور پذیرفته‌اند. نسنجیده: هیچ درخواستی از مسیرِ ArvanCloud (۴۴۳ بسته است)، پرداختِ کامل، خریدِ بازار. -**سوئیچ (ترتیب):** ۱) 443ِ ورودی باز شود. ۲) روی ۲۴۹ `zareian-mathapp` متوقف (پیامِ نگه‌داری در ArvanCloud)، `pg_dump -Fc`، -بازیابی روی سرورِ جدید در دیتابیسِ خالی‌شده، مقایسه‌ی تعدادِ ردیف‌ها. ۳) originِ هر دو دامنه در ArvanCloud به `78.38.35.216`. -۴) health و یک ورود و یک آزمون از بیرون. ۵) `tadrisino-pgbackrest-full` یک بار دستی (بعد از بازیابیِ دیتابیسِ نهایی)؛ روی ۲۴۷ -یونیت‌های بکاپِ ۲۴۹ (`zareian-pg-*`) متوقف و، با تأییدِ صاحبِ محصول، بکاپ‌های رمزنگاری‌نشده‌ی ۲۴۹ (`~/zareian-pgbackup`) پاک؛ -`pull-app-logs.sh` به آدرسِ جدید؛ در کدِ health، `_slot_state` و `OFFSITE_WAL_SLOT` حذف. ۶) CLAUDE.md و این سند. +### چه چیزی منتظرِ دیگران است -**باز، بعد از سوئیچ:** ورود با کلیدِ SSH برای `zareian` (صاحبِ محصول روی لپ‌تاپ `ssh-keygen -t ed25519` و `ssh-copy-id`)، بعد -`PasswordAuthentication no` با `Match Address 192.168.200.0/24` برای ورودِ با رمز از شبکه‌ی داخلی؛ private کردنِ مخزن در Gitea -(الان بی‌رمز از اینترنت خواندنی است) و توکنِ فقط‌خواندنی برای `deploy.sh`. -تا سوئیچ، `deploy.sh` روی هر دو سرور اجرا شود تا کدِ دو طرف یکی بماند. +درخواست از سینیور فرستاده شده (۲۰۲۶-۱۰-۱۷): ۱) 443ِ ورودی روی فایروالِ شرکت؛ ۲) حذفِ `temp`؛ ۳) عوض کردنِ originِ +`math.tadrisino2.ir` و `mathapi.tadrisino2.ir` در پنلِ ArvanCloud به `78.38.35.216` (ما به پنل دسترسی نداریم؛ هم‌زمان با قدمِ ۴ پایین)؛ +۴) private کردنِ مخزن در Gitea؛ ۵) ۱۲ هسته و رمِ بیشتر (اختیاری؛ سرور ریبوت را تحمل می‌کند، تست شده). زرین‌پال و بازار به +دامنه بسته‌اند نه IP، پس در پنلِ آن‌ها چیزی عوض نمی‌شود. + +### سوئیچ، قدم‌به‌قدم (وقتی سینیور گفت آماده است) + +1. **پیش‌شرط:** از لپ‌تاپ `curl -sk -o /dev/null -w '%{http_code}' https://78.38.35.216/` باید ۴۰۳ بدهد (نه ۰۰۰: یعنی 443 باز است و + nginx فقط آروان را راه می‌دهد). کامیت‌ها push شده باشند و `deploy.sh` روی هر دو سرور اجرا شده باشد (کدِ دو طرف یکی). +2. **۲۴۹ را بخوابان:** `sudo systemctl stop zareian-mathapp` (از این لحظه کاربران خطا می‌بینند تا قدمِ ۵؛ کلِ کار ~۱۵ دقیقه). +3. **دیتابیسِ نهایی:** `sudo -u postgres pg_dump -p 5440 -Fc zareian_mathapp` روی ۲۴۹، با pipe از لپ‌تاپ به + `/home/zareian/stage/` روی ۲۱۶ (مسیرِ داخلیِ ۲۴۹→۲۱۶ کلید ندارد). +4. **روی ۲۱۶:** `systemctl stop zareian-mathapp`؛ `dropdb -p 5440 zareian_mathapp && createdb -p 5440 -O zareian_app zareian_mathapp` (با + `sudo -u postgres`)؛ `pg_restore -p 5440 -d zareian_mathapp --no-owner --role=zareian_app --exit-on-error`؛ شمارشِ `accounts_user`، + `content_question`، `payment_order`، `payment_paymentevent`، `content_useranswer` با همان پرسش روی ۲۴۹ یکی باشد؛ `systemctl start + zareian-mathapp`؛ health با `X-Internal-Key` بی‌هشدار. داده‌های تستِ ۲۰۲۶-۱۰-۱۷ روی ۲۱۶ با همین قدم پاک می‌شوند. +5. **سینیور origin را در آروان عوض می‌کند.** بعد از بیرون: `https://mathapi.tadrisino2.ir/api/health` ok؛ در + `/var/log/nginx/access.log`ِ ۲۱۶ IPهای آروان دیده شوند؛ ورود در Chrome (روشِ OTPِ ادمین، بخشِ «ورود بی‌پیامک») و یک آزمون؛ کاربرِ + اندروید (WebView و `pay.html`) هم یک بار. +6. **بکاپِ تازه:** `sudo systemctl start tadrisino-pgbackrest-full` و بعد `tadrisino-offsite-sync`؛ `sudo -u postgres tadrisino-restore-check`. +7. **۲۴۹ را کنار بگذار (پاک نکن):** `sudo systemctl disable zareian-mathapp` روی ۲۴۹؛ اسلات را بردار تا WAL روی دیسکِ مشترک جمع نشود: + `sudo -u postgres psql -p 5440 -c "select pg_drop_replication_slot('zareian_247')"`؛ روی ۲۴۷ `systemctl disable --now zareian-pg-tunnel + zareian-pg-wal zareian-pg-basebackup.timer zareian-pg-export-events.timer zareian-applog-pull.timer`. دیتابیسِ ۲۴۹ یک هفته برای برگشت می‌ماند. +8. **برگشت (اگر قدمِ ۵ خراب شد):** origin در آروان دوباره ۲۴۹، و روی ۲۴۹ `systemctl start zareian-mathapp`. فقط تا وقتی درست است که ۲۱۶ + نوشتنِ واقعی (پرداخت، ثبت‌نام) نگرفته؛ بعد از آن اول dumpِ ۲۱۶ به ۲۴۹. +9. **اسناد:** CLAUDE.md (سرورِ زنده = ۲۱۶؛ رویه‌ی دیپلو با `zareian@78.38.35.216` و `sudo -u mathapp ./deploy.sh`)، این بخش، و + `ops/nginx/` با مسیرهای `/home/mathapp` (۲۱۶ نسخه‌ی sed‌شده را دارد). + +### بعد از سوئیچ + +- یک هفته بعد، با تأییدِ صاحبِ محصول: پاک کردنِ بکاپ‌های رمزنگاری‌نشده‌ی ۲۴۹ روی ۲۴۷ (`~/zareian-pgbackup`، یونیت‌های `zareian-pg-*`) + و حذفِ `_slot_state`/`OFFSITE_WAL_SLOT` از `config/health.py` و `settings.py`. +- لاگِ اپ: آرشیوِ شبانه روی ۲۱۶ هست (`zareian-applog-archive.timer`) ولی هنوز به ۲۴۷ نمی‌رود؛ راهِ پیشنهادی: افزودنِ + `logs/archive` به `tadrisino-offsite-sync` (همان rrsync، پوشه‌ی `app-logs/`). +- ورود با کلیدِ SSH برای `zareian` (صاحبِ محصول خواسته فعلاً بماند؛ روی لپ‌تاپ `ssh-keygen -t ed25519` و `ssh-copy-id`)، بعد + `PasswordAuthentication no` با `Match Address 192.168.200.0/24` برای ورودِ با رمز از شبکه‌ی داخلی. +- توکنِ فقط‌خواندنیِ Gitea برای `deploy.sh` روی ۲۱۶ (بعد از private شدنِ مخزن، `git fetch` بی‌رمز دیگر کار نمی‌کند). +- `CORS_ALLOWED_ORIGINS` در `.env`ِ سرور هنوز `localhost:5174` دارد؛ حذفش. +- برنامه‌ی صاحبِ محصول: مرورِ کاملِ یک فهرستِ امنیتیِ استاندارد (OWASP Top 10 / API Top 10 برای اپ، CIS Benchmark برای سرور، همراهِ + `docs/security-before-production.md`)، بعد لودتست روی ۲۱۶ (`tools/loadtest/README.md`؛ با هسته‌ی بیشتر: ۸ worker و `DB_POOL_MAX_SIZE` 6). ### Qdrant