토렌트 자동화하기 (1) – VPN + Prowlarr + Flaresolverr

포럼 등을 돌아다니다 보면 간간히 보이는 질문이 있습니다. 바로 ‘토렌트 자동화 어떻게 하나요?’와 같은 것들입니다.

보통 이런 질문들은 목적도, 대상도 뚜렷하지 않은 채 허공에 뜬구름 잡는 식의 질문이 많습니다. 그렇다보니, 아무런 관심도 받지 못하고 흘러가는 질문이 되기 일쑤죠.

물론 질문자도 핑프라서 그런 건 아닐겁니다. 알고 있는 것이 뚜렷하지 않으니 질문이 이럴 수 밖에 없죠. 근데 답변해주는 사람도, 이런 질문을 보면 막막해지기 때문에 답을 꺼리게 되는 것도 어쩔 수 없죠 ㅎ_ㅎ.

그래서, VPN을 세팅하고, qBittorrent를 설치하고, 토렌트 자동화에 필요한 여러 이미지를 설치, 세팅하여 실사용하는 법까지 글로 자세하게 작성해보려 합니다.

이 과정은 작성일 현재 TrueNAS 최종버전인 25.04에 직접 세팅하며 작성합니다. 또한, TrueNAS는 어플라이언스로서 apt를 막아두고 실행을 권장하지 않기 때문에, 다른 바이너리도 설치하기 어렵습니다. 따라서, 24.10부터 Apps 서비스의 기반이 된 Docker를 이용해 세팅됩니다.

기본 환경 구성

먼저, TrueNAS상에서 토렌트에 사용할 데이터셋을 생성해 주어야 합니다. 크게 세 개의 데이터셋이 필요합니다.

  1. 어플리케이션들의 데이터가 저장될 곳
  2. 토렌트로 다운로드 받은 파일들이 저장될 곳
  3. 실제 미디어 파일을 모아놓을 곳

예시에서는 아래와 같이 RN428 스토리지 풀 하위에 데이터셋을 생성했습니다.

  • /mnt/RN428/arr : 어플리케이션 데이터
  • /mnt/RN428/torrent : 토렌트
  • /mnt/RN428/media : 미디어 라이브러리

그리고 arr하위에 여러 개의 폴더를 생성합니다.

fentablog@rn428:/mnt/RN428/arr$ mkdir gluetun bazarr lidarr prowlarr sonarr radarr lidarr soularr slskd qbittorrent wireguard compose

아래처럼 폴더들이 생성되면 됩니다. 이 폴더들은 각 이름의 어플리케이션 데이터를 저장할 곳으로 쓰입니다.

사용하지 않을 서비스에 대해서는 과정을 생략하셔도 됩니다. 예를 들어,

lidarr는 음악 관리 도구입니다. slskd는 토렌트와는 완전히 다른 soulseek 기반의 프로그램이고 soularr는 lidarr와 slskd를 연동해 작동시켜주는 파이썬 스크립트입니다.

wireguard폴더는 VPN접속 프로필을 저장하는 용도이고 compose폴더는 docker-compose.yml을 배치할 용도이니 무조건 생성해 주세요.

폴더가 생성되었다면, 아래 명령어를 입력해 별도 도커 브리지 네트워크를 하나 생성해 줍니다.

sudo docker network create torrent_default

숫자와 암호로 이루어진 무작위 문자열이 출력된다면, 잘 생성된 것입니다.

이 브리지 네트워크는 이 글에서 설명할 VPN서비스가 속할 컨테이너입니다.

전문

저는 큰그림이 없이 조각조각만 던져주면 이해가 잘 안되는 사람이라 우선 Compose전문을 먼저 깔고 시작하겠습니다.

우선은 글을 차근차근 읽고 Compose를 적용해 주세요.

스스로 세팅할 줄 안다! 하시면 그냥 진행하시면 되겠습니다.

