بلاگ
۳ مهر ۱۴۰۵ - ۱۰ دقیقه مطالعه
فرایند ساخت یک پیام‌رسان بدون سرور، از ایده تا اجرا

فرایند ساخت یک پیام‌رسان بدون سرور، از ایده تا اجرا

بررسی دقیق فرایندی که برای طراحی و ساخت یک پیام‌رسان بدون سرور مرکزی طی می‌شود؛ از تعریف مسئله تا تصمیم‌های معماری، همراه با نکته‌های کاربردی برای هر مرحله.

رضا اکبرپور

Reza Akbarpour

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

در این مقاله، با استفاده از پروژهٔ اخیرم تلپاتی به‌عنوان مطالعهٔ موردی، فرایند ساخت یک پیام‌رسان بدون سرور را از تعریف مسئله تا تصمیم‌های نهایی معماری مرور می‌کنم.

مرحلهٔ اول: تعریف دقیق مسئله

هر پروژهٔ خوب با درک دقیق مسئله‌ای که قرار است حل شود آغاز می‌شود. «بدون سرور بودن» به‌تنهایی یک هدف مبهم است؛ باید مشخص شود دقیقاً کدام ضعف‌های مدل سنتی پیام‌رسانی قرار است حذف شوند.

تحلیل مدل رایج

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

  • محتوای گفتگو در دسترس مالک سرور قرار می‌گیرد، صرف‌نظر از هر تعهدنامهٔ حریم خصوصی.
  • حساب کاربر عملاً گروگان همان سرور است؛ اگر سرور بسته یا مسدود شود، کاربر بدون گفتگو و بدون راه بازیابی می‌ماند.
  • نگه‌داشتن سرور به‌صورت شبانه‌روزی، خودش یک پروژهٔ جداگانه با هزینه و دردسر دائمی است.

تعریف معیار موفقیت

پیش از هر تصمیم فنی، باید معیارهای روشنی برای موفقیت تعیین شوند. برای این نوع پروژه، سه شرط اصلی معمولاً مطرح می‌شوند:

  • محتوای گفتگو فقط برای فرستنده و گیرنده قابل خواندن باشد.
  • هیچ سرور اختصاصی‌ای برای نگه‌داری حساب یا داده وجود نداشته باشد.
  • پیام حتی در حالت آفلاین بودن طرف مقابل هم گم نشود.

نکتهٔ مهم این‌جاست که این سه شرط در نگاه اول با هم در تعارضند؛ معمولاً «بدون سرور» به قیمت از‌دست‌رفتن قابلیت تحویل آفلاین تمام می‌شود. حل همین تعارض، هستهٔ اصلی فرایند طراحی است.

مرحلهٔ دوم: انتخاب معماری

بعد از تعریف مسئله، مهم‌ترین تصمیم معماری این است: آیا یک فناوری واحد می‌تواند هم ارتباط زنده و هم تحویل آفلاین را پوشش دهد؟ تجربه نشان می‌دهد جواب معمولاً نه است.

جدا کردن دو نوع نیاز

دو نیاز باید از هم تفکیک شوند:

  1. تحویل در حالت آفلاین: نیازمند یک واسطهٔ نگه‌دارنده است؛ چیزی شبیه صندوق پستی که پیام را تا آنلاین‌شدن گیرنده نگه دارد.
  2. ارتباط زنده و انتقال فایل: اینجا واسطه فقط سربار و تأخیر اضافه می‌کند؛ اتصال مستقیم بین دو طرف منطقی‌تر است.

انتخاب واسطهٔ غیرمتمرکز

برای این‌که خودِ پروژه هم به زیرساخت اختصاصی نیاز نداشته باشد، به‌جای ساختن سرور صندوق پستی، می‌توان از شبکه‌ای از رله‌های عمومی و باز استفاده کرد که از قبل توسط جامعه‌ای مستقل نگه‌داری می‌شود. مزیت این انتخاب این است که حتی همان «صندوق پستی» هم در کنترل مالک پروژه نیست و بستنش ممکن نیست — یعنی پروژه واقعاً بدون سرور باقی می‌ماند.

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

مرحلهٔ سوم: طراحی لایهٔ امنیت

سخت‌ترین بخش کار، طراحی مدلی است که تضمین کند واسطهٔ نگه‌دارنده (که یک سرویس عمومی و خارج از کنترل سازنده است) هیچ‌وقت به محتوای واقعی دسترسی نداشته باشد.

اصل کلیدی این است: پیام باید پیش از خروج از دستگاه، کاملاً بسته‌بندی و قفل شده باشد — نه این‌که در مسیر انتقال رمزنگاری شود. این یعنی چند لایهٔ پیاپی امضا و رمزنگاری، به‌گونه‌ای که واسطه فقط بداند «این بسته باید به فلان مقصد برسد»، بدون این‌که بفهمد محتوا چیست، فرستنده کیست یا نوع پیام چیست.

