# Liara Deployment Playbook (عمومی) راهنمای عمومی دیپلوی روی Liara — جمع‌بندی مشکلات رایج و راه‌حل‌هاشون. برای **هر پروژه‌ای** قابل استفاده‌ست. جای `<...>`ها مقدار پروژه‌ی خودت رو بذار. > قرارداد نام‌گذاری در این سند: > `` = اسم اپ، `` = اپ فرانت، `` = اپ بک‌اند/پنل، > `` = هاست داخلی دیتابیس، `` = API token لیارا، > `` = پورتی که اپ روش گوش می‌ده (Docker static: معمولاً 7860، Node: 3000). --- ## ۱) CLI — احراز هویت **مشکل:** دستورها با `Authentication failed` رد می‌شن، حتی بعد از `liara login` (توکن بین شل‌ها/محیط‌ها share نمی‌شه). **راه‌حل:** روی **هر** دستور `--api-token` بده: ```bash liara deploy --app --api-token "" ``` توکن از داشبورد Liara → API. --- ## ۲) `liara deploy` روی prompt پورت هنگ می‌کنه **مشکل:** دیپلوی روی `Enter the port your app listens to:` گیر می‌کنه و چیزی به Liara نمی‌رسه (مخصوصاً در حالت غیرتعاملی). **راه‌حل:** پورت رو صریح بده — هم فلگ، هم `liara.json`: ```bash liara deploy --app --port ... ``` ```json { "platform": "docker", "port": } ``` اپ هم باید روی `process.env.PORT` گوش بده (Liara اون رو inject می‌کنه). --- ## ۳) `Dockerfile cannot be empty` **علت:** `.dockerignore` خود `Dockerfile` رو exclude کرده. **راه‌حل:** `Dockerfile` رو از `.dockerignore` **بردار** — Liara باید Dockerfile رو توی آرشیو ببینه. --- ## ۴) Docker Hub از ایران بلاکه (مهم‌ترین برای Docker) **مشکل:** `FROM ` با `Get "https://registry-1.docker.io/...": Client.Timeout exceeded` تایم‌اوت می‌خوره. **راه‌حل:** image پایه رو از **میرور Liara** بکش: ```dockerfile # ایمیج رسمی (node, nginx, postgres, python, ...): FROM docker-mirror.liara.ir/library/: # ایمیج یوزر/سازمان: FROM docker-mirror.liara.ir//: ``` میرورهای دیگر Liara (در صورت نیاز داخل build): | نوع | میرور | |---|---| | Docker Hub | `docker-mirror.liara.ir` | | Alpine (apk) | `https://linux-mirror.liara.ir/repository/alpine/` | | npm | `https://package-mirror.liara.ir/repository/npm/` | > `npm ci`/`pip install` معمولاً از ایران بدون میرور کار می‌کنن؛ فقط Docker Hub همیشه مشکل‌سازه. > اگه داخل build `apk add` داری، میرور apk رو هم ست کن. --- ## ۵) لوکیشن build **نکته‌ی کلیدی:** **لوکیشن build ≠ لوکیشن میزبانی.** اپ همیشه روی منطقه‌ی خودش سرو می‌شه؛ `--build-location` فقط می‌گه image کجا کامپایل شه. - build ایران + میرورهای بالا → سریع و بدون تحریم: ```bash liara deploy --app --build-location iran ... ``` - اگه از میرور استفاده نمی‌کنی، build ایران به Docker Hub نمی‌رسه (از مورد ۴ استفاده کن). --- ## ۶) متغیرهای build-time در فرانت (Vite / CRA / Next static) **مشکل:** متغیر API URL رو به‌عنوان env روی اپ ست کردی ولی فرانت بهش وصل نشد. **علت:** باندلرها متغیرهای `VITE_*` / `REACT_APP_*` / `NEXT_PUBLIC_*` رو **موقع build داخل باندل می‌نویسن** — env runtime روی کانتینر استاتیک بی‌اثره. **راه‌حل:** توی Dockerfile قبل از build: ```dockerfile ARG VITE_API_URL=https://.liara.run ENV VITE_API_URL=$VITE_API_URL RUN npm run build ``` --- ## ۷) اتصال اپ به دیتابیس (Private Network) **مشکل‌ها:** - آدرس داخلی دیتابیس → `getaddrinfo ENOTFOUND `. - آدرس عمومی دیتابیس از داخل اپ Liara → `ECONNREFUSED`. **علت:** اپ‌های Liara به endpoint عمومی DB وصل نمی‌شن؛ و هاست داخلی فقط وقتی resolve می‌شه که اپ و DB **روی یک Private Network مشترک** باشن. **راه‌حل:** 1. هم دیتابیس هم اپ رو به **یک Private Network** وصل کن. 2. **connection string کاملِ** داخلی (نه فقط host:port): ``` DATABASE_URL=postgresql://:@:5432/ ``` 3. روی شبکه‌ی داخلی TLS لازم نیست (برعکس endpoint عمومی که TLS می‌خواد). --- ## ۸) اپ موقع بوت کرش می‌کنه چون env ست نیست **نشانه:** کانتینر `unhealthy` / `exit 255` و لاگ مثل `FATAL: is not set`. **راه‌حل:** env های حیاتی رو **قبل** از انتظارِ سالم‌بودن ست کن. تغییر env خودش ری‌استارت می‌کنه. ست با CLI (به‌جای داشبورد): ```bash liara env:set "KEY=VALUE" "KEY2=VALUE2" --app --force --api-token "" ``` > اگه کد بدون یه env حیاتی `process.exit` می‌کنه، تا ست نشه اصلاً بالا نمیاد. --- ## ۹) فایل‌سیستم Ephemeral **مشکل‌ها:** دیتابیس فایلی (SQLite) و پوشه‌ی آپلود با هر ری‌دیپلوی پاک می‌شن؛ نوشتن/`mkdir` روی مسیرهای read-only کرش می‌کنه. **راه‌حل:** - دیتای دائمی → **دیتابیس مدیریت‌شده**. - فایل/مدیا → **Object Storage** (مورد ۱۰). - اگه واقعاً دیسک لازمه → یه **Disk** بساز و mount کن؛ مسیر رو **env-based** کن. - هر نوشتن روی دیسک رو دفاعی بنویس که موقع بوت کرش نکنه: ```js const dir = process.env.UPLOADS_DIR || path.join(__dirname, 'uploads'); try { if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); } catch {} ``` --- ## ۱۰) Object Storage (S3) برای مدیا - S3-compatible؛ endpoint مثل `storage.iran.liara.site` + bucket + access key + secret key. - در کد: SDK اس‌تری (`@aws-sdk/client-s3`)، `forcePathStyle: true`، endpoint = `https://`. - URL عمومی فایل: `https://./`. - **باکت رو public کن** وگرنه فایل‌ها 403 می‌شن. --- ## ۱۱) پلتفرم اپ ثابته نمی‌شه پلتفرم یه اپ رو عوض کرد (Node↔Docker↔Static). اگه اشتباه ساختی، **پاک و با پلتفرم درست دوباره بساز** (env و اتصال شبکه‌ی خصوصی رو هم از نو ست کن). --- ## ۱۲) CORS **مشکل:** بک‌اند درخواست‌ها رو با `Not allowed by CORS` رد می‌کنه (حتی origin خودش). **راه‌حل:** allow-list رو شامل **دامنه‌ی خود اپ + دامنه‌ی فرانت** کن: ``` ALLOWED_ORIGINS=https://.liara.run,https://.liara.run ``` --- ## ۱۳) Seed / یوزر ادمین دیتابیس تازه خالیه → لاگین «رمز اشتباه». seed رو از Console اپ بزن. اگه اسکریپت seed یوزر موجود رو رد می‌کنه و رمز عوض نمی‌شه، از **upsert** استفاده کن. نکته‌ی مهم برای اسکریپت‌های seed: آدرس و رمز رو **env-based** کن تا هم لوکال هم روی Liara کار کنه: ```js const BASE = process.env.SEED_BASE || `http://localhost:${process.env.PORT || 3000}`; ``` > روش بدون TLS-dependency: اسکریپت seed که فقط `fetch` می‌زنه رو می‌تونی از ماشین خودت با `SEED_BASE=https://.liara.run` اجرا کنی. --- ## ۱۴) همگام‌سازی lockfile بعد از هر تغییر وابستگی‌ها، **لوکال `npm install`** بزن تا `package-lock.json` به‌روز شه، بعد دیپلوی — وگرنه `npm ci` روی Liara به‌خاطر mismatch خطا می‌ده. `node_modules` رو پوش نکن (`.liaraignore` / `.dockerignore`). --- ## ۱۵) لاگ و exit code گمراه‌کننده - `liara deploy` گاهی با `exit code 2` تموم می‌شه ولی واقعاً **موفق** بوده (خطا فقط مرحله‌ی خوندن لاگ بعد از دیپلوی). - `liara logs` گاهی لاگ **کش‌شده** می‌ده. **راه‌حل:** وضعیت واقعی رو از خروجی کامل دیپلوی (`√ Release created` / `Deployment finished successfully`) و یه **درخواست HTTP واقعی به دامنه** بگیر؛ به exit code تنها اعتماد نکن. --- ## فایل‌های پایه‌ی هر اپ `liara.json` (Docker): ```json { "platform": "docker", "port": } ``` `liara.json` (Node): ```json { "platform": "node" } ``` `.liaraignore`: ``` node_modules .env *.db uploads ``` --- ## چک‌لیست دیپلوی (ترتیب درست) 1. **دیتابیس** بساز → Private Network روشن. 2. **اپ بک‌اند** بساز → به همون Private Network وصلش کن. 3. env های بک‌اند رو ست کن (`DATABASE_URL` داخلیِ کامل، سکرت‌ها، `ALLOWED_ORIGINS`، کلیدهای Object Storage، `NODE_ENV=production`). 4. `package-lock.json` رو لوکال sync کن. 5. (Docker) Dockerfile: میرور `docker-mirror.liara.ir` + `ARG` برای متغیرهای build-time. `.dockerignore` نباید `Dockerfile` رو حذف کنه. 6. `liara deploy --app --port --build-location iran --api-token ""`. 7. سلامت رو با درخواست HTTP به دامنه چک کن (نه فقط exit code). 8. **seed محتوا/ادمین** (قبل از دیپلوی فرانت، تا سایت خالی نباشه). 9. باکت Object Storage رو public کن. 10. **فرانت** رو با متغیر build-time = دامنه‌ی بک‌اند دیپلوی کن؛ `ALLOWED_ORIGINS` بک‌اند رو شامل دامنه‌ی فرانت کن.