Apache و Nginx

ریدایرکت HTTP به HTTPS با htaccess و یکسان کردن www در Apache

ریدایرکت HTTP به HTTPS با htaccess یعنی هر درخواست http با کد 301 به نسخه https همان آدرس فرستاده شود. چند خط RewriteRule در فایل .htaccess ریشه سایت همین کار را می کند و با یک شرط اضافه می توانید www را هم یکدست کنید.

نوشته تیم فنی پیکوهاستبه روزرسانی: ۲۰ مهر ۱۴۰۵۸ دقیقه مطالعه

برای ریدایرکت HTTP به HTTPS با htaccess کافی است فایل .htaccess را در ریشه سایت (معمولا public_html) باز کنید و چند خط RewriteRule بالای بقیه قوانین بگذارید. سه چیز را باید همراه آن بدانید: ریدایرکت باید 301 باشد، آدرس مقصد باید یکی باشد تا زنجیره نسازد، و قانون باید بالای بخش وردپرس بیاید. کد آماده برای هر دو حالت www و non-www پایین تر آمده است.

فایل .htaccess را پیش از هر ویرایش دانلود یا با نام .htaccess.bak کپی کنید. یک خط نادرست می تواند کل سایت را با خطای 500 از دسترس خارج کند و بازگرداندن نسخه قبلی سریع ترین راه برگشت است.

قبل از شروع

ریدایرکت به https وقتی معنی دارد که گواهی SSL روی دامنه نصب و فعال باشد. اگر هنوز نیست، ابتدا آن را درست کنید، چون ریدایرکت به آدرسی با گواهی خراب بازدیدکننده را به صفحه خطای اتصال امن نیست می برد. در cPanel بعد از نصب گواهی، در بخش Domains گزینه Force HTTPS Redirect هم هست که همین کار را بدون ویرایش فایل انجام می دهد. اگر آن گزینه را روشن کرده اید، قانون زیر را هم اضافه نکنید تا دو ریدایرکت با هم تداخل نکنند.

فایل .htaccess فقط روی وب سرور Apache و سرورهای سازگار مثل LiteSpeed خوانده می شود. روی Nginx این فایل اثری ندارد و ریدایرکت داخل تنظیمات سرور نوشته می شود. اگر در cPanel فایل را نمی بینید، در File Manager گزینه Show Hidden Files را روشن کنید.

ریدایرکت فقط HTTP به HTTPS

این کد هر درخواست http را به همان آدرس با https می برد و www را دست نمی زند:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

RewriteCond %{HTTPS} off یعنی قانون فقط وقتی اجرا شود که اتصال امن نباشد. %{HTTP_HOST} همان نام دامنه ای است که بازدیدکننده نوشته و %{REQUEST_URI} مسیر را نگه می دارد. رشته کوئری هم خودکار به آدرس مقصد اضافه می شود. [L,R=301] یعنی قانون آخر باشد و ریدایرکت دائمی بدهد. مستندات رسمی این دستورها در صفحه mod_rewrite است.

ریدایرکت به https بدون www

اگر می خواهید آدرس نهایی همیشه https://example.com باشد، هم http و هم نسخه www را به آن برگردانید:

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

[OR] یعنی کافی است یکی از دو شرط درست باشد. با این قانون چهار آدرس http://example.com، http://www.example.com، https://www.example.com و https://example.com همگی در یک مرحله به آدرس چهارم می رسند. example.com را با نام دامنه خودتان عوض کنید و نقطه ها را مثل مثال با بک اسلش بنویسید.

ریدایرکت به https با www

اگر نسخه www را انتخاب کرده اید، شرط دوم را برعکس کنید:

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

یک نکته درباره زیردامنه ها: شرط !^www\. هر نامی را که با www شروع نشود به www.example.com می فرستد، از جمله blog.example.com. اگر زیردامنه فعال دارید، به جای آن دقیقا ^example\.com$ را شرط بگذارید.

قانون را کجای فایل بگذارید

در وردپرس قوانین # BEGIN WordPress تا # END WordPress توسط خود وردپرس بازنویسی می شوند. قانون ریدایرکت باید بالای این بلوک بیاید، نه داخل آن:

