როგორ გავატაროთ ჰოსტის ტრაფიკი Docker VPN კონტეინერით
VPN კონტეინერი ქსელური სახელების სივრცეა და არა პროქსი. აირჩიეთ საერთო netns, ნამდვილი SOCKS მსმენელი ან მარშრუტიზებული კარიბჭე, შემდეგ შეამოწმეთ გასასვლელი გზა.
თქვენი გვირაბის კონტეინერი მუშაობს, docker compose exec vpn curl -s https://ifconfig.me პასუხობს პროვაიდერის მისამართით, და მაინც თქვენი სამუშაო მაგიდის ბრაუზერი თქვენი ISP-ით გადის. ეს სხვაობა მოსალოდნელია. VPN კლიენტის გამშვები კონტეინერი ინახავს ქსელური სახელების სივრცეს, მარშრუტებსა და გვირაბის ინტერფეისს და არაფერს, რაც HTTP-ს ან SOCKS-ს ლაპარაკობს; მასზე პორტის გამოქვეყნება ვერ შექმნის მსმენელს, რომელიც არასდროს ყოფილა.
სად მუშაობს კლიენტი, ეს წყვეტს დიზაინს. მეზობელ კონტეინერს შეუძლია გვირაბის სახელთა სივრცეში გადასვლა, სამუშაო მაგიდის აპლიკაციას არ შეუძლია, ხოლო როუტერს სჭირდება მარშრუტები და არა პროქსის ველი. თუ რუკებს არასწორად გააკეთებთ, სიმპტომი იგივეა: კავშირი უარყოფილია, ან ტრაფიკი ჩუმად ძველი გზით მიდის.
შეუსაბამეთ განლაგება იმ ადგილს, სადაც კლიენტი მუშაობს
Compose-ის რედაქტირებამდე ერთი კითხვა დასვით: შეიძლება კლიენტის გაშვება VPN კონტეინერის ქსელური სახელების სივრცეში? ყველაფერს, რაც უკვე Linux კონტეინერად მუშაობს, შეუძლია. თქვენს მაგიდაზე მყოფ ბრაუზერს, IDE-ს ან CLI-ს არ შეუძლია, რადგან მისი პროქსის პარამეტრი პროტოკოლურ სერვისს ელოდება და არა სახელთა სივრცეს.
| Client | Arrangement | What must already exist |
|---|---|---|
| Another Compose service | Shares the vpn namespace via network_mode: service:vpn | A working tunnel and correct start order |
| Host browser, IDE or CLI | Proxy listener inside the namespace, published to host loopback | A configured SOCKS or HTTP proxy and its access rules |
| Router, VM or phone | The container as a layer-3 gateway | Forwarding, NAT and a return route |
ეს სამი არ ირევა. კონტეინერის ხიდის მისამართზე მიმართული HTTP პროქსის ველი ვერაფერს მიაღწევს, თუ იქ პროქსი არ უსმენს, ხოლო პროქსის მსმენელი როუტერის ტრაფიკს არ მარშრუტიზებს. ჯერ გადაწყვიტეთ, შემდეგ მიჰყევით შესაბამის ნაწილს.
გაიზიარეთ გვირაბის სახელთა სივრცე მეზობელ კონტეინერთან
ეს ყველაზე იაფი ვარიანტია, რადგან პროქსის პროტოკოლი არ მონაწილეობს. აპლიკაცია უერთდება vpn სერვისის სახელთა სივრცეს და მემკვიდრეობით იღებს მის ინტერფეისებს, მარშრუტებსა და პორტების სივრცეს:
services:
vpn:
image: your-vpn-client
cap_add:
- NET_ADMIN
healthcheck:
test: ["CMD-SHELL", "ip link show tun0 >/dev/null"]
interval: 10s
retries: 5
app:
image: your-app
network_mode: service:vpn
depends_on:
vpn:
condition: service_healthyსამი შეზღუდვა გამომდინარეობს იქიდან, რომ სახელთა სივრცე სხვა სერვისს ეკუთვნის. აპლიკაცია არ იღებს საკუთარ networks გასაღებს, რადგან არ აქვს სახელთა სივრცე, რომელსაც მიეკრას. პორტების გამოქვეყნება vpn-ისაა, რადგან იქ ცხოვრობს სახელთა სივრცე. და vpn-ის ხელახლა შექმნა ანადგურებს იმ სახელთა სივრცეს, რომელშიც აპლიკაცია შევიდა, ამიტომ docker compose up -d --force-recreate vpn გიტოვებთ app-ის ხელახლა შექმნასაც; უბრალო გადატვირთვა ყოველთვის არ კმარა. Compose სერვისების ცნობარი განიხილავს ამ განლაგებას და მის პორტების გამოქვეყნების შეზღუდვას.
ნუ ჩათვლით, რომ რეზოლვერი თან მოდის. /etc/resolv.conf თითო კონტეინერის ფაილია და არა ქსელური სახელთა სივრცის ნაწილი, ამიტომ აპლიკაციას კვლავ შეუძლია ჰოსტის რეზოლვერს ჰკითხოს, სანამ მისი პაკეტები გვირაბით გადის. წაიკითხეთ იგი კონტეინერის შიგნიდან და დააყენეთ dns: აპლიკაციაზე, როცა კერძო სახელები გვირაბით უნდა გადაწყდეს.
docker compose exec app ip route
docker compose exec app cat /etc/resolv.conf
docker compose exec app curl -s https://ifconfig.meთუ მარშრუტების სია შეიცავს გვირაბის ინტერფეისს და მისამართი პროვაიდერისაა, აპლიკაცია გვირაბის შიგნითაა. თუ ინტერფეისი აკლია, app გაშვდა მანამ, სანამ vpn-ს გვირაბი ექნებოდა, ამიტომ ხელახლა შექმენით app, როგორც კი vpn ჯანმრთელობას შეატყობინებს.
მოათავსეთ ნამდვილი პროქსის მსმენელი სახელთა სივრცეში ჰოსტის კლიენტებისთვის
სამუშაო მაგიდის ბრაუზერი ვერ შევა სახელთა სივრცეში, ამიტომ გვირაბი სერვისად უნდა გამოვლინდეს. გაუშვით ნამდვილი SOCKS ან HTTP პროქსი vpn სახელთა სივრცის შიგნით და გამოაქვეყნეთ მხოლოდ მისი პორტი:
services:
vpn:
ports:
- "127.0.0.1:1080:1080"
proxy:
image: your-proxy
network_mode: service:vpn
command: ["--socks", "0.0.0.0:1080"]ჰოსტის მხრიდან მისამართი ამ რუკების მნიშვნელოვანი ნახევარია. მარცხენა 127.0.0.1:1080 მსმენელს თქვენი LAN-ის გარეთ ინახავს; შიშველი "1080:1080" ღია პროქსის აქვეყნებს ყველა მოწყობილობისთვის, რომელსაც თქვენს მანქანამდე მისვლა შეუძლია.
კონტეინერის მხარეს თავისი ხაფანგი აქვს. გამოქვეყნებული პორტები კონტეინერის ხიდის მისამართზე მიეწოდება და არა მის loopback-ზე, ამიტომ სახელთა სივრცის შიგნით --socks 127.0.0.1:1080-ით გაშვებული პროქსი იღებს მეზობლების კავშირებს და უარყოფს ყველაფერს, რაც გამოქვეყნებული პორტით მოდის. მიაბით იგი 0.0.0.0-ს და იზოლაციისთვის დაეყრდენით ჰოსტის მხრიდან loopback მიბმას. იგივე წესი ვრცელდება პროქსის კონფიგურაციის ფაილში მოსმენის მისამართზე.
შემდეგ გადაწყვიტეთ, სად გადაწყდება სახელები. curl-ში --socks5 ჰოსტის სახელს ლოკალურად წყვეტს, ხოლო --socks5-hostname სახელს პროქსის უგზავნის; ბრაუზერები იმავე გადამრთველს სხვა ეტიკეტით გვიჩვენებენ. ლოკალური გადაწყვეტა კითხვას ასხამს მაშინაც, როცა გვერდი გვირაბით იტვირთება.
კონტეინერი კარიბჭედ მხოლოდ დაბრუნების მარშრუტით მიიჩნიეთ
როუტერები, VM-ები და ტელეფონები HTTP პროქსის ველს არ გამოიყენებენ, ზოგი აპლიკაცია კი პროქსის ცვლადებს სრულიად უგულებელყოფს. მათი ტრაფიკის მარშრუტიზაცია ნიშნავს მე-3 დონეს: კონტეინერი პაკეტებს გადასცემს და მისამართებს გვირაბის ინტერფეისზე თარგმნის.
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADEორი რამ ადვილად გამოგვრჩება. კლიენტს სჭირდება მარშრუტი, რომელიც მის ნაგულისხმევ კარიბჭეს ამ ჰოსტზე მიმართავს, ხოლო პასუხებმა უკანა გზა უნდა იპოვონ, ან ზედა როუტერის სტატიკური მარშრუტით, ან კლიენტებისკენ მიმართული ინტერფეისის NAT-ით. ერთის გარეშე გვირაბი მოთხოვნას გარეთ გაიტანს და პასუხი გაქრება.
მას ყველაზე ფართო ზემოქმედებაც აქვს. ჰოსტი, რომელიც მთელი LAN-ის კარიბჭეა, ყოველ არასწორად კონფიგურირებულ კლიენტს თქვენი VPN ანგარიშით აგზავნის, ხოლო გვირაბის ვარდნა ან LAN-ს აბნელებს, ან ISP-ზე ბრუნდება kill switch-ის მიხედვით.
შეამოწმეთ გასასვლელი გზა, შემდეგ თანმიმდევრობით უკან დააბრუნეთ
შეამოწმეთ ამ თანმიმდევრობით და გაჩერდით პირველ წარუმატებლობაზე: გასასვლელი მისამართი სახელთა სივრცის შიგნით, გასასვლელი მისამართი ჰოსტიდან პროქსით, შემდეგ სახელების გადაწყვეტა კერძო ჰოსტისთვის.
docker compose exec vpn curl -s https://ifconfig.me
curl -s -x socks5h://127.0.0.1:1080 https://ifconfig.me
curl -s -x socks5h://127.0.0.1:1080 http://internal.example/healthპირველი ორი მისამართი პროვაიდერს უნდა შეესაბამებოდეს, ხოლო მესამე პროქსით უნდა გადაწყდეს და არა სახელის შეცდომით ჩავარდეს. პირველი სტრიქონის დამთხვევა და მეორის ჩავარდნა ნიშნავს, რომ მსმენელი ან გამოქვეყნებული პორტია არასწორი და არა გვირაბი.
უკან დაბრუნება დაყენების საპირისპიროა. წაშალეთ პროქსის გარემოს ცვლადები shell-ის პროფილიდან და ნებისმიერი systemd ერთეულიდან, შემდეგ ჩამოწიეთ სტეკი, რათა საერთო სახელთა სივრცე თავის მფლობელთან ერთად გაქრეს. წაშალეთ გამოქვეყნებული პორტი პროქსი სერვისის წაშლამდე, თორემ ჰოსტს დარჩება loopback მსმენელი, რომელსაც არავინ კითხულობს.
სანამ გააგრძელებთ, ოთხი რამ დაადასტურეთ: თქვენთვის მნიშვნელოვანი კლიენტი ნამდვილად აღწევს გვირაბამდე, პორტებს მხოლოდ სახელთა სივრცის მფლობელი აქვეყნებს, კერძო სახელები იქ გადაწყდება, სადაც გინდოდათ, და არაფერი უსმენს ჰოსტის ისეთ მისამართზე, რომელიც loopback არ არის. თითოეული მათგანი წარმოებაში ჩუმად ფუჭდება და თითოეული ზემოთ მოცემული ერთსტრიქონიანი შემოწმებაა.