هاست و سرور

حلقه ریدایرکت: رفع خطای ERR_TOO_MANY_REDIRECTS

سایت بالا نمی‌آید و مرورگر می‌گوید ERR_TOO_MANY_REDIRECTS؟ با curl زنجیره ریدایرکت را ببینید و حلقه www یا SSL را در چند دقیقه بشکنید.

هاست و سرور

مرورگر صفحه را باز نمی‌کند و فقط می‌چرخد؛ آخرش هم پیام ERR_TOO_MANY_REDIRECTS را نشان می‌دهد. اگر با curl -I هدرها را بگیرید، می‌بینید هر بار کد 301 یا 302 برمی‌گردد و آدرس مقصد دوباره به همان نقطه برمی‌گردد. این همان حلقه ریدایرکت است و تقریباً همیشه از یکی از سه جای مشخص می‌آید: تقابل www و بدون‌www، تنظیم SSL در Cloudflare، یا یک قانون rewrite که شرطش اشتباه نوشته شده.

قبل از هر تغییری، زنجیره را ببینید. حدس زدن این‌جا وقت‌کش است.

curl -sIL http://example.com | grep -Ei '^(HTTP/|location:)'
curl -sIL https://www.example.com | grep -Ei '^(HTTP/|location:)'

خروجی را از بالا به پایین بخوانید. اگر location: تکرار شد و به آدرسی برگشت که قبلاً دیده بودید، حلقه تأیید می‌شود. تعداد پرش‌ها را هم بشمارید؛ مرورگرها معمولاً بعد از حدود ۲۰ ریدایرکت متوقف می‌شوند، ولی حلقه در عمل با دو پرش هم سایت را از کار می‌اندازد.

حلقه www؛ شایع‌ترین شکل حلقه ریدایرکت

سناریوی کلاسیک این است: در پنل هاست یک قانون نوشته‌اید که example.com را به www.example.com ببرد، و همزمان در DNS رکورد www را با CNAME به دامنه اصلی اشاره داده‌اید یا در پنل دامنه یک Forwarding معکوس فعال است. نتیجه این می‌شود:

http://example.com   → 301 → https://www.example.com
https://www.example.com → 301 → https://example.com
https://example.com  → 301 → https://www.example.com   (و همین‌طور تا بی‌نهایت)

این‌جا اشتباه می‌کنند: فکر می‌کنند مشکل از مرورگر یا کش است و چند بار Ctrl+F5 می‌زنند. در حالی که حلقه در سرور است و هر بار هم پاسخ درست و تمیز برمی‌گردد. نشانه‌اش این است که در حالت Incognito هم دقیقاً همان اتفاق می‌افتد و curl هم همان زنجیره را نشان می‌دهد.

راه‌حل، یکسان‌کردن جهت است. یک نسخه را canonical انتخاب کنید و فقط یک لایه ریدایرکت بنویسد. در Apache با .htaccess:

RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=301,L]

نکته مهم در این قانون، [OR] و [L] است. اگر [L] را بردارید یا شرط را طوری بنویسید که روی خودِ www هم صدق کند، حلقه برمی‌گردد. در Nginx معادلش یک server بلوک جدا برای نسخه غیر‌canonical است، نه دو if تودرتو.

قبل از تغییر، DNS را چک کنید

گاهی حلقه اصلاً در وب‌سرور نیست. یک رکورد A یا CNAME اشتباه باعث می‌شود دامنه به سروری برسد که اصلاً سایت شما روی آن نیست و آن سرور هم دامنه را جای دیگری forward می‌کند. با ابزار بررسی DNS و شبکه رکوردهای A، AAAA و CNAME را ببینید و مطمئن شوید www و ریشه به یک مقصد اشاره می‌کنند.

Cloudflare و تله Flexible SSL

این مورد را زیاد می‌بینم و کمتر کسی اول به آن شک می‌کند. در Cloudflare حالت SSL روی Flexible است، یعنی ترافیک بین کاربر و Cloudflare روی HTTPS می‌رود، ولی بین Cloudflare و سرور شما روی HTTP. حالا اگر روی سرور یک قانون داشته باشید که «هر درخواست HTTP را به HTTPS ببر»، سرور پاسخی می‌دهد که به Cloudflare می‌گوید «برو HTTPS»، Cloudflare دوباره همان درخواست را روی HTTP به سرور می‌فرستد و حلقه کامل می‌شود.

دو راه دارد. یا حالت SSL را به Full (Strict) تغییر دهید و روی سرور گواهی معتبر نصب کنید، یا قانون ریدایرکت HTTPS را روی سرور غیرفعال کنید و اجازه دهید Cloudflare خودش این کار را با Page Rule یا Always Use HTTPS انجام دهد. من همیشه گزینه اول را انتخاب می‌کنم؛ چون Flexible در عمل یعنی ترافیک بین دو نقطه روی اینترنت بدون رمزنگاری رد و بدل می‌شود و این با هدف اولیه SSL در تناقض است. فقط اگر سرور شما گواهی معتبر ندارد و نمی‌توانید همین امروز نصبش کنید، موقتاً گزینه دوم قابل قبول است.

نشانه‌ای که در curl دیده می‌شود