# /mnt/RN428/arr/compose/docker-compose.yml
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
      - 8191:8191 # flaresolverr
      - 9696:9696 # prowlarr
      - 8989:8989 # sonarr
      - 7878:7878 # radarr
      - 8686:8686 # lidarr
      - 6767:6767 # bazarr
      - 5030:5030 # slskd
      - 5031:5031 # slskd
      - 50300:50300 # slskd
      - 8180:8180 # qbittorrent
    volumes:
      - ${CONFIG}/gluetun:/gluetun
      - ${CONFIG}/wireguard:/gluetun/wireguard
    environment:
      - FIREWALL_OUTBOUND_SUBNETS=${FIREWALL_OUTBOUND_SUBNETS}
      - VPN_TYPE=wireguard
      - VPN_SERVICE_PROVIDER=${VPN_PROVIDER}
      - TZ=${TZ}
      - VPN_KEEP_ALIVE=1
      - HEALTH_CHECK_INTERVAL=5m
      - WIREGUARD_PERSISTENT_KEEPALIVE=15
      - UPDATER_PERIOD=1m
    healthcheck:
      test: ["CMD", "wget", "--spider", "-q", "https://google.com"]
      interval: 30s
      timeout: 10s
      retries: 3
    networks:
      - torrent_default

  torrent_prowlarr:
    image: linuxserver/prowlarr:latest
    container_name: torrent_prowlarr
    environment:
      - PUID=${UID}
      - PGID=${GID}
      - TZ=${TZ}
    volumes:
      - ${CONFIG}/prowlarr/config:/config
    restart: unless-stopped
    depends_on:
      - gluetun
    network_mode: "service:gluetun"

  torrent_flaresolverr:
    image: flaresolverr/flaresolverr:latest
    container_name: torrent_flaresolverr
    environment:
      - LOG_LEVEL=${LOG_LEVEL:-info}
      - LOG_HTML=${LOG_HTML:-false}
      - CAPTCHA_SOLVER=${CAPTCHA_SOLVER:-none}
      - TZ=${TZ}
    restart: unless-stopped
    depends_on:
      - gluetun
    network_mode: "service:gluetun"
  
  torrent_sonarr:
    container_name: torrent_sonarr
    image: linuxserver/sonarr:latest
    restart: unless-stopped
    environment:
      - PUID=${UID}
      - PGID=${GID}
      - TZ=${TZ}
    volumes:
      - ${LIBRARY}/tv:/mnt/tv
      - ${CONFIG}/sonarr/config:/config
      - ${DOWNLOADS}:${DOWNLOADSMOUNT}
    depends_on:
      - gluetun
    network_mode: "service:gluetun"

  torrent_radarr:
    container_name: torrent_radarr
    image: linuxserver/radarr:latest
    restart: unless-stopped
    environment:
      - PUID=${UID}
      - PGID=${GID}
      - TZ=${TZ}
    volumes:
      - ${LIBRARY}/movie:/mnt/movie
      - ${CONFIG}/radarr/config:/config
      - ${DOWNLOADS}:${DOWNLOADSMOUNT}
    depends_on:
      - gluetun
    network_mode: "service:gluetun"
  
  torrent_lidarr:
    image: linuxserver/lidarr:latest
    container_name: torrent_lidarr
    environment:
      - PUID=${UID}
      - PGID=${GID}
      - TZ=${TZ}
    volumes:
      - ${CONFIG}/lidarr/config:/config
      - ${LIBRARY}/music:/mnt/music
      - ${DOWNLOADS}:${DOWNLOADSMOUNT}
    restart: unless-stopped
    depends_on:
      - gluetun
    network_mode: "service:gluetun"

  slskd:
    image: slskd/slskd:latest
    container_name: slskd
    restart: unless-stopped
    user: ${USER}
    environment:
      - SLSKD_REMOTE_CONFIGURATION=true
      - "SLSKD_SHARED_DIR=/mnt/music"
    volumes:
      - ${CONFIG}/slskd:/app
      - ${LIBRARY}/music:/mnt/music
      - ${DOWNLOADS}:${DOWNLOADSMOUNT}
    depends_on:
      - gluetun
    network_mode: "service:gluetun"

  soularr:
    image: mrusse08/soularr:latest
    container_name: soularr
    user: ${USER}
    environment:
      - TZ=${TZ}
      - SCRIPT_INTERVAL=600
    volumes:
      - ${DOWNLOADS}/soulseek:${DOWNLOADSMOUNT}/soulseek
      - ${CONFIG}/soularr:/data
    restart: unless-stopped
    depends_on:
      - gluetun
      - torrent_lidarr
      - slskd
    network_mode: "service:gluetun"
      
  torrent_bazarr:
    image: linuxserver/bazarr:latest
    container_name: torrent_bazarr
    environment:
      - PUID=${UID}
      - PGID=${GID}
      - TZ=${TZ}
    volumes:
      - ${CONFIG}/bazarr/config:/config
      - ${LIBRARY}:/mnt/media
      - ${DOWNLOADS}:${DOWNLOADSMOUNT}
    restart: unless-stopped
    depends_on:
      - gluetun
    network_mode: "service:gluetun"

  torrent_qbittorrent:
    image: linuxserver/qbittorrent:latest
    container_name: torrent_qbittorrent
    environment:
      - TZ=${TZ}
      - PUID=${UID}
      - PGID=${GID}
      - UMASK=022
      - WEBUI_PORT=8180
    volumes:
      - ${DOWNLOADS}:${DOWNLOADSMOUNT}
      - ${CONFIG}/qbittorrent:/config
    restart: unless-stopped
    depends_on:
      - gluetun
    network_mode: "service:gluetun"