# ریدایرکت HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [L,R=301]

# BEGIN WordPress
...
# END WordPress

ترتیب مهم است، چون وردپرس هر درخواستی را که فایلی نباشد به index.php می فرستد و اگر قانون شما بعد از آن بیاید، هیچ وقت به آن نمی رسد. اگر فایل .htaccess فقط شامل این ریدایرکت است و سایت وردپرسی نیست، فقط همان چند خط را نگه دارید.

اگر پشت پروکسی یا Cloudflare هستید

وقتی بین بازدیدکننده و سرور یک پروکسی یا CDN قرار دارد، اتصال به سرور ممکن است http باشد و %{HTTPS} همیشه off بماند. نتیجه اش حلقه ریدایرکت است. در این حالت شرط را روی هدر پروکسی بگذارید:

RewriteCond %{HTTP:X-Forwarded-Proto} !https

به جای خط RewriteCond %{HTTPS} off این شرط را بنویسید. اگر CDN هدر دیگری می فرستد، نام همان هدر را جایگزین کنید. جزئیات تشخیص و رفع حلقه در آموزش خطای ریدایرکت بیش از حد آمده است.

تست با curl

بعد از ذخیره فایل، کش مرورگر را کنار بگذارید و با curl درخواست بزنید:

curl -I http://example.com/
curl -I http://www.example.com/
curl -I https://www.example.com/

در خروجی هر سه باید HTTP/1.1 301 Moved Permanently و هدر Location: https://example.com/ ببینید. برای دنبال کردن زنجیره کامل از curl -IL http://www.example.com/ استفاده کنید. بیش از یک ریدایرکت پشت سر هم معمولا یعنی دو قانون با هم کار می کنند، مثلا یکی در .htaccess و دیگری در cPanel یا افزونه.

مرورگرها ریدایرکت 301 را کش می کنند. اگر در حال آزمایش هستید، به جای R=301 موقتا R=302 بنویسید و بعد از اطمینان به 301 برگردانید، وگرنه اشتباه اولیه تا مدتی در مرورگر می ماند.

چرا 301 و چرا فقط یک آدرس نهایی

موتورهای جستجو http و https و نسخه www و non-www را چهار آدرس جدا حساب می کنند. اگر هر چهار با محتوای یکسان باز شوند، سایت چهار نسخه تکراری دارد و اعتبار لینک ها بین آن ها تقسیم می شود. ریدایرکت 301 به گوگل می گوید آدرس اصلی کدام است. بعد از ریدایرکت این موارد را هم با آدرس جدید هماهنگ کنید:

  • آدرس سایت در Settings > General وردپرس، با همان پیشوند و www که انتخاب کرده اید.
  • فایل sitemap.xml و آدرس آن در robots.txt.
  • ویژگی Canonical در قالب یا افزونه سئو.
  • آدرس سایت در Google Search Console، به شکل Property جدید برای نسخه https.

اگر سایت را تازه به https برده اید و صفحه ها قفل ندارند، دنبال آدرس های http داخل محتوا بگردید. روش پیدا کردن آن ها در راهنمای mixed content آمده است.

ریدایرکت یک مسیر یا زیردامنه

گاهی فقط بخشی از سایت باید https شود، مثلا مسیر پرداخت یا پنل مدیریت. شرط را روی مسیر بگذارید:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(checkout|my-account|wp-admin)(/.*)?$ https://%{HTTP_HOST}/$1$2 [L,R=301]

این روش فقط وقتی لازم است که دلیل خاصی دارید. امروز بهتر است کل سایت روی https باشد، چون صفحه ای که با http باز شود و بعد ریدایرکت بخورد، یک درخواست اضافه می سازد و برای گوگل هم سیگنال ضعیف تری است.

برای زیردامنه ها دو حالت دارید. اگر زیردامنه Document Root جدا دارد (مثلا public_html/blog)، همان قانون را باید داخل .htaccess همان پوشه بگذارید. اگر زیردامنه به پوشه ای زیر public_html اشاره می کند، قانون پوشه والد هم روی آن اعمال می شود و لازم نیست آن را دوباره بنویسید. با curl هر دو را جداگانه امتحان کنید.

ریدایرکت فایل های ثابت و API

