Ad blocking + Secure DNS: Pi-hole + Cloudflared

 

Pi-hole + Cloudflared

Pi-hole은 광고 등의 원하지 않는 컨텐츠를 차단하는 기능을 가진 DNS로서, 우분투 서버에 Pi-hole을 설치하고 라우터 (인터넷 공유기) 의 DNS를 우분투 서버로 지정하면 라우터 하단에 연결된 모든 기기에 Pi-hole이 적용된다.

이때 DNS over HTTPS 프로토콜로 DNS 접속을 암호화해주는 Cloudflared를 함께 설치하고 Pi-hole의 DNS에 Cloudflared를 연결하면 라우터 하단에 연결된 모든 기기에서 DNS 접속도 암호화된다.

 

Pi-hole

 

작동 과정

접속 요청된 호스트 (광고) 가 Pi-hole의 차단 목록에 등록되어 있으면 Pi-hole은 이 호스트를 0.0.0.0 또는 우분투 서버의 IP 주소로 되돌려 보낸다.

0.0.0.0 으로 되돌려 보내도록 설정할 경우 별다른 추가 작업이 필요 없지만, 웹사이트의 차단된 광고 영역에 해당 주소를 찾을 수없다는 오류 메시지가 출력된다.

우분투 서버의 IP주소로 되돌려 보내도록 설정할 경우에는 우분투 서버에 운영 중인 웹 서버로 연결되며, 여러 개의 웹사이트를 운영 중이라면 기본 웹사이트 (Nginx의 경우 default_server 로 지정된 서버 블록) 에 연결되고, 이 웹사이트에는 요청받은 URI (광고) 가 없으므로 404 Page not found 오류를 반환한다. 이때 이 웹사이트에 별도로 제작한 404 오류 페이지를 설정해주면 차단된 광고 영역에는 별도로 제작한 404 오류 페이지가 표시된다. 404 오류 페이지를 내용이 없는 빈 페이지로 만들었다면 차단된 광고 영역은 비어있게 된다. 다만 접속 요청된 URI (광고) 가 https 연결을 사용한다면, 이 URI의 도메인과 우분투 서버의 웹사이트의 도메인은 서로 다르므로 인증서 확인 과정부터 실패하게 되고, 404 오류 페이지 출력 단계까지 가지 못하고 그 이전에 웹브라우저의 SSL 연결 오류 메시지가 출력된다.

한편 Pi-hole은 자제적으로 Pi-hole 설정 페이지를 제공하는데, 기본적으로 우분투 서버의 /var/www/html 경로에 설치된다. 따라서 기존에 우분투 서버에 /var/www/html 경로를 루트로 하는 웹사이트가 존재하지 않는 것이 설정하기에 수월하다. 그리고 이 Pi-hole 설정 페이지 또한 하나의 웹사이트이므로 이를 우분투 웹 서버의 기본 웹사이트로 지정 (Nginx의 경우 default_server 로 지정) 하는 것이 Pi-hole을 구성하기에 편리하다.

 

서브도메인 생성

Pi-hole 설정 페이지 접속에 사용할 서브도메인을 하나 생성한다. 여기서는 pihole.example.com을 생성한 것으로 가정한다. (도메인에 대한 일반적인 내용은 이전 글 도메인과 DNS를 참고한다.)

 

TLS 인증서 발급

Pi-hole 설정 페이지에 https 보안 연결을 사용하기 위해서 TLS 인증서를 발급받는다. 자세한 방법은 앞선 글 TLS 인증서: Let's Encrypt를 참고한다. 이 방법으로 인증서를 발급받으면 *.example.com 형태의 와일드카드 서브도메인에 대한 인증서가 발급되므로 이 인증서를 그대로 pihole.example.com 도메인에 사용할 수 있다.

 

Nginx 설치

Pi-hole은 Pi-hole 설정 페이지 운영에 사용할 웹 서버로 lighttpd 라는 웹 서버를 제공하는데, 여기서는 lighttpd를 사용하지 않고 기존에 우분투 서버에 운영 중인 Nginx 웹 서버를 이용한다. Nginx 설치 및 작동에 관한 내용은 앞선 글 웹 서버: Nginx를 참고한다.

 

