自動下載 - Gluten/Qbittorrent/Serverr系列

前言

自動化真的是人類的好朋友…

追記:為了Download安全,最好還是再加掛VPN進行,所以這篇會加上Gluetun整個改寫

Change Log:

Rev.2.0 - 2026/02/05

參考資料

基本概念

這套流程基本上使用九個工具來達成前端跟後端,基本上就是用Gluetun這個VPN套件把所有的工具(除了Emby以外)都包起來(目前測試沒有包起來的話會連不上qbittorrent)也因為這樣產生了depends的關係所以得整個重寫把工具全數包在一個docker-compose.yml

Rev.2.0
後來發現只把qbittorrent包在Gluten內是可以正常運作的,只要明確的定義好每個一不在Gluten內的服務ip就好,所以改版到Rev.2.0基本上就是把東西又都放出來,只留qbittorrent在裡面

後端 - 全部 只有qbittorrent包在Gluetun

Gluetun

這個基本上是一個VPN Client,具備了killswitch的功能可以讓依附在他身上的docker container全部走他的網路出去,一旦他断網就會切斷所有透過他的外部連線,確保透過他的container只會用他的VPN線路出去,所以會拿他這個特性來保護qbittorrent的下載安全

Sonarr & Radarr & Lidarr

基本的抓劇後端控制是Sonarr或是Radarr這個工具負責monitor你要的劇並且控制下載的條件與下載完後改名,因為抓音樂的Lidarr基本上也是share相同的架構所以就得一併塞進來(事後發現需要用flaresolverrtachidesk也得包起來)
Rev.2.0
雖然我沒把東西繼續包在Gluten內,但是我還是維持把這些東西跟Gluten放在同一個docker-compose.yml內,作為合併的服務系列一起管理

jackett

這是一個torrent網站的proxy,負責接收到sonarr/radarr的要求後到指定的網站上去抓相對應的種子訊息回來

Flaresolverr

這是一個用來解決cloudflare proxy造成Jackett異常的proxy工具

qBittorrent

這是實際下載的後端,其實不限定用這個,只要是Sonarr/radarr支援的後端就好了

ChineseSubFinderBazarr

因為ChineseSubFinder的作者停止維護與更新了,所以我順手把字幕尋找軟體換成了同為*rr系列的Bazarr
BazarrChineseSubFinder還有個重大的不同,就是Bazarr是去抓RadarrSonarr的資料來抓字幕的,而非透過Emby
不過如同我在Blog所述,字幕這種東西還是有就有,沒有只能認命的…

前端

類似Emby但是不需要刮取nfo,而是作為一個web player及提供串流服務的前端,算是拿來綁Lidarr的成果用的

Emby

這個負責刮取nfo檔與其他圖檔供chinesesubfinder去找字幕以及提供一個漂漂亮亮的media server給最終觀看的人

前期準備

RAM & Disk

因為這些所需的RAM & Disk相當大,所以建議在開始前就先把你的PhotonOS的環境調整好,要讓他有足夠的RAM/CPU能跑,可以的話在passthrough個可以協助硬體解碼的GPU給Emby用…

存放檔案的空間基本上肯定要用SMB或是NFS加掛了,畢竟要放的是電影/影集…千萬不要小看他的空間需求

Docker Network

因為發生了慘劇,所以建議在開始之前先規劃這堆container就放在同一個subnet裡面就好了…

Network

基本上就是所有的後端都得透過Gluetun連網所以內部這一塊也就沒什麼特別的網路設定(除了要固定Gluetun的container IP address以外)另外就是外面要有搭配的VPN可以使用
Rev.2.0
修改後,雖然沒全包在Gluten內,但還是需要定義每個ip address才不會連不上

外部VPN

