فعال‌سازی IPv6 سرور: از آدرس‌دهی تا فایروال

اگر سایت روی IPv6 جواب نمی‌دهد یا رکورد AAAA دارید ولی سرویس بالا نمی‌آید، این راهنما مسیر کامل پیکربندی IPv6 سرور را قدم‌به‌قدم پیش می‌برد.

۷ دقیقه به‌روزرسانی ۱۰ آبان ۱۴۰۵

سرور شما IPv6 دارد، رکورد AAAA را هم ست کرده‌اید، اما curl -6 https://example.com روی همان ماشین یا تایم‌اوت می‌شود یا بلافاصله Connection refused برمی‌گرداند. در همین حال نسخهٔ IPv4 سایت با سرعت کامل کار می‌کند. این دقیقاً همان نقطه‌ای است که اکثر مدیران سرور گیر می‌کنند: فرض می‌کنند چون آدرس IPv6 روی اینترفیس نشسته، همه‌چیز تمام شده. نشده. سه لایهٔ جدا باید هم‌راستا شوند و اگر یکی جا بماند، همان علائم گمراه‌کننده را می‌بینید.

اول بفهمید IPv6 سرور واقعاً فعال است یا فقط تخصیص داده شده

قبل از هر تغییری، وضعیت فعلی را بخوانید. دستور ip -6 addr show scope global فقط آدرس‌های عمومی IPv6 را نشان می‌دهد و آدرس‌های link-local را که با fe80:: شروع می‌شوند فیلتر می‌کند. اگر خروجی خالی بود، مشکل در لایهٔ شبکه است نه در وب‌سرور.

ip -6 addr show scope global
ip -6 route show default
sysctl net.ipv6.conf.all.disable_ipv6

خط آخر باید مقدار 0 برگرداند. اگر 1 بود، IPv6 در سطح کرنل خاموش است و هیچ پیکربندی دیگری جواب نمی‌دهد. این حالت روی بعضی ایمیج‌های قدیمی و برخی قالب‌های امنیتی پیش‌فرض دیده می‌شود. برای روشن کردن موقت:

sysctl -w net.ipv6.conf.all.disable_ipv6=0
sysctl -w net.ipv6.conf.default.disable_ipv6=0

برای دائمی شدن، این دو خط را در /etc/sysctl.d/99-ipv6.conf بگذارید و sysctl --system بزنید. نکته‌ای که خیلی‌ها از دست می‌دهند: اگر disable_ipv6 را روی all صفر کنید ولی روی اینترفیس مشخصی یک مقدار صریح 1 مانده باشد، همان اینترفیس خاموش می‌ماند. مقدار اینترفیس بر مقدار کلی اولویت دارد.

آدرس را دستی ست کنید یا از SLAAC بگیرید

روی سرورهای ابری معمولاً آدرس از سمت شبکه اعلام می‌شود و شما فقط باید آن را بپذیرید. اما روی سرور اختصاصی که بلاک IPv6 به شما تحویل داده شده، آدرس‌دهی دستی است. در توزیع‌های مبتنی بر systemd-networkd فایل /etc/systemd/network/10-static.network را این‌طور بنویسید:

[Network]
Address=2001:db8:1::10/64
Gateway=2001:db8:1::1
DNS=2001:4860:4860::8888

در Ubuntu با Netplan معادلش در /etc/netplan/01-netcfg.yaml زیر کلید addresses و routes می‌آید. اگر بعد از netplan apply ارتباط SSH شما قطع شد، نترسید؛ از کنسول یا حالت rescue برگردید و پیکربندی را اصلاح کنید. این سناریو آن‌قدر رایج است که ارزش دارد از قبل بدانید بازنصب سرور و کار با حالت rescue؛ نجات داده‌ها وقتی دسترسی را از دست دادید چطور کار می‌کند.

رکورد AAAA را درست ست کنید، نه فقط ست کنید

رکورد AAAA دقیقاً مثل A کار می‌کند، فقط مقدارش یک آدرس ۱۲۸ بیتی است. سینتکس در فایل zone بایند به این شکل است:

www     IN  AAAA    2001:db8:1::10
@       IN  AAAA    2001:db8:1::10

