시놀로지 나스 (Synology NAS)에서 DDNS 이용을 위한 스크립트 작성

예전에 작성했던 DNSZi에 DDNS 자동 업데이트 스크립트는 작업스케쥴러에 정해진 시간에만 업데이트가 이루어진다는 단점이 있었다. 만약 하루에 한 번 업데이트를 하도록 설정해놓으면, 업데이트 시점 바로 뒤에 아이피가 바뀐 경우 하루종일 아이피 업데이트가 이루어지지 않는다는 문제가 있다. 시놀로지 제어판의 외부 액세스 설정에 있는 DDNS에 DNSZi를 위한 설정을 추가하여 사용하면, 혹시나 아이피 변경 시 자동으로 감지하여 업데이트가 이루어질까 기대해 보았지만, 생성 시기를 기준으로 24시간마다 업데이트 되는 설정이었다. 작업 스케쥴러 자체를 짧은 간격 업데이트 하도록 해 놓는 방법이 있긴 하지만, 업데이트 주기를 짧게 하면 DDNS 서비스 제공 업체에서 블럭을 하는 등의 문제가 생기지 않을까 하는 걱정도 조금 생기는 것도 사실이다. 내 경우는 도메인과 네임서버 관리를 위해 AWS Route 53을 이용 중인데, 아이피 변경이 언제 될지도 모르고 빈번하게 일어나는 일도 아닌데 쓸데없이 AWS 리소스를 낭비하는 것도 별로라는 생각이 들었다.

아이피 변경이 생기면 DDNS 서버에 아이피를 업데이트 하고, 아이피 변경이 없다면 그것이 하루가 되었든 일주일이 되었든 업데이트를 하지 않는 것이 이 스크립트를 이용하는 목적이다. DDNS 서비스를 제공하는 곳이 10분마다 아이피 업데이트 요청을 해도 아무상관 없는 곳이라면 여기서 소개하는 이 스크립트는 그냥 쓰레기일 뿐이다.

스크립트의 흐름은 다음과 같다.

  1. 현재 나스의 외부아이피와 도메인에 연결되어있는 아이피를 확인
  2. 두 아이피가 일치하면 스크립트 종료
  3. 일치하지 않으면 업데이트 시도
  4. 업데이트 실패 시 다음 확인 시점에 다시 시도
  5. 1-4 무한 반복

아래 스크립트는 AWS Lambda에 만들어 놓은 함수에 필요한 변수를 기준으로 작성된 것이다.

#!/bin/sh
myDomain="도메인주소"
awsUsername="람다 함수에 지정한 유저명"
awsPassword="람다 함수에 지정한 비밀번호"
ipCurrent=$(curl bot.whatismyipaddress.com)
ipTarget=$(nslookup $myDomain | grep -A 1 $myDomain | grep "Address" | awk '{print $2}')
echo "${myDomain}'s IP is ${ipTarget}"
echo "Your current IP is ${ipCurrent}"
if [ "${ipTarget}" = "" ] || [ "${ipTarget}" != "${ipCurrent}" ]; then
	echo "외부 아이피가 변경되었습니다."
	sleep 5
	echo "${myDomain}에 새로운 아이피를 업데이트 합니다."
	ipUpdating=$(wget -q -O - "https://API게이트웨이엔드포인트이름.execute-api.AWS리전.amazonaws.com/default/람다함수명?hostname=${myDomain}&ip=${ipCurrent}&username=${awsUsername}&password=${awsPassword}")
	if [ ${ipUpdating} = "good" ]; then
		sleep 5
		echo "업데이트 후 확인까지 1분만 기다려 주세요."
		sleep 60
		ipUpdated=$(nslookup $myDomain | grep -A 1 $myDomain | grep "Address" | awk '{print $2}')
		echo "${myDomain}(${ipUpdated}) : 성공적으로 업데이트 되었습니다."
	else
		echo "업데이트를 실패했습니다."
	fi
else
	echo "외부 아이피가 아직 변경되지 않았습니다."
fi

60초를 기다리도록 한 이유는 도메인의 A레코드에 대한 리소스 레코드 캐시 TTL (Time to Live)를 60초로 해놓았기 때문에 60초가 지나야 반영이 되기 때문이다. 설정된 TTL 에 따라 아이피 업데이트 요청을 하였더라도 아이피 변경 확인이 안 될 수 있기 때문에 60초를 기다린 후 확인하도록 해 놓았다. 사실 업데이트를 실패할 이유가 없기 때문에 확인하는 과정은 무의미하다고 볼 수도 있을 것이다.

DNSZi에서는 업데이트 성공 시 서버에서 HTTP 200 응답을 보내주지 않기 때문에 응답코드를 통해 업데이트 성공 여부를 확인하는 과정을 완전히 없애거나, 고급설정에 있는 TTL을 5분으로 바꾸고, 업데이트 후 5분이 경과한 다음 확인하는 방식으로 하는 편이 낫다.
그런데 이 스크립트를 10분마다 실행하도록 한다면, 사실 5분 후에 확인하는 것이 의미가 없기 때문에 업데이트 성공 여부를 확인하는 과정을 아예 빼버리는 편이 나을 것이다. 다음 주기에 업데이트 여부를 확인할 수 있기 때문이다. 따라서 DNSZi 용으로 스크립트를 짠다면 다음과 같이 할 수 있다.