در این حالت، curl -I https://example.com یک 301 با location: https://example.com/ برمی‌گرداند؛ یعنی همان آدرس فعلی. این الگو تقریباً امضای حلقه SSL است. اگر server: cloudflare را هم در هدرها ببینید، تقریباً قطعی است.

قوانین rewrite که خودشان حلقه می‌سازند

گاهی مشکل نه www است و نه SSL، بلکه یک شرط اضافه یا یک پلاگین است. چند الگوی رایج:

  • دو پلاگین ریدایرکت همزمان فعال‌اند و هرکدام نسخه مخالف را canonical می‌داند.
  • در وردپرس، siteurl و home در جدول wp_options با هم فرق دارند؛ یکی با www و یکی بدون آن.
  • یک قانون RewriteRule بدون [L] نوشته شده و درخواست را دوباره به خودش می‌فرستد.
  • در Nginx، return 301 داخل بلوکی که خودش هم مشمول همان شرط است.

برای وردپرس، سریع‌ترین راه دیدن مقدار واقعی این است:

wp option get siteurl
wp option get home

اگر این دو یکی نبودند، همان اختلاف می‌تواند منبع حلقه باشد. اصلاحشان با wp option update انجام می‌شود، ولی قبلش بکاپ بگیرید.

وقتی سایت روی هاست اشتراکی است

روی هاست اشتراکی، دست شما برای تغییر کانفیگ Nginx یا Apache بسته است و فقط .htaccess در اختیارتان است. این‌جا ترتیب اهمیت دارد: قوانین .htaccess از بالا به پایین اجرا می‌شوند و اولین قانونی که [L] داشته باشد، بقیه را متوقف می‌کند. اگر قانون ریدایرکت HTTPS را بالای قانون وردپرس بگذارید و شرطش هم درست باشد، مشکلی پیش نمی‌آید؛ ولی اگر پایین‌تر و بعد از قوانین rewrite وردپرس باشد، ممکن است هرگز اجرا نشود یا بدتر، با آن‌ها تداخل کند.

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

روش مرحله‌به‌مرحله برای پیدا کردن حلقه

  1. با curl -sIL زنجیره کامل را برای هر چهار ترکیب (http/https و با/بدون www) بگیرید.
  2. هر location: را روی کاغذ بنویسید و ببینید کدام آدرس دو بار تکرار شده.
  3. اگر Cloudflare فعال است، موقتاً آن را روی حالت DNS Only بگذارید و دوباره تست کنید. اگر حلقه رفت، مشکل از تنظیمات SSL است.
  4. پلاگین‌های ریدایرکت را یکی‌یکی غیرفعال کنید.
  5. بعد از هر تغییر، کش مرورگر و کش سرور را پاک کنید و دوباره curl بزنید.

یک نکته که وقت زیادی از آدم می‌گیرد: کش. اگر از کش صفحه در سطح سرور یا CDN استفاده می‌کنید، ممکن است پاسخ قدیمی با هدر 301 همچنان سرو شود و شما فکر کنید تغییری اعمال نشده. هدر Cache-Control روی پاسخ‌های 301 را جدی بگیرید؛ اگر کش مرورگر و هدرهای Cache-Control درست تنظیم نشده باشند، یک ریدایرکت اشتباه می‌تواند ساعت‌ها در مرورگر کاربران بماند.

جلوگیری از برگشتن مشکل

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

for u in http://example.com http://www.example.com \
         https://example.com https://www.example.com; do
  n=$(curl -sIL "$u" | grep -c '^location:')
  echo "$u -> $n redirects"
done

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

پرسش‌های پرتکرار

چرا ERR_TOO_MANY_REDIRECTS فقط روی بعضی مرورگرها ظاهر می‌شود؟

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

آیا پاک‌کردن کش مرورگر حلقه ریدایرکت را برطرف می‌کند؟

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

حلقه www را با ریدایرکت در DNS حل کنم یا در وب‌سرور؟

در وب‌سرور. ریدایرکت در سطح DNS (Forwarding) کنترل کمتری می‌دهد و می‌تواند با قوانین سرور تداخل کند. یک قانون 301 تمیز در .htaccess یا کانفیگ Nginx هم قابل تست است و هم در لاگ‌ها دیده می‌شود.

چطور بفهمم حلقه از Cloudflare است یا از سرور؟

موقتاً رکورد را روی DNS Only بگذارید تا ترافیک مستقیم به سرور برسد. اگر حلقه از بین رفت، مشکل تنظیمات SSL در Cloudflare است. اگر باقی ماند، قانون ریدایرکت روی سرور مقصر است. بعد از تشخیص، حالت SSL را به Full (Strict) برگردانید.

پشتیبانی سرورنت

تیم فنی و تحریریه‌ی سرورنت — تخصص در زیرساخت، شبکه و میزبانی وب.

هاست لینوکس
اشتراک‌گذاری:

دیدگاه‌ها ۰

هنوز دیدگاهی ثبت نشده؛ اولین نفر باشید!

دیدگاه خود را بنویسید

سرویس مرتبط

هاست لینوکس

میزبانی PHP و MySQL روی NVMe RAID-10 با LiteSpeed — پایه‌ی مطمئن هر وب‌سایتی، از وبلاگ شخصی تا پروژه‌های لاراول سازمانی. با قیمتی که رقبا توضیحی برایش ندارند.