광고 차단: Pi-hole

July 1, 2019

    Pi-hole

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

    작동 과정

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

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

    우분투 서버의 IP주소로 되돌려 보내도록 설정할 경우에는 우분투 서버에 운영 중인 웹 서버로 연결되며, 여러 개의 웹사이트를 운영 중이라면 기본 웹사이트 (Nginx의 경우 default_server 로 지정된 서버 블록) 에 연결된다. 이렇게 연결된 웹사이트에는 요청받은 URI (광고) 가 없으므로 404 Page not found 오류를 반환한다. 이때 이 웹사이트의 404 오류 페이지를 아무런 내용이 없는 빈 페이지로 만들어 준다면 차단된 URI 영역 (광고 영역) 은 깔끔하게 비어있게 된다.

    다만 이 경우에도 본래의 광고 URI가 https 연결을 사용한다면, 이 URI의 도메인과 우분투 서버의 웹사이트의 도메인은 서로 다르므로 https 인증서 확인 과정을 실패하게 되고, 404 오류 페이지 출력 단계까지 가지 못하고 그 이전에 웹브라우저 자체의 SSL 연결 오류 메시지가 출력된다.

    한편 Pi-hole은 자제적으로 Pi-hole 설정 웹페이지를 제공하는데, 기본적으로 우분투 서버의 /var/www/html 경로에 설치된다. 따라서 기존에 우분투 서버에 /var/www/html 경로를 루트로 하는 웹사이트가 존재하지 않는 것이 좋다. 그리고 Pi-hole은 Nginx의 경우 default_server로 광고 URI를 돌려 보내므로 Pi-hole 설정 웹페이지를 default_server로 지정하는 것이 좋다.

    서브도메인 생성

    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? 단계는 앞서 방화벽 설정을 직접 적용했으므로 No를 선택했다.

    sudo pihole -a -p

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

    그다음, Pi-hole이 차단한 URI를 우분투 서버의 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이 제공하는 차단 페이지

    빈 페이지 생성

    웹사이트 상의 차단된 URI 영역 (광고 영역) 에 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 으로 지정했다.

    OpenSSL 업그레이드

    보안 연결을 구축하는 프로토콜 TLS는 2018년 8월에 1.3버전으로 업데이트 되었다. 우분투 서버에서는 OpenSSL이 TLS를 담당하는데, 2018년 9월에 출시된 OpenSSL 1.1.1 버전부터 TLS 1.3을 지원한다. 다만 우분투 서버 18.04 ~ 18.04.2 버전에 기본 탑재된 OpenSSL은 1.1.0g 버전이기 때문에, 자신의 시스템에 설치된 OpenSSL의 버전을 확인한 후 1.1.1 미만의 버전이라면 1.1.1 이상의 버전으로 업그레이드해야 TLS 1.3을 이용할 수 있다.

    openssl version

    이 명령으로 현재 시스템의 OpenSSL 버전을 확인한다. 1.1.1 미만의 버전이라면 아래의 절차대로 업그레이드 한다.

    sudo apt update
    
    sudo apt install --only-upgrade openssl
    

    패키지 저장소 정보를 업데이트하고, openssl을 업그레이드 한다. 위의 openssl 개별 업그레이드 명령 대신에 sudo apt upgrade 명령으로 시스템의 모든 패키지 전체를 업그레이드 할 수도 있다. 업그레이드가 완료되면 openssl version 명령으로 업그레이드된 OpenSSL의 버전이 1.1.1 이상인지 확인해본다.

    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 서버 블록을 설정하는데, 새로운 서버 블록 파일을 생성해도 되고, 여기서는 /var/www/html 디렉토리에 대해 Nginx가 기본적으로 제공하는 예시 서버 블록 파일인 /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 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-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 옵션을 삭제해야 한다.

    또한 이 서버 블록이 default_server 이므로, 반드시 이 서버 블록에 TLSv1.3 옵션을 추가해야 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 설정 페이지를 확인할 수 있다.

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

    SettingsBlocklists 메뉴에서 차단할 URI 리스트를 등록할 수 있는데, 유용한 URI 리스트는 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을 재시작한다.

     

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

Leave a comment

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