networks:
  torrent_default:
    external: true

자세히 보면 ${} 로 감싸져 있는 변수값들이 보일 겁니다. 이런 경우는 동일 폴더 내에 별도의 .env 파일을 두고 여기에 변수값을 입력함으로써 변수중복입력을 막거나, 비밀번호 등을 Compose에 다이렉트로 노출하는 것을 방지하는 것 등의 의미가 있습니다.

이 글의 경우에는 .env를 아래와 같이 사용할 수 있습니다. VPN_PROVIDER나 FIREWALL_OUTBOUND_SUBNETS같은 경우에는 개인 환경에 맞게 수정하셔야 하고, 기타 경로에 대한 변수도 마찬가지입니다.

# /mnt/RN428/arr/compose/.env
CONFIG=/mnt/RN428/arr
DOWNLOADS=/mnt/RN428/torrent
DOWNLOADSMOUNT=/mnt/torrent
LIBRARY=/mnt/RN428/media
UID=3001
GID=0
TZ=Asia/Seoul
CAPTCHA_SOLVER=hcaptcha-solver
USER="3001:0"
VPN_PROVIDER=mullvad
FIREWALL_OUTBOUND_SUBNETS=192.168.0.1/24

이해를 돕기 위해 설명하자면, 각 컨테이너가 사용할 데이터 경로는 모두 /mnt/RN428/arr/ 경로 하위에 있습니다. 이걸 compose마다 일일히 반복해서 기입하는 것도 피곤하고, 만일 추후 경로를 수정하게 되면 하나하나 수정해야 하지만, 이렇게 .env로 만들어 둘 경우 딱 한 번만 수정하면 되는 것이죠. 마찬가지로 TZ(Time Zone) 역시 전부 Asia/Seoul일텐데 이걸 전부 입력하는 것보다 이렇게 만들어두는 것이 경제적이죠.

그런데, TrueNAS는 아직 .env파일을 직접 활용하여 Compose구문을 사용할 수 없습니다. 따라서 동일 폴더, 이 글에서는 /mnt/RN428/arr/compose 내에 docker-compose.yml.env파일을 함께 모아두고 WEB UI에서 아래처럼 지정해야 합니다.

이렇게 구성해두실 경우 docker-compose.yml을 수정할 때, 일일히 쉘에 접속하지 않고 SMB를 통해 VSCode등을 이용해 가독성 높은 환경에서 수정할 수 있다는 장점도 있습니다.

이 상태로 바로 Save를 클릭해 컨테이너들을 실행하려고 하면 다운로드 해야 할 이미지가 많아 timeout에 걸려 에러메세지가 출력될 가능성이 높습니다.

따라서 아래 명령어를 입력해 먼저 이미지들을 다운로드 하는 것을 추천하며, 동시에 여러개의 이미지를 다운로드 받아야 하므로 잠시 root로 전환해 줍니다.

sudo -i
docker pull qmcgaw/gluetun &
docker pull linuxserver/prowlarr:latest &
docker pull flaresolverr/flaresolverr:latest &
docker pull linuxserver/sonarr:latest &
docker pull linuxserver/radarr:latest &
docker pull linuxserver/lidarr:latest &
docker pull slskd/slskd:latest &
docker pull mrusse08/soularr:latest &
docker pull linuxserver/bazarr:latest &
docker pull linuxserver/qbittorrent:latest &
wait

다운로드가 완료되면 Save를 클릭해 컨테이너를 실행하면 됩니다.

각 항목에 대한 설명은 밑에서 한개씩 설명하겠습니다.

Gluetun(VPN)

기본 설정

이 글에서 언급하는 모든 서비스는 전부 VPN을 경유하도록 세팅합니다. Compose구문 중 아래에 해당합니다.

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
      - 8191:8191 # flaresolverr
      - 9696:9696 # prowlarr
      - 8989:8989 # sonarr
      - 7878:7878 # radarr
      - 8686:8686 # lidarr
      - 6767:6767 # bazarr
      - 5030:5030 # slskd
      - 5031:5031 # slskd
      - 50300:50300 # slskd
      - 8080:8080 # qbittorrent
    volumes:
      - ${CONFIG}/gluetun:/gluetun
      - ${CONFIG}/wireguard:/gluetun/wireguard
    environment:
      - FIREWALL_OUTBOUND_SUBNETS=${FIREWALL_OUTBOUND_SUBNETS}
      - VPN_TYPE=wireguard
      - VPN_SERVICE_PROVIDER=${VPN_PROVIDER}
      - TZ=${TZ}
      - VPN_KEEP_ALIVE=1
      - HEALTH_CHECK_INTERVAL=5m
      - WIREGUARD_PERSISTENT_KEEPALIVE=15
      - UPDATER_PERIOD=1m
    healthcheck:
      test: ["CMD", "wget", "--spider", "-q", "https://google.com"]
      interval: 30s
      timeout: 10s
      retries: 3
    networks:
      - torrent_default
      