基本上我也很推崇使用付費的ProtonVPN,只要給錢看起來就是最佳選擇,但若是跟我一樣的赤貧人士的話也可以使用OCI free tier的白嫖機跑wireguard來當作外部VPN使用,反正重點就是不要用自己家的IP包個國外的用,減少被蟑螂纏上的風險(但是畢竟還是固定使用的IP不能說完全沒有風險)所以要是付的起錢的話其實用ProtonVPN的付費VPN會比較簡單

實際安裝

這裡我就把我的docker-compose.yml裡的重點貼出來就好了

後端

docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
Rev.2.0
docker-compose.yml
---------------------------------------------------------------------------------------------------------------------------------
services:
gluetun:
image: qmcgaw/gluetun:latest
container_name: gluetun
restart: unless-stopped
privileged: true
devices:
- /dev/net/tun:/dev/net/tun
ports:
- 8888:8888/tcp # HTTP proxy
- 8388:8388/tcp # Shadowsocks
- 8388:8388/udp # Shadowsocks
- 8000:8000
- 4080:4080 # Qbittorrent WebUI
- 6881:6881 # Qbittorrent
- 6881:6881/udp # Qbittorrent

volumes:
- gluetun:/gluetun
environment:
- VPN_SERVICE_PROVIDER=custom
- VPN_TYPE=wireguard
- WIREGUARD_ENDPOINT_IP=<Your Endpoint IP>
- WIREGUARD_ENDPOINT_PORT=<Your Endpoint Port>
- WIREGUARD_PUBLIC_KEY=<Your Public key from Wireguard setting>
- WIREGUARD_PRESHARED_KEY=<Your Preshared key from Wireguard setting>
- WIREGUARD_PRIVATE_KEY=<Your Private key from Wireguard setting>
- WIREGUARD_ADDRESSES=<Your wireguard address>
networks:
basic_net:
ipv4_address: <Your Cluetun container IP>

jackett:
image: ghcr.io/linuxserver/jackett:latest
container_name: jackett
environment:
- PUID=1000
- PGID=1000
- TZ=Asia/Taipei
- AUTO_UPDATE=true #optional
depends_on:
- gluetun
volumes:
- jackett-config:/config
restart: unless-stopped
networks:
basic_net:
ipv4_address: <Your jackett container IP>

flaresolverr:
image: ghcr.io/flaresolverr/flaresolverr:latest
container_name: flaresolverr
environment:
- LOG_LEVEL=${LOG_LEVEL:-info}
- LOG_HTML=${LOG_HTML:-false}
- CAPTCHA_SOLVER=${CAPTCHA_SOLVER:-none}
- TZ=Asia/Taipei
depends_on:
- gluetun
restart: unless-stopped
networks:
basic_net:
ipv4_address: <Your flaresikverr container IP>

lidarr:
image: lscr.io/linuxserver/lidarr
container_name: lidarr
environment:
- PUID=1000
- PGID=0
- TZ=Asia/Taipei
volumes:
- lidarr-config:/config
- <Your Music Location>:/music
- <Your Download Temp Location>:/downloads
depends_on:
- gluetun
restart: unless-stopped
networks:
basic_net:
ipv4_address: <Your lidarr container IP>

radarr:
image: ghcr.io/linuxserver/radarr:latest
container_name: radarr
environment:
- PUID=1000
- PGID=0
- TZ=Asia/Taipei
volumes:
- radarr-config:/config
- <Your Media Location>:/media
- <Your Download Temp Location>:/downloads
depends_on:
- gluetun
restart: unless-stopped
networks:
basic_net:
ipv4_address: <Your Radarr container IP>

sonarr-anime:
image: ghcr.io/linuxserver/sonarr:latest
container_name: sonarr-anime
environment:
- PUID=1000
- PGID=0
- TZ=Asia/Taipei
volumes:
- anime-config:/config
- <Your Media Location>:/media
- <Your Download Temp Location>:/downloads
depends_on:
- gluetun
restart: unless-stopped
networks:
basic_net:
ipv4_address: <Your sonarr-anime container IP>

