SSD Nodes Learn 🎉 VPS از $5.50/ماه
راهنماها Matt Connorتوسط Matt Connor · به‌روزرسانی شده 2026-08-13

آموزش نصب و میزبانی شخصی Planka با Docker Compose

راهنمای کامل استقرار Planka روی VPS با استفاده از Postgres و Traefik. نحوه تنظیم دقیق متغیر BASE_URL برای جلوگیری از خطای لاگین و پیکربندی صحیح دسترسی‌های ادمین.

مزایای میزبانی شخصی Planka

میزبانی شخصی Planka به تیم شما یک تخته کانبان با مدل کارت، لیست و برچسب می‌دهد که کاربران از Trello با آن آشنا هستند و روی یک VPS تحت کنترل شما اجرا می‌شود. هیچ محدودیتی برای تعداد کاربران وجود ندارد و هزینه‌ای به ازای هر کاربر پرداخت نمی‌کنید، زیرا تنها هزینه، همان هزینه سرور است. این راهنما Planka را با استفاده از Docker Compose پشت Traefik مستقر می‌کند؛ برای داده‌ها از Postgres و برای تمام فایل‌های آپلود شده توسط کاربران از یک named volume استفاده می‌شود.

مخاطب این راهنما تیمی دو تا پنج نفره است که قصد دارند از نسخه رایگان Trello مهاجرت کنند. اگر هنوز در حال تصمیم‌گیری برای انتخاب ابزار مدیریت پروژه هستید، ابتدا مقایسه جایگزین‌های Trello برای میزبانی شخصی را مطالعه کنید. این راهنما فرض را بر این می‌گذارد که انتخاب شما نهایی شده است و تنها به مراحل استقرار می‌پردازد.

شما به یک VPS نیاز دارید که Docker Engine به همراه پلاگین Compose روی آن نصب شده باشد و یک رکورد DNS از نوع A که به آن اشاره می‌کند. همچنین باید یک نمونه Traefik داشته باشید که در حال حاضر TLS (امنیت لایه انتقال) را روی همان سرور مدیریت می‌کند. اگر Traefik هنوز راه‌اندازی نشده است، ابتدا یک reverse proxy از نوع Traefik برای چندین برنامه Compose ایجاد کنید و اگر فایل زیر برایتان ناآشنا است، مبانی Docker Compose برای VPS را مطالعه کنید.

Planka به چه میزان منابع VPS نیاز دارد؟

این پروژه حداقل سخت‌افزار رسمی اعلام نکرده است، بنابراین هر عددی که مشاهده می‌کنید را به عنوان یک نقطه شروع در نظر بگیرید، نه یک معیار دقیق. ارقام 2 هسته vCPU و 4 گیگابایت رم که در صفحات میزبانی تکرار می‌شوند، مقادیر پیش‌فرض و راحت ارائه‌دهندگان هستند، نه الزامی که توسط تیم پروژه اندازه‌گیری شده باشد. این مقدار برای بردی که 5 نفر از آن استفاده می‌کنند، بسیار سخاوتمندانه است.

آنچه در واقع اجرا می‌شود، کوچک است: یک پردازش Node.js که API و فرانت‌اند کامپایل‌شده را سرویس‌دهی می‌کند و یک پردازش Postgres که داده‌ها را نگهداری می‌کند. یک پردازش پروکسی کوچک سوم نیز درون کانتینر Planka اجرا می‌شود تا درخواست‌های خروجی را فیلتر کند. یک پلن با 1 هسته vCPU و 2 گیگابایت رم برای یک برد با 2 تا 5 کاربر کافی است و بخش عمده‌ای از حافظه آزاد به عنوان کش Postgres استفاده خواهد شد.

پیش از تعیین اندازه حافظه، اندازه دیسک را مشخص کنید، زیرا فایل‌های پیوست بخشی هستند که رشد می‌کنند. به جای اعتماد به این پاراگراف، نمونه خود را اندازه‌گیری کنید:

docker stats --no-stream
docker system df -v

دستور اول، میزان لحظه‌ای مصرف حافظه و CPU هر کانتینر را نمایش می‌دهد. دستور دوم نشان می‌دهد که هر volume چه مقدار فضا اشغال کرده است. هر دو اندازه‌گیری را پس از یک هفته کاری عادی انجام دهید، نه در روز نصب؛ چرا که یک برد بدون فعالیت، اطلاعاتی درباره نحوه استفاده تیم شما ارائه نمی‌دهد.