networks:
  torrent_default:
    external: true

VPN컨테이너로는 gluetun을 사용합니다. 도커로 된 이미지 중 가장 잘 작동하고 트러블 없는 효자 이미지입니다. 심지어 심하게 트윅되어있고 커널버전도 낮은 시놀로지 DSM에서도 정상적으로 작동해 줍니다.

본래 각 컨테이너에서 사용할 개별 포트들은 그 컨테이너 하위의 ports에서 지정해줘야 하지만, 이 글의 목적은 모든 서비스가 VPN을 경유하도록 설정하는 것이므로, 모든 포트포워딩을 VPN컨테이너에서 해주고, 다른 컨테이너들은 VPN컨테이너를 통해서만 인터넷에 접속할 수 있도록 할 겁니다. 이 경우, 각 서비스가 사용하는 포트를 gluetun에서 열어주어야 합니다. 그래서 ports 하단에 각종 서비스 포트가 주렁주렁 매달려 있는 겁니다.

또한, 복잡해 보였던 .env 파일의 내용 중 이 부분에 해당하는 건 아래의 4줄입니다.

CONFIG=/mnt/RN428/arr
DOWNLOADS=/mnt/RN428/torrent
DOWNLOADSMOUNT=/mnt/torrent
LIBRARY=/mnt/media
UID=3001
GID=0
TZ=Asia/Seoul
CAPTCHA_SOLVER=hcaptcha-solver
USER="3001:0"
VPN_PROVIDER=mullvad
FIREWALL_OUTBOUND_SUBNETS=192.168.0.1/24

1행의 CONFIG와 7행의 TZ에 대해서는 위에서 설명했으니 넘어가겠습니다.

10행의 VPN_PROVIDER는 gluetun에서 VPN접속 시 요구하는 VPN제공자입니다. 이용하는 VPN서비스에 따라 이름이 달라져야 하는 부분입니다.
(서프샤크를 쓴다고 하면 surfshark, 노드VPN을 쓴다고 하면 nordvpn이 되겠죠)

11행의 FIREWALL_OUTBOUND_SUBNETS는 VPN을 경유하지 않을 IP대역을 이야기합니다. 이 설정은 로컬 네트워크(홈 네트워크) 간 연결을 보존하기 위해 주로 사용됩니다. 바꿔 말하면, 이 설정이 없을 경우 우리는 이 Compose로 작성된 모든 서비스에 접근할 수 없습니다. 아무리 192.168.0.x:9696을 해도 접근할 수 없게 된다는 뜻입니다. 그렇기 떄문에 이 곳엔 홈 네트워크 IP대역을 적어주셔야 합니다.

Wireguard 접속 설정

VPN을 이용할 때는 주로 OpenVPN과 Wireguard로 방식이 나뉩니다. 이 중에서 Wireguard 방식이 OpenVPN보다 좀 더 속도와 안정성이 좋기 때문에 Wireguard를 사용할 예정입니다.

먼저, 각 VPN제공업체에서 conf확장자로 된 설정파일을 다운받을 수 있습니다. 블로그를 가장한 광고글이 넘쳐나기 떄문에 별도로 추천하지는 않습니다.

이러한 conf파일을 wg0.conf파일로 이름을 수정한 다음 /mnt/RN428/arr/wireguard 폴더 하위에 놓습니다. gluetun은 wg0.conf파일을 직접 넘겨받아 이를 이용하여 접속하는 기능이 있습니다.

fentablog@rn428:/mnt/RN428/arr/wireguard$ ls -lah

위의 과정처럼 volumes에서 wg0.conf파일을 넘겨주는 방식 말고 environment항목 하위에 직접 아래와 같이 작성하는 방법도 있습니다.

