Faqat Docker konteynerlarining trafigini OpenVPN orqali yo‘naltirish
Xostni odatdagi uplinkda qoldiring va bitta konteyner quyi tarmog‘ini tunnelga joylashtiring: NAT tartibi, manba qoidalari, OpenVPN iroute va MSS tekshiruvlari.
Konteyner paketi hech qachon tun0 ga yetib bormaydi va konteynerdagi qo‘shimcha imkoniyatlar buni o‘zgartirmaydi. Mehmon va tunnel o‘rtasida ikkita marshrut qidiruvi bor: biri mehmonning tarmoq nomlar fazosida, biri ramka ko‘prikka tushgandan keyin xostda, ikkinchisi esa boshqa moslik qoidalari bo‘lgan boshqa jadvaldan so‘raydi. Mening etalon sxemam — Linux xosti, unda OpenVPN mijozi ishlaydi, u 10.8.0.10 ni tun0 da ushlab turadi, 172.18.0.0/16 da Docker ko‘prigi va faqat tunnel tomoni yeta oladigan xususiy manzil bor. Maqsad tor bo‘lib qoladi: o‘sha mehmon quyi tarmog‘i tunneldan chiqadi, xost esa odatdagi uplinkni saqlaydi.
VPN mijozini konteyner ichida ishga tushirish — boshqa dizayn , yorliq yo‘l emas. Unda konteyner o‘z tunneli va o‘z hisob ma’lumotlariga ega bo‘ladi, ish esa iptablesda qolmay Dockerfilega o‘tadi.
Qayta yo‘naltirish marshrutni manzil bo‘yicha tanlaydi, keyin NAT manbani qayta yozadi
O‘rnatilganda net.ipv4.ip_forward=1 , qayta yo‘naltirilgan paket asosiy jadvalda faqat manzil bo‘yicha marshrutlanadi. Manba bu qarorda hech qanday rol o‘ynamaydi. Marshrut tanlangandan keyingina yadro POSTROUTING ni bajaradi va aynan o‘sha yerda Dockerning o‘z qoidasi turadi: -s 172.18.0.0/16 ! -o br-appnet -j MASQUERADE . Ko‘prikdan boshqa interfeysga chiqadigan hamma narsa tarjima qilinadi va u qaysi manzilga aylanishi marshrut uni qaysi interfeysga yuborganiga bog‘liq.
Bu qoida mendan so‘raladigan alomatlarning ko‘pini tushuntiradi. Agar asosiy jadvalda xususiy manzil uchun marshrut bo‘lmasa, paket xostning jismoniy manzili bilan uplinkdan chiqadi. Provayderingiz manzilni tashlab yuboradi yoki uzoq sayt hech qachon kutmagan RFC 1918 manbasini tashlaydi, tunnel tik turgan va sog‘lom bo‘lsa-da konteyner vaqt tugashi bilan to‘xtaydi. tun0 da yozib olish hech narsa ko‘rsatmaydi va bu — belgi. Agar marshrut haqiqatan tun0 ga ishora qilsa, MASQUERADE manbani 10.8.0.10 ga qayta yozadi, o‘sha konteyner esa siz hech narsaga tegmasdan ishlaydi.
Mehmonning manbasini nomlaydigan qidiruvni so‘rang. from va iif bo‘lmasa, xost o‘z soketi uchun javob beradi va qayta yo‘naltirilgan paket hech qachon bosmaydigan yo‘lni bildiradi:
ip route get 192.168.11.222 from 172.18.0.5 iif br-appnetAgar bu javob uplinkni nomlasa, tunnel rasmda yo‘q va tunnel tomonidagi hech qanday sozlama yordam bermaydi.
Mehmonni tunnelning o‘z manziliga ko‘chiring
Eng kichik ishlaydigan o‘zgarish — chiqishda manbani aniq qayta yozish. Uni qo‘shish o‘rniga kiriting: Docker allaqachon POSTROUTING ning boshida o‘tiribdi, shuning uchun -A bilan qo‘shilgan qoida Docker qoidasidan keyin baholanadi va hech qachon ishga tushmaydi.
iptables -t nat -I POSTROUTING 1 -s 172.18.0.0/16 -o tun0 -j SNAT --to-source 10.8.0.10Bu saqlanib qoladimi, ikkita shart hal qiladi. Manzil mijoz haqiqatan ushlab turgan manzil bo‘lishi kerak, shuning uchun uni har bir mijoz uchun ifconfig-push 10.8.0.10 255.255.255.0 ni o‘z ichiga olgan yozuv bilan mahkamlang; hech qachon berilmagan manzilni nomlaydigan qoida xato emas, jim tashlashlarni keltirib chiqaradi. Uzoq tomon esa bu manbani qabul qilib, javoblarni qaytarib yo‘naltirishi kerak, shuning uchun u yerdagi ruxsat ro‘yxati mehmon quyi tarmog‘ini emas, tunnel manzilini nomlaydi. Mijoz manzili dinamik bo‘lsa, -j MASQUERADE bilan -o tun0 interfeysda bor narsaga ergashadi, lekin qat’iy qiymatga qarshi yozib bo‘lmaydigan uzoq siyosat hisobiga.
Filtrlash — ikkinchi yarmi. Docker FORWARD siyosatini drop ga qo‘yadi va har bir demon qayta ishga tushganda o‘ziga tegishli zanjirlarni tozalaydi, shuning uchun mahalliy siyosatni DOCKER-USER ga qo‘ying, u omon qoladi:
iptables -I DOCKER-USER -i br-appnet -o tun0 -j ACCEPT
iptables -I DOCKER-USER -i tun0 -o br-appnet -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPTQaytish qoidasi muhim: tun0 ga keladigan javob ko‘prik ochgan ulanish uchun faqat chiqish yo‘nalishi qabul qilingani sababli qabul qilinmaydi.
Xostni manba qoidasi bilan to‘g‘ridan-to‘g‘ri tuting
Butun ko‘prik tunneldan foydalanishi kerak, lekin xostda boshqa hech narsa kerak bo‘lmasa, NATni o‘tkazib yuboring va o‘sha manbaga o‘z jadvalini bering. Mehmon manzillari shunda boshidan oxirigacha ko‘rinib turadi.
echo "200 vpnbox" >> /etc/iproute2/rt_tables
ip rule add from 172.18.0.0/16 lookup vpnbox pref 1000
ip route add default dev tun0 table vpnboxQoidalar asosiy jadvaldan oldin ko‘rib chiqiladi va from manbaga mos keladi. Tunnelning o‘z tashqi paketlari xostning jismoniy manbasini olib yuradi, shuning uchun ular hech qachon from 172.18.0.0/16 ga mos kelmaydi va tunnel o‘zini o‘ziga qaytarib yo‘naltira olmaydi. Aynan shu o‘z-o‘zini istisno qilish sxemani barqaror qiladi.
Qaytish yo‘li endi yordamga muhtoj. Uzoq tomon tarjima qilinmagan 172.18.0.x ni ko‘radi va uning qayerda yashashini bilishga asosi yo‘q. Serverda har bir mijoz uchun faylga iroute 172.18.0.0 255.255.0.0 kerak, serverning ichki jadvali o‘sha prefiksni shu mijozga bersin, va itarilgan route 172.18.0.0 255.255.0.0 kerak, boshqa mijozlar uning borligini bilsin.
Ishonishdan oldin ikkita tekshiruv. Ishga tushiring ip route show default : redirect-gateway def1 bilan jadvalda 0.0.0.0/1 va 128.0.0.0/1 bor tun0 orqali, xost esa umuman to‘g‘ridan-to‘g‘ri emas, chunki o‘sha yarim-standartlar default ni almashtirmasdan yutadi. ip rule add bilan qo‘shilgan qoidalar ham qayta yuklashda yo‘qoladi, shuning uchun ularni up skriptida olib yuring.
Paket o‘lchami — duch keladigan ikkinchi nosozlik
1500 baytli ko‘prik interfeysi tashqi UDP va IP sarlavhalari qo‘shilganda tunnelga u ko‘tara oladiganidan ko‘proq beradi. Kichik almashinuvlar o‘tadi, shuning uchun DNS hal bo‘ladi va TLS qo‘l berib ko‘rishish tugaydi, keyin kattaroq yuklash hech qayerda xatosiz osilib qoladi. Yuboruvchi o‘sha segment o‘lchamini takrorlayveradi, chunki kichrayishni aytadigan ICMP fragmentatsiya zarurati xabari hech qachon yetib kelmaydi.
Uni interfeysda, MSSda yoki ikkalasida tuzating. Siqish mehmonning hamkorligini talab qilmaydi:
ip link set dev tun0 mtu 1400
iptables -t mangle -A FORWARD -o tun0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtuSiqish faqat TCPni qayta yozadi. UDP, QUIC bilan birga, buning o‘rniga pastroq mehmon interfeysini talab qiladi, --opt com.docker.network.driver.mtu=1400 bilan tarmoq yaratishda yoki mos compose kaliti bilan.
DNS va takrorlashga arziydigan tekshiruvlar
Nomlarni hal qilish o‘sha yo‘ldan boradi. Dockerning ichki rezolveri 127.0.0.11 da xostning sozlangan serverlariga uzatadi, shuning uchun konteyner xost ishlatadigan narsani meros oladi. Xususiy zona faqat tunnel orqali yetib boriladigan rezolver tomonidan javob bersa, mehmonni o‘sha manzilga yo‘naltiring va getent hosts bilan konteyner ichida sinab ko‘ring, xostda emas.
- Muvaffaqiyatsiz so‘rovni mehmon ichida ishga tushiring; xost tomonidagi sinov boshqa manba manzilidan foydalanadi va muammoni yashiradi.
- Qo‘shgan NAT va filtr qoidalaridagi hisoblagichlarni o‘qing. Nol moslikli qoida — marshrutlash xatosi, siyosat xatosi emas.
- SNAT qoidangizdagi tunnel manzili mijoz haqiqatan ushlab turgan manzil ekanini tasdiqlang.
- Serverni to‘xtab qolganlikda ayblashdan oldin mehmonning MTUsini pasaytiring yoki MSSni siqing.
Ro‘yxat bo‘ylab pastga tushing va birinchi nosozlikda to‘xtang. Aynan o‘sha qatlamni tuzatish kerak; pastroqqa qo‘shilgan har qanday narsa faqat sinayotgan chegarani yashiradi.