sonarr-tv:
image: ghcr.io/linuxserver/sonarr:latest
container_name: sonarr-tv
environment:
- PUID=1000
- PGID=0
- TZ=Asia/Taipei
volumes:
- tv-config:/config
- <Your Media Location>:/media
- <Your Download Temp Location>:/downloads
depends_on:
- gluetun
restart: unless-stopped
networks:
basic_net:
ipv4_address: <Your sonarr-tv container IP>


qbittorrent:
image: ghcr.io/linuxserver/qbittorrent
container_name: qbittorrent
environment:
- PUID=1000
- PGID=0
- TZ=Asia/Taipei
- WEBUI_PORT=4080
volumes:
- qb-config:/config
- <Your Download Temp Location>:/downloads
depends_on:
- gluetun
restart: unless-stopped
network_mode: "service:gluetun"

volumes:
gluetun:
jackett-config:
lidarr-config:
radarr-config:
anime-config:
tv-config:
qb-config:

networks:
basic_net:
name: backend
driver: bridge
ipam:
config:
- subnet: <Subnet for your containers>
gateway: <Your Cluetun container IP>

記得這些都在同一個subnet內,然後要定義個別的ip

整個docker-compose.yml結構
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Rev.2.0
# docker-compose.yml
---------------------------------------------------------------------------------------------------------------------------------
services:

<中間省略>

networks:
basic_net:
name: backend
driver: bridge
ipam:
config:
- subnet: <Subnet for your containers>
gateway: <Your Cluetun container IP>

整個docker-compose.yml其沒什麼特別的就是最後network的部份,因為中間所有的service都會需要連結到gluetun這個container但是又沒法內部透過http://gluetun的方式去連接,所以最簡單的方法就是全部都指向gluetun這個container的IP address來連線,所以若IP不能固定的話其他的設定會要一直改一直改很累,所以我強力建議要給一個固定的IP

Gluetun Section
/dev/net/tun
1
2
devices:                                                                                                                                                                                 
- /dev/net/tun:/dev/net/tun

這是一個必要的設定,主要是gluetun需要用到tun0這個虛擬的device所以需要mapping到docker host的tun就我用的PhotonOS實測結果,tun.ko default是不自動載入的

手動載入

1
2
3
4
5
# 使用modprobe指令載入tun
root@$> modprobe tun
# 使用lsmod確認有載入
root@$> lsmod | grep tun
tun 49152 0

設定為自動載入

1
root@$> echo tun > /etc/modules-load.d/tun.conf
ports

基本上除了gluetun本身用的到的port以外,依附於他的相關服務需要的port mapping也得一併放在這個section

1
2
3
4
5
6
7
8
ports:                                                                                                                                                                                   
- 8888:8888/tcp # HTTP proxy
- 8388:8388/tcp # Shadowsocks
- 8388:8388/udp # Shadowsocks
- 8000:8000
- 4080:4080 # Qbittorrent WebUI
- 6881:6881 # Qbittorrent
- 6881:6881/udp # Qbittorrent

可以看到我幾乎所有的服務都要放進來,這樣我連線的時候才能透過連到Gluetun的對應port到達我其他container去, 而設定好後,nginx proxy manager裡面的連結也得改,例如原先連到radarr設定檔是

http://內部Domain:80 -Link-> http://radarr:7878
需要改成
http://內部Domain:80 -Link-> http://gluetun:7878

這樣才能連上

Rev.2.0
還被包在Gluten內的qbittorrent的確是這樣沒錯

Environment
1
2
3
4
5
6
7
8
9
10
environment:                                                                                                                                                                             
- VPN_SERVICE_PROVIDER=custom
- VPN_TYPE=wireguard
- WIREGUARD_ENDPOINT_IP=<Your Endpoint IP>
- WIREGUARD_ENDPOINT_PORT=<Your Endpoint Port>
- WIREGUARD_PUBLIC_KEY=<Your Public key from Wireguard setting>
- WIREGUARD_PRESHARED_KEY=<Your Preshared key from Wireguard setting>
- WIREGUARD_PRIVATE_KEY=<Your Private key from Wireguard setting>
- WIREGUARD_ADDRESSES=<Your wireguard address>
- PUBLICIP_ENABLED=false