نوشتن فایل Compose

دایرکتوری را ایجاد کرده و مالکیت آن را در اختیار بگیرید تا دیگر نیازی نباشد این فایل‌ها را از طریق sudo ویرایش کنید.

sudo mkdir -p /opt/planka
sudo chown "$USER":"$USER" /opt/planka
cd /opt/planka

رازها (secrets) را در یک فایل .env در کنار فایل Compose تولید کنید. Compose به‌طور خودکار این فایل را می‌خواند و مقادیر را جایگزین می‌کند.

umask 077
{
  printf 'SECRET_KEY=%s\n' "$(openssl rand -hex 64)"
  printf 'POSTGRES_PASSWORD=%s\n' "$(openssl rand -hex 24)"
  printf 'ADMIN_PASSWORD=%s\n' "$(openssl rand -hex 12)"
} > .env
chmod 600 .env

استفاده از openssl rand -hex عمدی است. یک رشته هگزادسیمال فقط شامل ارقام و حروف a تا f است، بنابراین نمی‌تواند رشته اتصال DATABASE_URL را که در آن قرار می‌گیرد، مختل کند. یک رمز عبور base64 که دارای اسلش یا علامت at باشد، خطای اتصالی ایجاد می‌کند که شبیه به نام میزبان (hostname) اشتباه به نظر می‌رسد و عیب‌یابی آن یک ساعت وقت شما را می‌گیرد. الگوی کلی‌تر در نگهداری رازها خارج از فایل Compose پوشش داده شده است.

حالا docker-compose.yml را اجرا کنید. در هر دو جایی که kanban.example.com ظاهر شده است، آن را با نام میزبان خود جایگزین کنید.

services:
  planka:
    image: ghcr.io/plankanban/planka:2.1.1
    restart: unless-stopped
    volumes:
      - planka-data:/app/data
    environment:
      - BASE_URL=https://kanban.example.com
      - DATABASE_URL=postgresql://planka:${POSTGRES_PASSWORD}@postgres/planka
      - SECRET_KEY=${SECRET_KEY}
      - TRUST_PROXY=true
      - DEFAULT_ADMIN_EMAIL=you@example.com
      - DEFAULT_ADMIN_PASSWORD=${ADMIN_PASSWORD}
      - DEFAULT_ADMIN_NAME=Your Name
      - DEFAULT_ADMIN_USERNAME=admin
    networks:
      - proxy
      - internal
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=proxy"
      - "traefik.http.routers.planka.rule=Host(`kanban.example.com`)"
      - "traefik.http.routers.planka.entrypoints=websecure"
      - "traefik.http.routers.planka.tls.certresolver=default"
      - "traefik.http.services.planka.loadbalancer.server.port=1337"
    depends_on:
      postgres:
        condition: service_healthy

  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=planka
      - POSTGRES_USER=planka
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    networks:
      - internal
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U planka -d planka"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  planka-data:
  db-data:

networks:
  proxy:
    external: true
  internal:

چهار تصمیم در آن فایل ارزش توضیح دارند، زیرا مواردی هستند که افراد تغییر می‌دهند و سپس پشیمان می‌شوند.

  • هیچ بلوک ports: روی سرویس Planka وجود ندارد. Traefik از طریق شبکه proxy به کانتینر دسترسی پیدا می‌کند، بنابراین پورت 1337 هرگز روی میزبان منتشر (publish) نمی‌شود. انتشار آن به هر کسی اجازه می‌دهد پروکسی و گواهی شما را دور بزند.
  • loadbalancer.server.port=1337 پورت داخل کانتینر را نام‌گذاری می‌کند. Planka روی 1337 گوش می‌دهد و نمونه بالادستی (upstream) فقط روی 3000 به آن دسترسی دارد زیرا پورت را به میزبان نگاشت (map) می‌کند. در اینجا هیچ نگاشت میزبانی وجود ندارد، بنابراین باید پورت کانتینر به Traefik اعلام شود.
  • condition: service_healthy با بررسی سلامت (healthcheck) دیتابیس Postgres جفت می‌شود. بدون آن، Planka پیش از آنکه دیتابیس اتصالات را بپذیرد شروع به کار می‌کند، در اولین کوئری خود شکست می‌خورد و خارج می‌شود که شبیه به یک حلقه کرش (crash loop) به نظر می‌رسد. جزئیات فنی در بررسی‌های سلامت و ترتیب راه‌اندازی در Compose آمده است.
  • سرویس دیتابیس عمداً postgres نام‌گذاری شده است. Planka 2 درخواست‌های خروجی خود را از طریق یک فیلتر داخلی هدایت می‌کند که لیست مسدودسازی پیش‌فرض آن localhost,postgres است. اگر سرویس را تغییر نام دهید، دیتابیس خود را بی‌سروصدا از آن لیست خارج می‌کنید.