php 설치

Pi-hole 설정 페이지는 php로 작성되어 있다. 우분투 서버에 php가 설치되어 있지 않다면 아래의 명령어로 Nginx에 필요한 기본적인 php 모듈을 설치한다.

sudo apt install php-fpm php-zip

 

방화벽 설정

sudo iptables -A INPUT -p tcp -m tcp --dport 53 -j ACCEPT
sudo iptables -A INPUT -p udp -m udp --dport 53 -j ACCEPT
sudo iptables -A INPUT -p udp -m udp --dport 67 -j ACCEPT
sudo iptables -A INPUT -i lo -p tcp -m tcp --dport 4711:4720 -j ACCEPT

iptables 방화벽에서 Pi-hole 작동에 필요한 포트를 열어준다. (기본적인 방화벽 세팅은 앞선 글 우분투 서버 기본 설정에서 완료했다.)

sudo netfilter-persistent save
sudo netfilter-persistent reload

iptables 방화벽의 설정 내용을 저장하고 리로드한다. (iptables-persistent는 앞선 글 우분투 서버 기본 설정에서 설치했다.)

 

Pi-hole 설치

curl -V

Pi-hole 설치 스크립트는 curl 명령을 이용하므로 먼저 위 명령어로 (V는 대문자) 우분투 서버에 curl이 설치되어 있는지 확인한다. curl 7.58.0 등의 버전이 출력되지 않고 curl이 설치되어 있지 않다는 메시지가 출력된다면 sudo apt update && sudo apt install curl 명령으로 curl을 설치한다.

sudo curl -sSL https://install.pi-hole.net | bash

위 명령으로 Pi-hole 설치 스크립트를 실행하면 몇 가지 선택 사항을 질문해오는데, 기본 값 그대로 선택해도 무방하고, 나의 경우에는 Select Upstream DNS Provider 단계에서 Cloudflare를 선택했고, 우분투 서버에 기존에 설치되어 있는 Nginx를 사용하므로 Do you wish to install the web server (lighttpd)? 단계에서 Off를 선택했다. Install Pi-hole default firewall rules? 단계는 앞서 방화벽 설정을 직접 적용했으므로 Yes 또는 No 무엇을 선택해도 무방하다.

sudo pihole -a -p

Pi-hole 설치가 완료되고 나면, 위 명령어로 Pi-hole 설정 페이지의 세부 항목에 접근할 때 필요한 비밀번호를 설정한다.

그다음, Pi-hole이 차단한 호스트를 우분투 서버의 IP 주소로 되돌려 보내도록 설정하려면 아래 내용을 적용한다.

sudo nano /etc/pihole/pihole-FTL.conf

pihole-FTL.conf 파일을 nano 편집기로 연다

BLOCKINGMODE=IP-NODATA-AAAA

위 내용을 추가하고, Ctrl 키와 x 키를 동시에 눌러서 nano 편집기를 빠져나오면서 저장한다.

sudo systemctl restart pihole-FTL

pihole-FTL을 재시작한다.

 

lighttpd 중지

만일 Pi-hole 설치 과정에서 lighttpd를 설치했다면 Nginx와 충돌을 일으키므로 아래의 명령으로 lighttpd를 중지하고 Nginx를 활성화한다.

sudo systemctl stop lighttpd
sudo systemctl disable lighttpd
sudo systemctl start nginx
sudo systemctl enable nginx

 

디렉토리 체계

Pi-hole은 아래의 디렉토리를 이용한다.

/var/www/html/

차단된 URI가 도착하는 디렉토리

/var/www/html/admin

Pi-hole 설정 페이지

/var/www/html/pihole

Pi-hole이 제공하는 차단 페이지

 

빈 페이지 생성

웹사이트 상의 차단된 광고 영역에 Pi-hole이 제공하는 차단 페이지를 출력하는 대신에 공란으로 비어있게 하기 위해서 비어있는 내용의 html 파일을 생성한다.

sudo nano /var/www/html/pihole/error.html

nano 편집기로 적당한 위치에 html 파일을 생성한다.

<html>
        <head>
                <title></title>
        </head>
        <body></body>
</html>