اگر روی سایت یک API یا وبهوک دارید که فراخواننده خارجی آدرس http آن را ثبت کرده، ریدایرکت 301 همه چیز را خراب نمی کند، ولی بعضی کلاینت ها بعد از ریدایرکت متد POST را به GET تبدیل می کنند و بدنه درخواست از بین می رود. وبهوک تلگرام هم ریدایرکت را خطا حساب می کند. در این موارد آدرس https را مستقیم در سرویس فراخواننده ثبت کنید و مسیر را از قانون ریدایرکت مستثنا نگه دارید. نمونه شرط استثنا:

RewriteCond %{REQUEST_URI} !^/api/

این خط را بالای RewriteRule بگذارید تا آدرس هایی که با /api/ شروع می شوند ریدایرکت نشوند. بعد از آن آدرس سرویس ها را با https ثبت کنید تا استثنا لازم نباشد.

هدر HSTS بعد از اطمینان

بعد از اینکه مطمئن شدید همه صفحه ها و زیردامنه ها روی https درست کار می کنند، می توانید هدر Strict-Transport-Security را اضافه کنید تا مرورگر خودش درخواست های بعدی را مستقیم با https بفرستد:

<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=300" env=HTTPS
</IfModule>

مقدار max-age بر حسب ثانیه است. با عدد کوچک شروع کنید و فقط وقتی همه چیز درست بود آن را بالا ببرید، چون مرورگر تا پایان این مدت حاضر نیست آن دامنه را با http باز کند و اگر گواهی منقضی شود، بازدیدکننده راهی برای رد شدن از هشدار نخواهد داشت. اگر نمی دانید همه زیردامنه ها گواهی دارند، گزینه includeSubDomains را اضافه نکنید.

اگر فایل htaccess اثری ندارد

گاهی قانون درست نوشته شده ولی هیچ ریدایرکتی اتفاق نمی افتد. اول مطمئن شوید فایل در پوشه ریشه همان دامنه است و نام آن دقیقا .htaccess است، بدون پسوند .txt. روی VPS با Apache باید AllowOverride All برای آن پوشه در تنظیمات سایت فعال باشد و ماژول rewrite با sudo a2enmod rewrite روشن شود، بعد Apache را reload کنید. روی هاست اشتراکی معمولا این دو فعال هستند و اگر نیستند، پشتیبانی هاست باید آن را بررسی کند.

مشکلات بعد از ریدایرکت

علامتعلتراه حل
ERR_TOO_MANY_REDIRECTSدو قانون ریدایرکت یا پروکسی که HTTPS را نمی فرستدشرط X-Forwarded-Proto و حذف قانون تکراری
خطای 500 بعد از ذخیرهغلط تایپی یا ماژول mod_rewrite غیرفعالبرگرداندن بکاپ و بررسی خط به خط
صفحه باز می شود ولی قفل نداردفایل های http داخل صفحهرفع mixed content در وردپرس
خطای 403 روی بعضی مسیرهاقانون یا دسترسی دیگر در همان فایلآموزش رفع 403 در Apache

اگر AutoSSL برای دامنه گواهی صادر می کند، ریدایرکت اجباری ممکن است در اعتبارسنجی دخالت کند. در بعضی تنظیمات مسیر /.well-known/acme-challenge/ باید بدون ریدایرکت جواب بدهد. سرور شما اگر این مشکل را نشان داد، شرط RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/ را قبل از RewriteRule اضافه کنید.

روی VPS بدون htaccess

اگر VPS دارید و به تنظیمات Apache دسترسی دارید، ریدایرکت را بهتر است در VirtualHost پورت 80 بنویسید، چون سریع تر است و .htaccess لازم ندارد:

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    Redirect permanent / https://example.com/
</VirtualHost>

بعد از ویرایش sudo apachectl configtest را اجرا کنید و فقط اگر Syntax OK دیدید sudo systemctl reload apache2 را بزنید. روی هاست های اشتراکی پیکوهاست که LiteSpeed دارند، همان قوانین .htaccess بالا بدون تغییر کار می کنند؛ تفاوت این دو وب سرور را در مقایسه LiteSpeed و Apache برای وردپرس می خوانید.