سه اشتباه رایج که هر سه علائم یکسانی تولید می‌کنند. اول، آدرس را با فرم فشرده‌نشده یا با حروف بزرگ می‌نویسند و بعضی پنل‌های DNS آن را رد می‌کنند. دوم، :: را دو بار در یک آدرس به کار می‌برند که از نظر نحوی نامعتبر است. سوم، آدرس link-local یعنی همان fe80:: را در رکورد AAAA می‌گذارند. این آدرس از بیرون قابل مسیریابی نیست و کلاینت‌ها به آن نمی‌رسند.

برای بررسی، از dig استفاده کنید و صریحاً نوع AAAA بخواهید:

dig +short AAAA example.com @1.1.1.1
dig +trace AAAA example.com

اگر dig جواب می‌دهد ولی مرورگر نه، مشکل DNS نیست. مشکل مسیر برگشت یا فایروال است.

این‌جا اشتباه می‌کنند: فایروال IPv6 را جدا می‌بینند

این شایع‌ترین اشتباهی است که در تیکت‌ها می‌بینم. مدیر سرور پورت ۴۴۳ را در iptables باز می‌کند، IPv4 سایت بالا می‌آید، و فرض می‌کند کار تمام است. اما iptables فقط بسته‌های IPv4 را می‌بیند. ترافیک IPv6 از ip6tables یا از جدول inet در nftables عبور می‌کند. نتیجه؟ سایت روی IPv4 باز می‌شود، روی IPv6 تایم‌اوت می‌خورد، و چون مرورگرها Happy Eyeballs دارند کاربر معمولاً چیز عجیبی نمی‌بیند تا وقتی که یک بازدیدکننده با شبکهٔ IPv6-only بیاید و صفحه اصلاً بالا نیاید.

علامت تشخیصی‌اش این است: ss -6 -tlnp نشان می‌دهد سرویس روی :::443 گوش می‌دهد، ولی curl -6 از بیرون تایم‌اوت می‌شود. یعنی سرویس سالم است و فایروال جلویش را گرفته. برای دیدن قواعد فعلی:

nft list ruleset
ip6tables -L -n -v --line-numbers

اگر روی سیستم nftables دارید، iptables و ip6tables فقط لایهٔ سازگاری هستند و ممکن است قواعد واقعی را نشان ندهند. مرجع کامل دستورها را در دستورات فایروال لینوکس: مرجع سریع iptables، nftables و ufw ببینید تا بین این سه سردرگم نشوید.

سرویس را روی IPv6 گوش‌دادن وادار کنید

خیلی از سرویس‌ها به‌صورت پیش‌فرض فقط روی IPv4 گوش می‌دهند. در Nginx خط زیر را داخل بلوک server بگذارید:

listen [::]:443 ssl http2;
listen [::]:80;

براکت‌ها اجباری‌اند؛ بدون آن‌ها Nginx خطا می‌دهد چون : در آدرس IPv6 خودش جداکننده است. در Apache کافی است Listen [::]:443 را اضافه کنید. برای MySQL و PostgreSQL هم پارامتر bind-address را به :: تغییر دهید، ولی این کار را فقط وقتی بکنید که واقعاً به دسترسی از راه دور IPv6 نیاز دارید. باز کردن دیتابیس روی :: بدون فایروال، همان فاجعهٔ IPv4 را تکرار می‌کند. فهرست پورت‌هایی که هرگز نباید باز باشند در مرجع پورت سرویس‌های پرکاربرد و پورت‌هایی که نباید باز باشند آمده است.

بعد از تغییر، سرویس را ری‌استارت کنید و بررسی کنید که واقعاً روی IPv6 گوش می‌دهد:

ss -6 -tlnp | grep -E ':(80|443)'
curl -6 -I https://example.com
curl -6 -v telnet://[2001:db8:1::10]:443

اگر سرویس بالا نمی‌آید و در لاگ چیزی نیست، احتمالاً unit را دستی ویرایش کرده‌اید و systemd آن را نخوانده. ساختار درست و نحوهٔ ری‌استارت امن در فایل unit در systemd: بخش‌ها، ری‌استارت و وابستگی توضیح داده شده.

انتخاب بین IPv6 دوگانه و IPv6-only

دو مسیر واقعی پیش روی شماست و انتخابش به کاربرد بستگی دارد، نه به سلیقه.

معیارپیکربندی دوگانه (Dual-Stack)فقط IPv6
سازگاری با کاربران فعلیکاملنیازمند NAT64 یا پروکسی
پیچیدگی فایروالدو مجموعه قاعدهیک مجموعه قاعده
ریسک خطای پیکربندیبالاپایین
مناسب برایسایت عمومی، فروشگاهسرویس داخلی، بک‌اند API