위와 같이 빈 내용을 출력하는 html을 작성하고, Ctrl 키와 x키를 동시에 눌러서 nano 편집기를 빠져나오면서 저장한다.

 

DH Param 키 생성

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096

앞선 글 웹 서버: Nginx를 통해서 DH Param 키를 생성했다면 그 키 하나로 모든 웹사이트에 사용할 수 있으므로 이 단계는 건너뛴다. 만일 생성하지 않았다면 위 명령으로 DH Param 키를 생성한다. DH Param 키는 https 보안 연결에서 암호화 성능을 높이기 위해서 추가로 사용하는 난수인데, 위 명령어는 4096 비트 (512 바이트) 로 생성하므로 시간이 오래 걸린다. 서버 컴퓨터의 성능에 따라 다르지만 길게는 수십분 가량 소요되기도 한다. 2048 비트 (256 바이트) 로 생성하려면 위의 명령에서 끝에 4096을 2048로 바꿔서 입력한다. 키가 생성되는 위치는 /etc/ssl/certs/dhparam.pem 으로 지정했다.

 

Nginx 설정

sudo chown -R www-data:www-data /var/www/html
sudo chmod -R 755 /var/www/html

/var/www/html 디렉토리의 소유자와 소유그룹을 웹 서버 프로세스인 www-data로 지정하고, 쓰기 가능하도록 755 권한을 부여한다.

Pi-hole 설정 페이지는 앞서 설정한 비밀번호를 입력하기 이전에도 전반적인 시스템 상황이 공개적으로 출력되는데, 이를 비공개하려면 설정 페이지 접근 시에 ID/비밀번호 인증을 실행하도록 설정한다.

sudo sh -c "echo -n 'varins:' >> /etc/nginx/.pihole"

위 명령으로 ID를 생성한다. varins를 원하는 ID로 바꿔서 입력한다.

sudo sh -c "openssl passwd -apr1 >> /etc/nginx/.pihole"

비밀번호를 암호화해서 생성한다.

cat /etc/nginx/.pihole

암호화된 내용은 위 명령으로 확인할 수 있다.

그다음, Nginx 서버 블록을 설정하는데, 새로운 서버 블록 파일을 생성해도 되지만 여기서는 혼동을 방지하기 위해서 Nginx가 기본적으로 제공하는 /var/www/html 디렉토리에 대한 예시 서버 블록 파일인 /etc/nginx/sites-available/default 파일을 사용한다.

sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.original

필요하다면 위 명령어로 default 서버 블록 파일을 백업한다.

echo '' | sudo tee /etc/nginx/sites-available/default

default 서버 블록 파일의 내용을 삭제한다.

sudo nano /etc/nginx/sites-available/default

default 서버 블록 파일을 nano 편집기로 연다.

server {
        listen 80 default_server;

        server_name _;

        root /var/www/html;

        index pihole/index.php index.php index.html index.htm;

        error_page 403 404 /pihole/error.html;

        location / {
                try_files $uri $uri/ =404;
        }

        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/run/php/php7.2-fpm.sock;
        }

        location ~ ^/admin/?$ {
                deny all;
        }
}

server {
        listen 80;

        server_name pihole.example.com;

        return 301 https://$server_name$request_uri;
}

server {
        listen 443 ssl http2 default_server;

        server_name pihole.example.com;

        root /var/www/html;

        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
        ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
        ssl_dhparam /etc/ssl/certs/dhparam.pem;

        ssl_protocols TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256;
        ssl_ecdh_curve secp384r1;
        ssl_session_timeout 10m;
        ssl_session_cache shared:SSL:10m;
        ssl_session_tickets off;
        ssl_stapling on;
        ssl_stapling_verify on;
        resolver 1.1.1.1 1.0.0.1 valid=300s;
        resolver_timeout 5s;

        add_header Strict-Transport-Security max-age=31536000;
        add_header X-Robots-Tag none;
        add_header X-Frame-Options SAMEORIGIN;
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";

        index index.php index.html index.htm;

        location / {
                try_files $uri $uri/ =404;
        }

        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/run/php/php7.2-fpm.sock;
        }

        location /admin {
                auth_basic "Restricted";
                auth_basic_user_file /etc/nginx/.pihole;
        }

        location ~ ^/pihole/?$ {
                return 302 /admin;
        }
}

