Routing traffic of Docker containers through a VPN container.
Gluetun,一款專為Docker設計的開源軟體,可讓特定容器走VPN連線上網。
容器為什麼沒事要連VPN?嗯,Ivon覺得下載BT就是個好理由。
試想:如果我們將下載BT種子的qBittorrent服務跑在Docker裡面,並透過專門的VPN連線,就可以達成跟主機分開上網的功效。也就是說,Linux電腦看網頁時仍透過正常網路上網,電腦不會全域都是走VPN連線,唯有容器部份的服務走VPN。如此一來透過VPN下載檔案就不會干擾正常電腦使用了。因為有些網站對VPN過敏,用VPN上網會被當成Bot。
現在讓我們繼續談Gluetun,名字音近麩質,但其實應該是強力膠水的意思,或許可以解釋為「把TUN(虛擬網路裝置)黏在一起」。
開發者Quentin McGaw在Github放的圖示是二個水管,好像在玩瑪莉歐,這裡進去那裡出來。
Gluetun本身是作為VPN客戶端兼代理伺服器,支援連線至許多商業VPN,所有您聽過名字的大牌VPN都支援。商業VPN多半支援OpenVPN或WireGuard協定,只要到他們網站下載帶有密鑰的設定檔,Gluetun就能夠連上該公司的VPN。
為防止洩漏IP,Gluetun還會在VPN連線有問題的時候啟動Kill Switch,自動斷線,使依賴它的容器跟著無法上網。
1. 取得VPN供應商的設定檔#
這裡Ivon使用「ProtonVPN」做示範,其他家VPN的設定大同小異,各大商業VPN應該都會有地方可以下載OpenVPN或WireGuard的設定檔。
OpenVPN#
請參閱ProtonVPN官方文件,到你的Proton VPN帳號後台,取得OpenVPN帳號密碼。
WireGuard#
請參閱ProtonVPN官方文件,進入Downloads頁面,下滑到WireGuard,填寫服務名稱
在下方列表選取負載低的伺服器,由於我是付費方案所以有更多伺服器可選。點選Create。
下載WireGuard設定檔
2. 架設Gluetun服務#
由於等一下我們要讓容器走Gluetun的VPN,需要做些特別設定,編輯完後先別急著啟動Gluetun服務。
新增docker-compose#
- 參考Gluetun文件,新增docker-compose。
cd ~
mkdir gluetun
cd gluetun
vim docker-compose.yml
- 參考剛才取得的VPN設定檔內容,依序填入
environment
的參數。鑑於各家VPN供應商功能差異,在寫docker-compose的建議指定VPN供應商名稱,讓Gluetun可以正確識別。如果有需要也可以給容器設定固定IP。
OpenVPN#
填入ProtonVPN的OpenVPN的帳號、密碼,並指定伺服器國家
services:
gluetun:
image: qmcgaw/gluetun
container_name: gluetun
restart: unless-stopped
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
ports:
- 8888:8888/tcp # HTTP proxy
- 8388:8388/tcp # Shadowsocks
- 8388:8388/udp # Shadowsocks
volumes:
- /home/user/gluetun:/gluetun
environment: # 按照VPN供應商的OpenVPN設定檔填寫
- VPN_SERVICE_PROVIDER=protonvpn
- VPN_TYPE=openvpn
- OPENVPN_USER= # OpenVPN帳號
- OPENVPN_PASSWORD= # OpenVPN密碼
- SERVER_COUNTRIES=United Kingdom # 指定伺服器所在國家,以逗號分隔
networks: # (選擇性) 固定Gluetun容器的IP
network:
ipv4_address: 172.27.0.5
networks: # (選擇性) 固定Gluetun容器的IP
network:
driver: bridge
ipam:
config:
- subnet: 172.27.0.0/16
gateway: 172.27.0.5
WireGuard#
按照ProtonVPN的WireGuard設定檔填寫。
services:
gluetun:
image: qmcgaw/gluetun
container_name: gluetun
restart: unless-stopped
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
ports:
- 8888:8888/tcp # HTTP proxy
- 8388:8388/tcp # Shadowsocks
- 8388:8388/udp # Shadowsocks
volumes:
- /home/user/gluetun:/gluetun
environment:
- VPN_SERVICE_PROVIDER=protonvpn # 按照VPN供應商的WireGuard設定檔填寫
- VPN_TYPE=wireguard
- WIREGUARD_PRESHARED_KEY= # 預共享密鑰
- WIREGUARD_PRIVATE_KEY= # 私鑰
- WIREGUARD_ADDRESSES= # 填IPV4與IPV6位址,以逗號分隔
- SERVER_COUNTRIES=United Kingdom # 指定伺服器所在國家,以逗號分隔
networks: # (選擇性) 固定Gluetun容器的IP
network:
ipv4_address: 172.27.0.5
networks: # (選擇性) 固定Gluetun容器的IP
network:
driver: bridge
ipam:
config:
- subnet: 172.27.0.0/16
gateway: 172.27.0.5
3. 讓容器走Gluetun的VPN連線#
欲使容器走Gluetun的VPN連線,只需讓其使用該網路上網即可。我這裡有一個qBittorrent的下載服務要使用Gluetun。
- 相關文章:qBittorrent操作教學
如果容器服務跟Gluetun寫在同一個docker-compose:加入網路模式network_mode: "service:gluetun"
如果該容器跟Gluetun不是寫在同一個docker-compose:加入network_mode: "container:gluetun"
- 由於我的qBittorrent服務跟Gluetun不在同一個docker-compose,為此修改qBittorrent的docker-compose。下面是我位於
~/qbittorrent
目錄的檔案內容:
services:
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
container_name: qbittorrent
environment:
- PUID=1000
- PGID=1000
- TZ=Asia/Taipei
- WEBUI_PORT=8080
volumes:
- /home/user/qbittorrent/config:/config
- /home/user/qbittorrent/downloads:/downloads
ports:
- 8080:8080
- 6881:6881
- 6881:6881/udp
restart: unless-stopped
- 首先把qBittorrent暴露的通訊埠註解掉,因為這個會跟Gluetun網路衝突
#ports:
#- 8080:8080
#- 6881:6881
#- 6881:6881/udp
- 接著,在最下方加入Gluetun網路
network_mode: "container:gluetun"
- 現在還要處理qBittorrent通訊埠的問題。開啟Gluetun的docker-compose檔案,把qBittorrent用到的8080通訊埠加回來:
services:
gluetun:
image: qmcgaw/gluetun
container_name: gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
ports:
- 8888:8888/tcp # HTTP proxy
- 8388:8388/tcp # Shadowsocks
- 8388:8388/udp # Shadowsocks
- 8080:8080 # qBittorrent,左邊的可以自由改成想暴露的通訊埠,右邊則必須是qBittorrent容器使用的通訊埠。這裡的情況就是看qBittorrent的環境變數WEBUI_PORT的值決定。
- 之後,依序啟動Gluetun和qBittorrent的服務
cd ~/gluetun
docker compose up -d
cd ~/qbittorrent
docker compose up -d
- 檢查容器有無連上VPN,用docker exec進入qBittorrent容器的shell:
docker ps
docker exec -ti qbittorrent /bin/bash
- 檢查公共IP
curl ifconfig.io
容器公共IP應當跟您選擇的VPN伺服器一致:
如果你想測試Kill Switch有無運作,停掉Gluetun服務,再檢查qBittorrent能不能上網就知道了:
cd ~/gluetun
docker compose down
docker exec -ti qbittorrent /bin/bash
curl ifconfig.io
4. 如何存取使用Gluetun VPN上網的容器服務#
以qBittorrent來說,連上Gluetun的VPN後,該容器就只能從http://localhost:8080
存取,打http://伺服器IP:8080
是無效的。
所幸,剛才我們已經將qBittorrent的8080通訊埠加到Gluetun的docker-compose,您應當可以打http://伺服器IP:8080
或http://Gluetun的容器IP:8080
存取qBittorrent的網頁界面!
Gluetun容器的IP可以用docker inspect "gluetun" | grep "IPAddress"
取得。
實測在使用內網穿透軟體的情況下依然可以存取qBittorrent。
如果同一網路下的其他容器服務要連線至qBittorrent的容器,那麼就是打http://伺服器IP:8080
或http://Gluetun的容器IP:8080
來連線。
不過BT管理軟體Sonarr比較特別,其docker-compose相關的容器也必須使用network_mode: "container:gluetun"
才可以連線到qBittorrent。
當Gluetun偵測VPN無法連線後會讓網路斷線,您需要重新啟動Gluetun服務,以及使用Gluetun網路的容器。
5. 設定VPN通訊埠轉發#
此為選擇性功能。
如果你要提昇BT下載速度,並讓別人從你這裡下載檔案(做種),最好設定通訊埠轉發(port forwarding)。
注意不是每一家VPN供應商都有提供此功能。且就算VPN供應商有提供通訊埠轉發,也不是每台伺服器都有此功能。
根據Gluetun有關port forwarding的說明,每家VPN供應商的通訊埠轉發設定方式不同,請點選providers的Wiki頁面查詢。
此處以ProtonVPN為例。
鑑於Gluetun取得轉發通訊埠的方法有缺失,似乎只能用OpenVPN方式連線,用WireGuard的話會找不到VPN供應商所轉發的通訊埠。
參考Proton VPN官方文件,查看哪些國家伺服器支援P2P。
按照Proton VPN提供的OpenVPN帳號,修改Gluetun的
docker-compose.yml
,在你的帳號名稱後面加上+pmp
加入以下環境變數:
environment:
- VPN_PORT_FORWARDING=on
- 加入這段,啟用的Gluetun的Control Server
ports:
- 8000:8000
- 重新啟動Gluetun服務。
cd ~/gluetun
docker compose down
docker compose up -d
- ProtonVPN所轉發的通訊埠可從此網址得知。或者使用
docker logs gluetun
查看。
curl http://Gluetun容器IP:8000/v1/openvpn/portforwarded
在qBittorrent偏好設定 → 連線開啟通訊埠,填入ProtonVPN所轉發的通訊埠,並關閉UPnP功能。
要知道通訊埠轉發有無成功,進入Gluetun容器,使用port-checker程式檢測。這裡假定ProtonVPN轉發的通訊埠為61915
docker exec -it gluetun /bin/sh
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 -port 61915
- 開啟瀏覽器,輸入
http://VPN的公共IP:61915
,應該就會印出你目前的IP位址了。回到終端機,按CTRL+C關閉,並輸入exit退出shell。
參考資料#
下面這篇文章有討論Gluetun反向代理與自動重啟容器服務的進階設定,但該名作者竟然一次幫兩家商業VPN打廣告😅
Gluetun Docker Guide – Easy VPN Killswitch for Docker Containers - SmartHomeBeginner