پیش از شروع هر کاری، بررسی کنید که Compose می‌تواند رازهای شما را ببیند:

docker compose config | grep -E 'image:|BASE_URL|POSTGRES_USER'

این دستور فایل را با مقادیر .env که از قبل جایگزین شده‌اند چاپ می‌کند. مقدار خالی به این معنی است که Compose فایل .env را نمی‌خواند، که معمولاً به این دلیل است که دستور را از دایرکتوری متفاوتی اجرا می‌کنید.

متغیرهای bootstrap مدیر سیستم چه کاری انجام می‌دهند

از نسخه 1.13 به بعد Planka، هیچ حساب کاربری مدیری به‌طور خودکار برای شما ایجاد نمی‌شود؛ بنابراین در یک دیتابیس تازه، هیچ کاربری برای ورود وجود ندارد. گروه DEFAULT_ADMIN_* یکی از دو روش موجود برای حل این مشکل است.

در زمان راه‌اندازی، Planka به دنبال کاربری می‌گردد که با DEFAULT_ADMIN_EMAIL مطابقت داشته باشد. اگر چنین کاربری وجود نداشته باشد، Planka با استفاده از رمز عبور، نام نمایشی و نام کاربری تعیین‌شده در کنار آن، یک حساب ایجاد می‌کند. این اتفاق تنها در اولین بوت و روی یک دیتابیس خالی رخ می‌دهد؛ بنابراین این متغیرها برای bootstrap کردن یک حساب هستند، نه مدیریت آن.

DEFAULT_ADMIN_EMAIL وظیفه دومی هم دارد که باعث سردرگمی کاربران می‌شود. تا زمانی که این متغیر تنظیم شده باشد، حسابی که نام آن ذکر شده، از طریق رابط کاربری توسط هیچ‌کس قابل ویرایش یا حذف نیست. این یک محافظت در برابر قفل شدن (lock-out) است و به همین دلیل است که نمی‌توانید نام آن حساب یا آدرس ایمیل آن را در UI تغییر دهید. متغیر را حذف کرده و سرویس را restart کنید تا حساب به یک مدیر عادی تبدیل شود که مانند سایر حساب‌ها قابل ویرایش است.

در مورد خط رمز عبور باید دقت کنید. هر چیزی که تحت environment: باشد، برای هر کسی که بتواند docker inspect را روی container اجرا کند قابل خواندن است، بنابراین DEFAULT_ADMIN_PASSWORD نباید به‌صورت دائمی در آنجا باقی بماند. وارد سیستم شوید، رمز عبور خود را در رابط کاربری تغییر دهید، آن خط را حذف کنید و سپس دوباره docker compose up -d را اجرا کنید.

روش تمیزتر این است که کلاً از متغیرها صرف‌نظر کنید. کل گروه DEFAULT_ADMIN_* را comment کنید و سپس حساب را به‌صورت تعاملی ایجاد کنید:

docker compose run --rm planka npm run db:create-admin-user

این دستور از شما ایمیل، رمز عبور، نام نمایشی و یک نام کاربری اختیاری می‌خواهد و کاربر را مستقیماً در دیتابیس ثبت می‌کند. رمز عبور هرگز با فایل Compose یا محیط container تماس پیدا نمی‌کند. اگر بیش از یک نفر به shell سرور VPS دسترسی دارد، از این روش استفاده کنید. این دستور به دلیل depends_on ابتدا Postgres را بالا می‌آورد، بنابراین روی stackای که هرگز اجرا نشده نیز کار می‌کند.