위 내용을 자신의 시스템에 맞게 적절히 수정해서 입력한다.

주의할 사항은 이 Pi-hole 서버 블록이 default_server로 지정되어야 하며, 만일 우분투 서버에 default_server로 지정된 다른 서버 블록이 있다면 해당 서버 블록에서 default_server 옵션을 삭제해야 한다.

또한 위 예시에는 TLSv1.2만 적용되어 있는데, 만일 TLSv1.3을 사용한다면 이 서버 블록이 default_server 이므로 이 서버 블록에 반드시 TLSv1.3 옵션을 추가해야 한다. TLS 1.3에 대한 자세한 내용은 이전 글 Nginx TLS 1.3 설정을 참고한다.

그 밖의 서버 블록 내용은 이전 글 웹 서버: Nginx웹 사이트: WordPress를 참고한다.

입력을 마쳤으면 Ctrl키와 x키를 동시에 눌러서 nano 편집기를 빠져나오면서 저장한다.

sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/

편집한 서버 블록 파일을 작동시키기 위해 심볼릭 링크를 생성한다.

만일 이런 서버 블록을 여러 개 생성해서 다수의 웹사이트를 운영한다면 도메인 처리를 원활하게 하기 위해서 Nginx 설정 파일 nginx.conf에 아래의 설정을 추가한다.

sudo nano /etc/nginx/nginx.conf

Nginx 설정 파일인 nginx.conf 파일을 nano 편집기로 연다.

server_names_hash_bucket_size 64;

server_names_hash_bucket_size 64; 를 찾아서 앞에 주석 #을 제거하고, Ctrl키와 x키를 동시에 눌러서 nano 편집기를 빠져나오면서 저장한다. 이미 처리되어 있다면 그대로 nano 편집기를 빠져나온다.

이상으로 서버 블록 설정이 끝났으면, 설정한 서버 블록이 Nginx에 반영되도록 아래와 같이 Nginx를 재시작한다.

sudo nginx -t

Nginx 설정에 기본적인 문법 오류가 없는지 점검한다. 오류가 없다면
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
이런 메시지가 출력된다. 만일 다른 메시지가 나온다면 메시지를 참고해서 설정 사항을 점검한다.

sudo systemctl restart nginx

오류가 없으면 Nginx를 재시작한다.

 

라우터 설정

라우터 (인터넷 공유기) 설정 페이지에 접속해서 DHCP 서버가 사용하는 DNS 주소에 우분투 서버에 할당된 내부 (사설) IP 주소를 입력하고 라우터를 재부팅한다.

 

Pi-hole 설정

https://pihole.example.com/admin 주소로 접속하면 Pi-hole 설정 페이지를 확인할 수 있다.

pi-hole.png

Blacklist 메뉴에서 차단할 개별 호스트를 등록할 수 있고, Whitelist 메뉴에서 허용할 개별 호스트를 등록할 수 있다.

Settings - Blocklists 메뉴에서 차단할 호스트 리스트를 등록할 수 있는데, 유용한 호스트 리스트는 https://firebog.net 등을 참고한다.

만일 라우터 하단의 특정 기기에서 Pi-hole 적용이 원활하지 않다면 해당 기기를 재부팅해본다.

 

Pi-hole 명령어

pihole -up
Pi-hole 업데이트

pihole reconfigure
Pi-hole 재설정

pihole uninstall
Pi-hole 제거

위와 같이 우분투 서버 상에서 Pi-hole에 명령을 내릴 수 있는데, 보다 다양한 명령어는 Pi-hole 웹사이트 https://docs.pi-hole.net/core/pihole-command/ 를 참고한다.

 

VPN에 적용

만일 이전 글 VPN: IKEv2를 참고해서 우분투 서버에서 VPN을 운영 중이라면 아래의 설정으로 VPN으로 접속한 기기에도 Pi-hole을 적용할 수 있다.

sudo nano /etc/ipsec.conf

ipsec.conf 파일을 nano 편집기로 연다.

rightdns=123.123.123.123

rightdns 항목의 값을 우분투 서버에 할당된 내부 (사설) IP 주소로 변경한다. 변경했으면 Ctrl키와 x키를 동시에 눌러서 nano 편집기를 빠져나오면서 저장한다.