نکته‌ای که در این مرحله اهمیت زیادی دارد، صداقت در حد ادعاست: این مدل پیام را خصوصی می‌کند، نه لزوماً گمنام. واسطه همچنان می‌تواند ببیند چه حجمی از داده، در چه زمانی، به کدام مقصد رسیده — و بهتر است این محدودیت به‌جای پنهان‌شدن، صریح مستند شود.

مرحلهٔ چهارم: طراحی هویت بدون حساب کاربری

اگر سرور مرکزی وجود نداشته باشد، «ثبت‌نام» هم معنایی ندارد — چون کسی نیست که آن را نگه دارد. راه‌حل رایج این است که هویت هر کاربر یک جفت‌کلید رمزنگاری باشد که مستقیماً روی همان دستگاه ساخته می‌شود؛ نه چیزی که از یک سرور دریافت شود.

این تصمیم یک بهای مشخص دارد: اگر کاربر از هویتش پشتیبان نگیرد و دستگاهش را از دست بدهد، آن هویت برای همیشه از دست می‌رود. هیچ «فراموشی رمز عبور»ی در کار نیست، چون هیچ سرویس مرکزی‌ای برای بازیابی وجود ندارد. این دقیقاً قیمتی است که «بدون سرور بودن واقعی» می‌گیرد، و به نظرم صادقانه‌تر است این مصالحه را آشکار اعلام کرد تا این‌که وانمود شود مشکلی وجود ندارد. برای کاهش ریسک، معمولاً چند لایهٔ محافظتی اضافه می‌شود: قفل‌شدن کلید خصوصی پشت یک عبارت عبور، قفل خودکار برنامه بعد از بی‌کاری، و پشتیبان‌گیری رمزگذاری‌شده.

مرحلهٔ پنجم: مسیریابی هوشمند پیام

با معماری و امنیت مشخص، سؤال بعدی این است: هر پیام دقیقاً باید از کدام مسیر برود؟ یک لایهٔ مسیریابی مرکزی می‌تواند برای هر پیام تصمیم بگیرد:

  • اگر کانال مستقیم با گیرنده برقرار است، پیام از همان‌جا و بدون تأخیرِ واسطه می‌رود.
  • اگر گیرنده آفلاین است، پیام از مسیر واسطهٔ عمومی می‌رود و تا آنلاین‌شدن او نگه داشته می‌شود.
  • اگر هیچ مسیری در دسترس نیست، پیام در صف خروجی می‌ماند و با تلاش پله‌ای دوباره ارسال می‌شود.

یک نکتهٔ فنی ظریف اینجا این است که حتی هماهنگی برای برقراری همان اتصال مستقیم هم باید از مسیر امن انجام شود، بدون نیاز به یک سرور واسط برای رد و بدل آدرس‌های شبکه.

مرحلهٔ ششم: حل مشکل ترتیب پیام‌ها

یکی از دردهای پنهانِ سیستم‌های غیرمتمرکز، مسئلهٔ زمان است. وقتی هیچ سرور مرجعی برای نگه‌داشتن «ساعت درست» وجود ندارد، هر دستگاه فقط به ساعت داخلی خودش متکی است — و ساعت دستگاه‌ها همیشه قابل اعتماد نیست.

اگر ترتیب پیام‌ها صرفاً بر اساس زمان ثبت‌شده مرتب شود، یک دستگاه با ساعت اشتباه می‌تواند کل تاریخچهٔ گفتگو را به‌هم بریزد. راه‌حل رایج برای این مشکل، استفاده از یک شمارندهٔ منطقی برای هر گفتگو است؛ عددی که با هر پیام جدید افزایش می‌یابد و از پیام‌های دریافتی هم به‌روزرسانی می‌شود. زمان واقعی دستگاه فقط برای مرتب‌کردن حالت‌های مساوی به کار می‌رود، نه به‌عنوان مرجع اصلی ترتیب.

مرحلهٔ هفتم: انتقال فایل بدون افشای محتوا

فایل و عکس، جایی است که خیلی از پیام‌رسان‌های «امن» عملاً لو می‌روند؛ چون در نهایت فایل باید یک‌جا ذخیره شود. مرز روشنی که معمولاً کشیده می‌شود، جدا‌کردن «فراداده» از «محتوای واقعی فایل» است:

  • هدر فایل (نام، نوع، اندازه، و هشی برای بررسی صحت) از همان مسیر رمزنگاری‌شدهٔ معمولی پیام‌ها فرستاده می‌شود.
  • خودِ محتوای فایل هرگز از واسطهٔ عمومی عبور نمی‌کند؛ فقط از کانال مستقیم بین دو دستگاه، به‌صورت تکه‌تکه، منتقل می‌شود.