من برای هر سایتی که کاربر ناشناس دارد، دوگانه را انتخاب می‌کنم. دلیلش ساده است: هنوز بخش قابل‌توجهی از شبکه‌های سازمانی و ISPهای داخلی مسیر IPv6 ندارند و اگر فقط IPv6 سرو کنید، آن‌ها را از دست می‌دهید. اما برای API داخلی بین میکروسرویس‌ها، IPv6-only انتخاب درست است. یک مجموعه قاعده، بدون NAT، بدون سردرگمی آدرس‌های ترجمه‌شده. هزینه‌اش این است که هر ابزار مانیتورینگ و هر اسکریپت قدیمی باید IPv6 را بفهمد؛ بعضی اسکریپت‌های پایتون با socket.AF_INET هاردکد شده‌اند و بی‌صدا شکست می‌خورند.

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

اگر سرور شما پشت NAT64 یا پشت یک تونل 6to4 باشد، آدرس مبدأیی که سرویس شما می‌بیند با آدرس واقعی کلاینت یکی نیست. هر منطق rate-limit یا بلاک بر اساس IP در این حالت دور می‌خورد. قبل از راه‌اندازی، با tcpdump -i eth0 -n ip6 چند دقیقه ترافیک را نگاه کنید و ببینید آدرس‌های مبدأ چه شکلی‌اند. اگر همه از یک پیشوند خاص می‌آمدند، احتمالاً پشت مترجم هستید.

برای تست نهایی از بیرون، از سرویس‌های آنلاین تست IPv6 استفاده کنید یا از یک ماشین با شبکهٔ متفاوت curl -6 بزنید. تست از روی خود سرور هیچ‌وقت مسیر برگشت را اثبات نمی‌کند. اگر روی زیرساخت ابری کار می‌کنید، بخشی از این تنظیمات ممکن است در سطح شبکه انجام شده باشد و فقط باید در سیستم‌عامل تأیید شود؛ در سرور ابری معمولاً آدرس از قبل مسیریابی شده و کار شما کمتر است. روی سخت‌افزار اختصاصی، همهٔ این مراحل را خودتان می‌روید.

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

چرا سایت روی IPv4 باز می‌شود ولی روی IPv6 نه؟

تقریباً همیشه فایروال است. قواعد iptables روی ترافیک IPv6 اعمال نمی‌شوند و باید ip6tables یا جدول inet در nftables را جدا تنظیم کنید. تست کنید: اگر ss -6 -tlnp نشان می‌دهد سرویس روی :::443 گوش می‌دهد ولی curl -6 از بیرون تایم‌اوت می‌شود، سرویس سالم است و فایروال جلوی آن را گرفته.

آیا حذف رکورد AAAA مشکل را حل می‌کند؟

موقتاً بله، ولی راه‌حل نیست. با حذف AAAA کاربران IPv6-only کاملاً از دست می‌روند و بعضی مرورگرها به‌خاطر کش DNS تا چند ساعت رفتار عجیب نشان می‌دهند. اگر عجله دارید و باید سایت همین حالا بالا بیاید، حذف رکورد AAAA یک اقدام موقت قابل قبول است؛ ولی TTL را روی ۳۰۰ ثانیه بگذارید تا بعداً سریع برگردانید.

آدرس IPv6 را از کجا باید بگیرم؟

روی سرورهای ابری معمولاً از سمت شبکه اعلام می‌شود و شما فقط باید آن را بپذیرید. روی سرور اختصاصی، بلاک IPv6 همراه سرویس به شما تحویل داده می‌شود و آدرس‌دهی دستی است. در هر دو حالت، قبل از هر چیز با ip -6 addr show scope global بررسی کنید که آدرس واقعاً روی اینترفیس نشسته باشد.

چطور بفهمم فایروال IPv6 مقصر است یا خود سرویس؟

روی خود سرور با curl -6 http://[::1]:443 به loopback وصل شوید. اگر جواب داد، سرویس سالم است و مشکل در مسیر شبکه یا فایروال است. اگر جواب نداد، سرویس روی IPv6 گوش نمی‌دهد و باید خط listen [::] را در پیکربندی اضافه کنید.

قدم بعدی مشخص است: همین حالا ip -6 addr show scope global و nft list ruleset را بزنید و ببینید کدام لایه خالی است. در نود درصد موارد، جواب در همان دو خروجی پیدا می‌شود.

آیا این مطلب برایتان مفید بود؟