بهترین جایگزینهای خود-میزبانیشده Calendly
مقایسه Cal.com، Easy!Appointments، Rallly و DayOtter برای میزبانی روی VPS. بررسی دقیق دو چالش اصلی یعنی همگامسازی دوطرفه تقویم و تنظیمات ارسال ایمیل خروجی برای رزروها.
پاسخ کوتاه
یک جایگزین خود-میزبانیشده (self-hosted) برای Calendly باید کاری را انجام دهد که ابزارهای داخلی روی VPS شما هرگز انجام نمیدهند: پاسخگویی به عموم. صفحه رزرو، خودِ محصول است. این صفحه از همان روز اول به یک نام دامنه واقعی و TLS (امنیت لایه انتقال) نیاز دارد و باید بتواند برای افرادی که هرگز نام سرور شما را نشنیدهاند، ایمیل ارسال کند.
چهار پروژه، محدوده واقعبینانه این حوزه را پوشش میدهند. Cal.com نزدیکترین گزینه به Calendly و انتخاب پیشفرض برای یک مشاور مستقل است. ساده! Easy!Appointments گزینه سبکوزنی است که با PHP و MySQL کار میکند و روی یک VPS با 1 GB رم بهخوبی اجرا میشود. Rallly یک ابزار نظرسنجی گروهی است و اصلاً صفحه رزرو ندارد. DayOtter تازهواردترین گزینه است؛ یک پلتفرم زمانبندی تحت مجوز AGPLv3 که یک دستیار با قابلیت تأیید اولیه در مقابل آن قرار دارد.
دو پرسش تعیین میکنند که کدامیک را واقعاً میتوانید اجرا کنید. آیا این ابزار با تقویمی که هماکنون از آن استفاده میکنید، همگامسازی دوطرفه دارد؟ و آیا میتواند ایمیل ارسال کند؟ پرسش دوم جایی است که اکثر تنظیمات رزرو خود-میزبانیشده در سکوت شکست میخورند، بنابراین اولویت با آن است.
ارسال ایمیل خروجی بخشی است که با شکست مواجه میشود
تأییدیه رزرو به صندوق ورودی یک فرد ناشناس ارسال میشود. این یک ایمیل تراکنشی است که به Gmail یا Microsoft 365 میرسد و این گیرندگان شما را بر اساس آدرس IP فرستنده و رکوردهای DNS قضاوت میکنند.
ارسال مستقیم از VPS تقریباً هرگز کار نمیکند. اکثر ارائهدهندگان، پورت TCP 25 خروجی را در حسابهای جدید مسدود میکنند، بنابراین اتصال معلق مانده و سپس با خطای timeout مواجه میشود. حتی در مواردی که پورت 25 باز است، یک آدرس VPS تازه هیچ سابقه ارسالی ندارد و گیرندگان بزرگ، آدرسهای محدوده میزبانی ناشناخته را مشکوک تلقی میکنند. رزرو در دیتابیس ثبت میشود، صفحه پیام تأیید را نشان میدهد، اما هیچکس ایمیلی دریافت نمیکند. از سمت سرور همه چیز سالم به نظر میرسد و به همین دلیل است که این مشکل معمولاً هفتهها بعد توسط مشتری که هرگز مراجعه نکرده، کشف میشود.
از یک relay استفاده کنید. هر ارائهدهنده ایمیل تراکنشی کار میکند و برنامه فقط به یک hostname، یک پورت، یک نام کاربری و یک رمز عبور نیاز دارد. پیش از آنکه تنظیمات برنامه را تغییر دهید، بررسی کنید که آیا پورت در دسترس است یا خیر:
nc -vz -w 5 "$SMTP_HOST" 587یک خط succeeded به این معنی است که مسیر باز است. معلق ماندن یا Connection refused به این معنی است که پورت در سطح شبکه مسدود شده است و هیچ مقدار ویرایشی در .env آن را اصلاح نخواهد کرد. Relayها دقیقاً به این دلیل روی پورتهای 587 یا 465 گوش میدهند که پورت 25 اغلب مسدود است.
هر پروژه relay را به روش خاص خود دریافت میکند. Cal.com مقادیر EMAIL_FROM، EMAIL_SERVER_HOST، EMAIL_SERVER_PORT، EMAIL_SERVER_USER و EMAIL_SERVER_PASSWORD را میخواند و همچنین یک RESEND_API_KEY را نیز میپذیرد. مراقب آن باشید: فایل .env.example پیشفرض، EMAIL_SERVER_HOST را به localhost روی پورت 1025 اشاره میدهد که یک صندوق پستی محلی برای توسعه است. مقدار پیشفرض را همانطور رها کنید تا برنامه بدون هیچ خطایی، ایمیلها را به ناکجا بفرستد. Rallly مقادیر SMTP_HOST، SMTP_PORT، SMTP_USER و SMTP_PWD را میگیرد. DayOtter تنظیمات SMTP یا یک کلید Resend را میپذیرد. Easy!Appointments اعلانهای خود را از داخل برنامه ارسال میکند، بنابراین پیش از پذیرش رزرو واقعی، آن را از صفحه تنظیمات به همان relay اشاره دهید.
سپس رکوردهای DNS که relay به شما میدهد را منتشر کنید. یک رکورد SPF (چارچوب سیاست فرستنده) مشخص میکند که کدام سرورها مجاز به ارسال از طرف دامنه شما هستند و یک کلید DKIM (ایمیل شناساییشده با کلید دامنه) هر پیام را امضا میکند تا گیرنده بتواند ثابت کند که پیام تغییر نکرده است. پس از تأیید هر دو، یک سیاست DMARC (احراز هویت، گزارشدهی و انطباق ایمیل مبتنی بر دامنه) اضافه کنید. یک رزرو آزمایشی به یک آدرس واقعی در یک ارائهدهنده بزرگ بفرستید، هدرهای پیام را باز کنید و تأیید کنید که خطوط احراز هویت عبارت pass را نشان میدهند. یک صفحه رزرو که نمیتواند ایمیل بفرستد، از نداشتن صفحه رزرو بدتر است، زیرا بیسروصدا شکست میخورد.
کدام بکاندهای تقویم واقعاً همگامسازی دوطرفه دارند
همگامسازی دو جهت دارد و هر کدام ممکن است جداگانه با شکست مواجه شوند. جهت خواندن به معنای در دسترس بودن است: برنامه باید بلوکهای زمانی مشغول شما را ببیند، در غیر این صورت زمانی را به شما اختصاص میدهد که در آن مشغول هستید. جهت نوشتن به معنای خودِ فرآیند رزرو است: رویداد تأییدشده باید در تقویمی که واقعاً از آن استفاده میکنید ظاهر شود، نه فقط در داخل ابزار رزرو.
Google Calendar و Microsoft 365 هر دو جهت را پشتیبانی میکنند، البته با یک شرط در نصبهای self-hosted. شما باید کلاینت OAuth (مجوزدهی باز) را خودتان بسازید، زیرا Client ID محصول میزبانیشده در سورسکد وجود ندارد. برای Cal.com این مورد GOOGLE_API_CREDENTIALS در .env است که فایل JSON دانلود شده از Google Cloud console را در خود نگه میدارد. DayOtter نیز اعتبارنامههای OAuth گوگل و مایکروسافت را به همین روش دریافت میکند.
دو مورد در اینجا باعث بروز مشکل میشود که دانستن هر دو پیش از شروع کار مفید است. اول، آدرس redirect URI که ثبت میکنید باید دقیقاً با URL عمومی شما مطابقت داشته باشد، شامل طرح (scheme) و هر مسیر انتهایی؛ در غیر این صورت گوگل اتصال را با خطای redirect_uri_mismatch در صفحه رضایت (consent screen) متوقف میکند. دوم، پروژهای در گوگل که در وضعیت انتشار Testing باقی بماند، توکنهای تازهسازی (refresh tokens) صادر میکند که پس از هفت روز منقضی میشوند. همگامسازی در طول هفته کار میکند و سپس متوقف میشود و لاگهای برنامه در تازهسازی بعدی خطای invalid_grant را نشان میدهند. وضعیت صفحه رضایت را به In production تغییر دهید، یا بپذیرید که هر دوشنبه باید دوباره بهصورت دستی متصل شوید.
CalDAV (افزونههای تقویم برای WebDAV) گزینه متنباز است، اما پشتیبانی از آن محدودتر است. Cal.com یک برنامه CalDAV ارائه میدهد که هنوز در وضعیت بتا است و با سرورهایی از جمله Baikal، Radicale، Nextcloud و Kerio Connect تست شده است. Apple iCloud از طریق همین برنامه کار میکند اما به جای رمز عبور Apple ID، به یک رمز عبور مخصوص برنامه (app-specific password) نیاز دارد. DayOtter نیز Apple را از طریق CalDAV در کنار Google و Microsoft 365 فهرست کرده است.
فید ICS یک همگامسازی نیست. یک URL اشتراکی .ics طبق طراحی فقط خواندنی است، بنابراین میتواند زمان را در صفحه رزرو شما مسدود کند اما هرگز نمیتواند رزرو را دریافت کند. اگر ابزاری فقط ICS را برای تقویم شما ارائه میدهد، شما نیمی از زیرساخت را دارید و همچنان مجبور خواهید بود رویدادها را بهصورت دستی کپی کنید.
Easy!Appointments فقط با Google Calendar همگامسازی میشود و هیچ گزینه دیگری ندارد. Rallly اصلاً در دسترس بودن را نمیخواند: این ابزار فقط آرا را برای مجموعهای از تاریخهای پیشنهادی جمعآوری میکند. این ابزار برای سناریوی «چه زمانی هر شش نفر ما میتوانیم همدیگر را ببینیم» مناسب است و برای «رزرو 30 دقیقه وقت با من» ابزار اشتباهی است.
صفحه رزرو عمومی است، بنابراین TLS اولویت دارد
بیشتر سرویسهایی که افراد بهصورت self-host اجرا میکنند، خصوصی هستند. یک ویکی، یک تابلوی اعلانات یا یک داشبورد، همگی میتوانند پشت یک VPN یا ورود SSO قرار بگیرند و هرگز در معرض اینترنت آزاد نباشند. اما لینک رزرو نمیتواند اینگونه باشد. هر کسی که لینک را برایش میفرستید باید بتواند آن را بارگذاری کند، که این موضوع تنظیمات را از سه جهت مشخص تغییر میدهد.
پیش از نصب هر چیزی، به یک نام دامنه با رکورد A نیاز دارید که به VPS اشاره کند. از همان روز اول به گواهی نیاز دارید، زیرا مرورگرها فرمهای HTTP ساده را ناامن علامتگذاری میکنند و مشتری شما در حال وارد کردن نام و ایمیل خود در آن است. همچنین باید URL عمومی برنامه را بهدرستی در فایل پیکربندی آن تنظیم کنید، زیرا این مقدار در لینکهای موجود در ایمیلهای ارسالی و در URIهای بازگشت OAuth درج میشود. مقدار NEXT_PUBLIC_WEBAPP_URL را در Cal.com، DOMAIN را در Rallly، BASE_URL را در Easy!Appointments یا DAYOTTER_DOMAIN را در زمان نصب تنظیم کنید و آن را روی آدرس https:// که واقعاً استفاده خواهید کرد، قرار دهید.
برنامههای Rallly و DayOtter مشکل TLS را برای شما حل میکنند. پشته بستهبندیشده Rallly شامل Traefik است و با استفاده از آدرس موجود در ACME_EMAIL، گواهیهای Let's Encrypt صادر میکند. نصبکننده DayOtter نیز Caddy را با HTTPS خودکار بالا میآورد. برنامههای Cal.com و Easy!Appointments این قابلیت را ندارند، بنابراین باید nginx را در مقابل آنها قرار دهید و خودتان گواهی را صادر کنید؛ دقیقاً به همان روشی که برای صدور گواهی Let's Encrypt روی nginx با استفاده از Certbot انجام میدهید. کانتینر برنامه را به 127.0.0.1 متصل کنید تا تنها راه دسترسی، از طریق پروکسی تحت کنترل شما باشد. اگر همان سرور در حال حاضر یک جایگزین Trello برای بردهای داخلی شما را اجرا میکند، آن را پشت احراز هویت فعلی خود نگه دارید و فقط برای میزبان رزرو، یک server block عمومی تعریف کنید.
اجرای Cal.com روی VPS
پیکربندی Docker در مخزن اختصاصی خود قرار دارد و imageها از قبل در Docker Hub ساخته شدهاند، بنابراین بهجای build کردن، باید آنها را pull کنید.
git clone --recursive https://github.com/calcom/cal.diy.git
cd cal.diy
cp .env.example .env
openssl rand -base64 32
openssl rand -base64 24
docker compose pull
docker compose up -dاولین مقدار تصادفی در NEXTAUTH_SECRET و دومی در CALENDSO_ENCRYPTION_KEY قرار میگیرد. هر دو مقدار الزامی هستند. DATABASE_URL را تنظیم کنید و NEXT_PUBLIC_WEBAPP_URL را به آدرس عمومی خود اشاره دهید. پشتهٔ بستهبندیشده شامل برنامهٔ وب، PostgreSQL و Prisma Studio است؛ مستندات برای اجرای برنامه بهتنهایی در مقابل دیتابیسی که در جای دیگری میزبانی میکنید، docker compose up -d calcom را پیشنهاد میدهند که پس از نهایی شدن نصب، همان چیزی است که به آن نیاز دارید.
image را pull کنید و آن را روی VPS نسازید. دستورالعملهای خود پروژه به شما میگویند که هنگام build از سورس، NODE_OPTIONS="--max-old-space-size=16384" را export کنید که برای Node بهتنهایی به 16 گیگابایت حافظه نیاز دارد. روی سختافزار ARM، پسوند -arm را به تگ image اضافه کنید. پروژه حداقل حافظهٔ مشخصی برای اجرای image از پیش ساختهشده اعلام نکرده است، بنابراین عدد 2 گیگابایت برای برنامه بهعلاوهٔ PostgreSQL را بهعنوان رقم کاری من در نظر بگیرید (نه یک عدد مستند) و در هفتهٔ اول میزان مصرف حافظه را مانیتور کنید.
بالا آمدن آن را بررسی کنید:
docker compose ps
docker compose logs -f calcom
curl -sI https://cal.example.com | head -n 1دستور curl باید HTTP/2 200 را چاپ کند. دریافت 502 Bad Gateway از Nginx در حالی که container در وضعیت در حال اجرا است، معمولاً به این معنی است که اولین بوت هنوز در حال اعمال migrationهای دیتابیس است. چند دقیقه صبر کنید و پیش از آنکه نتیجه بگیرید برنامه خراب است، لاگها را بخوانید. webhookهای Cal.com با هر رزرو تأییدشده فعال میشوند، بنابراین یک رزرو میتواند هر اتوماسیونی که از قبل اجرا کردهاید را به کار بیندازد؛ برای مثال یک نمونه n8n که از طریق HTTPS روی VPS شما در دسترس است.
هستهٔ این پروژه AGPLv3 است و برخی قابلیتها در یک دایرکتوری سازمانی تحت لایسنس تجاری جداگانه قرار دارند. پیش از آنکه یک فرایند کسبوکار پولی را بر پایهٔ قابلیتهای تیمی بنا کنید، آن لایسنس را مطالعه کنید.
اجرای Easy!Appointments روی یک سرور 1 گیگابایتی
پیشنیازها شامل Apache یا Nginx، نسخه PHP 8.2 یا جدیدتر و MySQL است. یک ایمیج رسمی در alextselegidis/easyappointments وجود دارد.
ابتدا یک هشدار: docker-compose.yml موجود در مخزن، یک محیط توسعه (development) است. این محیط انتظار دارد که شما یک shell در کانتینر باز کنید و npm install && composer install && npm start را اجرا کنید. این یک محیط عملیاتی (deployment) نیست. بهجای آن از ایمیج منتشرشده استفاده کنید:
services:
easyappointments:
image: alextselegidis/easyappointments # pin the current tag from Docker Hub
environment:
- BASE_URL=https://book.example.com
- DB_HOST=mysql
- DB_NAME=easyappointments
- DB_USERNAME=easyapp
- DB_PASSWORD=change-me
ports:
- '127.0.0.1:8080:80'
depends_on:
- mysql
mysql:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=change-me-too
- MYSQL_DATABASE=easyappointments
- MYSQL_USER=easyapp
- MYSQL_PASSWORD=change-me
volumes:
- ./mysql:/var/lib/mysqlBASE_URL باید آدرس عمومی HTTPS باشد. اگر آن را اشتباه وارد کنید، لینکهای رزرو موجود در ایمیلهای تأیید به میزبانی اشاره میکنند که کلاینت شما به آن دسترسی ندارد. این ایمیج، HTTP ساده را روی پورت 80 ارائه میدهد و گواهی اختصاصی ندارد؛ به همین دلیل پورت به 127.0.0.1 متصل شده و Nginx وظیفه TLS termination را در مقابل آن بر عهده میگیرد. اگر سینتکس compose برای شما جدید است، با اصول Docker Compose روی VPS شروع کنید و سپس به اینجا بازگردید.
این گزینه با اختلاف زیاد، سبکترین گزینه در اینجا است. دو کانتینر، یکی برای برنامه PHP و دیگری برای MySQL، بهراحتی روی یک VPS با 1 گیگابایت رم اجرا میشوند. هزینه این سبکی، محدودیت در دسترسی است: Google Calendar تنها backend تقویم است و رابط کاربری آن یک پنل مدیریت سنتی است، نه یک جریان رزرو مدرن. اگر تقویم شما Microsoft 365، Fastmail یا Nextcloud است، این گزینه پیش از شروع کار برای شما مناسب نخواهد بود.
Rallly برای نظرسنجیهای گروهی
Rallly به پرسش متفاوتی پاسخ میدهد. این ابزار در دسترس بودن شما را منتشر نمیکند، بلکه مجموعهای از زمانهای پیشنهادی را در اختیار گروه قرار داده و رأیگیری میکند. این قابلیت برای جلسات هیئتمدیره مناسب است، اما برای لینکهای رزرو مشتری کاربردی ندارد.
curl -fsSL https://get.rallly.co | bashپیش از آنکه هر اسکریپتی را به shell بفرستید (pipe)، آن را مطالعه کنید. bash را با less جایگزین کنید، عملکرد آن را بخوانید و سپس اجرا کنید. مسیر دستی، همان کار را در مراحلی انجام میدهد که میتوانید مشاهده کنید:
git clone https://github.com/lukevella/rallly-selfhosted.git
cd rallly-selfhosted
./rallly.sh setup
./rallly.sh startنیازمندیهای مستندشده شامل حداقل 2 GB رم، Docker نسخه 19.03 یا جدیدتر با Compose v2، پورتهای 80 و 443 آزاد و یک دامنه متصل به سرور است. پشته (stack) بستهبندیشده شامل Traefik برای HTTPS، برنامه وب، PostgreSQL و Garage برای ذخیرهسازی شیء (object storage) سازگار با S3 است. مقادیر DOMAIN، یک SECRET_PASSWORD با حداقل 32 کاراکتر، SUPPORT_EMAIL و INITIAL_ADMIN_EMAIL را تنظیم کنید. اگر از قبل یک reverse proxy دارید، PROXY_MODE=external و WEB_PORT را تنظیم کنید تا Traefik دخالتی نداشته باشد. اگر از قبل یک سرویس ذخیرهسازی شیء سازگار با S3 به صورت self-hosted با MinIO اجرا میکنید، متغیرهای S3_* را به آن اشاره دهید و container مربوط به Garage را حذف کنید.
SMTP در اینجا اختیاری نیست، زیرا ورود به سیستم از طریق magic link انجام میشود. بدون یک relay فعال، هیچکس نمیتواند وارد شود، از جمله حساب کاربری مدیری که بهتازگی ایجاد کردهاید. این نسخه مثبت از شکست در ارسال ایمیل است: بهجای اینکه سه هفته بعد رزرو مشتری را از دست بدهید، همان ابتدا مانع ورود شما میشود.
DayOtter، تازهوارد این حوزه
DayOtter یک پلتفرم زمانبندی تحت مجوز AGPLv3 است که به یک دستیار هوشمند مجهز شده است. نصب نسخه production تنها با یک دستور انجام میشود:
curl -fsSL https://raw.githubusercontent.com/Dayotter/dayotter/main/deploy/install.sh \
| sudo DAYOTTER_DOMAIN=cal.example.com bashپیش از اجرای دستور بالا، آن را مطالعه کنید. این نصبکننده Docker را راهاندازی کرده، کلیدهای امنیتی (secrets) را تولید میکند و کل stack را بالا میآورد: اپلیکیشن وب Next.js، یک background worker برای مدیریت یادآورها، همگامسازی تقویم و webhooks، دیتابیس PostgreSQL، سرویس Redis و Caddy برای مدیریت خودکار HTTPS.
پشتیبانی از تقویم در این ابزار نسبت به چهار مورد دیگر گستردهتر است. این پلتفرم از Google، Microsoft 365، Apple از طریق CalDAV و فیدهای ICS (با در نظر گرفتن محدودیتهای ذکر شده برای ICS) پشتیبانی میکند. سایر قابلیتهای یکپارچهسازی بهصورت اختیاری و از طریق متغیرهای محیطی (environment variables) فعال میشوند؛ از جمله SMTP یا Resend برای ایمیل، ANTHROPIC_API_KEY برای دستیار هوشمند، Twilio برای پیامک و Stripe برای پرداختها. دستیار هوشمند بر اساس تأیید کاربر عمل میکند: ابتدا پیشنهاد میدهد، شما تأیید میکنید و هیچ تغییری بدون تأیید صریح شما در تقویم اعمال نمیشود. اگر کلید API را خالی بگذارید، آن بخش از محصول بهسادگی اجرا نخواهد شد.
وضعیت مجوز برای کسانی که قصد میزبانی شخصی (self-hosting) دارند شفاف است. هسته اصلی تحت مجوز AGPLv3 است و دایرکتوری ee/ شامل یک مجوز تجاری مخصوص سرویسهای ابری است که تا زمانی که DAYOTTER_CLOUD=1 تنظیم نشود، غیرفعال باقی میماند. این بدان معناست که قابلیتهای تیمی که در طرح میزبانیشده (hosted plan) با هزینه 9 دلار برای هر کاربر در ماه (تا اوت 2026) ارائه میشوند، در سرور شخصی شما نیز قابل استفاده هستند.
این سنگینترین stack در میان گزینههای این لیست و جوانترین پروژه است. پیشنهاد میشود آن را به مدت 2 هفته در کنار لینک رزرو فعلی خود اجرا کنید، رزروهای واقعی را از هر دو مسیر دریافت کنید و پیش از انتقال کامل مشتریان، لاگهای worker را بررسی نمایید.
هزینه واقعی هر پشته (Stack)
تعداد کانتینرها معیار صادقانهای برای سنجش میزان منابعی است که یک پشته از یک VPS کوچک طلب میکند، زیرا هر سرویس حداقل حافظه مصرفی خاص خود را دارد. این آمارها بر اساس پشتههای Docker منتشرشده توسط خود پروژهها در اوت 2026 استخراج شدهاند.
The data behind this chart
[
{
"tool": "Easy!Appointments",
"containers": 2,
"database": "MySQL"
},
{
"tool": "Cal.com",
"containers": 3,
"database": "PostgreSQL"
},
{
"tool": "Rallly",
"containers": 4,
"database": "PostgreSQL"
},
{
"tool": "DayOtter",
"containers": 5,
"database": "PostgreSQL and Redis"
}
]نصب Easy!Appointments به 2 کانتینر نیاز دارد و روی 1 گیگابایت رم اجرا میشود. پشته بستهبندیشده Rallly شامل 4 کانتینر است و مستندات آن 2 گیگابایت رم درخواست میکند. نصبکننده DayOtter تعداد 5 کانتینر را بالا میآورد و به همین دلیل است که به بزرگترین سرور در میان 4 مورد موجود در اینجا نیاز دارد. Cal.com و DayOtter هیچ حداقل حافظهای را اعلام نکردهاند، بنابراین 2 گیگابایت نقطه شروع پیشنهادی من برای هر دو است، نه یک عدد رسمی و پشتیبانیشده.
اگر از قبل زیرساختی دارید، تعداد کانتینرها در دو مورد کاهش مییابد. کانتینرهای Traefik و Garage در Rallly زمانی که آن را به پروکسی و فضای ذخیرهسازی شیء (object storage) خود متصل کنید، حذف میشوند. ابزار Prisma Studio در Cal.com یک ابزار توسعه است که نباید آن را روی سرور عمومی فعال نگه دارید.
کدام جایگزین self-hosted برای Calendly را انتخاب کنید
یک مشاور مستقل باید Cal.com را اجرا کند. این تنها پروژه در این فهرست است که یک صفحه رزرو شناختهشده برای کاربران، ایمیجهای از پیش ساختهشده (که VPS شما را از فرآیند Node build بینیاز میکند) و یک مسیر CalDAV برای کسانی که از تقویم Google یا Microsoft استفاده نمیکنند را ترکیب کرده است. یک دیتابیس PostgreSQL و یک کانتینر اپلیکیشن، بار نگهداری است که میتوانید سالها آن را مدیریت کنید. یک بعدازظهر را برای تنظیم OAuth client و mail relay در نظر بگیرید و توجه داشته باشید که اپلیکیشن CalDAV هنوز در مرحله بتا است؛ بنابراین پیش از انتشار لینک، یک رزرو واقعی را بهطور کامل تست کنید.
یک تیم کوچک باید DayOtter را بررسی کند. قابلیتهای weighted round robin و رزرو گروهی در هسته AGPLv3 این پروژه قرار دارند، بنابراین self-hosting به شما امکاناتی را میدهد که در سرویسهای میزبانیشده بابت آن هزینه دریافت میشود. همچنین worker process آن برای یادآورها و webhookهایی که تیمها واقعاً به آن متکی هستند، ساخته شده است. هزینه این انتخاب، بلوغ پروژه است: این جدیدترین پروژه در این فهرست است، بنابراین ابتدا آن را بهصورت موازی اجرا کنید و لینک قدیمی را تا زمانی که یک ماه کامل از رزروها را زیر نظر نگرفتهاید، فعال نگه دارید.
دو مورد محدودتر: اگر تنها چیزی که نیاز دارید یک نظرسنجی برای یافتن زمان مناسب جهت جلسه گروهی است، Rallly را نصب کنید و به همان بسنده کنید. اگر یک VPS با 1 GB رم دارید، از Google Calendar استفاده میکنید و به دنبال کوچکترین ابزاری هستید که رزرو انجام دهد، Easy!Appointments از هر گزینه پرزرقوبرق دیگری که روی آن سرور قرار دهید، ماندگارتر خواهد بود. برای پاسخ به پرسش کلیتر درباره اینکه چه چیزهای دیگری ارزش میزبانی روی همان سرور را دارند، به چه چیزی در سال 2026 ارزش self-hosting دارد مراجعه کنید.
FAQ
آیا میتوانم یک صفحه رزرو self-hosted را بدون نام دامنه اجرا کنم؟
خیر. تمام این برنامهها URL عمومی خود را در لینکهای داخل ایمیلهای تأیید مینویسند و Google و Microsoft هر دو URI تغییر مسیر OAuth را با همان مقدار تطبیق میدهند، بنابراین یک آدرس IP خام باعث میشود در صفحه رضایت با redirect_uri_mismatch مواجه شوید. Let’s Encrypt نیز برای یک آدرس IP گواهی صادر نمیکند، بنابراین صفحه از طریق HTTP ساده بارگذاری میشود و مرورگر فرم را به عنوان ناامن علامتگذاری میکند. ابتدا دامنه را بخرید، یک رکورد A به سمت VPS تنظیم کنید و سپس نصب را انجام دهید.
چرا ایمیلهای تأیید رزرو من هرگز نمیرسند؟
تقریباً همیشه به این دلیل است که سرور سعی میکند ایمیل را خودش ارسال کند. اکثر ارائهدهندگان VPS پورت 25 خروجی را در حسابهای جدید مسدود میکنند، بنابراین اتصال معلق میماند؛ حتی در مواردی که این پورت باز باشد، یک آدرس جدید اعتبار ارسال ندارد و سرویسدهندگان بزرگ ایمیل آن را رد میکنند. برنامه را به یک رله ایمیل تراکنشی روی پورت 587 متصل کنید، با استفاده از nc -vz -w 5 "$SMTP_HOST" 587 مطمئن شوید که پورت در دسترس است و سپس رکوردهای SPF و DKIM ارائهشده توسط رله را منتشر کنید. اگر از Cal.com استفاده میکنید، بررسی کنید که مقادیر پیشفرض EMAIL_SERVER_HOST=localhost و EMAIL_SERVER_PORT=1025 که به یک صندوق پستی توسعه محلی اشاره دارند را جایگزین کرده باشید.
آیا Cal.com نسخه self-hosted با CalDAV همگامسازی میشود یا فقط با Google؟
هر دو، با سطوح بلوغ متفاوت. برنامه CalDAV به عنوان نسخه بتا علامتگذاری شده و با سرورهایی از جمله Baikal، Radicale، Nextcloud و Kerio Connect تست شده است؛ Apple iCloud نیز با استفاده از یک رمز عبور مخصوص برنامه از طریق آن کار میکند. Google Calendar و Microsoft 365 هر دو در هر دو جهت همگامسازی میشوند، اما در یک نصب self-hosted باید کلاینت OAuth خود را ایجاد کرده و آن را از طریق GOOGLE_API_CREDENTIALS ارائه دهید، زیرا اعتبارنامههای سرویس میزبانیشده در سورسکد موجود نیست.
چرا همگامسازی Google Calendar من پس از یک هفته از کار میافتد؟
زیرا پروژه Google Cloud هنوز در وضعیت انتشار Testing قرار دارد. Google برای برنامههایی که در این وضعیت هستند، توکنهای بازخوانی (refresh tokens) صادر میکند که پس از هفت روز منقضی میشوند؛ بنابراین اتصال کار میکند، اما در بازخوانی بعدی توکن از کار میافتد و لاگ برنامه invalid_grant را نشان میدهد. صفحه رضایت OAuth را به وضعیت In production تغییر دهید و تقویم را یک بار دوباره متصل کنید. اتصال مجدد بدون تغییر وضعیت، فقط هفت روز دیگر به شما زمان میدهد و نه بیشتر.
کدامیک از اینها روی یک VPS با 1 GB رم اجرا میشوند؟
Easy!Appointments اجرا میشود، زیرا یک برنامه PHP به همراه MySQL است. Rallly حداقل 2 GB رم را مستند کرده و پشته بستهبندیشده آن چهار سرویس را اجرا میکند. Cal.com و DayOtter حداقل رم مشخصی اعلام نکردهاند، اما یک برنامه Next.js به همراه PostgreSQL، و در مورد DayOtter به همراه Redis و یک پردازش worker، به این معنی است که باید حداقل 2 GB یا بیشتر در نظر بگیرید. هرگز Cal.com را روی یک سرور کوچک از سورسکد build نکنید: دستورالعملهای build خود پروژه به 16 GB حافظه heap برای Node نیاز دارد، بنابراین از image پیشساخته استفاده کنید.