رفع مشکل

خطای Too many redirects بعد از فعال‌سازی SSL روی CDN؛ علت و راه‌حل قطعی

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

ERRToomanyredirectsرفع مشکلخطای Too many redirectsبعد از فعال‌سازی SSL رویCDN؛ علت و راه‌حل قطعیمجلهٔ کلودیفایclodify.net/blog
پاسخ کوتاه

خطای Too many redirects پس از اتصال CDN تقریباً همیشه یک علت دارد: CDN با HTTP به سرور وصل می‌شود (حالت Flexible) و سرور هر درخواست HTTP را به HTTPS ریدایرکت می‌کند؛ درخواست بعدی دوباره با HTTP به سرور می‌رسد و حلقه بی‌پایان می‌شود. راه‌حل اصلی: روی سرور گواهی SSL نصب کنید و حالت SSL در CDN را روی Full یا Full Strict بگذارید. اگر ممکن نیست، ریدایرکت سمت سرور را بردارید و آن را به CDN بسپارید.

این خطا دقیقاً چه می‌گوید؟

وقتی مرورگر پیغام ERR_TOO_MANY_REDIRECTS یا «This page isn't working – redirected you too many times» را نشان می‌دهد، یعنی سرور به‌جای صفحه، مدام مرورگر را به آدرس دیگری فرستاده و این زنجیره هیچ‌وقت به صفحهٔ واقعی نرسیده است. مرورگرها پس از تعداد مشخصی ریدایرکت پشت سر هم، دست می‌کشند و این خطا را نمایش می‌دهند.

ریدایرکت به‌خودی‌خود چیز بدی نیست. انتقال از http:// به https:// یا از example.com به www.example.com کاملاً رایج است. مشکل وقتی است که ریدایرکت‌ها یک حلقه بسازند: A به B، B به A و دوباره از اول.

حلقهٔ ریدایرکت در حالت Flexible
HTTPSفقط HTTPریدایرکتمرورگرhttps://example.comCDNحالت Flexibleسروردریافت با HTTPپاسخ 301برو به HTTPSHTTPSفقط HTTPریدایرکتمرورگرhttps://example.comCDNحالت Flexibleسروردریافت با HTTPپاسخ 301برو به HTTPS
شکل ۱ سرور فقط HTTP می‌بیند و مدام به HTTPS ریدایرکت می‌کند؛ مرورگر دوباره از اول شروع می‌کند.

علت رایج: حالت Flexible در CDN

پس از اتصال CDN، هر درخواست از دو مسیر جداگانه عبور می‌کند: مرورگر تا CDN و CDN تا سرور اصلی. حالت SSL در پنل CDN تعیین می‌کند مسیر دوم با HTTP باشد یا HTTPS. توضیح کامل حالت‌ها در حالت‌های SSL در CDN آمده است.

در حالت Flexible، مرورگر با HTTPS به CDN وصل می‌شود اما CDN با HTTP ساده به سرور شما می‌رسد. حالا اگر روی سرور قانونی داشته باشید که «هر درخواست HTTP را به HTTPS ریدایرکت کن» (که بسیار رایج است)، این اتفاق می‌افتد:

  1. مرورگر: https://example.com را از CDN می‌خواهد.
  2. CDN: همان صفحه را با http:// از سرور می‌خواهد.
  3. سرور: «این HTTP است؛ برو به HTTPS» و پاسخ 301 برمی‌گرداند.
  4. CDN: این ریدایرکت را به مرورگر می‌دهد.
  5. مرورگر: دوباره https://example.com را می‌خواهد و همه‌چیز از قدم ۱ تکرار می‌شود.

سرور هرگز نمی‌فهمد که کاربر در واقع با HTTPS آمده است، چون درخواستی که به او می‌رسد HTTP است.

راه‌حل اصلی: SSL روی سرور و حالت Full