這個section非常重要可以說是整個gluetun設定的重點,範例裡面我用的是custom wireguard的設定, 若是用付費的ProtonVPN的話是比較簡易的寫法,不過我還沒找到custom wireguard的port forwarding的相關有效設定, 詳細的話可以參考作者的wiki相關內容
Rev.2.0
因為我的會跳錯,所以我還會把public Ip檢查這段關掉PUBLICIP_ENABLED=false

Network
1
2
3
networks:                                                                                                                                                  
basic_net:
ipv4_address: <Your Cluetun container IP>

這裡只是指定Gluetun的IP

其他Container的通用部份
1
2
depends_on:                                                                                                                                                                              
- gluetun
Ports

除了Gluetun以外都不會有Port mapping
Rev.2.0
不包在內的,我也沒做Port Mapping,但是我是從外部直接連線被分配好的container ip

depends_on

因為Gluetunkill switch功能,在gluetun啟動完成之前其他的也沒辦法連上,而且我發現一個不知道是不是Bug的現象,若是不設定成連動以及depends on的話, 其他的container有時後會沒辦法連上gluetun, 所以我才會放在同一個docker-compose.yml內用depends_on連接其實再謹慎一點的話應該要替depends_on加上condition的(確認healthy後才啟動其他的之類的)

Network

模式要改成

network_mode: "service:gluetun"
若不放在同一個docker-compose.yml內的話則要改成
network_mode: "container:gluetun"

前端

前端的docker-compose.yml沒什麼特別的,就參考docker hub的說明就好了

通用注意事項

  • 所有的權限都要注意,我是搭配我的smb權限所以才設成UID=1000, GID=0
  • sonarr&radarr的profile設定請量力而為,我一開始都很開心的有多高設多高…然後就發現一個電影70幾GB,並也emby根本跑不動轉檔…然後我就全部downgrade到1080p了…

設定

太麻煩了直接看人家的Blog怎麼設就好了…

追加更新

20220908

  • Radarr, Sonarr, Lidarr這些工具在設定Jackett連動的indexer的時候不要用nginx proxy manager轉出來的url,建議直接把這些container的network放在同一個subnet裡面然後直接用http://${container_IP}:port形式處理不然很容易連不上

  • Jackett的新功能可以直接用/api/v2.0/indexers/all/results/torznab的形式讓你只要設一個indexer就可以回傳所有在Jackett上設定的indexer

  • Jackett內FlareSolverr API URL:也是一樣要用http://${container_IP}:port

  • 目前的實測,用自架的wireguard看起來Qbittorrent的效率不是很好…看到ProtonVPN Plus一次定兩年每個月4.99USD…其實還是有點心動的…過一陣子看吧,搞不好是我的下載物都差不多斷頭了??

    20250103

  • 沒有gluetun的話上述是正確的,但是用了gluetun就只能link設定到gluetun container ip才會動

  • 我知道Jackett的說明內有這個function,但是實際上在Sonarr, Radarr & Lidarr的設定中真的這樣設定之後其實會有error而且沒效果…

  • 其實也不能說錯啦,只是這個container IP是Gluetun的IP…

Rev.2.0 20260205

為什麼會變更設定?
主要的理由還是因為之前lidarr連接Musicbrainz失效的問題,然後我就在換版本的過程中發現gluten check public ip時有error,導致我弄了一早上的更換lidarr作業忽然又發生了add new裡連不上Musicbrainz的meta data的窘境
急火攻心之下,我就把Jackett, flaresolverr還有lidarr弄出來,結果就好了…(但是仔細一想這不是遷怒亂搞嗎??問題出在gluten上但是我卻動了其他東西…)然後我就一股腦把該搬的都搬了…