آموزش CDN و سرعت سایت

WebSocket و CDN؛ آیا CDN از وب‌سوکت پشتیبانی می‌کند و چطور تنظیمش کنیم؟

تهیه: کلودیفای (نگارش با کمک هوش مصنوعی) · انتشار: · زمان مطالعه: ۷ دقیقه

WebSocketCDNآموزش CDN و سرعت سایتWebSocket و CDN؛ آیا CDN ازوب‌سوکت پشتیبانی می‌کند وچطور تنظیمش کنیم؟مجلهٔ کلودیفایclodify.net/blog
پاسخ کوتاه

بیشتر CDNهای امروزی از WebSocket پشتیبانی می‌کنند، اما معمولاً باید این قابلیت در پنل فعال باشد و سرور اصلی هدرهای Upgrade و Connection را درست پاس بدهد. اتصال‌های وب‌سوکت کش نمی‌شوند و فقط از CDN عبور می‌کنند. مهم‌ترین نکته‌ها: فعال‌سازی وب‌سوکت در CDN، تنظیم proxy_http_version 1.1 و هدرهای Upgrade در Nginx، افزایش Timeout و ارسال پیام پینگ دوره‌ای تا اتصال بیکار قطع نشود.

WebSocket چیست و چه فرقی با HTTP معمولی دارد؟

در HTTP معمولی، مرورگر درخواستی می‌فرستد، سرور پاسخ می‌دهد و ارتباط تمام می‌شود. اگر سرور بخواهد خبری را به کاربر برساند، باید منتظر بماند تا مرورگر دوباره درخواست بدهد. برای برنامه‌هایی مثل چت، اعلان زنده، داشبورد لحظه‌ای، بازی آنلاین یا تابلوی قیمت، این مدل کند و پرهزینه است.

WebSocket یک کانال دوطرفه و پایدار بین مرورگر و سرور است. اتصال یک بار برقرار می‌شود و تا وقتی یکی از دو طرف آن را نبندد باز می‌ماند. در این مدت هم سرور و هم کاربر می‌توانند هر لحظه پیام بفرستند. شروع اتصال با یک درخواست HTTP عادی است که هدر Upgrade: websocket دارد؛ اگر سرور موافقت کند، با کد 101 Switching Protocols پاسخ می‌دهد و از آن لحظه پروتکل عوض می‌شود.

مسیر WebSocket پشت CDN
درخواست Upgradeپاس دادن هدرهاپاسخ 101مرورگرwss://app.example.comنود CDNعبور بدون کشNginxUpgrade و ConnectionبرنامهNode.js یا Socket.IOدرخواست Upgradeپاس دادن هدرهاپاسخ 101مرورگرwss://app.example.comنود CDNعبور بدون کشNginxUpgrade و ConnectionبرنامهNode.js یا Socket.IO
شکل ۱ اگر هر کدام از حلقه‌ها هدر Upgrade را حذف کند، اتصال وب‌سوکت برقرار نمی‌شود.

CDN و WebSocket: مشکل کجاست؟

CDN اساساً برای کش کردن و تحویل پاسخ‌های کوتاه HTTP طراحی شده است. WebSocket دو ویژگی دارد که با این مدل متفاوت است:

  1. قابل کش نیست: هر اتصال منحصربه‌فرد است و پیام‌ها لحظه‌ای‌اند. CDN فقط باید آن را عبور دهد.
  2. طولانی است: یک اتصال ممکن است ساعت‌ها باز بماند، در حالی که CDN برای درخواست‌های معمولی مهلت‌های کوتاهی در نظر می‌گیرد.

خبر خوب این است که بیشتر CDNهای مدرن، از جمله CDNهای ایرانی و بین‌المللی رایج، از WebSocket پشتیبانی می‌کنند. اما معمولاً باید سه چیز را درست کنید: فعال‌سازی در پنل CDN، تنظیم سرور اصلی و مدیریت مهلت اتصال. اگر با نقش CDN آشنا نیستید، CDN چیست؟ را بخوانید.

قدم اول: فعال‌سازی در پنل CDN

در پنل بیشتر CDNها، گزینه‌ای با نام WebSocket در بخش تنظیمات شبکه یا پیشرفته وجود دارد. اگر غیرفعال باشد، CDN هدر Upgrade را حذف می‌کند و درخواست به‌شکل HTTP عادی به سرور می‌رسد؛ نتیجه معمولاً خطای 400 یا قطع شدن فوری است.

