[install] powerdns 설치하기

[markdown]
## Private DNS? POWERDNS!

DB를 마스터/슬레이브로 운영하고 있을 경우, 마스터 디비가 죽으면 슬레이브 디비를 마스터로 승격시켜주는 녀석들이 있다.(MMM, MHA등등) 그런데, 보통 디비를 바라보고 있는 클라이언트는 보통 아이피나 도메인을 통해서 디비를 바라보고 있을 것이다. 그런 상황에서 슬레이브가 마스터로 승격되어 봤자 클라이언트들은 죽어있는 마스터를 바라보게 마련이다.

이런경우 슬레이브를 마스터로 승격 시켜주는 것과 별개로 아이피나 도메인도 같이 바꿔줘야 하는데,
아이피를 바꾸려면 가상아이피라는 녀석을 써야한다. 그런데 지금 사용하는 클라우드 서비스에서는 가상아이피를 지원하지 않는관계로,어쩔 수 없이(?!) 도메인을 써야하는 상황이었다.

어쨌든 클라이언트들이 모르게 도메인만 슬쩍 바꿔버리면, 클라이언트는 마스터가 죽었는지 살았는지 모를테니, dns서버라는 녀석을 도입하기로 했다. 그중에 제일 간편해 보이는 녀석이 powerdns 였는데..(설치는 간편하지 않다) web api도 지원하고 해서 실제 서비스에 도입해서 사용하고 있다.

Private DNS라고 쓰긴했지만, 내가 그렇게 쓴다는거지, Public DNS 서버로 못쓴다는 얘기는 아니다.