هر دو روش شما را ملزم می‌کنند که رمزهای عبور Planka را به‌صورت دستی مدیریت کنید. اگر این چهارمین مجموعه از اعتبارنامه‌هایی است که تیم شما جمع‌آوری کرده، Planka می‌تواند ورود به سیستم را به یک ارائه‌دهنده OIDC مانند Authentik که به‌عنوان سرور single sign-on اختصاصی شما اجرا می‌شود واگذار کند و مدیر bootstrap را به‌عنوان یک حساب اضطراری (break-glass) برای روزهایی که ارائه‌دهنده در دسترس نیست، نگه دارید.

چرا BASE_URL در صورت عدم تطابق با نام میزبان، باعث اختلال در ورود می‌شود

BASE_URL همان آدرس دقیقی است که کاربران در مرورگر وارد می‌کنند، شامل طرح (scheme) و بدون اسلش در انتها. برای این پشته، این مقدار https://kanban.example.com است. Planka لینک‌های خود و اتصال WebSocket را بر اساس این مقدار می‌سازد؛ بنابراین یک BASE_URL نادرست، خطای واضحی نمی‌دهد. در عوض، صفحه‌ای را مشاهده می‌کنید که بارگذاری می‌شود اما هرگز به پایان نمی‌رسد.

حالت رایج این است: شما مثال بالادستی (upstream) را کپی می‌کنید، BASE_URL=http://localhost:3000 را به همان صورت باقی می‌گذارید و از طریق HTTPS روی دامنه واقعی خود به سایت دسترسی پیدا می‌کنید. فرم ورود ارسال شده و اعتبارنامه‌های شما پذیرفته می‌شود، اما صفحه برد هرگز ظاهر نمی‌شود. کنسول توسعه‌دهنده مرورگر را باز کنید؛ خواهید دید که درخواست‌ها به /socket.io/ با شکست مواجه می‌شوند، زیرا به کلاینت گفته شده اتصال زنده خود را به localhost:3000 برقرار کند، در حالی که روی لپ‌تاپ شما آن آدرس اصلاً وجود ندارد.

TRUST_PROXY=true نیمه دیگر همین مشکل است. Planka پشت Traefik قرار دارد، بنابراین هر درخواست از طریق آدرس پروکسی و با پروتکل HTTP ساده در شبکه Docker به آن می‌رسد. بدون TRUST_PROXY، برنامه هدرهای X-Forwarded-Proto و X-Forwarded-For که توسط Traefik تنظیم شده‌اند را نادیده می‌گیرد؛ در نتیجه تصور می‌کند اتصال ناامن است و با تمام کلاینت‌ها مانند یک آدرس IP مشترک برخورد می‌کند. با تنظیم این مقدار، برنامه هدرها را می‌خواند و در مورد طرح اتصال با مرورگر هم‌نظر می‌شود.

Traefik اتصالات WebSocket را بدون پیکربندی اضافی پروکسی می‌کند، که یکی از دلایل ترجیح آن در اینجا است. در nginx، پروتکل socket.io به بلوک location اختصاصی خود نیاز دارد که شامل proxy_set_header Upgrade $http_upgrade و proxy_set_header Connection "upgrade" باشد، در غیر این صورت با همان مشکل توقف بارگذاری (spinner) اما به دلیلی متفاوت مواجه خواهید شد.

انتقال برد به یک نام میزبان جدید در آینده، مستلزم تغییر همزمان دو مورد است: مقدار BASE_URL و قانون Host() در Traefik. اگر یکی را تغییر دهید و دیگری را فراموش کنید، دوباره با مشکل توقف بارگذاری مواجه می‌شوید. ارائه Planka از یک زیرمسیر (subpath) مانند https://example.com/planka از نسخه 2.1.0 به بعد که در مارس 2026 منتشر شد، امکان‌پذیر است. در تگ‌های قدیمی‌تر، از یک زیردامنه اختصاصی برای آن استفاده کنید.

محل ذخیره‌سازی پیوست‌ها و آواتارها در Planka

