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 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 20:18:40 +03:30
parent f6d779255d
commit f2c57c1ad1

View File

@@ -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