#!/bin/sh
myDomain="도메인주소"
subDomain=""
userName="유저명"
authKey="인증키"
ipCurrent=$(curl bot.whatismyipaddress.com)
ipTarget=$(nslookup $myDomain | grep -A 1 $myDomain | grep "Address" | awk '{print $2}')
echo "${myDomain}'s IP is ${ipTarget}"
echo "Your current IP is ${ipCurrent}"
if [ "${ipTarget}" = "" ] || [ "${ipTarget}" != "${ipCurrent}" ]; then
	echo "외부 아이피가 변경되었습니다."
	sleep 5
	echo "${myDomain}에 새로운 아이피를 업데이트 합니다."
	ipUpdating=$(wget -q -O - "http://ddns.dnszi.com/set.html?user=${userName}&auth=${authKey}&domain=${myDomain}&record=${subDomain}")
else
	echo "외부 아이피가 아직 변경되지 않았습니다."
fi

한가지 주의할 점은 비밀번호나 인증키에 &, #, ! 같은 특수문자가 들어가는 경우 에러가 날 수 있다. 이럴 때에는 비밀번호를 HTML URL 인코더를 이용하여 특수문자를 엔티티(entity) 코드로 변경 후 입력해주어야 한다. 변경을 자동으로 해주는 곳은 금방 찾을 수 있다. 아래 사이트를 이용하면 바로 변환 가능!

https://www.urlencoder.io

예를 들어 인증키가 #@!&123asdf 라면 스크립트 상의 인증키 자리에 %23%40%21%26123asdf 라고 입력해야 한다.

또한 스크립트에서 주의해야할 점은 띄어쓰기. 위 스크립트에서 보이는 띄어쓰기를 유지하지 않으면 오류가 날 것이다. 수정해서 사용할 때에는 변수 설정하는 부분과 조건 문 내에서의 띄어쓰기를 유의해야 한다.

ipCurrent=$(curl bot.whatismyipaddress.com) 를 보면 명령을 실행한 값을 ipCurrent 변수에 넣는 것인데, 여기서 curl bot.whatismyipaddress.com 대신에 외부 아이피를 확인할 수 있는 다른 그 어떤 명령어를 집어 넣어도 무관하다. 그러나 결과값은 딱 아이피만 나오도록 해야한다.

만약 구글을 통해 외부아이피를 확인하고자 한다면 다음과 같이 할 수 있다.

ipCurrent=$(curl https://www.google.com/search?q=my\+ip\+address | grep -n "Client IP" | grep -Eo '[[:digit:]]{1,3}[.][[:digit:]]{1,3}[.][[:digit:]]{1,3}[.][[:digit:]]{1,3}')

아니면 네이버를 통해서도 외부 아이피를 가져올 수 있다.

ipCurrent=$(curl https://search.naver.com/search.naver?query=내아이피 | grep -n "이 컴퓨터의 IP주소는" | grep -Eo '[[:digit:]]{1,3}[.][[:digit:]]{1,3}[.][[:digit:]]{1,3}[.][[:digit:]]{1,3}'

구글이나 네이버를 통해 외부아이피를 확인하면 1분마다, 아니 10초마다 확인해도 서버로부터 블럭당할 일은 없을 것이라고 생각된다. 또한 내 아이피를 확인하는 기능이 사라질 가능성도 없을 것이라 생각되기 때문에, 외부아이피 확인에 구글이나 네이버를 사용하는 것도 좋을 것 같다는 생각이다. 아이피를 가져오는 방식은 간단하다. 터미널에서 curl을 이용하여 구글에서 my ip address를 검색하면 출력되는 결과에서 Client IP 라는 부분을 찾아서 아이피만 가져오는 것. 네이버 또한 내아이피 를 검색하면 출력되는 결과에서 이 컴퓨터의 IP주소는 이라는 부분을 찾아서 아이피만 따오는 것이다. 이런 방식으로 외부 아이피를 검색할 수 있는 어떤 사이트든지간에 아이피를 변수에 넣을 수 있다.

완성된 스크립트를 작업 스케쥴러에 넣고 5분이든 10분이든 30분이든 짧은 주기로 실행되게 해 놓으면 끝.

이 스크립트는 아이피가 변경되면 최대한 빨리 아이피가 업데이트 되어야 하는 상황, 그리고 나스에 도메인이 여러개 물려 있을 때 빛을 발한다. 도메인 하나만 체크를 하고 아이피가 변경이되면 한 번에 여러 도메인에 아이피를 업데이트 해버리도록 하면 되기 때문이다.

(서버 이전 준비 중이기 때문에 생각 나는대로 막 써놓는 중. 서버 이전 후 워드프레스 테마도 바꿀 예정이라 추후 내용도 다듬고 테마에 맞게 수정할 예정)

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다

이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.