services:
  gluetun:
    volumes:
      - ${CONFIG}/gluetun:/gluetun
    environment:
      - FIREWALL_OUTBOUND_SUBNETS=${FIREWALL_OUTBOUND_SUBNETS}
      - VPN_TYPE=wireguard
      - VPN_SERVICE_PROVIDER=${VPN_PROVIDER}
      - TZ=Asia/Seoul
      - VPN_KEEP_ALIVE=1
      - HEALTH_CHECK_INTERVAL=5m
      - WIREGUARD_PERSISTENT_KEEPALIVE=15
      - UPDATER_PERIOD=1m
      - WIREGUARD_PRIVATE_KEY=
      - WIREGUARD_ADDRESSES=
      - WIREGUARD_PUBLIC_KEY=
      - WIREGUARD_ENDPOINT_IP=
      - WIREGUARD_ENDPOINT_PORT=

개인적으로 이 방법은 키를 그대로 노출해야 하기도 하고, 접속경로를 바꿀때마다 docker-compose.yml을 수정해야 하므로 선호하지 않지만, 이 방식이 더 편할 경우 이렇게 사용하시면 됩니다.

맨 하위에는 이런 항목이 있습니다.

services:
  gluetun:
    networks:
      - torrent_default
      
networks:
  torrent_default:
    external: true

이는 맨 처음 위에서 별도로 생성해둔 torrent_default라는 도커 네트워크 안에 gluetun을 포함시키겠다는 의미입니다. 해당 네트워크는 이 compose파일과 별개로 외부에서 생성되었기 때문에 external: true를 통해 이를 알려주는 역할을 합니다. 나중에 설명할 Unpackerr라는 서비스를 위한 통로입니다.

실행 후 gluetun의 로그에서 아래와 같은 메세지가 출력되면 gluetun을 통한 VPN을 통한 접속은 잘 이루어졌다는 뜻이 됩니다.

통신이 되는건지 직접 확인하고 싶다면, 아래 그림처럼 gluetun의 Shell을 클릭하여 접속 후 ping google.com등을 해보셔도 좋습니다.

qBittorrent

토렌트를 다운로드하기 위한 클라이언트는 여러가지 종류가 있지만, 대중적이면서 많은API를 제공하고 나름 상세한 설정이 가능한 건 qBittorrent가 좋습니다. Compose구문에서는 아래에 해당합니다.

services:
  torrent_qbittorrent:
    image: linuxserver/qbittorrent:latest
    container_name: torrent_qbittorrent
    environment:
      - TZ=${TZ}
      - PUID=${UID}
      - PGID=${GID}
      - UMASK=022
      - WEBUI_PORT=8180
    volumes:
      - ${DOWNLOADS}:${DOWNLOADSMOUNT}
      - ${CONFIG}/qbittorrent:/config
    restart: unless-stopped
    depends_on:
      - gluetun
    network_mode: "service:gluetun"

WEBUI_PORT라는 환경변수는 qBittorrent의 접속 포트를 바로 설정할 수 있는 환경변수입니다. 기본값은 8080이지만, 8080을 사용하는 다른 컨테이너들이 상당히 많아 임의로 변경했습니다.

.env 에서 사용되는 부분은 아래와 같습니다.

CONFIG=/mnt/RN428/arr
DOWNLOADS=/mnt/RN428/torrent
DOWNLOADSMOUNT=/mnt/torrent
LIBRARY=/mnt/RN428/media
UID=3001
GID=0
TZ=Asia/Seoul
CAPTCHA_SOLVER=hcaptcha-solver
USER="3001:0"
VPN_PROVIDER=mullvad
FIREWALL_OUTBOUND_SUBNETS=192.168.0.1/24

DOWNLOADS는 TrueNAS에서 토렌트 다운로드에 사용할 데이터셋의 경로이고, DOWNLOADSMOUNT는 해당 경로를 컨테이너 내에 마운트할 경로입니다.

맨 위에서 토렌트 다운로드용도로 생성한 /mnt/RN428/torrent 경로를 컨테이너 내부의 /mnt/torrent로 사용한다는 뜻입니다.

Docker Compose로 보면 아래와 같이 구성되는 겁니다.

services:
  torrent_qbittorrent:
    volumes:
      - /mnt/RN428/torrent:/mnt/torrent

여기서, 굳이 변수를 이용해야 하냐는 질문이 있을 수 있습니다.

추후 Prowlarr, Sonarr 등이 다운로드 받은 토렌트를 확인하기 위해 토렌트 클라이언트가 사용하는 다운로드 경로와 동일한 경로에 직접 접근할 수 있어야 합니다(접근 못할 경우 다운로드 받은 토렌트 파일을 수동으로 옮겨야 하는 불편함이 있으며, 자동 다운로드 구성에도 문제가 발생합니다). 이를 위해 모든 서비스에서 사용하는 토렌트 다운로드 경로를 일치시키기 위해 .env에 변수로 지정했습니다.

