انتشار سرور خانگی از طریق VPS وقتی CGNAT پورتها را مسدود میکند
مسیر از مرورگر تا دستگاه خانه: ثابت کن خط پشت CGNAT است، DNS را به VPS اشاره بده، روی یک پورت DNAT انجام بده، مسیر بازگشت را درست کن و از بیرون بررسی کن.
از بیرون شروع کردم، همانطور که یک کاربر انجام میداد: نام را در مرورگر تلفن با داده همراه تایپ کردم و دیدم اتصال تا پایان مهلت معلق ماند. نام حل میشد، پس DNS درست بود. صفحهٔ ارسال پورت روتر خانه هم بنبست بود، چون نشانی WAN آن 100.64.31.42 را نشان میداد، و این نشانی نیست که یک ارائهدهنده مرا از اینترنت به آن هدایت کند. این عدد کل خرابی را توضیح میدهد: خط پشت carrier-grade NAT است، پس نشانی عمومی در سمت من از تونل به ارائهدهنده تعلق دارد. آنچه در ادامه میآید مسیری است که از آن زبانهٔ معلق تا سرویسی که پاسخ میدهد پیمودم.
از سمت کاربر شروع کن و به داخل برو
پیش از تغییر هر قاعدهای، ثابت کن زنجیره کجا متوقف میشود. روی لپتاپ dig +short files.example.net را اجرا کردم و نشانی VPS را برگرداندم، که DNS کهنه روی ماشین خودم را رد کرد. سپس curl -v --connect-timeout 5 files.example.net:5022 بهجای رد شدن، به پایان مهلت خورد. این تفاوت مهم است: پایان مهلت معمولاً یعنی بستهها در مسیر انداخته میشوند، در حالی که رد شدن یعنی چیزی پاسخ داده و نه گفته است.
قدم بعدی به داخل خود VPS بود. ss -ltnp چیزی نشان نداد که روی 5022 گوش کند، که پیش از وجود قاعدهٔ DNAT انتظار میرفت. روی همان ماشین wg show (یا ip -br a show tun0 برای OpenVPN) تأیید کرد که peer خانه فعال است و handshake تازه دارد. اگر peer کار نکند هیچ قاعدهٔ NAT کمکی نمیکند، و چراغ سبز صفحهٔ VPN روتر خانه هیچ معنایی ندارد.
تأیید کن که خط خانه واقعاً پشت CGNAT است
نشانیای که روتر روی رابط WAN خود گزارش میکند را با آنچه یک سرویس بیرونی میبیند مقایسه کن. هر چیزی در 100.64.0.0/10، یعنی از 100.64.x.x تا 100.127.x.x، محدودهٔ نشانیهای اشتراکی RFC 6598 است و از اینترنت در دسترس نیست. به همان نتیجه میرسی وقتی روتر ادعا میکند نشانی خصوصی معمولی دارد و جستوجوی عمومی چیز بیربطی برمیگرداند. خط CGNAT میتواند نشانی عمومی هم داشته باشد که فقط تا lease بعدی دوام میآورد، بنابراین ارسال پورت یک ساعت کار میکند و بعد بیصدا میمیرد.
برخی ارائهدهندگان واقعاً نشانی عمومی واقعی میدهند اما پورتهای ورودی 80 و 443 را در حسابهای خانگی مسدود میکنند. اگر سرویس تو فقط وب است و نشانی WAN واقعاً عمومی است، پیش از ساختن relay از پشتیبانی بپرس. اگر نیست، طراحی زیر به یکسان برای هر پورتی صدق میکند، و ارزش دارد که آزمایش را در سمت روتر متوقف کنی: مترجم در شبکهٔ ارائهدهنده اتصال را پیش از آنکه هرگز به رابط WAN تو برسد پایان میدهد.
نام را به نشانی VPS اشاره بده
DNS ترافیک را عبور نمیدهد، پس رکورد A سرویس باید نشانی عمومی VPS را داشته باشد. رکورد A به 192.168.1.20 فقط برای کارخواهانی که از قبل داخل VPN هستند بهشکل سودمند حل میشود؛ از اینترنت به نشانیای حل میشود که هیچکس نمیتواند هدایتش کند. برای دسترسی مدیریتی خود VPS نامی جدا نگه میدارم تا هرگز اشتباه نکنم که یک رکورد به کدام میزبان اشاره دارد.
اگر هم VPS و هم ماشین خانه HTTP سرو میکنند، به هرکدام نام خودش را بده و بگذار VPS تصمیم بگیرد چه کسی پاسخ میدهد. یکی کردن آنها در یک نام و امید به اینکه پروکسی backend درست را انتخاب کند، دقیقاً همان چیزی است که یک بعدازظهر را صرف اشکالزدایی از میزبان اشتباه میکنی.
یک پورت با DNAT، SSH روی 22 بماند
گزینهٔ مستقیم NAT مقصد روی VPS است. forwarding را برای هستهٔ در حال اجرا روشن کن و نشانی تونل سرور خانه را در قاعده نگه دار، نه نشانی LAN آن:
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A PREROUTING -p tcp -d 198.51.100.10 --dport 5022 -j DNAT --to-destination 10.8.0.2
SSH به خود VPS را روی 22 بگذار و پورت دیگری، مثلاً 5022، را به ماشین خانه هدایت کن. اگر 22 را به ماشینی خاموش هدایت کنی، تنها مسیری را از دست میدهی که میتوانست درستش کند. همین منطق برای پروکسی هم صدق میکند: پورت مدیریت VPS را بیرون از قاعدههای relay نگه دار.
قاعدهها را بهمحض کار کردن دائمی کن. در Debian یا Ubuntu، apt install iptables-persistent و سپس netfilter-persistent save آنها را در /etc/iptables/rules.v4 مینویسند. روی میزبان با firewalld معادل آن ارسال پورت دائمی در ناحیه است که پیش از اعمال به firewall-cmd --reload نیاز دارد. قاعدههایی که فقط در حافظه زندگی میکنند، در نخستین راهاندازی نگهداری ارائهدهنده ناپدید میشوند، معمولاً در ساعت بد.
مسیر بازگشت را درست کن یا از نیاز به آن بپرهیز
DNAT فقط مقصد را بازنویسی میکند. سرور خانه اتصالی از نشانی اصلی کارخواه میبیند، و اگر مسیر پیشفرضش به روتر خانه اشاره کند، پاسخ از WAN خانه بیرون میرود جایی که مترجم ارائهدهنده آن را میاندازد. این نامتقارنی دومین خرابی بود که به آن برخوردم، پس از آنکه قاعدهٔ DNAT کاملاً درست به نظر میرسید.
دو اصلاح کار میکند. به ماشین خانه یک مسیر سیاستی بده تا ترافیک تونل از تونل بازگردد:
ip rule add from 10.8.0.2 table 100
ip route add default dev wg0 table 100
یا بگذار VPS منبع را بازنویسی کند تا پاسخ نشانیای داشته باشد که میتواند به آن برسد، و بگذار conntrack آن را در خروج برگرداند:
iptables -t nat -A POSTROUTING -d 10.8.0.2 -p tcp --dport 5022 -j SNAT --to-source 10.8.0.1
نسخهٔ SNAT نشانی واقعی کارخواه را از سرور خانه پنهان میکند، پس گزارشهای برنامه 10.8.0.1 را بهعنوان peer نشان میدهند. نشانی اصلی را در لایهٔ برنامه منتقل کن، یا بپذیر که ثبت بهازای هر کارخواه از دست میرود، اما این را آگاهانه تصمیم بگیر نه اینکه در میانهٔ یک حادثه کشفش کنی.
کل مسیر را از بیرون بررسی کن
از شبکهای بررسی کن که نه VPS است و نه خانه: تلفنی با داده همراه، یا یک shell ارزان جای دیگر. nc -vz files.example.net 5022 باید اتصال موفق را گزارش کند، و openssl s_client -connect files.example.net:443 -servername files.example.net باید گواهی نام عمومی را نشان دهد. سپس گروه امنیتی یا دیوار آتش ابری ارائهدهنده را بررسی کن. قاعدهٔ DNAT که هرگز بستهای نمیبیند معمولاً یک لایه بالاتر از میزبان مسدود میشود.
در پایان تصمیم بگیر وقتی تونل میافتد چه میشود. قاعدهٔ DNAT همچنان اتصال میپذیرد و آنها را بیصدا به تونل مرده میفرستد، که دقیقاً مثل سرویس خراب به نظر میرسد. بررسی سلامت روی VPS که تا وقتی peer کار نمیکند پورت را رد میکند چند خط هزینه دارد و یک ساعت حدس را صرفهجویی میکند. بعد از آن ویرایش قاعدهها را رها کن و یک روز تماشایش کن پیش از آنکه به آن اعتماد کنی.