13 KiB
دیپلوی ClinicPro (Symfony) روی لیارا با پلتفرم PHP (بدون داکر)
پروژه
clinicpro (Backend Symfony 7.4 + پنل ادمین React 19).
راهنما + تسک پیادهسازی برای دیپلوی روی پلتفرم PHP لیارا (buildpack بومی؛ لیارا خودش از سورس با composer install build میکند — بدون Dockerfile).
منابع: مستندات لیارا — paas/php/how-tos (set-envs، use-disk، set-logs، customize-php-ini، customize-htaccess، use-queues، set-http-security-headers، use-hooks، set-cron-job) و paas/laravel (quick-start، set-envs، set-cron-job، choose-version، manage-logs).
زمینه
تا الان دو مسیر دیپلوی برای این پروژه آماده شده:
- داکر/Coolify:
Dockerfile+docker-compose.yml - داکر/لیارا:
liara.json(platform docker) +liara-compose.yaml
این پرامپت مسیر سومی را میسازد: پلتفرم PHP لیارا (نوع برنامه = php هنگام «ساخت برنامهی جدید»). اینجا داکری در کار نیست؛ لیارا کد را میگیرد، composer install میزند و روی Apache + PHP-FPM سرو میکند.
تفاوتهای کلیدی پلتفرم PHP که معماری را تعیین میکنند (از مستندات):
- Hookها فایلهای شلاند، نه JSON:
liara_pre_build.sh(قبل build، بدون دسترسی به env، مناسب apt) وliara_pre_start.sh(قبل start، با env، مناسب migration). - Worker با
supervisor.conf: فایلsupervisor.confدر ریشه؛ هر[program]یک دستور دلخواه (php bin/console messenger:consume ...) را زنده نگه میدارد.$ROOT= ریشهٔ اپ،user=www-data. - php.ini با
liara_php.iniدر ریشه. - سرو با Apache +
.htaccess؛ documentRoot بایدpublic/شود. - دیسکها در
liara.jsonبا مسیر absolute. - نسخهٔ PHP: 7.2 تا 8.4 (پیشفرض 7.4) — پروژه
php: >=8.2میخواهد، پس باید 8.2+ انتخاب شود.
مشکل / هدف
اجرای کامل Symfony روی پلتفرم PHP لیارا، شامل:
- سرو front-controller سیمفونی از
public/روی Apache. - اجرای migration و تولید کلید JWT در زمان استقرار.
- اجرای دو مصرفکنندهٔ Messenger (
asyncوscheduler_default) بهصورت پایدار. - آپلودِ assetهای buildشدهٔ React (که
composer installآنها را نمیسازد). - اتصال به MariaDB و Redis مدیریتشدهٔ لیارا.
فایلهای مرتبط
| فایل | نقش | وضعیت |
|---|---|---|
liara.json |
پیکربندی دیپلوی | بازنویسی برای platform php (فعلاً platform docker است) |
public/.htaccess |
rewrite سیمفونی برای Apache | وجود ندارد — ساخته شود (apache-pack نصب نیست) |
liara_pre_start.sh |
hook قبل start (migration/JWT) | جدید |
supervisor.conf |
اجرای دو worker | جدید |
liara_php.ini |
تنظیم php.ini | جدید |
.liaraignore |
کنترل فایلهای آپلودی | جدید (تا public/build آپلود شود) |
composer.json |
اسکریپتهای نصب | بدون تغییر (با احتیاط؛ پایین) |
⚠️ تداخل liara.json: الان
liara.jsonبرای platform docker است. پلتفرم PHP به محتوای متفاوتی نیاز دارد. فقط یک مسیر را همزمان نگه دار. اگر PHP را انتخاب کردی، محتوای docker را با نسخهٔ PHP زیر جایگزین کن (یا برنچ جدا).
وضعیت فعلی (کد واقعی)
composer.json هنگام نصب این اسکریپتها را اجرا میکند (روی build لیارا هم اجرا میشوند):
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
},
"post-install-cmd": ["@auto-scripts"]
.gitignore اینها را نادیده میگیرد (پس بهصورت پیشفرض آپلود نمیشوند):
/public/build/ # ← خروجی yarn build؛ باید آپلود شود
/config/jwt/*.pem # ← روی دیسک ساخته میشود
/var/
.env
public/.htaccess وجود ندارد؛ extensionهای موردنیاز Symfony: pdo_mysql, intl, opcache, و برای Messenger روی Redis: redis (phpredis).
وظایف
۱. ساخت liara.json برای پلتفرم PHP
محتوای فعلی (platform docker) را با این جایگزین کن:
{
"app": "clinicpro-api",
"platform": "php",
"port": 80,
"php": {
"version": "8.2"
},
"documentRoot": "public",
"disks": [
{ "name": "jwt", "mountTo": "/var/www/config/jwt" },
{ "name": "uploads", "mountTo": "/var/www/public/uploads" },
{ "name": "var-uploads", "mountTo": "/var/www/var/uploads" }
]
}
نکات:
documentRoot: "public"تا Apache front-controller سیمفونی را سرو کند.- مسیر mount دیسکها absolute است؛ ریشهٔ اپ روی پلتفرم PHP معمولاً
/var/wwwاست — اگر در کنسول/لاگ مسیر دیگری دیدی، اصلاح کن. - کلید
php.versionوdocumentRootرا اگر کنسول نپذیرفت، از تنظیمات کنسول (Platform Settings) ست کن — مستند نسخهگزینی را از طریق کنسول هم ممکن میداند. - سه دیسک
jwt/uploads/var-uploadsرا پیش از دیپلوی در کنسول بساز.
۲. ساخت public/.htaccess (rewrite سیمفونی)
چون symfony/apache-pack نصب نیست، یا نصبش کن:
ddev exec composer require symfony/apache-pack
(این بهصورت تعاملی public/.htaccess استاندارد سیمفونی را میسازد) — یا فایل را دستی بساز:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI}::$0 ^(/.+)/(.*)::\2$
RewriteRule .* - [E=BASE:%1]
RewriteCond %{HTTP:Authorization} .+
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%0]
RewriteCond %{ENV:REDIRECT_STATUS} =""
RewriteRule ^index\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
RewriteRule ^ %{ENV:BASE}/index.php [L]
</IfModule>
<IfModule !mod_rewrite.c>
<IfModule mod_alias.c>
RedirectMatch 307 ^/$ /index.php/
</IfModule>
</IfModule>
۳. ساخت supervisor.conf (دو worker مسنجر)
روی پلتفرم PHP، خود لیارا Apache/PHP-FPM را اجرا میکند؛ supervisor.conf فقط workerها را اضافه میکند (نه وب). در ریشه بساز:
[program:worker-async]
process_name=%(program_name)s_%(process_num)02d
command=cd $ROOT && php bin/console messenger:consume async --time-limit=3600 --memory-limit=128M -v
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
numprocs=1
user=www-data
redirect_stderr=true
stdout_logfile=/tmp/worker-async.log
[program:worker-scheduler]
process_name=%(program_name)s_%(process_num)02d
command=cd $ROOT && php bin/console messenger:consume scheduler_default --time-limit=3600 -v
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
numprocs=1
user=www-data
redirect_stderr=true
stdout_logfile=/tmp/worker-scheduler.log
جایگزینِ cron: اگر نخواهی scheduler بهصورت worker بماند، میتوانی همان کار را با Cron Job کنسول (
* * * * *→ دستوری که یک پیام scheduler را مصرف کند) انجام دهی. ولی worker async (SMS) حتماً باید درsupervisor.confبماند.
۴. ساخت liara_pre_start.sh (migration + JWT + cache)
در ریشه، با env در دسترس:
#!/bin/sh
set -e
echo "pre-start: waiting for database..."
i=0
until php bin/console doctrine:query:sql "SELECT 1" >/dev/null 2>&1; do
i=$((i + 1))
[ "$i" -ge 30 ] && { echo "DB not reachable after 60s" >&2; exit 1; }
sleep 2
done
# کلید JWT روی دیسک ماندگار jwt
php bin/console lexik:jwt:generate-keypair --skip-if-exists --no-interaction
php bin/console cache:clear --no-warmup
php bin/console cache:warmup
php bin/console doctrine:migrations:migrate --all-or-nothing --no-interaction
فایل را اجرایی کن: chmod +x liara_pre_start.sh.
۵. ساخت liara_php.ini
برای پشتیبانی از آپلود (سقف اپ ۵MB ولی هدر/چندبخشی بزرگتر) و زمان اجرا:
memory_limit = 256M
upload_max_filesize = 16M
post_max_size = 24M
max_execution_time = 120
file_uploads = On
۶. ساخت .liaraignore تا assetهای build آپلود شوند
.gitignore پوشهٔ /public/build/ را نادیده میگیرد و لیارا بهصورت پیشفرض از gitignore پیروی میکند → assetها آپلود نمیشوند. با ساخت .liaraignore کنترل را بهدست بگیر (فقط واقعاً غیرلازمها را کنار بگذار، public/build را نگه دار):
.git
.ddev
.claude
.github
.vscode
node_modules
tests
var/cache
var/log
docs
graphify-out
*.sql
*.sql.gz
.DS_Store
پیش از هر دیپلوی، assetها را محلی build کن (لیارا yarn build نمیزند):
ddev exec yarn install --frozen-lockfile
ddev exec yarn build # خروجی در public/build
۷. دیتابیس و Redis مدیریتشده + متغیرهای محیطی
مثل مسیر داکر:
- در کنسول، MariaDB 11.8 و Redis بساز، شبکهٔ خصوصی فعال، برنامه را به همان شبکه وصل کن.
- envها را با
liara env set ... --app clinicpro-apiیا تب Environment ست کن (مرجع کامل:.env.liara.example). حداقل:APP_ENV=prod,APP_DEBUG=0APP_SECRET,JWT_PASSPHRASE(ثابت)DATABASE_URL(هاست خصوصی MariaDB،serverVersion=mariadb-11.8.0)REDIS_URL,MESSENGER_TRANSPORT_DSN(هاست خصوصی Redis)JWT_SECRET_KEY/JWT_PUBLIC_KEY(مسیرconfig/jwt/*.pem)APP_BASE_URL,DEFAULT_URI,TRUSTED_PROXIESALLOWED_FRONTEND_HOSTS,CORS_ALLOW_ORIGIN(خروجیphp docker/gen-cors-env.php)API_IR_BASE_URL,API_IR_TOKEN
- مهم:
APP_ENV=prodباید موقع build هم موجود باشد، چونcomposer installاسکریپتcache:clearرا اجرا میکند.
۸. استقرار و تأیید
liara deploy # از ریشهٔ clinicpro، با liara.json platform php
سپس:
GET https://<domain>/health→ 200- لاگ: در کنسول/
liara logsهر دو worker (worker-async,worker-scheduler) بالا باشند - ورود
/adminو تست یک endpoint
نکات مهم
- ext-redis ریسک اصلی است: اگر پلتفرم PHP لیارا افزونهٔ
redis(phpredis) را نداشته باشد،REDIS_URLوMESSENGER_TRANSPORT_DSN: redis://...کار نمیکنند. اول در محیط لیارا چک کن (php -m | grep redis). اگر نبود:- برای Messenger به transport مبتنی بر Doctrine سوییچ کن (
MESSENGER_TRANSPORT_DSN=doctrine://default) و جدول مسنجر را با migration بساز، - برای cache هم به adapter فایلسیستم/Doctrine برگرد.
- برای Messenger به transport مبتنی بر Doctrine سوییچ کن (
- اسکریپتهای composer در build:
cache:clearدر prod بدون DB معمولاً سالم است؛ اگر build به خاطر اسکریپتها شکست، میتوان نصب را بدون اسکریپت کرد و همهچیز را بهliara_pre_start.shسپرد (هماهنگ با کاری کهDockerfileبا--no-scriptsمیکند). - ماندگاری کلید JWT: دیسک
jwtحتماً mount شود؛ وگرنه هر دیپلوی کلید نو میسازد و توکنها باطل میشوند. - assetها فراموش نشوند: اگر
public/buildآپلود نشود، پنل ادمین لود نمیشود — قبل دیپلویyarn buildو.liaraignoreدرست. - documentRoot: اگر روی
publicست نشود، Apache فایلهای ریشه را سرو میکند و اپ ۴۰۴/۴۰۳ میدهد. - هماهنگی نسخهٔ DB:
serverVersionدرDATABASE_URLبا نسخهٔ MariaDB مدیریتشده یکی باشد (11.8). - این تغییر فقط زیرساخت دیپلوی است و هیچ route/endpoint را عوض نمیکند → نیازی بهروزرسانی
docs/api/*نیست. - یک مسیر را انتخاب کن: Docker (
liara.jsonفعلی +liara-compose.yaml) یا PHP platform (این پرامپت). همزمان هر دوliara.jsonنگهداشتنی نیست.