قیمت این تصمیم این است که برای انتقال فایل، هر دو طرف باید هم‌زمان آنلاین باشند. این را باید یک مصالحهٔ طبیعی دید، نه یک محدودیت شرم‌آور — چون تنها راه جایگزین، ذخیرهٔ فایل روی یک سرور واسط است؛ یعنی دقیقاً همان چیزی که کل پروژه از اول قرار بوده از آن دوری کند.

چالش‌های اصلی این مسیر

سه چالش معمولاً بیش از بقیه وقت می‌گیرند:

  • تعادل بین سه هدف متناقض: امنیت، آفلاین‌پذیری و بدون‌سرور بودن، معمولاً یکدیگر را نقض می‌کنند. رسیدن به نقطه‌ای که هر سه هم‌زمان برقرار باشند، نیازمند طراحی چندلایه است، نه یک راه‌حل ساده.
  • ترتیب پیام بدون منبع زمان مرکزی: بدون شمارندهٔ منطقی، حفظ ترتیب صحیح گفتگو عملاً ممکن نیست.
  • اطمینان از درستی منطق رمزنگاری و مسیریابی: چون سروری برای دیباگ مرکزی وجود ندارد، هستهٔ اصلی برنامه باید کاملاً مستقل از رابط کاربری و به‌شدت تست‌شده باشد.

در تلپاتی، برای پوشش همین ریسک آخر، هستهٔ اصلی برنامه کاملاً جدا از لایهٔ ظاهری نوشته شد و بیش از ۳۴۰ تست واحد در ۴۲ فایل برایش نوشتم؛ از رمزگشایی پاکت تا محدودیت‌های ضد سوءاستفاده.

آنچه معمولاً حل‌نشده باقی می‌ماند

هیچ پیام‌رسان بدون‌سروری «کامل» نیست؛ صداقت دربارهٔ محدودیت‌ها بخش مهمی از فرایند طراحی است:

  • گمنامی مطلق معمولاً به‌دست نمی‌آید؛ واسطهٔ عمومی همچنان می‌تواند ببیند چه حجمی از داده، در چه زمانی، به کدام مقصد رسیده. «خصوصی‌بودن» و «گمنام‌بودن» دو ادعای متفاوتند.
  • محرمانگی پیش‌رو (forward secrecy) کامل برای پیام‌های ذخیره‌شدهٔ آفلاین، نیازمند ساختاری پیچیده‌تر است که پیاده‌سازی پایدار و استانداردی روی مرورگر برایش هنوز وجود ندارد.
  • پنهان‌کردن آدرس شبکهٔ کاربر از طرف مقابل، معمولاً به یک سرور کمکی نیاز دارد — که خودش، هرچند کوچک، بازگشتی به مفهوم «سرور» است.
  • هیچ رمزنگاری‌ای نمی‌تواند جلوی خطرِ دستگاه آلوده یا در دسترس‌بودن فیزیکی گوشی برای شخص دیگر را بگیرد.

نتیجه‌گیری

ساخت یک پیام‌رسان بدون سرور، نیازمند اختراع الگوریتم تازه نیست؛ چالش اصلی این است که چند قطعهٔ شناخته‌شده (رمزنگاری کلید عمومی، واسط‌های عمومی غیرمتمرکز، اتصال مستقیم بین دو دستگاه) طوری کنار هم چیده شوند که یک شرط سخت نقض نشود: بدون سرور اختصاصی بودن، بدون این‌که امنیت، آفلاین‌پذیری یا تاریخچهٔ گفتگو قربانی شود.

بزرگ‌ترین درس این فرایند این است که «بدون سرور بودن» یک تصمیم رایگان نیست؛ هر بخشی که از دوش یک سرور مرکزی برداشته می‌شود، جایی دیگر — در لایهٔ رمزنگاری، در مدیریت هویت، یا در مسیریابی پیام — باید با طراحی دقیق‌تر جبران شود. تلپاتی یکی از نمونه‌های عملی این رویکرد است که می‌توانید کدش را ببینید یا خودتان امتحان کنید: telepatty.ir

خوشحال می‌شوم دربارهٔ تجربهٔ خودتان در ساخت سیستم‌های غیرمتمرکز یا سؤالاتی که دربارهٔ این فرایند دارید بشنوم. در بخش دیدگاه‌ها با من در ارتباط باشید.

Me on Bale
توسعه داده شده توسط رضا اکبرپور • © 2026