광고 차단: Pi-hole

June 22, 2020

    Pi-hole

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

    Pi-hole 체계

    작동 방식

    접속 요청된 URI (광고) 가 Pi-hole의 차단 목록에 등록되어 있으면 Pi-hole은 이 URI를 IP 주소 0.0.0.0 으로 되돌려 보낸다. 또는 /etc/pihole/pihole-FTL.conf 파일 설정을 통해 0.0.0.0 대신에 우분투 서버의 IP 주소 등의 특정 IP 주소로 되돌려 보내도록 설정할 수도 있다.

    Pi-hole 디렉토리

    Pi-hole은 자제적으로 Pi-hole 설정 웹페이지를 제공하는데, 이 웹페이지는 기본적으로 우분투 서버의 /var/www/html 경로에 설치된다. 따라서 기존에 우분투 서버에 /var/www/html 경로를 루트로 하는 웹사이트가 존재하지 않는 것이 좋다.

    보다 구체적으로 Pi-hole이 이용하는 디렉토리는 아래와 같다.

    /var/www/html/
    

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

    /var/www/html/admin
    

    Pi-hole 설정 페이지

    /var/www/html/pihole
    

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

    Pi-hole 설치 준비

    서브도메인 생성

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

    TLS 인증서 발급

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

    TLS 1.3 적용 준비

    보안 연결을 구축하는 프로토콜 TLS는 2018년 8월에 1.3버전으로 업데이트 되었다. 우분투 서버에서는 OpenSSL이 TLS를 담당하는데, 2018년 9월에 출시된 OpenSSL 1.1.1 버전부터 TLS 1.3을 지원한다. 따라서 자신의 시스템에 설치된 OpenSSL의 버전을 확인한 후 1.1.1 미만의 버전이라면 1.1.1 이상의 버전으로 업그레이드해야 TLS 1.3을 이용할 수 있다. 이후 TLS 1.3 설정은 Nginx의 여러 서버 블록 중에서 default_server로 지정된 서버 블록에 TLS 1.3 설정이 되어 있어야 TLS 1.3이 작동한다. default_server 옵션과 TLS 1.3, OpenSSL 업그레이드에 관해서는 앞선 글 웹 서버: Nginx를 참고한다.

    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 으로 지정했다.

    방화벽 설정

    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 --sport 67:68 --dport 67:68 -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는 앞선 글 우분투 서버 기본 설정에서 설치했다.)

    Nginx 설치

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

    php 설치

    sudo apt install php-cgi php-fpm php-intl php-sqlite3 php-xml php-zip
    

    Pi-hole 설정 페이지는 php로 작성되어 있다. 필요한 php 모듈을 우분투 서버에 설치한다.

    Pi-hole 설치

    curl -V

    Pi-hole 설치 스크립트는 curl 명령을 이용하므로 먼저 위 명령어로 (V는 대문자) 우분투 서버에 curl이 설치되어 있는지 확인한다. curl 7.68.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를 선택했다.

    sudo pihole -a -p

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

    Pi-hole 설정 페이지 Nginx 연결

    lighttpd 중지

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

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

    Nginx 설정

    sudo chown -R www-data:www-data /var/www/html
    sudo chmod -R 755 /var/www/html
    sudo usermod -a -G pihole www-data
    

    Pi-hole이 이용하는 /var/www/html 디렉토리의 소유자와 소유그룹을 웹 서버 프로세스인 www-data로 지정하고, 쓰기 가능하도록 755 권한을 부여한다. www-data가 설정 웹페이지를 사용할 수 있도록 pihole 그룹에 포함시킨다.

    Pi-hole 설정 페이지는 전반적인 시스템의 상태를 공개적으로 출력하는데, 이를 비공개하려면 Nginx 설정을 통해 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 서버 블록을 설정한다.

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

    pihole 서버 블록 파일을 nano 편집기로 새로 생성한다. 여기서는 서버 블록 파일 이름을 구분하기 쉽도록 pihole로 생성했다.

    server {
            listen 80;
    
            server_name pihole.example.com;
    
            return 301 https://$server_name$request_uri;
    }
    
    server {
            listen 443 ssl http2;
    
            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 TLSv1.3;
            ssl_prefer_server_ciphers on;
            ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-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-Content-Type-Options "nosniff" always;
            add_header X-Frame-Options "SAMEORIGIN" always;
            add_header X-Robots-Tag "none" always;
            add_header X-XSS-Protection "1; mode=block" always;
    
            index pihole/index.php index.php index.html index.htm;
    
            location / {
                    expires max;
                    try_files $uri $uri/ =404;
            }
    
            location ~ \.php$ {
                    include snippets/fastcgi-php.conf;
                    fastcgi_pass unix:/run/php/php7.4-fpm.sock;
                    fastcgi_param FQDN true;
                    auth_basic "Restricted";
                    auth_basic_user_file /etc/nginx/.pihole;
            }
    
            location /*.js {
                    index pihole/index.js;
                    auth_basic "Restricted";
                    auth_basic_user_file /etc/nginx/.pihole;
            }
    
            location /admin {
                    root /var/www/html;
                    index index.php index.html index.htm;
                    auth_basic "Restricted";
                    auth_basic_user_file /etc/nginx/.pihole;
            }
    
            location ~ /\.ht {
                    deny all;
            }
    }
    

    위 내용을 자신의 시스템에 맞게 적절히 수정해서 작성한다. 도메인과 인증서 경로를 자신의 것으로 바꾸고, ssl_dhparam 항목에는 DH Param 키의 위치를 입력하고, auth_basic_user_file 항목에는 앞서 생성한 ID/비밀번호 암호화 파일의 경로를 입력한다.

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

    sudo ln -s /etc/nginx/sites-available/pihole /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 설정 페이지를 확인할 수 있다.

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

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

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

    Pi-hole 명령어

    우분투 서버 상에서 Pi-hole 자체 명령어 pihole로 명령을 내릴 수 있다.

    pihole -up
    

    Pi-hole을 업데이트한다.

    pihole reconfigure
    

    Pi-hole을 재설정한다.

    pihole uninstall
    

    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을 재시작한다.

     

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

Leave a comment

댓글은 관리자의 승인 이후에 게시됩니다.