راه‌حل درست و امن این است که ارتباط CDN با سرور هم رمزنگاری شود:

  1. روی سرور گواهی SSL نصب کنید. ساده‌ترین راه، گواهی رایگان Let's Encrypt با Certbot است؛ آموزش کامل در Nginx و Let's Encrypt. اگر دامنه پشت CDN است و صدور گواهی با روش HTTP مشکل دارد، از روش DNS یا گواهی مبدأ (Origin Certificate) که برخی CDNها ارائه می‌دهند استفاده کنید.
  2. در پنل CDN، حالت SSL را روی Full یا ترجیحاً Full (Strict) بگذارید.
  3. کش CDN را پاک کنید، چون ممکن است پاسخ ریدایرکت 301 در کش مانده باشد.
  4. مرورگر را با پنجرهٔ ناشناس آزمایش کنید؛ مرورگرها ریدایرکت‌های 301 را هم کش می‌کنند.

با این تغییر، CDN با HTTPS به سرور می‌رسد، قانون ریدایرکت سرور دیگر فعال نمی‌شود و حلقه می‌شکند.

Flexible در برابر Full Strict
Flexible
  • CDN تا سرور با HTTP
  • مستعد حلقهٔ ریدایرکت
  • داده‌ها بین CDN و سرور رمزنگاری نمی‌شوند
  • فقط به‌عنوان راه‌حل موقت
در برابر
Full (Strict)
  • CDN تا سرور با HTTPS
  • ریدایرکت سرور بی‌اثر و بدون حلقه
  • گواهی سرور اعتبارسنجی می‌شود
  • امن از ابتدا تا انتها
شکل ۲ نصب گواهی روی سرور و انتخاب Full Strict، هم خطا را رفع می‌کند و هم امنیت را کامل.

راه‌حل جایگزین: ریدایرکت را به CDN بسپارید

اگر به هر دلیل نمی‌توانید روی سرور گواهی نصب کنید (که توصیه نمی‌شود)، باید ریدایرکت سمت سرور را حذف کنید و کار انتقال به HTTPS را به CDN بسپارید. بیشتر CDNها گزینه‌ای مثل «Always Use HTTPS» یا «ریدایرکت HTTP به HTTPS» دارند.

در Nginx، بلوکی شبیه این را پیدا و غیرفعال کنید:

server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

اما توجه کنید: در این حالت ارتباط CDN تا سرور رمزنگاری نشده است و داده‌ها، از جمله رمزهای کاربران، بین CDN و سرور به‌شکل متن ساده عبور می‌کنند. این وضعیت فقط به‌عنوان راه‌حل موقت قابل قبول است.

حلقه در وردپرس

وردپرس در تنظیمات خود آدرس سایت را نگه می‌دارد. اگر آدرس روی https:// باشد اما وردپرس تشخیص دهد درخواست با HTTP آمده است، کاربر را به HTTPS ریدایرکت می‌کند و همان حلقه ساخته می‌شود. افزونه‌های SSL هم ممکن است ریدایرکت اضافه کنند.

اگر حالت Full ممکن نیست و ناچارید با Flexible کار کنید، باید به وردپرس بگویید که درخواست در اصل HTTPS بوده است. خطوط زیر را بالای فایل wp-config.php اضافه کنید:

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
}

بیشتر CDNها هدر X-Forwarded-Proto را ارسال می‌کنند. اگر پس از این تغییر هم مشکل ادامه داشت، افزونه‌های SSL و ریدایرکت را موقتاً غیرفعال کنید.

ردیابی دقیق زنجیرهٔ ریدایرکت

به‌جای حدس زدن، زنجیره را ببینید. با curl می‌توانید هر ریدایرکت و مقصد بعدی را مشاهده کنید:

curl -sIL --max-redirs 10 https://example.com | grep -iE "^HTTP|^location"

خروجی، کد هر پاسخ و هدر Location را نشان می‌دهد. اگر می‌بینید آدرس‌ها تکرار می‌شوند، حلقه را پیدا کرده‌اید. برای دور زدن CDN و آزمایش مستقیم سرور:

curl -sI --resolve example.com:443:203.0.113.10 https://example.com
curl -sI --resolve example.com:80:203.0.113.10 http://example.com

به‌جای 203.0.113.10 آی‌پی واقعی سرور را قرار دهید. اگر سرور مستقیم روی HTTPS پاسخ 200 می‌دهد، مشکل در تنظیمات CDN است.

user@laptop: ~
$ curl -sIL --max-redirs 5 https://example.com | grep -iE '^HTTP|^location'HTTP/2 301location: https://example.com/HTTP/2 301location: https://example.com/curl: (47) Maximum (5) redirects followed$ 
شکل ۳ تکرار یک Location ثابت یعنی حلقه؛ پس از تغییر حالت SSL به Full، پاسخ باید 200 باشد.

علت‌های کمتر رایج

  • ریدایرکت www در دو جا: CDN www را به دامنهٔ اصلی می‌برد و سرور دامنهٔ اصلی را به www. فقط در یک جا ریدایرکت تعریف کنید.
  • قوانین تکراری در .htaccess و افزونه‌ها: در سایت‌های Apache، چند قانون ریدایرکت متناقض ممکن است حلقه بسازند.
  • کوکی‌های خراب: گاهی حلقه به‌خاطر کوکی ورود معیوب است؛ کوکی‌های دامنه را پاک کنید.
  • کش 301 در مرورگر یا CDN: پس از رفع مشکل، کش هر دو را پاک کنید.
  • HSTS: اگر قبلاً هدر HSTS فعال کرده‌اید، مرورگر خودش همه‌چیز را به HTTPS می‌برد؛ این به‌خودی‌خود حلقه نمی‌سازد اما برگشت به HTTP را ناممکن می‌کند.

جمع‌بندی و پیشگیری

پیش از اتصال هر دامنه به CDN، ابتدا روی سرور گواهی معتبر نصب کنید و سپس حالت Full (Strict) را انتخاب کنید. این ترتیب ساده، هم از خطای حلقهٔ ریدایرکت جلوگیری می‌کند و هم ارتباط شما را از ابتدا تا انتها امن نگه می‌دارد. اگر سایت پس از اتصال به‌طور کلی بالا نمی‌آید، سایت پس از CDN بالا نمی‌آید و برای خطاهای سرور خطاهای 5xx در CDN را ببینید. راهنمای تنظیم دامنه در CDN کلودیفای هم در مستندات تنظیم CNAME آمده است.

چرا این خطا بیشتر در روز اول دیده می‌شود؟

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

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

چرا سایت قبل از CDN درست کار می‌کرد ولی الان حلقه دارد؟

چون قبل از CDN مرورگر مستقیم با HTTPS به سرور وصل می‌شد. حالا CDN در حالت Flexible با HTTP به سرور می‌رسد و قانون ریدایرکت سرور هر بار درخواست را به HTTPS برمی‌گرداند.

حالت Full بهتر است یا Full Strict؟

Full Strict امن‌تر است چون اعتبار گواهی سرور را هم بررسی می‌کند. اگر گواهی معتبر Let's Encrypt یا گواهی مبدأ CDN روی سرور دارید، Full Strict را انتخاب کنید.

بعد از اصلاح تنظیمات هنوز خطا می‌بینم؛ چرا؟

احتمالاً ریدایرکت 301 در کش مرورگر یا CDN مانده است. کش CDN را پاک کنید و سایت را در پنجرهٔ ناشناس یا مرورگر دیگری باز کنید.

آیا Flexible همیشه اشتباه است؟

Flexible ارتباط بین CDN و سرور را رمزنگاری نمی‌کند و مستعد حلقهٔ ریدایرکت است. فقط برای مدت کوتاه و تا زمان نصب گواهی روی سرور قابل استفاده است.

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

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

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

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