VPN 활용한 안전한 서버 운영
Why You Need a VPN?
다들 Torrent를 한두번씩 이용해 보셨을 겁니다.
Torrent의 개념을 보면 원본 파일을 제공하는 시더 (Seeder)가 시드 (Seed) 파일을 제공하고,
각각의 사용자가 각자 다른 시드 (Seed)을 부분적으로 나누어 다운로드 받아 서로 서로 공유해 주는 개념 입니다.
즉, 다운로드를 받고 있음과 동시에 다른이에게 업로드 (공유)를 해주는 개념 입니다.
여기서 문제는 시더, 다운로더, 업로더 모든 사람들의 IP 주소가 노출되며, 누가 어디서 무었을 하고 있는지를 마음만 먹으면 알아낼수 있습니다.
특히 저작권이 있는 자료라면 문제가 심각해 질 수 있습니다.
여기서 소개하려는 "haugene/transmission-openvpn"은 기본적으로는 Transmission이라는 Torrent 프로그램 이며,
모든 네트워크 통신을 Open VPN을 이용하여 torrent가 이용하는 공인 IP가 외부에 노출되지 않게 설계되어 있습니다.
또한 Kill Switch라는 중요한 기능을 제공하여 만일 VPN이 장애나 특정사유로 끊어 질 시 Transmission이 즉시 종료되어
IP가 절대 노출되지 않는 안전장치까지 지원해 주고 있습니다.
사전준비
완벽한 IP 보호를 위해서는 외부 VPN Server의 연결이 필요 합니다.
세계적으로 유명한 VPN Provider로는 ExpressVPN, Nord VPN 등등이 있으며,
여기서는 ExpressVPN을 예제로 설명 드립니다.
타 VPN을 사용하신다면 아래 Githgub에서 맞는 Parameter 값을 찾아 수정해 주셔야 합니다.
https://haugene.github.io/docker-transmission-openvpn/
https://haugene.github.io/docker-transmission-openvpn/supported-providers/
설치
[Torrent만 VPN 적용] haugene/transmission-openvpn 설치
본 장에서는 ExpressVPN을 이용한 방법으로 설명을 합니다. 설명이 부족한 부분은 아래 공식 홈페이지를 참고하세요.
공식홈페이지 : https://haugene.github.io/docker-transmission-openvpn/
Github : https://github.com/haugene/docker-transmission-openvpn
ExpressVPN이 아닌 다른 VPN을 이용하신다면 아래 링크를 참고하여 Yaml 문장을 수정해 주시면 됩니다.
- Supported Providers : https://haugene.github.io/docker-transmission-openvpn/supported-providers/
environment의 OPENVPN_PROVIDER 변수에 사용하시는 "Provider Name"의 "Config Value (OPENVPN_PROVIDER)" 값을 찾아 입력하시면 됩니다. - OpenVPN Config : https://github.com/haugene/vpn-configs-contrib
1) openvpn 디렉토리로 이동합니다.
2) 해당되는 VPN Provider 디렉토리로 이동합니다.
3) environment의 OPENVPN_CONFIG 변수에 원하시는 지역의 config 파일명을 입력합니다. (.ovpn은 생략 후 파일명만 입력 합니다.) - VPN 계정인증 : 각 VPN Provider마다 인증하는 방식이 다릅니다. VPN 제공사의 설명을 참고하세요.
먼저 볼륨을 Mapping할 디렉트로를 생성합니다. 이 디렉토리로 Torrent 파일을 올리고, 다운로드 경로가 설정 됩니다.
제 경우 "/volume2/Transmission" 이라는 디렉토리를 생성하고, 하위에 "config"와 "data" 디렉토리를 생성 합니다.
mkdir /volume2/Transmission
mkdir /volume2/Transmission/config
mkdir /volume2/Transmission/data
아래와 같이 "docker-compose.yml" 파일을 작성합니다.
version: '3.3'
services:
transmission-openvpn:
restart: always
cap_add:
- NET_ADMIN
volumes:
- '/volume2/Transmission/data/:/data' # incomplete, completed, torrentfile 디렉토리 볼륨입니다.
- '/volume2/Transmission/config/:/config' # json, log와 같이 config 파일이 있는 볼륨입니다.
environment:
- OPENVPN_PROVIDER=EXPRESSVPN # 사용하시는 VPN Provider 입니다. 위 본문을 참고하세요.
- OPENVPN_USERNAME=[설명1] # VPN Provider에서 요구하는 방식을 따르셔야 합니다.
- OPENVPN_PASSWORD=[설명1] # VPN Provider에서 요구하는 방식을 따르셔야 합니다.
- OPENVPN_CONFIG=my_expressvpn_south_korea_-_2_udp # 한국 서버를 예제로 합니다. .opvn은 생략하고 입력합니다.
- OPENVPN_OPTS=--inactive 3600 --ping 10 --ping-exit 60 # 킬스위치 기능입니다.
- LOCAL_NETWORK=192.168.1.0/24 # 사용하는 네트워크 대역대로 변경이 필요합니다. 예제는 192.168.1.*의 대역대를 가정했습니다.
- CREATE_TUN_DEVICE=true
- TZ=Asia/Seoul
- HEALTH_CHECK_HOST=google.com
- TRANSMISSION_WEB_UI=flood-for-transmission # 스킨 옵션 입니다. 가장 유명한 flood-for-transmission 스킨을 예제로 합니다.
- PUID=1026 #ssh에서 'id 계정명'으로 맞는 값을 찾아 입력
- PGID=100 #ssh에서 'id 계정명'으로 맞는 값을 찾아 입력
- TRANSMISSION_WATCH_DIR_ENABLED=true
- TRANSMISSION_WATCH_DIR=/data/torrentfile # 이 위치에 .torrent 파일을 넣으면 자동으로 다운로드가 시작되고 원본 파일은 .added로 변경 됩니다.
# 아래는 보안 옵션 입니다. Nginx Proxy Manager 접속 인증 같은 별도 접속 인증을 사용하신다면 생략을 권장 드립니다.
# 이유는 잦은 인증과정에서 브라우저 쿠키에 문제가 생겨 가끔 브라우저의 쿠키 초기화가 필요하기 때문입니다.
#- TRANSMISSION_RPC_AUTHENTICATION_REQUIRED=true
#- TRANSMISSION_RPC_USERNAME=webgui_id
#- TRANSMISSION_RPC_PASSWORD=webgui_pw
#- TRANSMISSION_RPC_HOST_WHITELIST="127.0.0.1,192.168.1.*"
logging:
driver: json-file
options:
max-size: 10m
ports:
- '9091:9091'
image: haugene/transmission-openvpn
만일 VPN Provider가 mullvad 일때는 아래를 yaml에 추가해 줍니다.
sysctls:
- "net.ipv6.conf.all.disable_ipv6=0"
[주의] 다운로드 디렉토리는 위 예제와 같이 "/data" 하나만 볼륨으로 맵핑하셔야 합니다. "/data" 볼륨하나만 맵핑해도 아래의 3개의 하위 디렉토리가 자동으로 생성됩니다. 만일 "completed"와 "incomplete"를 따로 볼륨으로 맵핑하신다면, 다운로드 완료 시 "incomplete"에서 "completed"로 이동과정이 copy (완료 후 소스 delete)로 동작되고, copy 과정에서 transmission 랙이 발생 됩니다.
[설명1] ExpressVPN 계정코드
OPENVPN_USERNAME : ExpressVPN 사용자명
OPENVPN_PASSWORD : ExpressVPN 비밀번호
이 값은 ExpressVPN 아래와 같이 확인 할 수 있습니다.
[설명2] LOCAL_NETWORK : 사용하시는 네트워크 대역대를 입력 합니다. 여러개 일 경우 "," 여러개를 지정할 수 있습니다.
예제 : "192.168.1.0/24" (CIDR 값을 사용해야 합니다.)
Docker를 실행 합니다.
docker-compose up -d
Transmission이 사용하는 IP가 정상적으로 VPN을 통한 IP인지 확인하기 위해 도커쉘에 접속해 아래 명령을 입력합니다.
curl ifconfig.me
설치를 마치면 "/volume1/Transmission/data" 디렉토리가 아래와 같이 구성 됐음을 확인 할 수 있습니다.
"completed" : 다운로드가 끝난 파일이 옮겨지는 디렉토리 입니다.
"incomplete" : 다운로드가 진행 중인 파일이 있는 디렉토리 입니다.
"torrentfile" : Transmission이 Watch 중인 디렉토리로 ".torrent" 파일을 이 디렉토리로 위치 시 바로 다운로드가 시작 됩니다.
다운로드 후 목록에서 자동 삭제하고 텔레그램 봇으로 다운로드 완료 상태를 안내하기 위해 작성한 스크립트로 다른장에서 별도 설명 드리겠습니다.
설치가 완료되면 "IP:9091"로 접속 합니다.
보안 옵션 미적용시 관리 페이지의 외부 노출이 걱정될 경우 Nginx Proxy Manager의 Proxy Host를 통해
"Access List"에 인증정보를 넣어 접속시에 2차 인증 절차를 추가하실 수 있습니다.
[NAS 전체 VPN 적용] 시놀로지 NAS VPN 적용 방법
VPN 설정
시놀로지 NAS기준 ExpressVPN을 가정한 방법을 설명 합니다.
1. DSM에 접속해 "제어판 > 네트워크 > 네트워크 인터페이스"로 들어가 "생성"을 누릅니다.
2. "VPN 프로파일 생성"을 선택하고 OpenVPN 항목을 선택 합니다.
3.아래와 같이 값을 입력하고 .ovpen에 VPN 제공사에서 다운받은 원하시는 지역의 .opvn 파일을 업로드 합니다.
4. 아래와 같이 고급 설정 값을 선택해 줍니다.
5. "제어판 > 네트워크 > 네트워크 인터페이스"에 들어가보면 아래와 같이 VPN 프로파일이 생성됐음을 확인할 수 있으며 상단의 "연결"을 클릭합니다.
자동 재연결 설정
이제 킬스위치 (VPN이 끊어질 시 자동 재연결)을 설정할 차례 입니다.
아래 내용으로 "killswitch.sh" 파일을 생성하고, DSM의 작업스케줄러에서 "생성", "예약된 작업", "사용자 정의 스크립트"로 들어가서 아래의 "bash /경로값/killswitch.sh"를 입력해 줍니다. (주기는 5분 주기로 설정해 줍니다.)
#-------------------------------------------------------------------------------
# 네트워크 작동 여부 확인
#-------------------------------------------------------------------------------
ping -c 1 8.8.8.8
if [ "$?" == "0" ] ; then
echo "네트워크가 정상 작동중입니다." >> log.txt
else
echo "네트워크가 정상 작동하지 않습니다. VPN 재연결을 시도합니다." >> log.txt
if [[ -f /usr/syno/etc/synovpnclient/l2tp/l2tpclient.conf ]]; then
L2TP_CONFIG=$(cat /usr/syno/etc/synovpnclient/l2tp/l2tpclient.conf)
else
L2TP_CONFIG=""
fi
if [[ -f /usr/syno/etc/synovpnclient/openvpn/ovpnclient.conf ]]; then
OPENVPN_CONFIG=$(cat /usr/syno/etc/synovpnclient/openvpn/ovpnclient.conf)
else
OPENVPN_CONFIG=""
fi
if [[ -f /usr/syno/etc/synovpnclient/pptp/pptpclient.conf ]]; then
PPTP_CONFIG=$(cat /usr/syno/etc/synovpnclient/pptp/pptpclient.conf)
else
PPTP_CONFIG=""
fi
#-------------------------------------------------------------------------------
# 설정 파일 확인
#-------------------------------------------------------------------------------
# 설정 파일 연결
CONFIGS_ALL="$L2TP_CONFIG $OPENVPN_CONFIG $PPTP_CONFIG"
# VPN 프로필 개수 확인
CONFIGS_QTY=$(echo "$CONFIGS_ALL" | grep -e '\[l' -e '\[o' -e '\[p' | wc -l)
# VPN 프로필이 하나일 때만 작동하도록 하기
if [[ $CONFIGS_QTY -eq 1 ]]; then
echo "[I] 1개의 VPN 프로필이 있음. 계속 진행..."
elif [[ $CONFIGS_QTY -gt 1 ]]; then
echo "[E] $CONFIGS_QTY 개의 VPN 프로필이 있음. 이 스크립트는 1개의 VPN 프로필까지만 지원이 가능함. 종료..."
exit 1
else
echo "[W] VPN 프로필이 존재하지 않음. VPN 프로필 생성 필요. 종료..."
exit 1
fi
#-------------------------------------------------------------------------------
# 변수 설정
#-------------------------------------------------------------------------------
PROFILE_ID=$(echo $CONFIGS_ALL | cut -d "[" -f2 | cut -d "]" -f1)
PROFILE_NAME=$(echo "$CONFIGS_ALL" | grep -oP "conf_name=+\K\w+")
PROFILE_RECONNECT=$(echo "$CONFIGS_ALL" | grep -oP "reconnect=+\K\w+")
if [[ $(echo "$CONFIGS_ALL" | grep '\[l') ]]; then
PROFILE_PROTOCOL="l2tp"
elif [[ $(echo "$CONFIGS_ALL" | grep '\[o') ]]; then
PROFILE_PROTOCOL="openvpn"
elif [[ $(echo "$CONFIGS_ALL" | grep '\[p') ]]; then
PROFILE_PROTOCOL="pptp"
fi
/usr/syno/bin/synovpnc kill_client
sleep 20
echo conf_id=$PROFILE_ID > /usr/syno/etc/synovpnclient/vpnc_connecting
echo conf_name=$PROFILE_NAME >> /usr/syno/etc/synovpnclient/vpnc_connecting
echo proto=$PROFILE_PROTOCOL >> /usr/syno/etc/synovpnclient/vpnc_connecting
/usr/syno/bin/synovpnc connect --id=$PROFILE_ID
sleep 20
#-------------------------------------------------------------------------------
# VPN 연결 여부 다시 확인
#-------------------------------------------------------------------------------
if [[ $(/usr/syno/bin/synovpnc get_conn | grep Uptime) ]]; then
echo "[I] VPN이 성공적으로 재접속됨. 종료..." >> log.txt
exit 1
else
echo "[E] VPN 재접속에 실패. 종료..." >> log.txt
exit 1
fi
sleep 20
echo conf_id=$PROFILE_ID > /usr/syno/etc/synovpnclient/vpnc_connecting
echo conf_name=$PROFILE_NAME >> /usr/syno/etc/synovpnclient/vpnc_connecting
echo proto=$PROFILE_PROTOCOL >> /usr/syno/etc/synovpnclient/vpnc_connecting
/usr/syno/bin/synovpnc connect --id=$PROFILE_ID
sleep 20
fi
외부 DSM 접속 허용
VPN 외부에서 DSM에 접속하기 위해서는 아래와 같이 다중게이트웨이 설정이 필요합니다.
1. DSM에 접속해 "제어판 > 네트워크 > 일반"으로 들어가 "고급설정"을 선택 합니다.
2. "다중 게이트웨이 활성화"를 체크 합니다.
3. NAS의 IPv4를 DHCP가 아닌 수동으로 IP를 설정해 줍니다. 예를 들어 제 경우 "192.168.1.200"으로 설정했습니다.
4. "제어판 > 네트워크 > 일반"에서 기본 게이트웨이 옆 "편집"을 눌러줍니다.
5. "서비스 순서"를 보면 사용하는 네트워크와 VPN네트워크가 보입니다. 순서를 조정해 VPN네트워크가 상단해 위치하게 조정합니다. 반드시 상단에 있어야 VPN 뒤에 실제 사용 네트워크를 위치시킬 수 있습니다.
손쉬운 사용
VPN 우회 접속 동작여부 확인 방법
VPN이 정상적으로 작동하고 있는지에 대한 확인 방법입니다.
1. https://ipleak.net/ 에 접속한 후 아래에 있는 "Torrent Address detection"의 "Activate"를 클릭합니다.
2. "This Magnet Link"를 마우스로 우클릭 한후 "링크 주소 복사"를 선택 합니다. (이 브라우저의 창을 닫으시면 안됩니다.)
3. Transmission GUI로 접속한 후 "Add Torrents"에서 복사된 Magnet 주소를 추가해 줍니다.
4. 다시 https://ipleak.net/ 브라우저 화면으로 이동하면 현재 가상 torrent를 받고 있는 IP가 나옵니다.
이 IP가 사용하는 공인 IP가 아닌 VPN에서 제공받은 IP라면 정상작동하고 있는 것입니다. 공인 IP가 나오면 VPN이 동작하지
않음을 의미 합니다.
5. 옆에 있는 아래 화면의 "Activate"를 누르시면 구글앱에서 받고 있는 IP가 어느지역인지 지도로 표시 되기도 합니다.
6. Test가 끝났으면 추가한 torrent를 수동으로 지워주셔야 합니다.
다운로드 완료 알림 및 다운로드목록 자동 삭제
다운로드가 완료되면 텔레그램봇으로 다운로드 완료 여부를 안내하고. Transmision에서 다운로드 완료 항목에 대한
리스트를 자동삭제하는 스크립입니다.
"tr.sh"라는 파일명으로 아래 스크립트를 작성 합니다.
텔레그램봇에 대한 부분은 설명을 생략하며 구글을 검색하시면 많은 정보들이 있습니다.
(텔레그램에 봇파더 설정 후 Token 값과 CHAT_ID 값을 얻으셔야 합니다....)
1. 도커 콘솔에 접속 합니다.
docker exec -it 컨테이너명 /bin/bash
또는 Portainer를 이용하면 편합니다.
2. "/config"로 이동해 "tr.sh"라는 파일을 생성합니다.
cd config
touch tr.sh
3. nano를 이용해 "tr.sh" 내용을 작성합니다.
nano tr.sh
입력해야할 내용은 아래와 같습니다. 내역 작성 후 ctrl + x 로 빠져나가고 엔터를 쳐줍니다.
#!/bin/sh
# telegram bot
SERVER="9091"
TOKEN='텔레그램_TOKEN'
CHAT_ID="텔레그램챗_ID"
URL='https://api.telegram.org/bot'$TOKEN
MSG_URL=$URL'/sendMessage?chat_id='
sleep 1s
# torrent remove
TORRENTLIST=`transmission-remote $SERVER --list | sed -e '1d;$d;s/^ *//' | cut -s -d " " -f 1`
for TORRENTID in $TORRENTLIST
do
FILENAME=`/usr/bin/transmission-remote $SERVER --torrent $TORRENTID --info | grep Name | cut -c 9-60`
DL_COMPLETED=`transmission-remote $SERVER --torrent $TORRENTID --info | grep "Percent Done: 100%"`
STATE_STOPPED=`transmission-remote $SERVER --torrent $TORRENTID --info | grep "State: Seeding\|Stopped\|Finished\|Idle"`
if [ "$DL_COMPLETED" ] && [ "$STATE_STOPPED" ]; then
transmission-remote $SERVER --torrent $TORRENTID --remove
# telegram message send
/usr/bin/curl --data-urlencode "text=Download Complete : $FILENAME" "$MSG_URL"$CHAT_ID"&"
fi
done
Log를 남기고 싶으면 아래 문장을 끝부분에 추가해 주시면 됩니다.
LOG_FILE=/config/tr.log
transmission-remote $SERVER --list >>$LOG_FILE
4. 도커에서 "tr.sh"를 실행할 수 있는 권한을 부여해 줍니다.
chmod +x tr.sh
5. 도커 콘솔을 빠져나갔니다.
6. 작성한 "tr.sh"를 Transmission에 등록이 필요 합니다. Transmission GUI 페이지로 접속 후 "Settings"로 이동합니다.
"Torrets" 탭을 보면 "Run script when complete"라는 항목이 있고, 이 옵션을 활성화 합니다.
활성화 후 작성된 "/config/tr.sh"를 등록해 주시고, 도커를 재시작 합니다.
또는 "settings.json"에 아래 내용출 추가하여 "tr.sh" 파일을 적용 시켜 줄수도 있습니다.
"script-torrent-done-enabled": true,
"script-torrent-done-filename": "/config/tr.sh",
JSON을 수정할 때 아래도 같이 해주시며 좋습니다.
"ratio-limit": 0,
"ratio-limit-enabled": true,
"blocklist-enabled": true,
"blocklist-url": "http://list.iblocklist.com/?list=bt_level1&fileformat=p2p&archiveformat=gz",
Docker를 이용하신다면 JSON 수정시 컨테이너를 중지 후 JSON를 수정해 주셔야 Docker 재시작 시에도 변경값이 유지 됩니다. 중지를 안하고 수정하면 Docker 재시작이 이전 내용으로 원복 됩니다.
다운로드 완료 후 자동 파일 처리
아래는 다운로드가 완료된 파일에 대해 자동으로 네이밍, 이동을 시켜주는 스크립트 입니다.
편의에 맞게 수정 후 시놀로지의 "스케줄러"에 등록하여 주기적으로 실행 시켜주면 됩니다.
#!/bin/bash
# .added 파일 삭제
rm -f /volume2/Transmission/torrentfile/*.added &
# 파일명의 특정 문자 삭제
find /volume2/Transmission/completed -name "*abcde*" | sed -e 'p' -e "s/abcde//g" | xargs -n 2 mv
sleep 1s
# txt, nfo 파일 삭제
find /volume2/Transmission/completed -iname "*.txt" -print0 | xargs --null rm -f
find /volume2/Transmission/completed -iname "*.nfo" -print0 | xargs --null rm -f
find /volume2/Transmission/completed -iname "*.html" -print0 | xargs --null rm -f
find /volume2/Transmission/completed -iname "*.url" -print0 | xargs --null rm -f
sleep 1s
# rar, zip, egg 파일 이동
\find /volume2/Transmission/completed -iname "*.rar" -print0 | xargs --null mv -t /volume2/Temp_Vol2/
\find /volume2/Transmission/completed -iname "*.zip" -print0 | xargs --null mv -t /volume2/Temp_Vol2/
\find /volume2/Transmission/completed -iname "*.egg" -print0 | xargs --null mv -t /volume2/Temp_Vol2/
sleep 1s
# 빈폴더 삭제
find /volume2/Transmission/completed/* -empty | xargs rm -r
sleep 1s
# 모든파일 GD Sync로 이동
mv -f /volume2/Transmission/completed/* /volume2/'GD Sync'/
[설명]
1. "Transmission > torrentfile" 디렉토리에 ".torrent" 파일을 업로드하면 자동으로 torrent 다운로드 리스트에 등록을하고 이
".torrent" 파일은 ".torrent.added"로 변경이 됩니다, 이후 이 파일은 쓸모가 없으므로 삭제시키는 시크립트 입니다.
2. 다운로드가 완료된 파일명을 보면 시더가 자신들을 홍보하려는 특정 문구들이 들어갈때가 있습니다. 다운로드 완료 후 이 부분을
삭제 시키는 스크립트 이며, 예제는 파일명에서 "abcde"를 찾아 삭제시키는 스크립드 입니다.
3. 다운로드가 완료된 파일에는 txt, nfo와 같이 필요가 없는 파일이 있을 수 있습니다. 원하는 파일 확장자를 삭제시키는 스크립트
입니다.
4. 다운로드가 완료된 파일에 특정 압축 파일이 있을 시 지정된 디렉토리로 자동 이동시키는 스크립트 입니다.
5. 위 처리가 완료 된 자료를 원하는 특정 위치로 이동시키는 스크립트 입니다.