วิธีตั้งค่า Gluetun Port Forwarding สำหรับ Torrent
แก้ไขปัญหาดาวน์โหลดได้แต่ไม่มีการเชื่อมต่อขาเข้าด้วยการตั้งค่า Gluetun port forwarding พร้อมวิธีส่งพอร์ตใหม่ไปยังไคลเอนต์อัตโนมัติทุกครั้งที่เชื่อมต่อ VPN ใหม่
เหตุใดจึงไม่มีการเชื่อมต่อจากภายนอกหากไม่ได้ทำ port forwarding
Gluetun port forwarding จะร้องขอให้ผู้ให้บริการ VPN ทำการแมปพอร์ตสาธารณะหนึ่งพอร์ตบนแอดเดรสขาออก (exit address) กลับมายังคอนเทนเนอร์ของคุณ ซึ่งเป็นวิธีเดียวที่ peer อื่นจะสามารถเริ่มต้นการเชื่อมต่อมายังไคลเอนต์ torrent ของคุณได้ หากไม่มีการแมปดังกล่าว อุโมงค์ (tunnel) จะยังคงทำงานได้ปกติ การดาวน์โหลดจะดำเนินไป แต่จะไม่มีข้อมูลใดส่งเข้ามาได้ด้วยตัวเอง การเชื่อมต่อที่ใช้งานได้ทั้งหมดจะเป็นการเชื่อมต่อที่ไคลเอนต์ของคุณเป็นผู้เปิดก่อนเท่านั้น
กลไกที่เกี่ยวข้องคือ NAT (network address translation) คอนเทนเนอร์ของคุณใช้แอดเดรสขาออกร่วมกับลูกค้าคนอื่น ๆ ของผู้ให้บริการจำนวนมาก เมื่อไคลเอนต์ของคุณเปิดการเชื่อมต่อออกไปข้างนอก ผู้ให้บริการจะบันทึกกระแสข้อมูลนั้นไว้และส่งการตอบกลับกลับมาตามอุโมงค์ของคุณ แต่เมื่อมี peer อื่นพยายามเชื่อมต่อเข้ามาโดยไม่มีกระแสข้อมูลที่บันทึกไว้ แพ็กเก็ตจะไปถึงแอดเดรสขาออกแล้วถูกทิ้งไป ไคลเอนต์ของคุณยังคงเข้าถึง peer ทุกรายที่สามารถรับการเชื่อมต่อได้ด้วยตัวเอง ดังนั้นการดาวน์โหลดจึงเสร็จสิ้นและปัญหาจะยังคงไม่ปรากฏชัดเจน แต่จะเห็นผลชัดเจนในส่วนของการ seeding เนื่องจาก seeder คือเครื่องที่ผู้อื่นต้องเชื่อมต่อเข้ามาหา
การเปิดพอร์ตขาเข้าจะเปลี่ยนสถานะสองประการ คือคุณจะเข้าร่วม swarm ได้เร็วขึ้น เนื่องจาก peer ที่ไม่สามารถรับการเชื่อมต่อได้ด้วยตัวเองจะสามารถเข้าถึงคุณได้ และคุณจะสามารถอัปโหลดข้อมูลไปยัง peer เหล่านั้นได้ด้วย
เหตุผลที่ผู้ให้บริการ VPN ส่วนใหญ่ไม่เปิดให้ใช้งาน port forwarding
Port forwarding เป็นทรัพยากรที่มีจำกัดบน IP address แบบใช้ร่วมกัน ผู้ให้บริการต้องสำรองหมายเลขพอร์ตหนึ่งพอร์ตบน IP ขาออกหนึ่งหมายเลขให้กับลูกค้าหนึ่งราย และต้องรับผิดชอบต่อสิ่งที่ลูกค้าทำผ่านพอร์ตนั้น ผู้ให้บริการรายใหญ่หลายรายจึงยกเลิกฟีเจอร์นี้โดยอ้างเหตุผลเรื่องการจัดการการใช้งานในทางที่ผิด ให้มองว่าการรองรับฟีเจอร์นี้เป็นคำถามเชิงหมวดหมู่มากกว่าแค่การติ๊กเลือกในรายการ โดยให้สอบถามว่าผู้ให้บริการรองรับ port forwarding ในปัจจุบันหรือไม่ บนแพ็กเกจที่คุณเลือก และบนเซิร์ฟเวอร์ที่คุณสามารถเลือกใช้งานได้จริง
ในกรณีที่มีการเปิดให้ใช้งาน พอร์ตที่ได้จะเป็นแบบไดนามิก ซึ่งจะผูกอยู่กับเซสชัน VPN ไม่ใช่ผูกกับบัญชีผู้ใช้งานของคุณ ดังนั้นหมายเลขพอร์ตอาจเปลี่ยนไปทุกครั้งที่เชื่อมต่อใหม่ Private Internet Access จะออกพอร์ตที่ลงลายเซ็นดิจิทัลซึ่ง gluetun จะคอยรีเฟรชให้ โดยเอกสารประกอบของผู้ให้บริการระบุว่าคุณจะได้รับพอร์ตเดิมเป็นเวลา 60 วัน ตราบใดที่คุณทำ bind mount ไดเรกทอรี /gluetun เพื่อให้สถานะคงอยู่หลังการรีสตาร์ท ส่วน ProtonVPN จะกำหนดพอร์ตแบบสุ่มผ่าน NAT-PMP (NAT port mapping protocol) โดยมีระยะเวลาเช่าสั้นๆ ซึ่งต้องต่ออายุอย่างต่อเนื่อง นี่คือเหตุผลว่าทำไมการตั้งค่าพอร์ตในไคลเอนต์เพียงครั้งเดียวจึงไม่สามารถใช้งานได้ตลอดไป
ผู้ให้บริการรายใดบ้างที่ gluetun สามารถร้องขอพอร์ตได้
ณ gluetun v3.41.3 ซึ่งปล่อยออกมาเมื่อวันที่ 30 กรกฎาคม 2026 การเชื่อมต่อแบบเนทีฟรองรับการตรวจสอบกับชื่อผู้ให้บริการ 4 ราย ได้แก่ Private Internet Access, ProtonVPN, Perfect Privacy และ PrivateVPN โดยเปิดใช้งานด้วย VPN_PORT_FORWARDING=on ซึ่งมีค่าเริ่มต้นเป็น off คู่มือรุ่นเก่าจะใช้ PORT_FORWARDING หรือ PRIVATE_INTERNET_ACCESS_VPN_PORT_FORWARDING ซึ่งทั้งสองชื่อยังคงใช้งานได้ในเวอร์ชันนี้ในฐานะชื่อที่รองรับย้อนหลัง แต่กำลังจะถูกยกเลิกในอนาคต
รายละเอียดของผู้ให้บริการสองประการจะเป็นตัวตัดสินว่าการร้องขอจะสำเร็จหรือไม่ ProtonVPN จำเป็นต้องใช้แผนบริการแบบชำระเงินและต้องเปิดใช้งาน NAT-PMP: ให้เปิด NAT-PMP (Port Forwarding) ภายใต้ตัวเลือก VPN เมื่อคุณสร้างการตั้งค่า WireGuard หรือเพิ่ม +pmp ต่อท้ายชื่อผู้ใช้ของคุณเมื่อใช้ OpenVPN สำหรับ Private Internet Access บน OpenVPN จะมี PORT_FORWARD_ONLY ซึ่งจะจำกัดการเลือกเซิร์ฟเวอร์ให้เหลือเฉพาะเซิร์ฟเวอร์ที่รองรับการส่งต่อพอร์ต เพื่อป้องกันไม่ให้คุณเชื่อมต่อไปยังเซิร์ฟเวอร์ที่ไม่รองรับ WireGuard และ OpenVPN มีวิธีการร้องขอพอร์ตที่แตกต่างกัน ดังนั้นโปรดอ่านหน้าข้อมูลของผู้ให้บริการของคุณก่อนตัดสินใจเลือก
เมื่อ gluetun ทำงานด้วยการตั้งค่าแบบกำหนดเองแทนการใช้ผู้ให้บริการที่มีมาให้ในตัว VPN_PORT_FORWARDING_PROVIDER จะเป็นตัวระบุชื่อ API ที่ gluetun ควรเรียกใช้งาน หน้าข้อมูลของ Private Internet Access จะจับคู่ตัวแปรดังกล่าวกับ VPN_PORT_FORWARDING_USERNAME และ VPN_PORT_FORWARDING_PASSWORD ซึ่งใช้สำหรับส่งข้อมูลประจำตัวบัญชีที่จำเป็นต่อการร้องขอพอร์ต
การเปิดใช้งาน port forwarding ของ gluetun ใน docker compose
ส่วนนี้อนุมานว่าอุโมงค์เครือข่ายทำงานได้ปกติแล้ว หากยังไม่ทำงาน ให้เริ่มจากการ กำหนดเส้นทางทราฟฟิกของ Docker container ผ่าน gluetun และกลับมาดำเนินการต่อเมื่อดาวน์โหลดข้อมูลได้แล้ว
services:
gluetun:
image: qmcgaw/gluetun:v3.41.3
container_name: gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
ports:
- 8080:8080/tcp
- 8000:8000/tcp
volumes:
- ./gluetun:/gluetun
environment:
- VPN_SERVICE_PROVIDER=protonvpn
- VPN_TYPE=wireguard
- WIREGUARD_PRIVATE_KEY=${WIREGUARD_PRIVATE_KEY}
- VPN_PORT_FORWARDING=on
- TZ=Etc/UTC
restart: unless-stopped
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:5.2.3
container_name: qbittorrent
network_mode: "service:gluetun"
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
- WEBUI_PORT=8080
volumes:
- ./qbittorrent:/config
- ./downloads:/downloads
depends_on:
- gluetun
restart: unless-stoppedให้ระบุเวอร์ชันของ image ไว้ (pin the tag) เนื่องจาก qmcgaw/gluetun:latest ติดตาม branch master ซึ่งมีการเปลี่ยนแปลงโครงสร้างภายในของ port forwarding สำหรับ v4 ดังนั้น image ที่ไม่ได้ระบุเวอร์ชันอาจเปลี่ยนพฤติกรรมในการทำ docker compose pull ครั้งถัดไป ควรเก็บ private key ไว้นอกไฟล์ compose โดยใช้ ไฟล์ env สำหรับจัดการความลับใน compose
ตำแหน่งที่ gluetun เขียนพอร์ตที่ส่งต่อ (forwarded port)
Gluetun จะเปิดเผยหมายเลขพอร์ตไว้ใน 3 ตำแหน่ง ซึ่งทั้งหมดจะมีค่าเดียวกัน
ระบบจะบันทึกพอร์ตลงใน log หนึ่งครั้งเมื่อได้รับค่า โดยบรรทัดดังกล่าวจะแสดงเป็น port forwarded is 45678 และแสดงเป็น no port forwarded ในกรณีที่คำขอไม่ส่งค่าใดๆ กลับมา
docker logs gluetun 2>&1 | grep -i "port forwarded"ระบบจะเขียนหมายเลขพอร์ตลงในไฟล์ที่ระบุโดย VPN_PORT_FORWARDING_STATUS_FILE ซึ่งค่าเริ่มต้นคือ /tmp/gluetun/forwarded_port ไฟล์นี้จะเก็บพอร์ตไว้หนึ่งรายการต่อหนึ่งบรรทัด โดยเขียนด้วยโหมด 0644 และเปลี่ยนเจ้าของ (chown) เป็น PUID และ PGID ของคอนเทนเนอร์ เมื่อการส่งต่อพอร์ตสิ้นสุดลง gluetun จะล้างข้อมูลในไฟล์แทนการลบไฟล์ทิ้ง เพื่อให้โปรแกรมอื่นที่มาอ่านไฟล์สามารถอ่านไฟล์ว่างได้แทนที่จะพบข้อผิดพลาดว่าไม่พบไฟล์
docker exec gluetun cat /tmp/gluetun/forwarded_portระบบจะให้บริการค่าพอร์ตผ่าน control server ซึ่งโดยปกติจะฟังอยู่ที่ :8000 และสามารถกำหนดค่าได้ผ่าน HTTP_CONTROL_SERVER_ADDRESS
curl -s http://127.0.0.1:8000/v1/portforward{"port":45678,"ports":[45678]}นอกจากนี้ gluetun ยังเปิดพอร์ตดังกล่าวใน firewall ของตนเองบน VPN interface ดังนั้นจึงไม่จำเป็นต้องใช้ FIREWALL_VPN_INPUT_PORTS ในขณะที่การทำงานร่วมกันแบบ native กำลังดำเนินการอยู่ ตัวแปรดังกล่าวมีไว้สำหรับกรณีอื่น คือกรณีที่ผู้ให้บริการไม่รองรับการสอบถามจาก gluetun ซึ่งคุณได้รับพอร์ตแบบ static มาจากช่องทางอื่นและจำเป็นต้องอนุญาตพอร์ตนั้นด้วยตนเอง
ใน 3 ตำแหน่งนี้ มีเพียงตำแหน่งเดียวที่เป็นแบบถาวร ส่วนอีกสองตำแหน่งไม่ใช่ เอกสารประกอบของ upstream ได้ระบุว่าไฟล์สถานะ (status file) จะถูกเลิกใช้งานใน v4.0.0 และ GET /v1/openvpn/portforwarded ได้ตอบกลับด้วย 301 Moved Permanently ซึ่งชี้ไปยัง /v1/portforward แล้ว ดังนั้นการพัฒนาใหม่ควรเลือกอ่านค่าจาก control server แทน
เหตุผลที่ต้องแจ้งพอร์ตให้ไคลเอนต์ทราบทุกครั้งที่มีการเชื่อมต่อใหม่
Torrent client จะจัดเก็บพอร์ตที่ใช้รับฟัง (listening port) ไว้ในการตั้งค่าของตัวเองและใช้หมายเลขเดิมเสมอหลังจากรีสตาร์ท แต่พอร์ตที่ทำ port forwarding นั้นเป็นคุณสมบัติของเซสชัน VPN เมื่อมีการเชื่อมต่อใหม่ หมายเลขทั้งสองจะไม่ตรงกัน ส่งผลให้ผู้ให้บริการแมปพอร์ตไปยังจุดที่ไม่มีบริการใดรับฟังอยู่ ในขณะที่ไคลเอนต์ก็รับฟังบนพอร์ตที่ไม่มีการแมปไว้ การเชื่อมต่อใหม่เกิดขึ้นได้บ่อยครั้ง เช่น การรีสตาร์ทคอนเทนเนอร์, การเปลี่ยนเซิร์ฟเวอร์, การที่ tunnel หลุดจน gluetun ต้องรีสตาร์ท health check หรือการที่ lease ไม่สามารถต่ออายุได้ ผลลัพธ์ที่ได้คือระบบที่เคยเข้าถึงได้เมื่อวานกลับเข้าถึงไม่ได้ในวันนี้โดยไม่มีข้อความแจ้งเตือนความผิดพลาดใน log ของทั้งสองฝั่ง
ดังนั้น จึงจำเป็นต้องกำหนดค่าพอร์ตในขณะที่ gluetun ได้รับพอร์ตนั้นมา วิธีการเชื่อมต่อข้อมูลนี้มี 2 รูปแบบ ซึ่งแตกต่างกันที่กระบวนการทำงานของแต่ละวิธี
ทางเลือกที่ 1: gluetun ส่งต่อพอร์ตด้วยคำสั่ง up
VPN_PORT_FORWARDING_UP_COMMAND จะทำงานเมื่อการทำ port forwarding เริ่มต้นขึ้น และ VPN_PORT_FORWARDING_DOWN_COMMAND จะทำงานเมื่อการเชื่อมต่อสิ้นสุดลง gluetun จะแทนที่ค่า {{PORT}} (พอร์ตแรก), {{PORTS}} (พอร์ตทั้งหมดที่คั่นด้วยเครื่องหมายจุลภาค) และ {{VPN_INTERFACE}} (ชื่ออินเทอร์เฟซของ tunnel ซึ่งค่าเริ่มต้นคือ tun0) ก่อนที่จะรันคำสั่ง ไวยากรณ์ของ shell จำเป็นต้องมีตัวครอบ /bin/sh -c อย่างชัดเจน นี่คือตัวอย่างของ qBittorrent ที่เป็น upstream โดยเขียนเป็นรายการ environment ใน compose สองรายการ:
- VPN_PORT_FORWARDING_UP_COMMAND=/bin/sh -c 'wget -O- -nv --retry-connrefused --post-data "json={\"listen_port\":{{PORT}},\"current_network_interface\":\"{{VPN_INTERFACE}}\",\"random_port\":false,\"upnp\":false}" http://127.0.0.1:8080/api/v2/app/setPreferences'
- VPN_PORT_FORWARDING_DOWN_COMMAND=/bin/sh -c 'wget -O- -nv --retry-connrefused --post-data "json={\"listen_port\":0,\"current_network_interface\":\"lo\"}" http://127.0.0.1:8080/api/v2/app/setPreferences'แต่ละฟิลด์ในการเรียกใช้งานนั้นมีหน้าที่เฉพาะ listen_port คือพอร์ตใหม่ current_network_interface ใช้ผูก qBittorrent เข้ากับ tunnel ส่วน random_port ที่ตั้งค่าเป็น false จะป้องกันไม่ให้ qBittorrent เลือกพอร์ตเองในการเริ่มทำงานครั้งถัดไป และ upnp ที่ตั้งค่าเป็น false จะหยุดไม่ให้โปรแกรมพยายามทำ port mapping ผ่านเราเตอร์ที่ไม่มีอยู่จริง
แนวทางนี้มีข้อกำหนดสองประการ ประการแรก Web UI ของ qBittorrent ต้องตอบสนองต่อ 127.0.0.1:8080 จากภายในคอนเทนเนอร์ gluetun ซึ่งจะเกิดขึ้นโดยอัตโนมัติเมื่อไคลเอนต์ใช้ network namespace ร่วมกับ gluetun ประการที่สอง ต้องเปิดใช้งาน Bypass authentication for clients on localhost (bypass_local_auth) เนื่องจากคำสั่งดังกล่าวไม่ได้ส่งข้อมูลรับรอง (credentials) ไปด้วย ส่วนคำสั่ง down นั้นจำเป็นเพราะ qBittorrent ไม่ได้สร้างพอร์ตขึ้นใหม่เสมอไปหลังจากตัดการเชื่อมต่อ
คำสั่งจะทำงานภายในคอนเทนเนอร์ gluetun ซึ่งสร้างบน Alpine และมาพร้อมกับ wget แต่ในอิมเมจนั้นไม่มี curl ดังนั้นคำสั่งที่ระบุชื่อ binary ที่ไม่มีอยู่ในอิมเมจจะล้มเหลวทุกครั้งที่มีการเริ่มทำ forwarding
ทางเลือกที่ 2: กระบวนการภายนอก gluetun อ่านพอร์ต
รูปแบบอีกอย่างหนึ่งคือการรันกระบวนการขนาดเล็กควบคู่ไปกับ gluetun เพื่อดึงค่าพอร์ตและส่งต่อไปยังไคลเอนต์ผ่าน API ของไคลเอนต์เอง โดยอ่านค่าจาก control server:
port=$(curl -s http://127.0.0.1:8000/v1/portforward | jq -r .port)หรืออ่านจากไฟล์หากกระบวนการนั้นสามารถเข้าถึงไฟล์ได้ /tmp/gluetun/forwarded_port อยู่ภายในคอนเทนเนอร์ gluetun ดังนั้น sidecar จำเป็นต้องใช้ shared volume ที่ mount ไว้ที่ /tmp/gluetun ในทั้งสองคอนเทนเนอร์ หรือคุณอาจชี้ VPN_PORT_FORWARDING_STATUS_FILE ไปยัง path ภายใต้ volume ที่คุณ mount ไว้แล้ว
การยืนยันตัวตนเป็นเรื่องสำคัญในกรณีนี้ ในเวอร์ชัน v3.41.3 เส้นทาง GET /v1/portforward อยู่ภายใต้บทบาทเริ่มต้นที่ชื่อ public พร้อมด้วย auth = "none" จึงสามารถตอบกลับได้โดยไม่ต้องใช้ข้อมูลรับรอง และ gluetun จะบันทึกคำเตือนที่ขึ้นต้นด้วย route GET /v1/portforward is unprotected by default, please set up authentication ซึ่งต้นทางจะปิดช่องทางนี้ในรุ่นถัดไป ให้กำหนดบทบาทตั้งแต่ตอนนี้ในไฟล์ที่ bind mount ไว้ที่ /gluetun/auth/config.toml:
roles = [
{ name = "qbittorrent", routes = ["GET /v1/portforward"], auth = "apikey", apikey = "myapikey" }
]สร้างคีย์ด้วย docker run --rm qmcgaw/gluetun:v3.41.3 genkey และส่งใน header X-API-Key ส่วน HTTP_CONTROL_SERVER_AUTH_DEFAULT_ROLE ทำหน้าที่เช่นเดียวกับ environment variable ที่เข้ารหัสแบบ JSON ในกรณีที่คุณไม่ต้องการ mount ไฟล์ การเปิดพอร์ต 8000 โดยไม่มีการกำหนดบทบาทจะทำให้ทุกคนที่เข้าถึงพอร์ตนี้สามารถควบคุมสถานะ VPN ได้ ดังนั้นควรตัดสินใจอย่างรอบคอบว่าพอร์ตนี้จะเข้าถึงได้จากที่ใดบ้างเมื่อคุณศึกษา วิธีการเข้าถึง gluetun จากโฮสต์และคอนเทนเนอร์อื่น
ให้เลือกใช้คำสั่ง up เมื่อไคลเอนต์เปิด API ที่สามารถสั่งการได้ด้วยการเรียก wget เพียงครั้งเดียว เพราะคำสั่งนี้จะทำงานเพียงครั้งเดียวต่อเหตุการณ์และไม่ต้องรันกระบวนการค้างไว้ ให้เลือกใช้กระบวนการภายนอกเมื่อไคลเอนต์ต้องการขั้นตอนการล็อกอิน การเขียนไฟล์ config ใหม่ หรือการรีสตาร์ท ใน arr stack ที่อยู่หลังคอนเทนเนอร์ gluetun โดยทั่วไปมักจบลงด้วยการใช้ poller ขนาดเล็กเพียงตัวเดียว เนื่องจากมีเพียง torrent client เท่านั้นที่จำเป็นต้องใช้พอร์ตดังกล่าว
กับดัก: การแชร์ namespace ไม่ได้เป็นการตั้งค่าพอร์ตสำหรับรับฟัง (listening port)
ความผิดพลาดนี้ทำให้เสียเวลามากที่สุด network_mode: "service:gluetun" จะนำ client เข้าไปอยู่ใน network namespace ของ gluetun ทำให้ client ได้รับ IP address ของ VPN, เส้นทาง routing ของ tunnel และกฎ firewall ของ gluetun แต่สิ่งเหล่านี้ไม่ได้เป็นการตั้งค่าพอร์ตสำหรับรับฟังของ client แต่อย่างใด gluetun จะเปิดพอร์ตที่ถูก forward ไว้บน interface ของ VPN ซึ่งแพ็กเก็ตจะเข้ามาถึงใน namespace นั้น แต่หาก client ไปรับฟังที่พอร์ตอื่น เคอร์เนลก็ไม่มีปลายทางที่จะส่งแพ็กเก็ตเหล่านั้นไปให้ ผลที่ตามมาคือการเชื่อมต่อถูกปฏิเสธหรือหมดเวลา (timeout) ในขณะที่การตรวจสอบขาออกทุกอย่างดูปกติ พอร์ตที่ถูก forward และพอร์ตที่ client รับฟังนั้นเป็นคนละหมายเลขกัน และหน้าที่หลักคือการทำให้ทั้งสองค่านี้ตรงกัน
ให้ใช้วิธีเปรียบเทียบค่าแทนการคาดเดา โดยรันคำสั่งทั้งสองนี้กับ namespace เดียวกัน:
docker exec gluetun cat /tmp/gluetun/forwarded_port
docker exec gluetun wget -qO- http://127.0.0.1:8080/api/v2/app/preferences | grep -o '"listen_port":[0-9]*'มีการตั้งค่าอีกหนึ่งอย่างที่ทำให้ผู้ใช้งานเข้าใจผิด คือ VPN_PORT_FORWARDING_LISTENING_PORT ซึ่งจะเปลี่ยนเส้นทาง (redirect) ทราฟฟิกขาเข้าจากพอร์ตที่ถูก forward ไปยังพอร์ตภายในที่กำหนดไว้ตายตัวโดยใช้ iptables ทางผู้พัฒนาต้นทางแนะนำว่าไม่ควรใช้ร่วมกับโปรแกรม torrent เนื่องจาก client จะประกาศพอร์ตที่ตนเองรับฟังไปยัง tracker และ peer ทำให้ swarm ได้รับหมายเลขพอร์ตที่ไม่ถูกต้องไปใช้งาน
วิธีตรวจสอบว่าพอร์ตที่ส่งต่อ (forwarded port) สามารถเข้าถึงได้จริง
ตัวบ่งชี้การเชื่อมต่อของไคลเอนต์แสดงเฉพาะการเชื่อมต่อขาออกไปยัง tracker เท่านั้น จึงอาจแสดงสถานะเป็นสีเขียวทั้งที่ไม่มีใครสามารถเชื่อมต่อเข้ามาหาคุณได้ ให้ทดสอบด้วย listener ที่คุณควบคุมได้จากเครือข่ายภายนอกอุโมงค์ VPN โดยผู้พัฒนาต้นทางได้จัดเตรียมเครื่องมือขนาดเล็กไว้สำหรับการนี้ ให้หยุดการทำงานของ torrent client ก่อน เนื่องจากสองกระบวนการไม่สามารถ bind พอร์ตเดียวกันได้
docker stop qbittorrent
docker exec -it gluetun /bin/shภายในคอนเทนเนอร์ ให้เปลี่ยน amd64 ให้ตรงกับสถาปัตยกรรม CPU ของคุณ และเปลี่ยน 4567 เป็นพอร์ตที่คุณส่งต่อ:
wget -qO port-checker https://github.com/qdm12/port-checker/releases/download/v0.4.0/port-checker_0.4.0_linux_amd64
chmod +x port-checker
./port-checker --listening-address=":4567"จากนั้นค้นหาที่อยู่ขาออก (exit address) ที่ gluetun กำลังใช้งานอยู่ ผลลัพธ์จะเป็นรูปแบบ JSON และที่อยู่จะอยู่ในฟิลด์ public_ip
curl -s http://127.0.0.1:8000/v1/publicip/ipเปิด http://<that address>:4567 จากอุปกรณ์ที่ไม่ได้เชื่อมต่อ VPN เดียวกัน (การใช้โทรศัพท์ผ่านเครือข่ายมือถือสามารถทำได้) หากหน้าเว็บแสดง IP address และ user agent ของเบราว์เซอร์คุณ พร้อมกับมีการบันทึก request ที่ตรงกันใน port-checker แสดงว่า TCP ขาเข้าสามารถเข้าถึง namespace ได้ หากเกิด timeout แสดงว่าเข้าถึงไม่ได้ ซึ่งสาเหตุจะอยู่เหนือระดับของไคลเอนต์ ให้หยุดเครื่องมือด้วยการกด CTRL+C ออกจาก shell ด้วย exit แล้วจึงเริ่มการทำงานของไคลเอนต์ใหม่อีกครั้ง การตรวจสอบนี้ครอบคลุมเฉพาะ TCP เท่านั้น ส่วน DHT (distributed hash table) และทราฟฟิก uTP จะใช้ UDP บนพอร์ตหมายเลขเดียวกัน ซึ่งการทดสอบนี้ไม่ครอบคลุมถึง
รูปแบบความล้มเหลวและข้อความที่คุณจะพบ
ไม่มีบรรทัดระบุพอร์ตใน log เลย ไม่มีการร้องขอพอร์ตเกิดขึ้น ให้ยืนยันว่าตัวแปรถูกส่งไปยัง container จริงด้วย docker exec gluetun printenv | grep PORT_FORWARDING เนื่องจากสาเหตุที่พบบ่อยคือการตั้งค่าตัวแปรผิด service ในไฟล์ compose
Gluetun ปฏิเสธที่จะเริ่มทำงานและแจ้งเตือนเกี่ยวกับผู้ให้บริการ ค่า VPN_PORT_FORWARDING_PROVIDER จะถูกตรวจสอบกับชื่อที่รองรับทั้ง 4 ชื่อ ดังนั้นหากพิมพ์ผิดจะทำให้ container หยุดทำงานแทนที่จะรันโดยไม่มีการส่งต่อพอร์ต
log แสดงข้อความ no port forwarded Gluetun ได้ร้องขอไปแล้วแต่ผู้ให้บริการไม่ตอบกลับ สำหรับ ProtonVPN มักหมายความว่าไม่ได้เปิดใช้งาน NAT-PMP ในการตั้งค่าที่คุณสร้างขึ้น หรือแพ็กเกจของคุณไม่รองรับการส่งต่อพอร์ต สำหรับ Private Internet Access มักหมายความว่าเซิร์ฟเวอร์ที่เลือกไม่รองรับฟีเจอร์นี้
ได้รับพอร์ตมาแล้ว แต่ไม่มีการเชื่อมต่อเข้ามา ให้เปรียบเทียบพอร์ตที่ส่งต่อกับพอร์ตที่ client ใช้งานโดยใช้คำสั่งสองคำสั่งด้านบน หากพอร์ตตรงกัน ให้ตรวจสอบว่า client ผูกอยู่กับ tunnel interface และปิดตัวเลือก random-port แล้ว เพราะตัวเลือกดังกล่าวจะเปลี่ยนพอร์ตที่ใช้งานทุกครั้งที่เริ่มโปรแกรมใหม่
คำสั่ง up ดูเหมือนไม่ทำงาน ให้รันคำสั่งนั้นโดยตรงภายใน container เพื่อดูข้อผิดพลาด: docker exec gluetun /bin/sh -c '<your command>' ผลลัพธ์ที่พบบ่อยคือ curl: not found เนื่องจาก image นี้มีเพียง wget เท่านั้น
401 Unauthorized จาก control server คุณกำหนดการตั้งค่าการยืนยันตัวตนไว้ แต่ role ที่กำหนดไม่ได้ระบุ route ที่คุณเรียกใช้งาน การจับคู่ route จะพิจารณาจาก method และ path ดังนั้นการระบุเพียง /v1/portforward ใน role จะไม่ครอบคลุมถึง GET /v1/portforward
ได้รับพอร์ตใหม่ทุกครั้งที่รีสตาร์ทบน Private Internet Access ให้ทำ bind mount ที่ /gluetun เพื่อให้สถานะของพอร์ตที่บันทึกไว้คงอยู่หลังการรีสตาร์ท หากไม่มี volume นี้ Gluetun จะร้องขอพอร์ตใหม่ทุกครั้งที่เริ่มทำงาน
FAQ
ทำไม torrent ของฉันถึงดาวน์โหลดได้ แต่ไม่มีการเชื่อมต่อขาเข้าเลย?
หากไม่มีการทำ port forwarding ผู้ให้บริการ VPN จะไม่มีกฎ NAT สำหรับส่งแพ็กเก็ตขาเข้าผ่านพอร์ตใดๆ ไปยัง tunnel ของคุณ ทำให้การเชื่อมต่อที่คุณไม่ได้เป็นผู้เริ่มถูกปฏิเสธที่ exit address การดาวน์โหลดจึงยังคงทำงานได้เพราะไคลเอนต์ของคุณเป็นผู้เปิดการเชื่อมต่อเหล่านั้นเอง และสามารถเข้าถึง peer ใดก็ตามที่เปิดรับการเชื่อมต่อได้ แต่การปล่อยไฟล์ (seeding) และการเข้าร่วม swarm จะได้รับผลกระทบเนื่องจากทั้งสองอย่างต้องอาศัยให้ผู้อื่นเชื่อมต่อเข้ามาหาคุณ วิธีแก้ไขคือการเลือกใช้ผู้ให้บริการที่มีบริการ port forwarding, ใช้ VPN_PORT_FORWARDING=on ใน gluetun และนำพอร์ตที่ได้ไปตั้งค่าเป็นพอร์ตสำหรับรับฟัง (listening port) ของไคลเอนต์
gluetun รองรับ port forwarding ของผู้ให้บริการ VPN ทุกรายหรือไม่?
ไม่รองรับ Gluetun v3.41.3 มีการรวมระบบ (integration) สำหรับผู้ให้บริการ 4 ราย ได้แก่ Private Internet Access, ProtonVPN, Perfect Privacy และ PrivateVPN หากอยู่นอกเหนือจากรายการนี้จะทำให้การตรวจสอบ VPN_PORT_FORWARDING_PROVIDER ล้มเหลว และคอนเทนเนอร์จะหยุดทำงานทันทีที่เริ่มระบบ หากผู้ให้บริการของคุณออกพอร์ตแบบคงที่ผ่านแผงควบคุมของเขาเอง gluetun จะไม่สามารถร้องขอพอร์ตนั้นให้คุณได้ แต่ FIREWALL_VPN_INPUT_PORTS จะช่วยให้พอร์ตคงที่ดังกล่าวผ่านไฟร์วอลล์ของ gluetun ได้ นโยบายของผู้ให้บริการมีการเปลี่ยนแปลงอยู่เสมอ ดังนั้นควรตรวจสอบหน้าข้อมูลของผู้ให้บริการปัจจุบันก่อนตัดสินใจซื้อแพ็กเกจ
ฉันต้องอัปเดตพอร์ตทุกครั้งที่เชื่อมต่อใหม่หรือไม่?
ใช่ และการอัปเดตนั้นควรเป็นไปโดยอัตโนมัติ พอร์ตที่ทำ forwarding จะผูกติดกับเซสชัน VPN ดังนั้นการรีสตาร์ทคอนเทนเนอร์ การเปลี่ยนเซิร์ฟเวอร์ หรือการต่ออายุ lease ที่ล้มเหลวอาจทำให้ได้หมายเลขพอร์ตใหม่ ในขณะที่ไคลเอนต์ยังคงใช้พอร์ตเดิมที่บันทึกไว้ในการตั้งค่า คุณควรปล่อยให้ gluetun ส่งค่าพอร์ตด้วย VPN_PORT_FORWARDING_UP_COMMAND ซึ่งจะทำงานทันทีที่การ forwarding พร้อมใช้งาน หรือรันโปรเซสขนาดเล็กเพื่ออ่านค่า GET /v1/portforward จากเซิร์ฟเวอร์ควบคุมและเขียนค่าดังกล่าวลงในไคลเอนต์ผ่าน API ของไคลเอนต์เอง
ฉันจะตรวจสอบได้อย่างไรว่าพอร์ตที่ทำ forwarding นั้นเปิดอยู่จริง?
ให้รันโปรแกรมรับฟัง (listener) บนพอร์ตนั้นภายใน network namespace ของ gluetun แล้วเชื่อมต่อจากภายนอก VPN ให้หยุดการทำงานของ torrent client ก่อนเพื่อให้พอร์ตว่าง จากนั้นรัน binary สำหรับตรวจสอบพอร์ต (port-checker) ภายในคอนเทนเนอร์ gluetun ด้วย --listening-address=":<port>" ตรวจสอบ exit address จาก curl -s http://127.0.0.1:8000/v1/publicip/ip แล้วเปิด http://<address>:<port> จากโทรศัพท์มือถือที่ใช้เครือข่ายข้อมูลมือถือ หากมีคำขอปรากฏใน log ของ port-checker แสดงว่า TCP ขาเข้าสามารถเข้ามาได้จริง หากเกิด timeout แสดงว่าไม่สามารถเชื่อมต่อได้ ไม่ว่าไอคอนสถานะในไคลเอนต์จะแสดงผลอย่างไรก็ตาม