PUID, PGID는 컨테이너 내에서 사용되는 계정의 UID, GID를 설정할 수 있는 옵션으로 이 글의 .env에서는 아래와 같이 정해져 있습니다.

이는 현재 사용되는 계정의 UID와 GID를 확인해 기입해주시면 되며, TrueNAS 쉘에서는 아래의 명령어를 통해 확인 가능합니다.

fentablog@rn428:~$ id

혹은 TrueNAS의 Credentials → Users 탭에서도 아래와 같이 확인할 수 있습니다. 이 값은 개별환경마다 모두 다를 수 있으므로 무지성으로 3001, 0을 사용하지마시고 직접 확인해보시는 걸 강력히 권장합니다.

컨테이너가 실행된 후엔 로그에서 초기 로그인 ID/PW를 확보해야 합니다. TrueNAS UI에서 아래와 같이 편하게 Logs를 확인하셔도 되고,

쉘이 더 익숙하신 분들은

sudo docker logs torrent_qbittorrent

를 수행하시면 됩니다.

로그 최하단에 아래와 같이 admin/Q6YPdV7Mc라는 임시 로그인계정을 확인할 수 있고

TrueNAS IP:8180으로 접속해 이 계정을 입력하면 qBittorrent화면으로 진입할 수 있습니다.

설정에서 언어를 한국어로 변경할 수 있습니다.

또한 설정-Web UI탭에서 로그인 계정을 변경할 수 있습니다.

로컬 호스트에서 클라이언트에 대한 인증 우회하기 옵션을 클릭할 경우 도커 네트워크 대역의 서비스간 인증이 우회됩니다. 본래는 집에서 사용하는 내부 네트워크를 위한 옵션이지만, qBittorrent가 도커 브리지 네트워크에 속해있고 localhost가 그 네트워크 대역을 가리키기 때문에 발생하는 일입니다.

그러나, 오히려 이 덕분에 Sonarr, Radarr 등의 서비스에서 인증과정을 생략하고 곧바로 토렌트를 추가할 수 있기 때문에 체크해주면 좋습니다.

또한, 허용 목록에 있는 IP 서브넷의 클라이언트에 대한 인증 우회 기능을 이용하여 192.168.0.0/24 등의 대역을 추가해 집 내부 네트워크에 대한 인증도 우회할 수 있습니다.

마지막으로, 내려받기 탭에서 기본 저장경로를 /mnt/torrent [다운로드 폴더 컨테이너 내부 마운트 경로]로 변경합니다.

변경하지 않을 시 재부팅때마다 다운로드된 토렌트가 전부 초기화되어 불편함을 유발하게 됩니다. 나아가, TrueNAS의 Docker 기본 볼륨에 토렌트를 다운로드 받게 되는 꼴이 되어 호스트의 저장 공간 부족을 초래하게 됩니다.

Prowlarr & Flaresolverr

Prowlarr

Prowlarr는 여러 토렌트 사이트를 긁어와 저장하고 이를 다시 뿌려주는 역할을 합니다. 이와 같은 역할을 하는 Jackett이라는 프로그램 역시 유명한데, Prowlarr가 Sonarr, Radarr, Lidarr 등의 서비스들과 연동이 더 간편해 Prowlarr를 사용합니다.

Compose 구문 중 아래에 해당합니다.

services:
  torrent_prowlarr:
    image: linuxserver/prowlarr:latest
    container_name: torrent_prowlarr
    environment:
      - PUID=${UID}
      - PGID=${GID}
      - TZ=${TZ}
    volumes:
      - ${CONFIG}/prowlarr/config:/config
    restart: unless-stopped
    depends_on:
      - gluetun
    network_mode: "service:gluetun"

여기서 network_mode: "service:gluetun"은 gluetun컨테이너를 이용해 통신하겠다는 뜻이고, depends_on: - gluetun은 의존성을 정의하는 부분으로 gluetun이 다운되면 같이 다운시키겠다는 뜻입니다(킬 스위치).

기본적으로 9696포트로 접속할 수 있으며, 브라우저에 TrueNAS IP:9696를 입력해 접속할 수 있습니다. 초기 접속 시 아래처럼 설정페이지를 만나게 됩니다.

Authentication Method는 로그인 시 입력 폼에 대한 설정입니다.

Basic (Browser Popup)의 경우 HTTP를 통해 바로 로그인 정보를 보내는 방식입니다. 상대적으로 보안성이 떨어지지만, Authentik 등을 이용해 SSO를 구현할 수 있다는 장점이 있습니다.

