DnsmasqからPi-holeへの移行ガイド

長年、自宅や職場でdnsmasqによる内部DNSを運用し、特定のドメインの問い合わせ先を個別で設定するなどの使い方をしてきました。

最近、広告ブロック機能やWeb UIによる管理の利便性から、Pi-holeへ移行を試みました。

この記事では、Dockerを用いてPi-holeをセットアップする手順を、3つの異なる環境(自宅、職場、VPS+Tailscale)のユースケースに分けて解説します。

前提条件

  • 稼働中のdnsmasqやbindなど、53番ポートを使用するDNSサービスは停止しておきます。
  • Upstream DNSサーバーにはCloudflare (1.1.1.1) を利用します。
  • Tailscale連携のセクションでは、既にTailscaleがセットアップ済みであることを前提とします。
  • ファイアウォールの設定は本記事の対象外とし、必要なポートが解放済みであることとします。
  • Pi-holeのDHCP機能は利用しません。

1. 自宅用(基本構成)

まずは基本的な構成として、自宅ネットワークでPi-holeを稼働させます。

ディレクトリ構成
$ mkdir cloudflare-pihole; cd $_
$ mkdir -p pihole/etc-dnsmasq.d
$ tree
.
├── docker-compose.yml
└── pihole
    └── etc-dnsmasq.d
        └── 99-custom.conf
docker-compose.yml
  • version: "2.2" の指定は、古いDocker環境向けです。近年のバージョンでは不要です。
  • Web管理画面には 8053 ポートを利用します(任意に変更可能)。
version: "2.2"
services:
  cloudflared:
    image: cloudflare/cloudflared:latest
    command: >
      proxy-dns
      --address 0.0.0.0
      --port 5053
      --upstream https://1.1.1.1/dns-query
      --upstream https://1.0.0.1/dns-query
    restart: unless-stopped
    networks:
      - dnsnet
  pihole:
    image: pihole/pihole:latest
    environment:
      TZ: Asia/Tokyo
      DNSMASQ_LISTENING: all
      FTLCONF_DNS_UPSTREAMS: "cloudflared#5053"
      FTLCONF_LOCAL_NETWORK: "192.168.1.0/24"
      FTLCONF_webserver_api_password: "password"
    volumes:
      # - ./pihole/etc-pihole:/etc/pihole # 設定を永続化したい場合はコメントアウトを解除
      - ./pihole/etc-dnsmasq.d:/etc/dnsmasq.d
    ports:
      - "0.0.0.0:53:53/tcp"
      - "0.0.0.0:53:53/udp"
      - "8053:80/tcp"
    depends_on:
      - cloudflared
    restart: unless-stopped
    networks:
      - dnsnet
networks:
  dnsnet:
    driver: bridge
セキュリティ警告: 環境変数 FTLCONF_webserver_api_password で設定したパスワードは、初期ログイン後に必ず変更してください。
カスタム設定 (99-custom.conf)

./pihole/etc-dnsmasq.d/99-custom.conf として下記の内容で作成します。localnetserver のIPアドレスはご自身の環境に合わせてください。

strict-order
localnet=192.168.1.0/24
server=/168.192.in-addr.arpa/192.168.1.1
listen-address=0.0.0.0

2. 職場用(パフォーマンス調整)

基本的な構成は自宅用と同じですが、FTLCONF_LOCAL_NETWORK のサブネットをご自身の環境に合わせて変更してください。

また、職場などアクセス数が多い環境では、コンテナの共有メモリが不足することがあります。その場合は、piholeサービスにshm_sizeを追加して、割り当てるメモリサイズを増やします。

services:
  pihole:
    image: pihole/pihole:latest
    shm_size: "256m"
    # ... 他の設定は自宅用と同様

3. VPS + Tailscale 連携

VPS上でPi-holeを稼働させ、Tailscale VPN経由でのみ利用する構成です。Traefikをリバースプロキシとして利用し、Web UIにHTTPSでアクセスします。

要件:

  • 独自ドメイン
  • Traefikが稼働中であること
  • Tailscaleがセットアップ済みであること
services:
  cloudflared:
    image: cloudflare/cloudflared:latest
    command: >
      proxy-dns
      --address 0.0.0.0
      --port 5053
      --upstream https://1.1.1.1/dns-query
      --upstream https://1.0.0.1/dns-query
    restart: unless-stopped
    networks: 
      - dnsnet
      - traefik-network

  pihole:
    image: pihole/pihole:latest
    shm_size: "256m"
    environment:
      TZ: Asia/Tokyo
      FTLCONF_webserver_api_password: "password"
      DNSMASQ_LISTENING: all
      FTLCONF_DNS_UPSTREAMS: "cloudflared#5053"
      # Tailscaleのデフォルトサブネット(100.x.x.x/10)を追加
      FTLCONF_LOCAL_NETWORK: "100.64.0.0/10"
    volumes:
      - ./pihole/etc-pihole:/etc/pihole
      - ./pihole/etc-dnsmasq.d:/etc/dnsmasq.d
      - ./pihole/hosts-dnsmasq:/etc/hosts-dnsmasq
    ports:
      # Tailscale経由でアクセス可能にする(ファイアウォールがオフなら0.0.0.0でOK)
      - "0.0.0.0:53:53/tcp"
      - "0.0.0.0:53:53/udp"
      # Web UIはTraefik経由のため、ポートは公開しない
    depends_on:
      - cloudflared
    restart: unless-stopped
    networks: 
      - dnsnet
      - traefik-network
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=traefik-network"
      - "traefik.http.routers.pihole.rule=Host(`pihole.yourdomain.com`)"
      - "traefik.http.routers.pihole.entrypoints=websecure"
      - "traefik.http.routers.pihole.tls=true"
      - "traefik.http.routers.pihole.tls.certresolver=cloudflare"
      - "traefik.http.services.pihole.loadbalancer.server.port=80"