sudo ipsec restart

ipsec을 재시작한다.

 

 

Cloudflared

Pi-hole 설정이 완료되었으면 Pi-hole에 Cloudflared를 연결에서 DNS 접속 암호화도 적용한다.

 

Cloudflared 설치

cd /tmp

작업하기 편하도록 /tmp 디렉토리로 이동한다.

wget https://bin.equinox.io/c/VdrWdbjqyF/cloudflared-stable-linux-amd64.deb

Cloudflared의 .deb 설치 파일을 내려받는다. 다운로드 주소는 https://developers.cloudflare.com/argo-tunnel/downloads/ 에서 확인할 수 있다.

sudo apt install ./cloudflared-stable-linux-amd64.deb

내려받은 .deb 파일을 설치한다.

cloudflared --version

위 명령어로 Cloudflared 설치 여부를 확인할 수 있다.

sudo useradd -s /usr/sbin/nologin -r -M cloudflared

cloudflared 사용자를 생성한다.

sudo nano /etc/default/cloudflared

nano 편집기로 Cloudflared 설정 파일을 생성한다.

CLOUDFLARED_OPTS=--port 5053 --upstream https://1.1.1.1/dns-query --upstream https://1.0.0.1/dns-query

위 내용을 입력하고, Ctrl키와 x키를 동시에 눌러서 nano 편집기를 빠져나오면서 저장한다.

sudo chown cloudflared:cloudflared /etc/default/cloudflared
sudo chown cloudflared:cloudflared /usr/local/bin/cloudflared

Cloudflared 작동에 필요한 소유자와 소유그룹을 설정한다.

sudo nano /lib/systemd/system/cloudflared.service

Cloudflared를 시스템 서비스로 등록하기 위해서 nano 편집기로 cloudflared.service 파일을 생성한다.

[Unit]
Description=cloudflared DNS over HTTPS proxy
After=syslog.target network-online.target

[Service]
Type=simple
User=cloudflared
EnvironmentFile=/etc/default/cloudflared
ExecStart=/usr/local/bin/cloudflared proxy-dns $CLOUDFLARED_OPTS
Restart=on-failure
RestartSec=10
KillMode=process

[Install]
WantedBy=multi-user.target

위 내용을 입력하고, Ctrl키와 x키를 동시에 눌러서 nano 편집기를 빠져나오면서 저장한다.

sudo systemctl enable cloudflared
sudo systemctl start cloudflared

우분투 서버 시작 시에 Cloudflared가 실행되도록 enable 하고, Cloudflared를 시작한다.

sudo iptables -A INPUT -p tcp -m tcp --dport 5053 -j ACCEPT
sudo iptables -A INPUT -p udp -m udp --dport 5053 -j ACCEPT

iptables 방화벽에서 Cloudflared 작동에 필요한 포트를 열어준다. (기본적인 방화벽 세팅은 앞선 글 우분투 서버 기본 설정에서 완료했다.)

sudo netfilter-persistent save
sudo netfilter-persistent reload

iptables 방화벽의 설정 내용을 저장하고 리로드한다. (iptables-persistent는 앞선 글 우분투 서버 기본 설정에서 설치했다.)

 

Pi-hole 설정

Pi-hole 설정 페이지에 접속한다.

Settings - DNS 메뉴의 Upstream DNS Servers 항목에서 기존에 선택되어 있는 모든 항목을 체크 해제한다.

Custom 1 (IPv4) 항목에 체크하고 127.0.0.1#5053입력한다.

Save 버튼을 클릭해서 저장한다.

 

DNS 접속 암호화 확인

https://www.cloudflare.com/ssl/encrypted-sni/ 웹사이트에 접속해서 Check My Browser 버튼을 클릭하면 Secure DNS 항목에서 DNS 접속 암호화 여부를 확인할 수 있다.

sdns-check.png

 

본 글의 저작권은 작성자 Varins에게 있습니다.
Varins의 사전 서면 동의 없이는 본 글의 전부 또는 일부를 무단으로 전재, 게시, 배포하는 것을 금지합니다.

코멘트 없음
맨위로