Forms (Login Page)의 경우 별도 로그인 페이지를 띄워 ID/PW를 입력받는 방식으로 상대적으로 보안성은 조금 더 좋으나 통합 로그인 구현을 할 수 없습니다. 저는 전자의 방식을 사용중입니다.

Authentication Required 항목에서는 로컬 대역에 대해 인증을 생략할 수 있도록 하고 있습니다. 설정해두면 편의상 도움이 됩니다.

저의 경우 Authentik과 통합된 상태라 굳이 필요하지 않지만, 일반적인 사용자의 경우 설정해두면 귀차니즘을 덜어낼 수 있습니다.

기타 그 외 Username, Password는 각자 설정하시면 됩니다.

초기 설정을 마쳤다면, Prowlarr에서 토렌트를 긁을 사이트들을 추가 해야 합니다. 이것을 Prowlarr에선 Indexer라고 부릅니다.

Protocol – Torrent, Launguage – en-US, ko-KR을 선택해 중구난방으로 펼쳐져있는 Indexer들에서 필요한 사이트를 추출해낼 수 있습니다.

스크린샷 하단에 보이듯, 나름 국내 사이트도 지원합니다(지원하긴 하지만, 계속해서 주소가 변경되는 특성 때문에 수시로 연결이 끊겼다 붙었다 합니다).

목적에 맞는 Indexer를 클릭해 Test버튼을 클릭하고, 접속Test가 성공적으로 완료되면 추가할 수 있게 됩니다.

추가하고 나면 메인페이지에 아래와 같이 Indexer가 추가되며,

이 Indexer를 활용해 다른 어플리케이션과 연동해 토렌트 자동화에 쓸 수 있게 됩니다. 또한, 자동화 외에도 Prowlarr에서 긁어 만든 DB를 통해 직접 토렌트를 검색할 수도 있습니다.

Prowlarr에서 검색한 토렌트를 직접 다운로드받을 수도 있습니다. 예시로 리스트 상의 SNL을 하나 다운받아 보겠습니다.

먼저, 이를 위해선 Prowlarr에서 qBittorrent를 등록해야 합니다.

Settings → Download Clients로 이동해 +를 클릭합니다.

qBittorrent를 클릭합니다.

만일, 위에서 설명한대로 qBittorrent WEB UI 설정에서 로컬 호스트에서 클라이언트에 대한 인증 우회하기를 활성화했다면,

아래처럼 Prowlarr에서 포트번호만 넣으면 바로 Test를 통과합니다.

그렇지 않을 경우 Username과 Password를 입력해주어야 합니다. Username/Password는 qBittorrent WEB UI 로그인 ID/PW입니다.

클라이언트를 성공적으로 등록했다면, 아래처럼 리스트에 추가된 qBittorrent 클라이언트를 확인할 수 있고,

토렌트를 검색해 다운로드 버튼을 클릭해 qBittorrent로 다운로드를 시작할 수 있게 됩니다.

예시로 리스트 맨 하단의 토렌트를 클릭하면,

이렇게 qBittorrent에 알아서 추가되는 것을 보실 수 있습니다.

기본적인 Prowlarr 사용법은 위와 같이 간단합니다. 이후에는 Sonarr, Radarr 등에서 피드를 긁어 조건에 맞는 토렌트를 다운로드하도록 설정하는 것이 전부입니다.

예시에선 Indexer로 EZTV 하나만을 등록했지만, 리스트를 천천히 살펴보면 굉장히 많은 Indexer들이 있으니 직접 찾아서 설정하시면 됩니다.

단, Indexer를 많이 사용할수록 검색과 파싱에 많은 시간이 들어가므로 일장일단이 있음을 유념하셔야 합니다. 사용하고 싶은 Indexer를 여럿 추가해두고 사용하면서 모니터링하다가, 자주 연결이 끊기는 Indexer를 제거하는 방향으로 가는 것이 좋습니다.

FlareSolverr

Prowlarr에 여러 Indexer를 추가하다 보면, 아래와 같은 탭이 달려 있는 Indexer를 보게 됩니다.

몇몇 사이트들의 경우 클플의 DDoS 방지가 적용되어 있어 사이트에 바로 접근할 수 없습니다. 이럴 때 FlareSolverr를 이용해 체크박스를 클릭해 넘어가는 과정을 진행할 수 있습니다.

Compose는 아래 부분입니다.

services:
  torrent_flaresolverr:
    image: flaresolverr/flaresolverr:latest
    container_name: torrent_flaresolverr
    environment:
      - LOG_LEVEL=${LOG_LEVEL:-info}
      - LOG_HTML=${LOG_HTML:-false}
      - CAPTCHA_SOLVER=${CAPTCHA_SOLVER:-none}
      - TZ=${TZ}
    restart: unless-stopped
    depends_on:
      - gluetun
    network_mode: "service:gluetun"

