feat(deploy): configure deployment for ClinicPro on Liara PHP platform

This commit is contained in:
hamed
2026-06-29 16:11:54 +03:30
parent efee966efb
commit b4273cfa8b
11 changed files with 683 additions and 83 deletions
+208
View File
@@ -0,0 +1,208 @@
# راهنمای دیپلوی ClinicPro روی لیارا (پلتفرم PHP)
دیپلوی بک‌اند Symfony روی **پلتفرم PHP لیارا** (نوع برنامه `php` هنگام «ساخت برنامه‌ی جدید»). اینجا داکری در کار نیست؛ لیارا کد را می‌گیرد، خودش `composer install` می‌زند و روی Apache + PHP-FPM سرو می‌کند.
> مسیر جایگزین (داکر) در [docs/deploy-liara.md](deploy-liara.md) است. **همزمان فقط یک مسیر** را نگه دار — هر دو از یک `liara.json` استفاده می‌کنند.
---
## نمای کلی
```
┌──────────────── Liara private network ─────────────────┐
│ │
│ ┌──────────────────────────────┐ ┌──────────────┐ │
│ │ clinicpro-api (PHP app) │ │ MariaDB 11.8 │ │
│ │ • Apache + PHP-FPM (docroot │◄─►│ (managed) │ │
│ │ = public/) :80 │ └──────────────┘ │
│ │ • supervisor.conf: │ ┌──────────────┐ │
│ │ worker-async │◄─►│ Redis │ │
│ │ worker-scheduler │ │ (managed) │ │
│ └──────────────────────────────┘ └──────────────┘ │
│ disks: jwt / uploads / var-uploads │
└────────────────────────────────────────────────────────┘
│ :80
▼ https://<domain>
```
همهٔ پروسه‌ها (وب + هر دو worker) در **یک** کانتینر اجرا می‌شوند؛ workerها کانتینر جدا ندارند (برخلاف نسخهٔ docker-compose).
---
## فایل‌های دخیل (همه ساخته شده‌اند)
| فایل | نقش |
|---|---|
| [`liara.json`](../liara.json) | `platform: php`، `php.version: 8.2`، `documentRoot: public`، دیسک‌ها |
| [`public/.htaccess`](../public/.htaccess) | rewrite front-controller سیمفونی روی Apache |
| [`liara_pre_build.sh`](../liara_pre_build.sh) | قبل `composer install`: ساخت `.env` مینیمال prod |
| [`liara_pre_start.sh`](../liara_pre_start.sh) | قبل start: انتظار DB، تولید JWT، cache، migration |
| [`supervisor.conf`](../supervisor.conf) | دو worker مسنجر (`async` + `scheduler_default`) |
| [`liara_php.ini`](../liara_php.ini) | memory_limit، حجم آپلود، زمان اجرا |
| [`.liaraignore`](../.liaraignore) | کنترل آپلود (تا `public/build` آپلود شود، سکرت‌ها مستثنی) |
| [`.env.liara.example`](../.env.liara.example) | مرجع متغیرهای محیطی |
---
## پیش‌نیاز
```bash
npm i -g @liara/cli
liara login
```
مقادیر آماده:
```bash
php -r "echo bin2hex(random_bytes(32)).\"\n\";" # APP_SECRET
openssl rand -hex 32 # JWT_PASSPHRASE
ddev exec php docker/gen-cors-env.php # ALLOWED_FRONTEND_HOSTS + CORS_ALLOW_ORIGIN
```
---
## گام ۱ — build محلی asset‌ها (حیاتی)
پلتفرم PHP لیارا **`yarn` اجرا نمی‌کند** و asset‌های React را نمی‌سازد. قبل هر دیپلوی محلی build کن (خروجی در `public/build`؛ `.liaraignore` آن را آپلود می‌کند):
```bash
ddev exec yarn install --frozen-lockfile
ddev exec yarn build
```
> اگر این مرحله را رد کنی، پنل ادمین `/admin` لود نمی‌شود.
---
## گام ۲ — ساخت دیتابیس و Redis
کنسول لیارا:
1. **MariaDB 11.8** بساز (هماهنگ با `serverVersion=mariadb-11.8.0`).
2. **Redis** بساز.
3. روی هر دو **شبکهٔ خصوصی** فعال؛ هاست خصوصی/کاربر/رمز را یادداشت کن.
---
## گام ۳ — ساخت برنامهٔ PHP
1. New App → نوع **PHP** → نسخهٔ **8.2** (پروژه `php: >=8.2` می‌خواهد) → شناسه `clinicpro-api`.
2. آن را به **همان شبکهٔ خصوصیِ** DB و Redis وصل کن.
---
## گام ۴ — ساخت دیسک‌های ماندگار
در صفحهٔ برنامه، بخش Disks، این سه دیسک را با همین نام‌ها بساز (mount از `liara.json`):
| نام | mountTo | محتوا |
|---|---|---|
| `jwt` | `/var/www/config/jwt` | کلید JWT (نباید هر دیپلوی نو شود) |
| `uploads` | `/var/www/public/uploads` | فایل‌های عمومی |
| `var-uploads` | `/var/www/var/uploads` | فایل‌های خصوصی |
> ⚠️ ریشهٔ اپ فرض شده `/var/www`. اگر در لاگ مسیر دیگری دیدی، `mountTo` در `liara.json` را اصلاح کن.
---
## گام ۵ — متغیرهای محیطی
از روی [`.env.liara.example`](../.env.liara.example) ست کن (تب Environment یا CLI). یک‌بار روی app؛ workerها همان را می‌گیرند.
```bash
liara env set APP_ENV=prod APP_DEBUG=0 --app clinicpro-api
liara env set APP_SECRET=<...> JWT_PASSPHRASE=<...> --app clinicpro-api
liara env set DATABASE_URL="mysql://<user>:<pass>@<db-private-host>:3306/<db>?serverVersion=mariadb-11.8.0&charset=utf8mb4" --app clinicpro-api
liara env set REDIS_URL="redis://:<pass>@<redis-private-host>:6379" --app clinicpro-api
liara env set MESSENGER_TRANSPORT_DSN="redis://:<pass>@<redis-private-host>:6379/messages" --app clinicpro-api
liara env set JWT_SECRET_KEY='%kernel.project_dir%/config/jwt/private.pem' JWT_PUBLIC_KEY='%kernel.project_dir%/config/jwt/public.pem' --app clinicpro-api
liara env set APP_BASE_URL=https://<domain> DEFAULT_URI=https://<domain> --app clinicpro-api
liara env set TRUSTED_PROXIES="10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.1" --app clinicpro-api
liara env set ALLOWED_FRONTEND_HOSTS="<output>" CORS_ALLOW_ORIGIN="<output>" --app clinicpro-api
liara env set API_IR_BASE_URL=https://s.api.ir API_IR_TOKEN=<token> --app clinicpro-api
liara env set REFRESH_TOKEN_TTL=2592000 OTP_TTL=1200 MAX_FILE_SIZE_BYTES=5242880 UPLOAD_DIR=var/uploads --app clinicpro-api
```
نکته‌ها:
- `RUN_INIT` را ست **نکن** — init یک‌بار در `liara_pre_start.sh` اجرا می‌شود.
- `APP_ENV=prod` موقع build هم لازم است (composer اسکریپت `cache:clear` را اجرا می‌کند).
- کلیدهای SMS و درگاه پرداخت از **دیتابیس** خوانده می‌شوند، نه env.
---
## گام ۶ — دیپلوی
از ریشهٔ `clinicpro/`:
```bash
liara deploy
```
روند خودکار:
1. `liara_pre_build.sh``.env` مینیمال prod (اگر نبود).
2. `composer install` (لیارا).
3. `liara_pre_start.sh` → انتظار DB → تولید JWT (روی دیسک) → warmup → migration.
4. Apache (docroot=`public`) + `supervisor.conf` (هر دو worker) بالا می‌آیند.
---
## گام ۷ — اتصال دامنه و تأیید
1. بخش Domains: دامنهٔ API را وصل کن، TLS بگیر.
2. سلامت:
```bash
curl -i https://<domain>/health # باید 200
```
3. workerها:
```bash
# در کنسول/CLI برنامه:
supervisorctl status # worker-async و worker-scheduler = RUNNING
```
4. ورود `/admin` و تست یک endpoint (تأیید DB/Redis).
---
## دیپلوی‌های بعدی
```bash
ddev exec yarn build # اگر assets عوض شد
liara deploy
```
migrationها خودکار در `liara_pre_start.sh` اجرا می‌شوند. دیسک‌ها و env حفظ می‌شوند.
---
## نگاشت compose → لیارا (PHP platform)
در `docker-compose.yml` هر worker یک کانتینر جدا بود؛ اینجا هر دو در همان کانتینر با `supervisor.conf`:
| compose | لیارا |
|---|---|
| سرویس `app` (php-fpm+nginx) | خود پلتفرم PHP (Apache+PHP-FPM)، docroot=`public` |
| `worker-async` (کانتینر جدا) | `[program:worker-async]` در `supervisor.conf` |
| `worker-scheduler` (کانتینر جدا) | `[program:worker-scheduler]` در `supervisor.conf` |
| `environment: *app-env` + `RUN_INIT` | env روی app؛ init در `liara_pre_start.sh` |
| `volumes` | دیسک‌های `liara.json` |
| `networks: [coolify]` | شبکهٔ خصوصی لیارا |
| `restart`/`healthcheck` | `autorestart=true` |
| `stop_grace_period: 30s` | `stopsignal=TERM` + `stopwaitsecs=30` |
---
## رفع اشکال
| نشانه | علت | راه‌حل |
|---|---|---|
| پنل `/admin` سفید/۴۰۴ asset | `public/build` آپلود نشده | `ddev exec yarn build` قبل deploy؛ `.liaraignore` build را مستثنی نکند |
| کل سایت ۴۰۳/۴۰۴ | documentRoot روی `public` نیست یا `.htaccess` نیست | `documentRoot: public` در liara.json + `public/.htaccess` |
| `Database not reachable after 60s` | شبکهٔ خصوصی/`DATABASE_URL` غلط | DB و app یک شبکه؛ هاست خصوصی را چک کن |
| توکن‌ها بعد هر دیپلوی باطل | دیسک `jwt` mount نشده | دیسک `jwt` → `/var/www/config/jwt` |
| worker بالا نمی‌آید / messenger خطای redis | افزونهٔ `redis` روی پلتفرم نیست | `php -m \| grep redis`؛ نبود → `MESSENGER_TRANSPORT_DSN=doctrine://default` + کش فایل‌سیستم |
| build به‌خاطر composer scripts شکست | `cache:clear` موقع نصب | مطمئن شو `APP_ENV=prod` ست است؛ در صورت لزوم نصب را `--no-scripts` کن و همه‌چیز را به `liara_pre_start.sh` بسپار |
| خطای CORS از فرانت | `CORS_ALLOW_ORIGIN` قدیمی | `docker/gen-cors-env.php` دوباره؛ env به‌روز |
---
## ریسک‌های شناخته‌شده
- **ext-redis:** اگر پلتفرم PHP لیارا phpredis نداشته باشد، Redis (cache + messenger) کار نمی‌کند → fallback به Doctrine transport و کش فایل‌سیستم. قبل اتکا verify کن.
- **مسیر دیسک:** ریشهٔ `/var/www` فرض است؛ با لاگ واقعی تطبیق بده.
- **انتخاب مسیر:** یا Docker یا PHP platform — هر دو `liara.json` را همزمان نگه ندار.