نسخه 2 نرم‌افزار Planka تمام فایل‌های آپلود شده توسط کاربر را در یک مسیر واحد داخل کانتینر ذخیره می‌کند: /app/data. پیوست‌ها، آواتارهای کاربران و تصاویر پس‌زمینه بردها همگی در این مسیر قرار دارند. نسخه 1 از سه دایرکتوری مجزا استفاده می‌کرد؛ بنابراین اگر فایل Compose را از آموزش‌های قدیمی کپی کرده باشید، مسیرهایی را mount می‌کنید که دیگر وجود ندارند و دایرکتوری اصلی داده‌ها بدون mount باقی می‌ماند.

آن mount واحد، تفاوت بین بردی است که پس از ارتقا سالم می‌ماند و بردی که باعث دردسر می‌شود. اگر /app/data روی یک volume قرار نداشته باشد، فایل‌های آپلود شده در لایه قابل‌نوشتن (writable layer) کانتینر ذخیره می‌شوند. این لایه با هر بار بازسازی کانتینر از بین می‌رود و کانتینر با هر بار تغییر تگ image بازسازی می‌شود. در این حالت، برد پس از بالا آمدن ظاهر درستی دارد و کارت‌ها سر جایشان هستند، اما تمام لینک‌های پیوست از کار می‌افتند؛ زیرا ردیف‌های دیتابیس همچنان به فایل‌هایی اشاره می‌کنند که دیگر وجود ندارند.

استفاده از named volume در فایل Compose بالا از این اتفاق جلوگیری می‌کند. bind mount نیز کارساز است و پشتیبان‌گیری از فایل‌ها را با ابزارهای معمولی آسان‌تر می‌کند، اما به یک مرحله اضافی نیاز دارد. پردازش Node داخل کانتینر با UID 1000 اجرا می‌شود، بنابراین اگر مالکیت دایرکتوری میزبان (host) در اختیار root باشد، در اولین آپلود با خطای مجوز مواجه خواهید شد:

sudo chown -R 1000:1000 /opt/planka/data

مزایا و معایب این دو روش در bind mounts در برابر named volumes بررسی شده است.

اگر حجم پیوست‌ها از فضای دیسک پلن شما فراتر رفت، Planka می‌تواند آن‌ها را از طریق S3_ENDPOINT، S3_BUCKET و متغیرهای کلیدی مربوطه، در فضای ذخیره‌سازی سازگار با S3 بنویسد. این تنظیم می‌تواند به یک bucket میزبانی‌شده یا یک سرویس ذخیره‌سازی شیء MinIO خودمیزبان روی سروری دیگر اشاره کند. پیش از آنکه تیم شما برد را پر کند، در این مورد تصمیم بگیرید، زیرا این تنظیم فقط برای آپلودهای جدید اعمال می‌شود.

راه‌اندازی استک و بررسی عملکرد آن

docker compose pull
docker compose up -d
docker compose ps

docker compose ps باید postgres را به عنوان healthy و planka را به عنوان running نشان دهد. اگر Planka در یک حلقه مدام در حال restart شدن است، اولین چیزی که باید بررسی کنید اتصال دیتابیس است، نه خود برنامه.

docker compose logs -f planka

یک راه‌اندازی اولیه موفق، ابتدا migrationهای دیتابیس را اجرا کرده و سپس گزارش می‌دهد که سرور روی پورت 1337 در حال گوش دادن است. برای اطمینان از اینکه schema واقعاً ایجاد شده است، به جای اعتماد به لاگ، مستقیماً از Postgres پرس‌وجو کنید:

docker compose exec postgres psql -U planka -d planka -c '\dt'

لیستی از جداول که شامل board و card باشد، به این معنی است که migrationها با موفقیت اجرا شده‌اند. پیام "Did not find any relations" یعنی Planka هرگز متصل نشده است؛ بنابراین DATABASE_URL را با مقادیر POSTGRES_USER و POSTGRES_PASSWORD در فایل .env خود مقایسه کنید.

سپس مسیر دسترسی را از دستگاه خودتان بررسی کنید، نه از داخل VPS:

curl -I https://kanban.example.com