همچنین به پورت‌های مجاز دقت کنید. CDNها فقط روی پورت‌های مشخصی ترافیک را عبور می‌دهند؛ معمولاً 80 و 443 و چند پورت دیگر که در مستندات هر CDN فهرست شده است. اگر سرویس وب‌سوکت شما روی پورت دلخواهی مثل 3001 اجرا می‌شود، آن را پشت Nginx روی پورت 443 قرار دهید یا مطمئن شوید پورت در فهرست مجاز است.

قدم دوم: تنظیم Nginx روی سرور اصلی

اگر برنامهٔ شما (مثلاً یک سرور Node.js با Socket.IO) پشت Nginx است، Nginx باید هدرهای ارتقا را به برنامه پاس بدهد. Nginx به‌طور پیش‌فرض این کار را نمی‌کند:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 443 ssl;
    server_name app.example.com;

    location /ws/ {
        proxy_pass http://127.0.0.1:3001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $host;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }
}

سه خط کلیدی‌اند: proxy_http_version 1.1 (چون ارتقای پروتکل در HTTP/1.0 وجود ندارد) و دو هدر Upgrade و Connection. بلوک map باید در بخش http قرار گیرد، نه داخل server. پس از تغییر، با nginx -t && systemctl reload nginx اعمال کنید. اصول کلی پراکسی معکوس را در Nginx به‌عنوان Reverse Proxy برای داکر و ساختار تنظیمات را در مبانی پیکربندی Nginx ببینید.

HTTP معمولی یا WebSocket
HTTP معمولی
  • درخواست و پاسخ کوتاه
  • سرور نمی‌تواند خودش پیام بفرستد
  • قابل کش در CDN
  • مناسب صفحات و API
در برابر
WebSocket
  • اتصال پایدار و دوطرفه
  • ارسال لحظه‌ای از هر دو طرف
  • هرگز کش نمی‌شود
  • مناسب چت، اعلان و داشبورد زنده
شکل ۲ CDN با هر دو کار می‌کند اما WebSocket تنظیمات ویژهٔ هدر و مهلت اتصال دارد.

قدم سوم: مهلت اتصال و پیام پینگ

حتی با تنظیم درست، اتصال‌های بیکار پس از مدتی قطع می‌شوند. هم Nginx (با proxy_read_timeout که پیش‌فرض آن ۶۰ ثانیه است) و هم CDN مهلتی برای اتصال بدون فعالیت دارند. مهلت CDN معمولاً قابل تغییر نیست.

راه‌حل استاندارد، پیام پینگ دوره‌ای است: سرور یا کلاینت در فاصله‌های منظم (کوتاه‌تر از کمترین مهلت در مسیر) یک پیام کوچک می‌فرستد تا اتصال فعال بماند. بیشتر کتابخانه‌ها این قابلیت را دارند؛ مثلاً Socket.IO به‌طور خودکار ضربان قلب (Heartbeat) می‌فرستد و در کتابخانهٔ ws در Node.js باید ping را خودتان زمان‌بندی کنید.

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

Socket.IO و Long Polling

کتابخانهٔ Socket.IO ابتدا با درخواست‌های HTTP معمولی (Long Polling) شروع می‌کند و سپس به WebSocket ارتقا می‌یابد. پشت CDN یا چند سرور، این رفتار ممکن است باعث خطای «Session ID unknown» شود، چون درخواست‌های پشت سر هم به سرورهای مختلف می‌رسند. دو راه‌حل رایج:

  • در کلاینت، transports: ["websocket"] را تنظیم کنید تا مستقیم با WebSocket شروع شود.
  • اگر چند سرور پشت Load Balancer دارید، چسبندگی نشست (Sticky Session) را فعال کنید.

رفع خطاهای رایج

  • خطای 400 Bad Request: هدرهای Upgrade و Connection به برنامه نمی‌رسند. تنظیمات Nginx و فعال بودن WebSocket در CDN را بررسی کنید.
  • خطای 502 یا 504: برنامهٔ پشتی در دسترس نیست یا کند پاسخ می‌دهد. با curl از خود سرور به 127.0.0.1:3001 بررسی کنید. مقالهٔ خطاهای 5xx در CDN هم کمک می‌کند.
  • قطع شدن پس از حدود یک دقیقه: proxy_read_timeout کوتاه است یا پینگ دوره‌ای ندارید.
  • کار می‌کند ولی پشت CDN نه: پورت غیرمجاز است یا گزینهٔ WebSocket در CDN خاموش است.
  • Mixed Content: صفحه با HTTPS باز شده ولی آدرس وب‌سوکت ws:// است. از wss:// استفاده کنید.

برای آزمایش مستقیم اتصال از خط فرمان، ابزار websocat یا این دستور curl کمک می‌کند:

curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==" https://app.example.com/ws/

اگر پاسخ HTTP/1.1 101 Switching Protocols بود، مسیر تا برنامه درست است.

چک‌لیست راه‌اندازی
  1. فعال‌سازی در CDN

    گزینهٔ WebSocket و پورت مجاز.

  2. هدرها در Nginx

    proxy_http_version 1.1 و Upgrade و Connection.

  3. افزایش Timeout

    proxy_read_timeout برای اتصال‌های طولانی.

  4. پینگ دوره‌ای

    پیام کوچک منظم تا اتصال بیکار قطع نشود.

  5. اتصال مجدد خودکار

    کلاینت پس از قطعی دوباره وصل شود.

شکل ۳ این پنج مورد تقریباً همهٔ مشکلات وب‌سوکت پشت CDN را پوشش می‌دهند.

کی WebSocket را از CDN عبور ندهیم؟

اگر سرویس شما اتصال‌های بسیار زیاد و طولانی دارد و به کمترین تأخیر نیاز دارد (مثل سرور بازی)، گاهی بهتر است ترافیک وب‌سوکت روی یک زیردامنهٔ جداگانه مستقیم به سرور برود و بقیهٔ سایت پشت CDN بماند. البته در این حالت آی‌پی سرور برای آن زیردامنه آشکار است و محافظت CDN در برابر حملات را از دست می‌دهید؛ این مصالحه را آگاهانه انتخاب کنید. دربارهٔ اهمیت پنهان ماندن آی‌پی، حمله DDoS و CDN را ببینید.

در CDN کلودیفای پیش از راه‌اندازی، پورت‌ها و تنظیمات پشتیبانی‌شده را در مستندات بررسی کنید و پس از اتصال با دستور curl بالا مسیر را آزمایش کنید.

مقیاس‌پذیری اتصال‌های هم‌زمان

هر اتصال WebSocket باز، روی سرور مقداری حافظه مصرف می‌کند و یک توصیف‌گر فایل (File Descriptor) را اشغال می‌کند. وقتی تعداد کاربران هم‌زمان زیاد می‌شود، محدودیت‌های پیش‌فرض سیستم‌عامل و Nginx زودتر از رم یا پردازنده به سقف می‌رسند. نشانهٔ آن خطاهایی مثل Too many open files در لاگ است.

برای رفع آن، مقدار worker_connections در Nginx را افزایش دهید و سقف فایل‌های باز سرویس را بالا ببرید؛ در systemd با گزینهٔ LimitNOFILE در فایل سرویس. نوشتن فایل سرویس را در راهنمای سرویس‌های systemd توضیح داده‌ایم. اگر تعداد اتصال‌ها از توان یک سرور بیشتر شد، چند نمونه از برنامه را پشت Load Balancer اجرا کنید و برای ارسال پیام بین آن‌ها از یک لایهٔ پیام‌رسان مثل Redis استفاده کنید؛ Socket.IO برای این کار آداپتور آماده دارد.

امنیت اتصال‌های وب‌سوکت

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

سؤالات متداول

آیا ترافیک WebSocket در CDN کش می‌شود؟

خیر. اتصال وب‌سوکت دوطرفه و لحظه‌ای است و CDN فقط آن را بین کاربر و سرور اصلی عبور می‌دهد. محاسبهٔ ترافیک آن معمولاً مانند ترافیک عادی بر اساس حجم داده است.

چرا اتصال وب‌سوکت من بعد از یک دقیقه قطع می‌شود؟

مقدار پیش‌فرض proxy_read_timeout در Nginx ۶۰ ثانیه است و CDN هم برای اتصال بیکار مهلت دارد. Timeout را در Nginx افزایش دهید و در برنامه پیام پینگ دوره‌ای بفرستید.

wss و ws چه فرقی دارند؟

ws اتصال بدون رمزنگاری و wss اتصال رمزنگاری‌شده با TLS است، مشابه http و https. در سایت‌های HTTPS و پشت CDN همیشه از wss استفاده کنید.

Socket.IO پشت CDN خطای Session ID unknown می‌دهد؛ چه کنم؟

در کلاینت transports را فقط روی websocket تنظیم کنید یا اگر چند سرور پشت Load Balancer دارید، Sticky Session را فعال کنید تا درخواست‌های یک کاربر به یک سرور برسند.

آماده‌اید؟ سرورتان را بسازید.

از ۱٬۲۰۰ تومان در ساعت · پرداخت ریالی

سرورتان را همین حالا بسازید.

ساعتی بپردازید. هر وقت خواستید حذف کنید.