פרסום שרת ביתי דרך 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 באמת ציבורית, שאל את התמיכה לפני שאתה בונה ממסר. אם לא, העיצוב שלהלן חל על כל פורט באותה מידה, וכדאי להפסיק את הניסוי בצד הראוטר: המתרגם ברשת הספק מסיים את החיבור לפני שהוא מגיע לממשק ה-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 מחוץ לכללי הממסר.
הפוך את הכללים לקבועים ברגע שהם עובדים. ב-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 לא פעיל עולה כמה שורות וחוסכת שעה של ניחושים. אחרי זה הפסק לערוך כללים וצפה בזה יום לפני שאתה סומך עליו.