HTTP/2 200 به این معنی است که Traefik گواهی را در اختیار دارد و به container دسترسی پیدا کرده است. خطای 404 که توسط Traefik ارسال می‌شود، یعنی برچسب‌های (labels) مسیریاب مطابقت ندارند؛ این مشکل معمولاً به این دلیل رخ می‌دهد که container به شبکه proxy متصل نشده است. اکنون سایت را باز کرده و با حساب کاربری مدیر وارد شوید.

پیش از هر ارتقای نسخه، یک pg_dump بگیرید

دو فضای ذخیره‌سازی مجزا، داده‌های برد شما را نگهداری می‌کنند، بنابراین پشتیبان‌گیری باید هر دو را پوشش دهد: پایگاه داده Postgres و volume مربوط به planka-data. در حالی که stack در حال اجرا است، از پایگاه داده dump بگیرید.

docker compose exec -T postgres pg_dump -U planka -d planka > "planka-db-$(date +%F).sql"

استفاده از -T اختیاری نیست. بدون آن، Compose یک pseudo-terminal تخصیص می‌دهد و لایه ترمینال، پایانه‌های خط را در جریان داده بازنویسی می‌کند؛ در نتیجه فایل dump حاصل در حین بازیابی دچار خطا می‌شود. این خطا ممکن است هفته‌ها بعد بروز کند که بدترین زمان ممکن برای مواجهه با آن است.

سپس نوبت به فایل‌های آپلود شده می‌رسد. ابتدا نام واقعی volume را پیدا کنید، زیرا Compose نام دایرکتوری پروژه را به عنوان پیشوند به آن اضافه می‌کند.

docker volume ls | grep planka
docker run --rm -v planka_planka-data:/data -v "$PWD":/backup alpine \
  tar czf /backup/planka-files-$(date +%F).tgz -C /data .

این پروژه همچنین docker-backup.sh و docker-restore.sh را در مخزن خود ارائه می‌دهد و مستندات رسمی، اجرای آن‌ها را در یک cron job شبانه توصیه می‌کنند. هر دو روش مناسب هستند. آنچه مناسب نیست، داشتن پشتیبانی است که هرگز آن را بازیابی نکرده‌اید؛ بنابراین یک بار آن را روی یک VPS آزمایشی بازیابی کنید و تأیید کنید که می‌توانید وارد سیستم شوید و یک فایل پیوست را باز کنید.

بلافاصله پیش از هر تغییر نسخه، dump بگیرید. پشتیبان شب گذشته با پشتیبانی که دقیقاً پیش از مهاجرتی که قصد انجام آن را دارید گرفته شده، متفاوت است.

تگ‌ها را ثابت (Pin) کنید و یادداشت‌های انتشار را بخوانید

هر دو تگ image در آن فایل، به‌عمد ثابت شده‌اند.

ghcr.io/plankanban/planka:2.1.1 یک انتشار خاص است که تا اوت 2026 معتبر است. latest با هر انتشار جدید توسط توسعه‌دهنده تغییر می‌کند، بنابراین یک docker compose pull روتین می‌تواند باعث اجرای یک migration طرح‌واره (schema) در زمانی شود که شما انتخاب نکرده‌اید. پیش از تغییر آن عدد، یادداشت‌های انتشار را بخوانید، زیرا تغییرات اساسی و اصلاحات امنیتی در آنجا شرح داده شده‌اند. نسخه 2.0.3 به‌عنوان یک انتشار امنیتی منتشر شد؛ این دقیقاً همان موردی است که می‌خواهید پیش از مواجهه ناگهانی با آن، درباره‌اش مطالعه کنید.

postgres:16-alpine به دلیل مهم‌تری روی یک نسخه اصلی (major version) ثابت شده است. Postgres دایرکتوری داده‌های خود را با فرمتی می‌نویسد که به نسخه اصلی وابسته است و سرور از باز کردن دایرکتوری که توسط نسخه دیگری نوشته شده، خودداری می‌کند. اگر postgres:latest را بنویسید و اجازه دهید تگ به 17 تغییر کند، container اجرا نخواهد شد:

FATAL:  database files are incompatible with server
DETAIL:  The data directory was initialized by PostgreSQL version 16, which is not compatible with this version 17.