.env 파일에서 지정하고 있는 것은 딱 하나 CAPTCHA_SOLVER로(TZ는 공통변수이므로 생략..), 단순히 체크박스를 클릭하는 게 아니라 captcha challenge를 만났을 때, 이를 풀어주는 역할입니다. FlareSolverr 이미지에 자체적으로 포함되어 있습니다.

CONFIG=/mnt/RN428/arr
DOWNLOADS=/mnt/torrent
DOWNLOADSMOUNT=/mnt/torrent
LIBRARY=/mnt/RN428/media
UID=3001
GID=0
TZ=Asia/Seoul
CAPTCHA_SOLVER=hcaptcha-solver
USER="3001:0"
VPN_PROVIDER=mullvad
FIREWALL_OUTBOUND_SUBNETS=192.168.0.1/24

FlareSolverr는 Challenge가 등장할 경우 Selenium으로 Chrome을 열어 이를 해결하는 역할만 수행하기 때문에 별도의 UI가 없습니다.

실행 후 아래처럼 Test Successful!/Serving on http://0.0.0.0:8191 와 같은 메세지가 출력되었다면, 문제없이 실행된 것입니다.

정상적으로 실행된 것을 확인했으니 Prowlarr에서 Flaresolverr를 추가해야 합니다.

Prowlarr의 Settings → Indexers로 이동해 +를 클릭한 뒤 FlareSolverr를 선택합니다.

Host의 http://localhost:8191/은 그대로 놔두고, 태그만 적절하게 하나 추가해 줍니다. 태그를 추가하는 이유는 FlareSolverr를 사용하는 Indexer에 직접 적용해주기 위함입니다.

이후 Test버튼을 클릭해서 정상적으로 통신이 되는 것을 확인한 후, Save버튼을 클릭해 추가를 완료해주면 됩니다.

이후, Prowlarr 메인페이지로 이동해 FlareSolverr를 필요로 하는 Indexer의 태그란에 위에서 설정한 태그를 넣어준 후 Test버튼을 클릭합니다.

그러면, FlareSolverr가 적용되기 전보다 조금 더 시간이 오래 걸린 후 초록색 체크 표시를 확인할 수 있게 됩니다.

FlareSolverr 로그를 살펴보면 실제 작동시엔 아래처럼 로그가 출력됩니다.

2025-05-01 22:37:59 INFO     Incoming request => POST /v1 body: {'headers': {'contentType': 'application/x-www-form-urlencoded'}, 'postData': 'f[]=1&f[]=2&f[]=3&f[]=17&f[]=6&f[]=4&f[]=5&f[]=7&f[]=8&f[]=10&f[]=11&f[]=12&f[]=13&f[]=14&f[]=15&f[]=16&f[]=9&f[]=18&f[]=19&prev_allw=1&prev_a=0&prev_dla=0&prev_dlc=0&prev_dld=0&prev_dlw=0&prev_my=0&prev_new=0&prev_sd=0&prev_da=1&prev_dc=0&prev_df=1&prev_ds=0&prev_tor_type=0&o=1&s=2&tm=-1&sns=-1&srg=-1&df=1&da=1&allw=1&submit=Search', 'maxTimeout': 180000, 'cmd': 'request.post', 'url': 'https://example.com', 'proxy': {}}
2025-05-01 22:37:59 WARNING  Request parameter 'headers' was removed in FlareSolverr v2.
2025-05-01 22:38:04 INFO     Challenge detected. Title found: Just a moment...
2025-05-01 22:38:17 INFO     Challenge solved!
2025-05-01 22:38:17 INFO     Response in 17.909 s

captcha를 풀지 못했을 경우엔 아래처럼 출력됩니다.

2025-05-02 03:17:12 INFO     Incoming request => POST /v1 body: {'maxTimeout': 180000, 'cmd': 'request.get', 'url': 'https://example.com', 'proxy': {}}
2025-05-02 03:17:18 INFO     Challenge detected. Title found: Just a moment...
2025-05-02 03:20:13 ERROR    Error: Error solving the challenge. Timeout after 180.0 seconds.
2025-05-02 03:20:13 INFO     Response in 180.74 s

하필, Indexer를 추가할 때 실패하는 경우도 있기 때문에, 실패하는 경우에도 2~3번 더 눌러봐주면 성공하는 경우도 있습니다.

여기까지 설정했다면 토렌트 파싱을 위한 준비는 모두 끝났습니다.

다음 글에서는, Sonarr, Radarr 등을 이용하는 방법에 대해 적겠습니다.

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