سایت را باز میکنید و صفحه سفید است. یا بدتر: مرورگر میگوید 500 Internal Server Error و هیچ لاگی هم چیزی نمیگوید. در نُه مورد از ده موردی که این علامت را دیدهام، فایل .htaccess در ریشه public_html مقصر بوده؛ یک خط اضافه، یک فاصله اشتباه، یا قاعدهای که بعد از RewriteEngine On نیامده. این راهنما همان چیزهایی است که موقع دیباگ واقعی به آنها میرسید.
htaccess چیست و چرا ترتیب خطوطش مهم است
فایل .htaccess یک فایل متنی ساده است که وبسرور Apache یا LiteSpeed آن را در هر درخواست میخواند و قبل از رسیدن به PHP اجرا میکند. یعنی هر خطی که در آن بنویسید، روی هر بازدید اثر میگذارد. همین ویژگی باعث میشود یک خط اشتباه، کل سایت را از دسترس خارج کند.
ترتیب اجرا از بالا به پایین است و اولین قاعدهای که مطابقت کند، برنده است. اگر یک ریدایرکت عمومی را قبل از یک استثنا بنویسید، استثنا هرگز اجرا نمیشود. این را در عمل زیاد میبینم: کسی میخواهد همه چیز به HTTPS برود، اما فایل robots.txt یا مسیر /.well-known/acme-challenge/ را مستثنا نکرده و بعد تمدید SSL خودکار شکست میخورد.
ترتیب درست بلوکها
- تنظیمات پایه:
Options -Indexes، کدگذاری پیشفرض - ریدایرکتهای اجباری (HTTPS، حذف www یا افزودن آن)
- قواعد بازنویسی وردپرس یا فریمورک
- محافظت از فایلها و پوشهها
- هدرها و کش
ریدایرکت 301 را درست بنویسید
رایجترین کار، انتقال همه ترافیک به نسخه HTTPS و یک دامنه واحد است. این بلوک را بالای فایل بگذارید:
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]
نکتهای که خیلیها از دست میدهند: پرچم [OR] فقط بین دو RewriteCond پشت سر هم کار میکند، نه بین سهتا. اگر شرط سوم اضافه کنید، منطق عوض میشود و ریدایرکت حلقهای میشود. نشانهاش هم واضح است: مرورگر میگوید ERR_TOO_MANY_REDIRECTS و سایت بالا نمیآید.
برای انتقال یک صفحه مشخص، سادهتر از بازنویسی، از Redirect استفاده کنید:
Redirect 301 /old-page.html https://www.example.com/new-page/
این خط فقط برای مسیر دقیق کار میکند و روی زیرمسیرها اثر ندارد. اگر میخواهید کل یک پوشه منتقل شود، RedirectMatch 301 ^/old-folder/(.*)$ /new-folder/$1 بنویسید. اگر دامنه سایت را کامل عوض میکنید، پیش از هر چیز راهنمای تغییر دامنه بدون افت سئو را بخوانید؛ ریدایرکت اشتباه در این مرحله میتواند رتبههای چندساله را از بین ببرد.
محافظت از پوشه و فایلهای حساس
فایل wp-config.php، پوشه wp-includes و فایلهای پشتیبان .sql یا .zip نباید از بیرون قابل دسترسی باشند. این بلوک را در ریشه بگذارید:
<Files wp-config.php>
Require all denied
</Files>
<FilesMatch "\.(sql|bak|log|env)$">
Require all denied
</FilesMatch>
روی Apache نسخه 2.2 دستور Require all denied پشتیبانی نمیشود و باید Order allow,deny و Deny from all بنویسید. اگر سرور شما Apache 2.4 به بالا دارد (که تقریباً همه جا دارد)، همان Require درست است. اشتباه گرفتن این دو، خطای 500 میدهد بدون هیچ توضیحی.
برای محافظت از یک پوشه با رمز، اول فایل رمز را بسازید:
htpasswd -c /home/user/.htpasswd admin
سپس در .htaccess همان پوشه:
AuthType Basic
AuthName "Restricted"
AuthUserFile /home/user/.htpasswd
Require valid-user
مسیر AuthUserFile باید مطلق باشد. مسیر نسبی یکی از خطاهای پرتکرار است و نتیجهاش خطای 500 است، نه پیام «رمز اشتباه».
صفحه خطای سفارشی و هدرها
صفحه 404 پیشفرض سرور، تجربه بدی به کاربر میدهد. یک فایل 404.html بسازید و این خط را اضافه کنید:
ErrorDocument 404 /404.html
ErrorDocument 403 /403.html
مسیر باید نسبت به ریشه دامنه باشد، نه نسبت به فایل. اگر ErrorDocument 404 404.html بنویسید (بدون اسلش ابتدایی)، Apache آن را بهعنوان متن ساده برمیگرداند و کاربر یک خط متن میبیند.
برای هدرهای امنیتی و کش، ماژول mod_headers لازم است:
<IfModule mod_headers.c>
Header set X-Content-Type-Options "nosniff"
Header set X-Frame-Options "SAMEORIGIN"
<FilesMatch "\.(css|js|jpg|png|webp|woff2)$">
Header set Cache-Control "max-age=2592000, public"
</FilesMatch>
</IfModule>
عدد 2592000 معادل 30 روز است. برای فایلهای استاتیک این عدد منطقی است، اما برای index.html یا هر چیزی که ممکن است تغییر کند، کش یکماهه یعنی کاربر تا یک ماه نسخه قدیمی را میبیند. اینجا اشتباه میکنند: کسی استایل سایت را عوض میکند، سایت را رفرش میکند، تغییر را نمیبیند و فکر میکند آپلود نشده. در واقع کش مرورگر است.
خطای 500: کجا را نگاه کنیم
وقتی سایت 500 میدهد، اولین کار این است که فایل را موقتاً غیرفعال کنید:
mv .htaccess .htaccess.bak
اگر سایت بالا آمد، مشکل قطعاً در همان فایل است. حالا خطبهخط برگردانید یا از انتها کامنت کنید. سه علت رایج:
- دستوری که ماژولش روی سرور نصب نیست، مثل
php_valueروی سرورهایی که PHP را با FastCGI اجرا میکنند - فاصله یا کاراکتر نامرئی (مثلاً BOM) در ابتدای فایل که با ویرایشگر ویندوزی ذخیره شده
- قاعدهای که در
<IfModule>پیچیده نشده و ماژولش غیرفعال است
مورد دوم را جدی بگیرید. فایل را با file .htaccess چک کنید؛ اگر UTF-8 Unicode (with BOM) دید، BOM را حذف کنید. این یک بایت اضافه، کل سایت را زمین میزند و در لاگ هم چیز خاصی نمیبینید.
اگر خطا در وردپرس است و صفحه سفید میگیرید نه 500، مسیر عیبیابی متفاوت است؛ راهنمای رفع صفحه سفید در وردپرس و PHP گامبهگام همین را پوشش میدهد.
htaccess و محدودیتهای منابع هاست
یک نکته که کمتر گفته میشود: .htaccess روی هر درخواست خوانده میشود و اگر دهها قاعده سنگین داشته باشید، روی زمان پاسخ اثر میگذارد. روی هاست اشتراکی که منابع بین چند سایت تقسیم میشود، این اثر بیشتر به چشم میآید. اگر میبینید سایت کند شده و قواعد htaccess تازه اضافه کردهاید، اول مفهوم Entry Process و تفاوتش با بازدید را بفهمید؛ ممکن است مشکل کندی از جای دیگری باشد.
در عمل، بیشتر سایتها به کمتر از 30 خط htaccess نیاز دارند. اگر فایل شما از 200 خط گذشته، احتمالاً بخشی از کار باید در سطح سرور یا در کد اپلیکیشن انجام شود. روی هاست لینوکس میتوانید قواعد را در سطح دامنه مدیریت کنید، اما اگر ترافیک و نیاز به تنظیمات سراسری از حد هاست اشتراکی گذشته، سرور اختصاصی گزینه منطقیتری است چون آنجا تنظیمات را یکبار در httpd.conf مینویسید، نه در هر پوشه.
قبل از ذخیره، این کارها را بکنید
همیشه یک نسخه پشتیبان از فایل سالم داشته باشید. قبل از هر تغییر، cp .htaccess .htaccess.backup بزنید. اگر FTP دارید، راهنمای مدیریت اکانت FTP نشان میدهد چطور بدون دردسر فایل را دانلود و آپلود کنید. برای تست ریدایرکتها از حالت ناشناس مرورگر استفاده کنید، چون کش 301 در مرورگر عادی تقریباً پاک نمیشود و شما را گمراه میکند.
و اگر مطمئن نیستید دامنه درست به سرور اشاره میکند یا مشکل از DNS است، قبل از دستزدن به htaccess یک بار ابزار بررسی DNS و شبکه را چک کنید. نصف مواردی که بهعنوان «مشکل htaccess» گزارش میشود، در واقع رکورد A اشتباه است.
پرسشهای پرتکرار
چرا بعد از تغییر htaccess سایت خطای 500 میدهد؟
تقریباً همیشه یکی از این سه علت است: دستوری که ماژولش روی سرور فعال نیست، کاراکتر BOM در ابتدای فایل، یا خطای نگارشی مثل جاافتادن </IfModule>. فایل را با mv .htaccess .htaccess.bak موقتاً کنار بگذارید؛ اگر سایت بالا آمد، مشکل قطعاً در همان فایل است.
تفاوت Redirect و RewriteRule در htaccess چیست؟
Redirect برای مسیرهای ثابت و ساده است و روی زیرمسیرها اثر ندارد. RewriteRule با RewriteCond ترکیب میشود و شرطهای پیچیده مثل پروتکل، دامنه یا نوع مرورگر را پشتیبانی میکند. برای انتقال یک صفحه از اولی و برای منطق شرطی از دومی استفاده کنید.
آیا htaccess روی Nginx کار میکند؟
نه. Nginx فایل htaccess را نمیخواند و قواعد باید در بلوک server فایل کانفیگ نوشته شوند. اگر روی هاستی هستید که وبسرورش Nginx است، باید از پنل یا تیم پشتیبانی بخواهید قواعد را در سطح سرور اعمال کنند.
چطور بفهمم htaccess باعث کندی سایت شده؟
فایل را موقتاً غیرفعال کنید و زمان پاسخ را با ابزار اندازهگیری سرعت مقایسه کنید. اگر تفاوت محسوس بود، قواعد تکراری یا شرطهای سنگین را حذف کنید. در بیشتر موارد اثر htaccess روی سرعت ناچیز است و کندی از افزونهها یا کوئریهای دیتابیس میآید.