هیچ داده‌ای از دست نمی‌رود و با restart کردن هم چیزی درست نمی‌شود. انتقال به یک نسخه اصلی جدید Postgres، مستلزم گرفتن dump از نسخه قدیمی و restore کردن آن در یک دایرکتوری داده جدید است. این یک عملیات برنامه‌ریزی‌شده است که باید در زمان خاموش بودن stack انجام شود، نه یک اثر جانبی ناشی از pull کردن image.

اگر به‌جای شروع از صفر، قصد انتقال یک نصب موجود از Planka 1.x را دارید، این ارتقا رویه مستند خاص خود را در مستندات پروژه دارد و بدون داشتن backup که از قبل تهیه شده باشد، راه بازگشتی به نسخه 1 وجود ندارد.

حالت‌های شکست و پیام‌هایی که مشاهده خواهید کرد

برنامه Planka در یک حلقه مدام restart می‌شود و لاگ به پایگاه داده اشاره دارد. اعتبارنامه‌های موجود در DATABASE_URL با متغیرهای محیطی Postgres مطابقت ندارند. توجه داشته باشید که POSTGRES_PASSWORD فقط در زمان اولین مقداردهی اولیه دایرکتوری داده اعمال می‌شود، بنابراین اصلاح متغیر پس از یک بوت ناموفق اولیه، تغییری ایجاد نمی‌کند. باید volume مربوط به db-data را حذف کرده و دوباره شروع کنید.

ورود موفقیت‌آمیز است اما برد (board) هرگز بارگذاری نمی‌شود. مقدار BASE_URL با آدرس موجود در نوار مرورگر مطابقت ندارد یا TRUST_PROXY تنظیم نشده است. کنسول مرورگر درخواست‌های ناموفق به /socket.io/ را نشان می‌دهد.

آپلودها با خطا مواجه می‌شوند اما سایر بخش‌ها کار می‌کنند. یک bind mount متعلق به کاربر root است. دستور sudo chown -R 1000:1000 را روی دایرکتوری میزبان اجرا کرده و container را restart کنید.

فایل‌های پیوست پس از ارتقا ناپدید شده‌اند. مسیر /app/data روی یک volume قرار نداشته است، بنابراین فایل‌ها در لایه container باقی مانده بودند که در فرآیند ارتقا جایگزین شد. فایل‌ها را از نسخه پشتیبان بازیابی کنید و پیش از تغییر مجدد تگ image، حتماً volume را اضافه کنید.

سرویس Traefik خطای 404 برمی‌گرداند. container در شبکه proxy قرار ندارد یا قانون Host() با رکورد DNS شما مطابقت ندارد. دستور docker compose config برچسب‌ها را پس از جایگذاری نشان می‌دهد؛ جایی که غلط‌های تایپی آشکار می‌شوند.

اعلان‌ها یا webhookها هرگز دریافت نمی‌شوند. نسخه 2 از Planka درخواست‌های HTTP خروجی خود را از طریق یک فیلتر داخلی ارسال می‌کند و لیست مسدودسازی پیش‌فرض شامل localhost و postgres است. یک webhook که به container دیگری روی همان میزبان اشاره دارد، ممکن است طبق طراحی مسدود شود. به جای حذف فیلتر، OUTGOING_ALLOWED_HOSTS را تنظیم کنید.

هنگامی که سرویس اجرا می‌شود، بار عملیاتی آن ناچیز است. یادداشت‌های انتشار (release notes) را دنبال کنید و پیش از هر ارتقا، از پایگاه داده dump بگیرید. یک reboot به دلیل وجود restart: unless-stopped، stack را به‌طور خودکار بالا می‌آورد، به شرطی که سرویس Docker در زمان بوت فعال باشد. بخش Compose stacks that come back after a reboot مواردی را که این اتفاق نمی‌افتد، پوشش می‌دهد.

FAQ

چرا Planka پس از ورود به سیستم، بی‌نهایت در حال بارگذاری می‌ماند؟

اعتبارنامه‌ها پذیرفته شده‌اند اما اتصال زنده برقرار نشده است. Planka آدرس WebSocket خود را از BASE_URL می‌سازد؛ بنابراین اگر این متغیر همچنان http://localhost:3000 باشد در حالی که شما از طریق https://kanban.example.com به سایت دسترسی دارید، مرورگر تلاش می‌کند سوکتی به آدرسی باز کند که روی ماشین شما وجود ندارد. کنسول توسعه‌دهنده مرورگر، درخواست‌های ناموفق به /socket.io/ را نشان می‌دهد. مقدار BASE_URL را دقیقاً روی آدرس عمومی بدون اسلش انتهایی تنظیم کنید، TRUST_PROXY=true را اضافه کنید تا برنامه هدر X-Forwarded-Proto را از reverse proxy شما بپذیرد، سپس دستور docker compose up -d را اجرا کنید.