궁금한 사람은 [powerdns](https://doc.powerdns.com) 문서 페이지와 [github](https://github.com/PowerDNS/pdns)에서 더 많은 정보를 볼 수 있을 것이다.

### MariaDB설치
PowerDNS는 벡엔드로 Mysql을 사용할 수 있는데, 나는 MariaDB를 사용하기로 했다. (이유가 있었던것 같은데, 까먹었다.)
여튼 설치를 해보자. root 유저로 들어가서 실행해야한다.

“`
# apt-get update && apt-get upgrade -y
# apt-get install software-properties-common
# apt-key adv –recv-keys –keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db
# add-apt-repository ‘deb http://ftp.kaist.ac.kr/mariadb/repo/5.5/ubuntu trusty main’
# apt-get -y install libaio1 libdbd-mysql-perl libdbi-perl libmariadbclient18 libmysqlclient18 libnet-daemon-perl libplrpc-perl mariadb-client-5.5 mariadb-client-core-5.5 mariadb-common mysql-common mariadb-server mariadb-server-5.5 mariadb-server-core-5.5
“`

### mariadb 보안 적용
보안을 위해서 하는 건데, 테스트환경이라면 굳이 하지 않아도 된다.

“`
$ mysql_secure_installation
“`

위의 코드를 실행하면 아래와 같이 물어보는데, 읽어보고 yes를 해주면 된다.

“`
Change the root password? [Y/n] n
Remove anonymous users? [Y/n] y
Disallow root login remotely? [Y/n] y
Remove test database and access to it? [Y/n] y
Reload privilege tables now? [Y/n] y
Thanks for using MariaDB!
“`

### powerdns 유저 생성및 데이터베이스와 테이블 생성

powerdns_init.sql이라는 파일을 하나 생성하고 아래의 내용을 채워넣자. (*패스워드는 알아서 잘 바꿔주자. 복붙금지!*)

“`
CREATE DATABASE powerdns;
GRANT ALL ON powerdns.* TO ‘pdns’@’localhost’ IDENTIFIED BY ‘password’;
FLUSH PRIVILEGES;
USE powerdns;
CREATE TABLE domains (
id INT AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
master VARCHAR(128) DEFAULT NULL,
last_check INT DEFAULT NULL,
type VARCHAR(6) NOT NULL,
notified_serial INT DEFAULT NULL,
account VARCHAR(40) DEFAULT NULL,
PRIMARY KEY (id)
) Engine=InnoDB;

CREATE UNIQUE INDEX name_index ON domains(name);
CREATE TABLE records (
id INT AUTO_INCREMENT,
domain_id INT DEFAULT NULL,
name VARCHAR(255) DEFAULT NULL,
type VARCHAR(10) DEFAULT NULL,
content VARCHAR(64000) DEFAULT NULL,
ttl INT DEFAULT NULL,
prio INT DEFAULT NULL,
change_date INT DEFAULT NULL,
disabled TINYINT(1) DEFAULT 0,
ordername VARCHAR(255) BINARY DEFAULT NULL,
auth TINYINT(1) DEFAULT 1,
PRIMARY KEY (id)
) Engine=InnoDB;

CREATE INDEX nametype_index ON records(name,type);
CREATE INDEX domain_id ON records(domain_id);
CREATE INDEX recordorder ON records (domain_id, ordername);

CREATE TABLE supermasters (
ip VARCHAR(64) NOT NULL,
nameserver VARCHAR(255) NOT NULL,
account VARCHAR(40) NOT NULL,
PRIMARY KEY (ip, nameserver)
) Engine=InnoDB;
CREATE TABLE comments (
id INT AUTO_INCREMENT,
domain_id INT NOT NULL,
name VARCHAR(255) NOT NULL,
type VARCHAR(10) NOT NULL,
modified_at INT NOT NULL,
account VARCHAR(40) NOT NULL,
comment VARCHAR(64000) NOT NULL,
PRIMARY KEY (id)
) Engine=InnoDB;

CREATE INDEX comments_domain_id_idx ON comments (domain_id);
CREATE INDEX comments_name_type_idx ON comments (name, type);
CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
CREATE TABLE domainmetadata (
id INT AUTO_INCREMENT,
domain_id INT NOT NULL,
kind VARCHAR(32),
content TEXT,
PRIMARY KEY (id)
) Engine=InnoDB;

CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind);
CREATE TABLE cryptokeys (
id INT AUTO_INCREMENT,
domain_id INT NOT NULL,
flags INT NOT NULL,
active BOOL,
content TEXT,
PRIMARY KEY(id)
) Engine=InnoDB;

CREATE INDEX domainidindex ON cryptokeys(domain_id);
CREATE TABLE tsigkeys (
id INT AUTO_INCREMENT,
name VARCHAR(255),
algorithm VARCHAR(50),
secret VARCHAR(255),
PRIMARY KEY (id)
) Engine=InnoDB;

CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
“`

디비생성후에 다음의 커맨드로 mariadb에 반영해주자.

“`
$ mysql -u root -p < powerdns_init.sql ``` ### Powerdns설치 (4.0.X) /etc/apt/source.list에 아래한줄을 추가한다. ``` # add-apt-repository 'deb [arch=amd64] http://repo.powerdns.com/ubuntu trusty-auth-40 main' ``` 그리고 `/etc/apt/preferences.d/pdns` 파일을 생성하고 아래 내용을 추가한다. ``` # touch /etc/apt/preferences.d/pdns # echo -e "Package: pdns-*\nPin: origin repo.powerdns.com\nPin-Priority: 600" | sudo tee /etc/apt/preferences.d/pdns ``` 위의 것들을 하면 아래의 명령어로 실행할 수 있다. ``` # curl https://repo.powerdns.com/FD380FBB-pub.asc | sudo apt-key add - # apt-get update && apt-get upgrade # apt-get install -y pdns-server pdns-backend-mysql # rm /etc/powerdns/pdns.d/* ### 기존의 설정 삭제 꼭 해줘야한다. ``` 설치시에 아래와 같은 에러가 난다면, 아래의 명령을 실행해주자. `# apt-get -f purge -y mysql-client` ``` You might want to run 'apt-get -f install' to correct these. The following packages have unmet dependencies: mariadb-server : Depends: mariadb-server-5.5 (= 5.5.49+maria-1~trusty) but 5.5.49-1ubuntu0.14.04.1 is installed E: Unmet dependencies. Try using -f. ``` 설치시 아래와 같은 화면이 나오는데, No를 선택해주자. [![](http://gyus.me/wp-content/uploads/2016/05/pdns1-1-1.png)](http://gyus.me/wp-content/uploads/2016/05/pdns1-1-1.png) 그리고 /etc/powerdns/pdns.d/pdns.local.gmysql.conf 파일을 아래와같이 수정해 주어야 한다. 디비의 유저와 패스워드를 잘 바꿔서 넣어주자. ``` ### MySQL Configuration file launch=gmysql gmysql-host=localhost gmysql-dbname=디비명 gmysql-user=유저명 gmysql-password=

###수정후 mariadb를 재시작해준다.
$ service pdns restart
“`

### pdns가 잘동작하는지 테스트
netstat와 dig를 사용했을 때 아래와 비슷하게 나와야 한다.

“`
$ netstat -nlp |grep pdns
tcp 0 0 0.0.0.0:53 0.0.0.0:* LISTEN 6793/pdns_server-in
udp 0 0 0.0.0.0:53 0.0.0.0:* 6793/pdns_server-in
unix 2 [ ACC ] STREAM LISTENING 46518 6789/pdns_server /var/run/pdns.controlsocket
$ dig @localhost
; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> @localhost
; (3 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28331 ;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 2800 ;; QUESTION SECTION: ;. IN NS ;; Query time: 2 msec ;; SERVER: 127.0.0.1#53(127.0.0.1) ;; WHEN: Thu Mar 10 20:06:16 KST 2016 ;; MSG SIZE rcvd: 29 ``` ### Poweradmin 설치 powerdns에는 Poweradmin 이라는 php관리 페이지가 따로 있다. 설치가 어렵지않고, 설치하면 많은 기능을 웹기반으로 쉽게사용할 수 있으니 설치하도록 하자. (커맨드라인으로 굳이하겠다면 말리지는 않음) ``` $ apt-get install -y unzip apache2 gettext libapache2-mod-php5 php5 php5-common php5-curl php5-dev php5-gd php-pear php5-imap php5-ming php5-mysql php5-xmlrpc php5-mhash php5-mcrypt $ pear upgrade pear/PEAR $ pear install DB $ pear install pear/MDB2#mysql ### php 모듈 활성화 $ php5enmod mcrypt $ service apache2 restart $ cd tmp $ wget https://github.com/poweradmin/poweradmin/archive/master.zip -O poweradmin.zip $ unzip poweradmin.zip $ mv poweradmin-master /var/www/html/poweradmin ``` ###Poweradmin 설정 설치가 끝났으니 아래의 주소로 들어가서 설정을 하도록하자. http://#{server_ip}/poweradmin/install/ [![](http://gyus.me/wp-content/uploads/2016/05/pdns2-1-1.png)](http://gyus.me/wp-content/uploads/2016/05/pdns2-1-1.png) 들어가면 위와 같은 언어 선택 화면이 나온다. 대부분 영어겠지만, 익숙한 언어를 선택하고 Go to step2로 가자. 나는 영어를 선택했다. [![](http://gyus.me/wp-content/uploads/2016/05/pdns3-1-1.png)](http://gyus.me/wp-content/uploads/2016/05/pdns3-1-1.png) 스텝2는 별거 없다. 바로 Go to step3 를 누르자. [![](http://gyus.me/wp-content/uploads/2016/05/pdns4-1-1.png)](http://gyus.me/wp-content/uploads/2016/05/pdns4-1-1.png) Step3에서는 DB와 Poweradmin에 대한 설정을 하게 된다. 적절한 값을 넣도록 하자. ``` Username : DB와 연결할 유저명을 적으면 된다. 우리는 위에서 pdns라는 유저를 생성했다. Password : 디비패스워드 Database type : MySQL Hostname : localhost DB Port : 3306 Database : powerdns Poweradmin administrator password : 파워애드민에서 사용할 관리자 패스워드 ``` [![](http://gyus.me/wp-content/uploads/2016/05/pdns5-1-1.png)](http://gyus.me/wp-content/uploads/2016/05/pdns5-1-1.png) Username : poweradmin의 관리자명 Password: poweradmin의 관리자 패스워드 hostmaster.unixmen.local – SOA레코드를 만들때 없을경우 기본값으로 들어가는 값. 다음과 같은 방식이 된다. “hostmaster.example.net”. ns1.unixmen.local – 템플릿을 만들때 주 네임서버로 설정되는 값. 요런식으로 적는다. “ns1.example.net”. ns2.unixmen.local – 템플릿을 만들때 주 네임서버로 설정되는 값. 요런식으로 적는다. “ns2.example.net”. 잘 적은뒤에 Step5로 가자. [![](http://gyus.me/wp-content/uploads/2016/05/pdns6-1-1.png)](http://gyus.me/wp-content/uploads/2016/05/pdns6-1-1.png) Step5에서는 poweradmin에서 powerdns의 유저가 디비에 접근할때의 권한을 SELECT, INSERT, UPDATE, DELETE 만주라고 권장하고 있다. 화면에 있는 내용을 mysql에서 실행해주면 된다. [![](http://gyus.me/wp-content/uploads/2016/05/pdns7-1-1.png)](http://gyus.me/wp-content/uploads/2016/05/pdns7-1-1.png) Step6에서는 poweradmin의 설정파일을 "../inc/config.inc.php" 경로에 만들어라고 말을하고 있다. 해당 내용을 복사해서 만들어주자. 설정파일에 db_user가 admin 이라고 되어있는데, 디비에 유저가 생성되지 않은 경우가 있으므로 그경우에는 기존의 'pdns'유저로 해당 파일의 설정을 변경해주자. 나 같은 경우는 "/var/www/html/poweradmin/inc/config.inc.php" 경로에 생성을 했다. 7단계로 가자. 이게 설치는 거의 다되어 간다! [![](http://gyus.me/wp-content/uploads/2016/05/pdns8-1-1.png)](http://gyus.me/wp-content/uploads/2016/05/pdns8-1-1.png) 7단계에서는 DDNS를 사용하고 싶으면 mod_rewrite를 활성화 하라고 하고 있다. 그리고 반드시 "install" 디렉토리를 삭제하라고 한다. 다음으로 poweradmin의 "install" 디렉토리를 반.드.시. 삭제해야한다. (나는 사실 이름만 바꿨다. 실서버에서는 이렇게 하면 안된다.) [![](http://gyus.me/wp-content/uploads/2016/05/pdns9-1-1.png)](http://gyus.me/wp-content/uploads/2016/05/pdns9-1-1.png) http://server_ip/poweradmin 으로 들어왔을 때 위와 같은 화면이 나오면 설치는 성공이다. Username과 Password에 위에서 설정한 값을 넣으면 Poweradmin에 접근이 가능하다. 이제 설치는 끝이다. ### DNS서버 설정 [![](http://gyus.me/wp-content/uploads/2016/05/pdns1-10-1-1.png)](http://gyus.me/wp-content/uploads/2016/05/pdns1-10-1-1.png) Add Master Zone을 추가하자. [![](http://gyus.me/wp-content/uploads/2016/05/pdns1-11-1-1.png)](http://gyus.me/wp-content/uploads/2016/05/pdns1-11-1-1.png) Zone name에 'pkpk.com' 등과 같은 사용하고 싶은 주도메인을 입력하고 Add zone 을 눌러서 추가해준다. [![](http://gyus.me/wp-content/uploads/2016/05/pdns1-12-1-1.png)](http://gyus.me/wp-content/uploads/2016/05/pdns1-12-1-1.png) List zones에 들어가면 위와같은 화면이 나오고 빨간 동그라미친 곳에 들어가면 A record등을 추가할 수 있다. [![](http://gyus.me/wp-content/uploads/2016/05/pdns1-13-1-1.png)](http://gyus.me/wp-content/uploads/2016/05/pdns1-13-1-1.png) `alpha.pkpk.com` 이라는 도메인을 요청하면 `192.168.0.8`로 응답을 주도록 세팅을 했다. ### DNS서버 테스트 이제 잘되는지 테스트를 해보자. 먼저는 powerdns가 설치된 서버에서 실행을 해보자. 다음과 같은 코드를 실행해보자 `$ dig alpha.pkpk.com A @127.0.0.1` 아래와 비슷한 결과가 나오면 성공이다. ``` ; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> alpha.pkpk.com A @127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18817 ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 2800 ;; QUESTION SECTION: ;alpha.pkpk.com. IN A ;; ANSWER SECTION: alpha.pkpk.com. 5 IN A 192.168.0.8 ;; Query time: 0 msec ;; SERVER: 127.0.0.1#53(127.0.0.1) ;; WHEN: Thu Mar 10 21:21:09 KST 2016 ;; MSG SIZE rcvd: 59 ``` 이제 다른 서버에 DNS서버를 연결해서 테스트해보자. ``` ### ubuntu14.04에서 실행했다. root권한으로 실행해야한다. $ echo "nameserver dnsserver의 아이피" >> /etc/resolvconf/resolv.conf.d/head
$ service networking restart
$ sudo resolvconf -u
“`

설정이 끝났으니 위에서 추가한 alpha.pkpk.com 으로 핑을 날려보자.

“`
$ ping alpha.pkpk.com
PING alpha.pkpk.com (192.168.0.8) 56(84) bytes of data.
64 bytes from 192.168.0.8: icmp_seq=1 ttl=64 time=0.398 ms
64 bytes from 192.168.0.8: icmp_seq=2 ttl=64 time=0.279 ms
64 bytes from 192.168.0.8: icmp_seq=3 ttl=64 time=0.282 ms
64 bytes from 192.168.0.8: icmp_seq=4 ttl=64 time=0.303 ms

— alpha.pkpk.com ping statistics —
4 packets transmitted, 4 received, 0% packet loss, time 3001ms
rtt min/avg/max/mdev = 0.279/0.315/0.398/0.051 ms
“`

위와 같이 핑테스트가 잘되면 성공이다.

### API

powerdns의 3.4버전부터 api를 사용가능하다.
우분투에서 `apt-get install`로 설치하는 녀석들은 버전이 낮은 경우가 많으니 주의하자.
설정파일에 아래와 같은 부분을 설정하고, powerdns를 재시작 해주면 활성화가 된다.

“`
설정을 업데이트하는 API를 사용하려면, mysql의 설정의 binlog_format을 row로 변경해주어야 한다.
“`

“`
api=yes
api-key=changeme
webserver=yes
“`

### API 사용예제

<`주의`> API를 사용해서 만든 zone 정보만 API를 사용해서 조작할 수 있다. 이점에 유의해야한다.

“`
# zone list
$ curl -H ‘X-API-Key: changeme’ http://192.168.0.44:8081/api/v1/servers/localhost/zones | jq .

# create zone
$ curl -X POST –data ‘{“name”:”example.org.”, “kind”: “Native”, “masters”: [], “nameservers”: [“ns1.example.org.”, “ns2.example.org.”]}’ -v -H ‘X-API-Key: changeme’ http://192.168.0.44:8081/api/v1/servers/localhost/zones | jq .

# show zone info
$ curl -H ‘X-API-Key: changeme’ http://192.168.0.44:8081/api/v1/servers/localhost/zones/pkpk.com | jq .

# change sub domain info
$curl -X PATCH –data ‘{“rrsets”: [ {“name”: “gamedb1.pkpk.com”, “type”: “A”, “ttl”: 0, “changetype”: “REPLACE”, “records”: [ {“content”: “192.168.0.29”, “disabled”: false } ] } ] }’ -H ‘X-API-Key: changeme’ http://192.168.0.44:8081/api/v1/servers/localhost/zones/pkpk.com | jq .

“`
[/markdown]