networks:
  dnsnet:
    driver: bridge
  traefik-network:
    external: true
ポイント
  • SSL/TLS対応: TraefikとCloudflareを連携させることで、独自ドメインでSSL/TLS証明書を自動的に取得・更新できます。
  • セキュアなアクセス: Web UIへのアクセスはTraefikがリバースプロキシとして処理するため、portsでWeb UIのポート(80番)を外部に公開する必要がありません。
  • Tailscale連携: FTLCONF_LOCAL_NETWORK にTailscaleのIPアドレス範囲 (100.64.0.0/10) を指定することで、Tailscaleネットワーク内のクライアントからのクエリを正しく処理できるようになります。

起動と確認

docker compose up -d コマンドでサービスを起動します。

  • 自宅・職場環境: http://<サーバーのIPアドレス>:8053 でWeb UIにアクセスできます。
  • VPS環境: Traefikで設定したドメイン (https://pihole.yourdomain.com) でアクセスします。

設定したパスワードでログインできることを確認した後、セキュリティのため、速やかに管理画面からパスワードを変更してください。

Tailscaleとの連携設定

VPS上に構築したPi-holeを、Tailscaleネットワーク全体のDNSサーバーとして設定します。

  1. まず、Tailscaleの管理画面にアクセスし、DNSサーバーとして設定したいデバイス(今回はVPS)のIPアドレスを控えます。
  2. 次に、DNSタブへ移動し、「Add nameserver」から「Custom」を選択して、先ほど控えたIPアドレスを入力します。
  3. 最後に「Override local DNS」を有効にすることで、Tailscaleネットワーク全体のDNS設定が上書きされます。
    Image in a image block

「Override local DNS」を有効にすると:

  • Tailscaleネットワークに接続しているすべてのデバイスが、ここで指定したDNSサーバーを利用して名前解決を行うようになります。
  • 各デバイスのローカルDNS設定は無視され、強制的にPi-holeが使われるため、ネットワーク全体で広告ブロックなどが有効になります。
  • Exit-nodeを利用している場合でも、この設定が優先されます。
クライアントからPi-holeへのDNSクエリの流れ(Override local DNS利用時)
flowchart LR
    Client["Tailscale Network<br>クライアント端末"] 
    TailscaleNet["Tailscale<br>Mesh ネットワーク"]
    PiHole["VPS (Pi-hole)<br>Custom DNS設定端末"]
    Cloudflare["Cloudflare DNS (1.1.1.1)"]

    Client -- "任意のDNSクエリ" --> TailscaleNet
    TailscaleNet -- "Override local DNS<br>で強制転送" --> PiHole
    PiHole -- "上流へDNSクエリ(DoH)" --> Cloudflare
    PiHole -- "広告/追跡ブロック結果" --> TailscaleNet
    TailscaleNet -- "応答" --> Client
  • クライアントのDNS設定はTailscaleにより上書きされ、必ずVPS上のPi-holeに問い合わせるようになります。
  • Pi-holeが該当ドメインをブロックすればブロック応答、許可ならCloudflareなど上流DNSへ中継されます。
  • すべてのやりとりはTailscaleネットワーク内で暗号化されて行われます。

まとめ

Pi-holeを導入することで、誰でも簡単に広告ブロック機能を備えたDNSサーバーを構築できます。Web UIによる直感的な管理画面により、ブロックリストの追加やクエリログの確認も容易です。

特に、Tailscale連携の構成は初見では少し難解に感じるかもしれませんが、一度設定してしまえば、外出先のモバイル通信や公衆Wi-Fi環境でも自動的に広告ブロックが効くようになります。

これにより、どこにいても快適で安全なインターネット環境を維持できます。

自宅、職場、VPSと、用途に応じた3つの構成例を紹介しましたが、いずれも基本的な仕組みは同じです。まずは自宅環境で試してみて、徐々にTailscaleなどの高度な連携に挑戦してみることをおすすめします。

注意点

Pi-holeは非常に便利なツールですが、いくつか留意すべき点があります。

  • すべての広告がブロックされるわけではありません: Pi-holeはDNSレベルでのブロックを行うため、同一ドメインから配信される広告や、JavaScriptで動的に生成される広告などはブロックできない場合があります。
  • 誤検知(False Positive)の可能性: ブロックリストによっては、正常なWebサイトの機能や通信が意図せずブロックされることがあります。特定のサービスが正しく動作しない場合は、Pi-holeの管理画面でクエリログを確認し、必要に応じてホワイトリストに追加してください。
  • CDNや共有ドメインの問題: 広告配信とコンテンツ配信が同じドメインから行われている場合、ドメイン全体をブロックすると正常なコンテンツも表示されなくなる可能性があります。

これらの問題に遭遇した場合は、Pi-holeのWeb UIから該当ドメインをホワイトリストに追加するか、ブロックリストの設定を見直すことで対応できます。