چگونه اولین کاربر مدیر Planka را ایجاد کنم؟

از نسخه 1.13 به بعد، هیچ مدیر سیستمی به‌طور خودکار ایجاد نمی‌شود. یا متغیرهای DEFAULT_ADMIN_EMAIL را به همراه رمز عبور، نام و نام کاربری مربوطه تنظیم کرده و stack را اجرا کنید، یا دستور docker compose run --rm planka npm run db:create-admin-user را اجرا کرده و به پرسش‌ها پاسخ دهید. دستور تعاملی در سرورهای اشتراکی امن‌تر است، زیرا رمز عبور وارد محیط container نمی‌شود که docker inspect بتواند آن را بخواند. نگه داشتن DEFAULT_ADMIN_EMAIL پس از آن، باعث قفل شدن آن حساب در برابر ویرایش و حذف از طریق رابط کاربری می‌شود.

Planka فایل‌های پیوست و آواتارها را کجا ذخیره می‌کند؟

در Planka 2، تمام فایل‌های آپلود شده شامل پیوست‌ها، آواتارهای کاربران و پس‌زمینه بردها در مسیر /app/data داخل container قرار دارند. این مسیر را روی یک volume نام‌گذاری‌شده mount کنید. اگر این مسیر mount نشود، فایل‌ها در لایه قابل‌نوشتن container باقی می‌مانند و با بازسازی container (که در هر ارتقای image رخ می‌دهد) از بین می‌روند. bind mount نیز کار می‌کند، اما چون پردازش Node با UID 1000 اجرا می‌شود، باید دستور sudo chown -R 1000:1000 را روی دایرکتوری میزبان اجرا کنید، در غیر این صورت آپلودها با خطای مجوز مواجه می‌شوند.

Planka برای میزبانی شخصی به چه مقدار RAM نیاز دارد؟

این پروژه هیچ حداقل سخت‌افزاری رسمی منتشر نکرده است. عدد 2 vCPU و 4 GB که در صفحات میزبانی تکرار می‌شود، پیش‌فرض ارائه‌دهندگان است نه یک اندازه‌گیری دقیق، و برای یک برد کوچک بسیار سخاوتمندانه است. کل بار کاری شامل یک پردازش Node و یک پردازش Postgres است، بنابراین یک پلن با 1 vCPU و 2 GB برای تیمی دو تا پنج نفره کافی است. پس از یک هفته استفاده عادی، دستور docker stats --no-stream را اجرا کنید و بر اساس اعداد واقعی خود تصمیم بگیرید. دیسک را دقیق‌تر از حافظه زیر نظر بگیرید، زیرا فایل‌های پیوست عامل اصلی رشد مصرف منابع هستند.

چگونه Planka را بدون از دست دادن داده‌ها ارتقا دهم؟

بلافاصله پیش از ارتقا، از دیتابیس dump بگیرید و از volume فایل‌های آپلود شده آرشیو تهیه کنید؛ به پشتیبان‌گیری‌های شب گذشته اکتفا نکنید. از docker compose exec -T postgres pg_dump -U planka -d planka > planka-db.sql استفاده کنید و -T را نگه دارید تا pseudo-terminal باعث خرابی خروجی هدایت‌شده (redirected output) نشود. یادداشت‌های انتشار (release notes) مربوط به تمام نسخه‌هایی که از آن‌ها عبور می‌کنید را بخوانید، تگ image را از latest به یک نسخه خاص تغییر دهید، سپس docker compose pull و docker compose up -d را اجرا کرده و لاگ را برای مشاهده فرآیند migration زیر نظر بگیرید. تگ Postgres را روی نسخه اصلی (major version) خود ثابت نگه دارید، زیرا سرور از باز کردن دایرکتوری داده‌ای که توسط نسخه اصلی دیگری نوشته شده است، خودداری می‌کند.