Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install Pihole Ubuntu
GUIDEInstall Guides

How to Install Pi-hole on Ubuntu 24.04 VPS — Network-Wide Ad Blocking

27 min read

How to Install Pi-hole on Ubuntu 24.04 VPS — Network-Wide Ad Blocking

Pi-hole turns any Linux server into a DNS sinkhole that blocks ads, trackers, and malware domains for every device that uses it as a resolver — no browser extensions, no per-device apps, no licensing fees. This guide walks you through a complete install on an Ubuntu 24.04 VPS, including the classic one-line installer, a Docker alternative, a hardened Unbound recursive resolver upstream, optional DHCP, and a WireGuard tunnel so your phone and laptop can use the ad blocker from anywhere.

Prefer not to self-host? CloudCore's Starter VPS at EUR 7.99/month gives you everything Pi-hole needs and plenty of headroom to run WireGuard, Unbound, and a reverse proxy on the same box.

Table of Contents

  • What is Pi-hole?
  • Why Self-Host Pi-hole on a VPS?
  • Pi-hole vs NextDNS vs Control D Cost Comparison
  • Prerequisites
  • Step 1: Update System Packages
  • Step 2: Pin a Static IP
  • Step 3: Install Pi-hole (Official Script)
  • Step 4: Capture the Admin Password
  • Step 5: Open Firewall Ports
  • Step 6: Verify DNS Resolution
  • Alternative: Install Pi-hole with Docker
  • Step 7: Add Unbound as a Recursive Upstream
  • Step 8: Enable DHCP (Optional)
  • Step 9: WireGuard Client Access
  • Step 10: Front Pi-hole with Nginx (Optional)
  • Post-Install: Blocklists and Tuning
  • Troubleshooting
  • FAQ
  • Next Steps
  • What is Pi-hole?

    Pi-hole is an open-source DNS sinkhole that acts as a local resolver for your entire network. When a device asks for ads.doubleclick.net, Pi-hole checks the request against a list of known advertising, tracking, and malware domains. Matches are answered with 0.0.0.0 — the ad never loads, saves bandwidth, and leaves your browser faster. Legitimate queries are forwarded to an upstream resolver of your choice (Cloudflare, Quad9, or a local Unbound instance).

    Originally written for the Raspberry Pi, Pi-hole now runs cleanly on any Debian or Ubuntu server. The stack is straightforward: pihole-FTL (a fork of dnsmasq that stores query logs in SQLite), lighttpd or your own web server for the admin UI, and a PHP dashboard that visualises blocked queries, top clients, and top domains. The official documentation at docs.pi-hole.net is thorough and well-maintained.

    Typical use cases include network-wide ad blocking for families and small offices, parental controls by blocking adult or social-media categories, malware domain blocking at the DNS layer before a request ever leaves the network, IoT device lockdown to stop smart TVs and appliances phoning home, and privacy auditing so you can see exactly which hostnames your devices contact.

    If you are deciding between similar tools, see our companion guide on AdGuard Home — AdGuard is a newer Go-based alternative with DNS-over-HTTPS built in. Pi-hole is the more battle-tested option with a larger blocklist ecosystem.

    Why Self-Host Pi-hole on a VPS?

    Running Pi-hole on a VPS instead of a Raspberry Pi at home has several concrete advantages:

    • Always on, anywhere — A VPS has 99.9%+ uptime. You do not lose DNS when your home router reboots or your ISP drops the line.
    • Protects mobile devices — Combined with a WireGuard tunnel, your phone gets the same ad blocking on cellular data as on home Wi-Fi.
    • Shared across locations — Family members, a second home, or a small office can all use the same Pi-hole instance.
    • No local hardware to maintain — No SD card corruption, no power outages, no heat issues.
    • Symmetric gigabit upstream — A datacenter VPS resolves DNS faster than most residential connections, especially when paired with a local Unbound recursive resolver.
    • Multi-purpose — The same VPS can host WireGuard, Uptime Kuma, a static site behind an Nginx reverse proxy, and Pi-hole simultaneously.
    • Full privacy — Unlike NextDNS or Control D, no third party sees your queries. Logs stay on a machine you control.

    Pi-hole vs NextDNS vs Control D Cost Comparison

    Pi-hole on a VPS competes most directly with cloud DNS filters. Here is how the three options compare for a typical household or small team:

    FeatureNextDNS ProControl D Full ControlSelf-Hosted Pi-hole (CloudCore Starter)
    Annual cost~$20/year (300k queries/mo cap)~$40/yearEUR 59.88/year (EUR 7.99/mo)
    Query volumeSoft-cappedUnlimitedUnlimited
    Device limitUnlimitedUnlimitedUnlimited
    Who sees your queries?NextDNS (stated no-log)Control DOnly you
    Custom blocklistsYes (URL-based)YesYes (unlimited)
    DNS-over-HTTPS / TLSBuilt-inBuilt-inAdd via Unbound + cloudflared
    Runs other workloads?NoNoYes — WireGuard, Nginx, Uptime Kuma
    Regulatory / GDPR controlProvider-dependentProvider-dependentFully yours
    Hardware reuseN/AN/AFull Linux VPS
    If all you want is a DNS filter for a single household and you will never use the VPS for anything else, NextDNS at $20/year is cheaper on paper. The moment you add a WireGuard endpoint, a status page, or a reverse proxy, a single EUR 7.99 VPS becomes the better deal — and you own the data.

    Prerequisites

    Before you begin, make sure you have:

    • A VPS running Ubuntu 24.04 LTS with root or sudo access
    • A public IPv4 address (and ideally IPv6) that your clients can reach
    • SSH access to the server
    • A domain name pointing to the VPS if you plan to use Nginx + SSL for the admin UI (optional)
    • At least 1 GB of RAM and 10 GB of disk space — Pi-hole itself is tiny, but you want headroom for logs and co-tenants like Unbound and WireGuard
    Recommended Plan: CloudCore Starter
    >
    For a DNS + WireGuard + Unbound stack, the CloudCore Starter plan is more than enough:
    >
    - 2 vCPU cores
    - 4 GB RAM
    - 50 GB NVMe SSD
    - Unmetered bandwidth
    - EUR 7.99/month
    >
    Pi-hole's FTL daemon rarely consumes more than 30 MB of RAM even with a million queries per day. The Starter plan leaves plenty of room to grow. For heavier workloads or multiple co-tenants, upgrade to CloudCore Professional (6 vCPU, 12 GB RAM, EUR 19.99/month).

    Connect to your server via SSH to begin:

    bash
    ssh root@your-server-ip

    Step 1: Update System Packages

    Start with a clean, fully-patched base. Pi-hole's installer expects a recent glibc and will refuse to continue on very out-of-date systems.

    bash
    sudo apt update && sudo apt upgrade -y

    Expected output (abbreviated):

    text
    Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease
    Reading package lists... Done
    Building dependency tree... Done
    0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

    If the kernel was upgraded, reboot and reconnect:

    bash
    sudo reboot

    Step 2: Pin a Static IP

    Pi-hole advertises itself as a DNS server, so its IP must not change. Most VPS providers already give you a fixed public IPv4, but make sure netplan reflects that.

    Check the current interface and address:

    bash
    ip -4 addr show

    Expected output:

    text
    2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
        inet 203.0.113.45/24 brd 203.0.113.255 scope global eth0

    Edit the netplan file (yours may be named differently — check /etc/netplan/):

    bash
    sudo nano /etc/netplan/50-cloud-init.yaml

    Confirm the config hard-codes the address:

    yaml
    network:
      version: 2
      ethernets:
        eth0:
          addresses:
            - 203.0.113.45/24
          routes:
            - to: default
              via: 203.0.113.1
          nameservers:
            addresses: [1.1.1.1, 9.9.9.9]

    Apply:

    bash
    sudo netplan apply

    Step 3: Install Pi-hole (Official Script)

    The Pi-hole team ships a well-audited installer that handles user creation, dependency installation, and TUI-driven configuration.

    bash
    curl -sSL https://install.pi-hole.net | bash
    Security note: Some administrators prefer to inspect installers before piping to a shell. You can download first: curl -sSL https://install.pi-hole.net -o pihole-install.sh && less pihole-install.sh && sudo bash pihole-install.sh. The script is open source and hosted on github.com/pi-hole/pi-hole.

    The installer launches a text-mode wizard. Accept the defaults unless you have a reason to deviate:

  • Static IP warning — Confirm your current IP will remain the Pi-hole address.
  • Upstream DNS provider — Pick Cloudflare, Quad9, or Custom. Choose Custom and enter 127.0.0.1#5335 if you plan to add Unbound in Step 7, otherwise Cloudflare (1.1.1.1, 1.0.0.1) is a safe default.
  • Block lists — Accept the default StevenBlack list. You can add more later.
  • Protocols — Enable both IPv4 and IPv6 unless you have a specific reason not to.
  • Install web admin interface — Yes.
  • Install web server (lighttpd) — Yes, unless you plan to front everything with Nginx (covered in Step 10).
  • Enable logging — Yes, for visibility. You can disable later if you want zero logs.
  • Privacy mode — "Show everything" during setup; tighten later from the UI.
  • Installation takes 3-5 minutes. Expected tail output:

    text
    [i] The install log is located at: /etc/pihole/install.log
      [✓] Installation Complete!
      Web Interface Password: a8F3p9Xk

    Step 4: Capture the Admin Password

    Copy the generated password immediately. If you missed it, reset to a value you choose:

    bash
    sudo pihole setpassword

    You will be prompted twice:

    text
    Enter New Password (Blank for no password):
    Confirm Password:
    [✓] New password set

    Open the admin UI in your browser:

    text
    http://203.0.113.45/admin

    Log in with the password you just set. You should see the dashboard with total queries, queries blocked, and percentage blocked.

    Step 5: Open Firewall Ports

    Pi-hole needs port 53 (DNS) reachable by your clients and port 80 (optionally 443) for the admin UI. If you will only use Pi-hole from inside a WireGuard tunnel (covered in Step 9), you can skip opening 53 to the internet — highly recommended.

    Basic UFW setup:

    bash
    sudo ufw allow OpenSSH
    sudo ufw allow 80/tcp comment 'Pi-hole admin UI'
    sudo ufw allow 53/tcp comment 'DNS'
    sudo ufw allow 53/udp comment 'DNS'
    sudo ufw enable
    sudo ufw status verbose

    Expected output:

    text
    Status: active
    To                         Action      From
    --                         ------      ----
    22/tcp                     ALLOW       Anywhere
    80/tcp                     ALLOW       Anywhere
    53/tcp                     ALLOW       Anywhere
    53/udp                     ALLOW       Anywhere
    Do not leave port 53 open to the world in production. Open recursive resolvers are abused in DNS amplification DDoS attacks and will earn complaints from your VPS provider. Restrict to specific IPs or the WireGuard subnet:
    >
    bash
    > sudo ufw delete allow 53/udp
    > sudo ufw delete allow 53/tcp > sudo ufw allow from 10.8.0.0/24 to any port 53 >

    Step 6: Verify DNS Resolution

    Test that Pi-hole resolves good domains and blocks bad ones.

    From a workstation with dig installed:

    bash
    dig @203.0.113.45 google.com +short

    Expected output (a real IP):

    text
    142.250.74.110

    Now query a known-ad domain:

    bash
    dig @203.0.113.45 doubleclick.net +short

    Expected output (blocked):

    text
    0.0.0.0

    The 0.0.0.0 response proves the sinkhole is working. From the Pi-hole admin UI, the query will also appear in the Query Log marked as Blocked (gravity).

    Alternative: Install Pi-hole with Docker

    If you prefer container-based deployments (easier upgrades, clean uninstall, isolation from the host), the official pihole/pihole image is the recommended path.

    Install Docker first:

    bash
    curl -fsSL https://get.docker.com | sudo sh
    sudo usermod -aG docker $USER

    Log out and back in so the group change takes effect, then create a compose file:

    bash
    mkdir -p ~/pihole && cd ~/pihole
    bash
    cat > docker-compose.yml <<'EOF'
    services:
      pihole:
        container_name: pihole
        image: pihole/pihole:latest
        restart: unless-stopped
        ports:
          - "53:53/tcp"
          - "53:53/udp"
          - "80:80/tcp"
        environment:
          TZ: "Europe/Berlin"
          FTLCONF_webserver_api_password: "ChooseAStrongPassword"
          FTLCONF_dns_upstreams: "1.1.1.1;9.9.9.9"
        volumes:
          - ./etc-pihole:/etc/pihole
          - ./etc-dnsmasq.d:/etc/dnsmasq.d
        cap_add:
          - NET_ADMIN
    EOF

    On Ubuntu, systemd-resolved listens on port 53 by default. Disable its stub listener before starting Pi-hole:

    bash
    sudo sed -i 's/#DNSStubListener=yes/DNSStubListener=no/' /etc/systemd/resolved.conf
    sudo sh -c 'rm /etc/resolv.conf && ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf'
    sudo systemctl restart systemd-resolved

    Start the container:

    bash
    docker compose up -d
    docker compose logs -f pihole

    Expected output (tail):

    text
    pihole  | [✓] FTL is listening on port 53
    pihole  | [✓] Pi-hole Enabled

    The admin UI is reachable at http://your-server/admin, exactly as with the bare-metal install. All subsequent tuning — blocklists, upstreams, clients — works the same way.

    When to choose Docker over the script: you want atomic upgrades (docker compose pull && docker compose up -d), you already run a container stack, or you want to pin a specific Pi-hole version. When to choose the script: you want the tightest integration with systemd, the lowest RAM overhead, and the official pihole CLI on the host.

    Step 7: Add Unbound as a Recursive Upstream

    By default, Pi-hole forwards unblocked queries to Cloudflare or Quad9. Those providers say they do not log, but every query still leaves your machine. A local Unbound instance resolves queries directly against the DNS root servers, so no single third party sees your browsing pattern.

    Install Unbound:

    bash
    sudo apt install -y unbound

    Create a Pi-hole-optimised config:

    bash
    sudo tee /etc/unbound/unbound.conf.d/pi-hole.conf > /dev/null <<'EOF'
    server:
        verbosity: 0
        interface: 127.0.0.1
        port: 5335
        do-ip4: yes
        do-udp: yes
        do-tcp: yes
        do-ip6: no

    # Trust glue only if signed harden-glue: yes harden-dnssec-stripped: yes use-caps-for-id: no

    # Reasonable privacy & perf defaults edns-buffer-size: 1232 prefetch: yes num-threads: 1 so-rcvbuf: 1m

    # Rebind protection private-address: 10.0.0.0/8 private-address: 172.16.0.0/12 private-address: 192.168.0.0/16 private-address: 169.254.0.0/16 private-address: fd00::/8 private-address: fe80::/10 EOF

    Restart Unbound and test it:

    bash
    sudo systemctl restart unbound
    dig @127.0.0.1 -p 5335 pi-hole.net +short

    Expected output (real IPs):

    text
    3.18.136.52

    Point Pi-hole upstream at Unbound. In the admin UI go to Settings → DNS, uncheck all upstream boxes, tick Custom 1 (IPv4), and enter 127.0.0.1#5335. Save.

    Confirm queries are flowing through Unbound by tailing its log if you enable verbosity, or by checking the Pi-hole query log — responses should show CNAME chains all the way to the authoritative server.

    For a deeper dive, see our standalone Unbound tutorial, which covers DNSSEC validation tuning and RAM cache sizing.

    Step 8: Enable DHCP (Optional)

    Pi-hole can replace your router's DHCP server, which has one huge benefit: every client appears in the query log by hostname rather than IP. The caveat is that DHCP only works if the Pi-hole server is on the same L2 broadcast domain as the clients. On a public VPS this almost never applies — skip this section unless you are running Pi-hole on a LAN box, or you have a layer-2 VPN like ZeroTier or Tailscale subnet routing.

    If your scenario qualifies, disable DHCP on your router first, then in the Pi-hole UI go to Settings → DHCP and enable it:

    • Range of IP addresses to hand out — e.g. 192.168.1.100 to 192.168.1.250
    • Router (gateway) IP — your physical router's LAN IP, e.g. 192.168.1.1
    • Lease time — 24 hours is standard
    • Enable IPv6 support (SLAAC + RA) — on, if your network uses IPv6
    On a public VPS setup, the realistic approach is: keep DHCP on your home router, and configure the router to hand out the VPS address (or a WireGuard address — see the next step) as the DNS server for all clients.

    Step 9: WireGuard Client Access

    A WireGuard tunnel is the cleanest way to route your phone and laptop DNS through Pi-hole from anywhere — coffee shops, cellular data, hotel Wi-Fi — without exposing port 53 publicly.

    Install WireGuard and enable IP forwarding:

    bash
    sudo apt install -y wireguard qrencode
    echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-wireguard.conf
    sudo sysctl -p /etc/sysctl.d/99-wireguard.conf

    Generate server keys:

    bash
    cd /etc/wireguard
    sudo sh -c 'umask 077 && wg genkey | tee server_private.key | wg pubkey > server_public.key'

    Create /etc/wireguard/wg0.conf:

    bash
    sudo tee /etc/wireguard/wg0.conf > /dev/null <<EOF
    [Interface]
    Address = 10.8.0.1/24
    ListenPort = 51820
    PrivateKey = $(sudo cat /etc/wireguard/server_private.key)
    PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
    PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
    EOF

    Generate a client (repeat for each device):

    bash
    cd /etc/wireguard
    sudo sh -c 'umask 077 && wg genkey | tee phone_private.key | wg pubkey > phone_public.key'

    Add the peer block to wg0.conf:

    ini
    [Peer]
    

    phone

    PublicKey = <contents of phone_public.key> AllowedIPs = 10.8.0.2/32

    Start WireGuard:

    bash
    sudo systemctl enable --now wg-quick@wg0

    Open the WireGuard port in UFW:

    bash
    sudo ufw allow 51820/udp

    Tell Pi-hole it is OK to answer the tunnel subnet — Settings → DNS → Interface listening behavior → Respond only on interface eth0 (or "Permit all origins" if you want maximum flexibility, but prefer the former). Also restrict UFW so port 53 is only reachable from 10.8.0.0/24.

    Create a phone config and render a QR code:

    bash
    cat <<EOF | sudo tee /etc/wireguard/phone.conf
    [Interface]
    PrivateKey = $(sudo cat /etc/wireguard/phone_private.key)
    Address = 10.8.0.2/32
    DNS = 10.8.0.1

    [Peer] PublicKey = $(sudo cat /etc/wireguard/server_public.key) Endpoint = 203.0.113.45:51820 AllowedIPs = 0.0.0.0/0 PersistentKeepalive = 25 EOF

    sudo qrencode -t ansiutf8 < /etc/wireguard/phone.conf

    Scan the QR code with the official WireGuard app on iOS or Android, connect, and your phone's DNS now flows through Pi-hole — ads blocked on cellular, airport Wi-Fi, and everywhere else.

    For a detailed WireGuard walkthrough including split-tunnel setups, see our WireGuard installation guide.

    Step 10: Front Pi-hole with Nginx (Optional)

    The default lighttpd admin UI runs on port 80 without HTTPS. For remote admin over the public internet, put Pi-hole behind Nginx with a Let's Encrypt certificate. If the admin UI will only be reached over WireGuard, you can safely skip this section.

    Install Nginx and Certbot:

    bash
    sudo apt install -y nginx certbot python3-certbot-nginx

    Change Pi-hole's lighttpd to listen only on localhost. Edit /etc/lighttpd/lighttpd.conf and set:

    text
    server.bind = "127.0.0.1"
    server.port = 8080

    Restart lighttpd:

    bash
    sudo systemctl restart lighttpd

    Create the Nginx vhost:

    bash
    sudo tee /etc/nginx/sites-available/pihole > /dev/null <<'EOF'
    server {
        listen 80;
        server_name pihole.example.com;
        return 301 https://$host$request_uri;
    }

    server { listen 443 ssl http2; server_name pihole.example.com;

    ssl_certificate /etc/letsencrypt/live/pihole.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/pihole.example.com/privkey.pem;

    add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff;

    location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } EOF

    sudo ln -s /etc/nginx/sites-available/pihole /etc/nginx/sites-enabled/ sudo certbot --nginx -d pihole.example.com sudo nginx -t && sudo systemctl reload nginx

    For the full reverse-proxy reference including rate-limits, HTTP/3, and multi-vhost patterns, see our Nginx reverse proxy guide.

    Post-Install: Blocklists and Tuning

    Out of the box Pi-hole ships with the Steven Black unified host list, which blocks the major ad networks. You can add more from the UI under Group Management → Adlists. Popular additions:

    • https://adaway.org/hosts.txt — mobile ad networks
    • https://v.firebog.net/hosts/Easyprivacy.txt — tracking
    • https://raw.githubusercontent.com/PolishFiltersTeam/KADhosts/master/KADhosts.txt — phishing
    • https://urlhaus.abuse.ch/downloads/hostfile/ — malware C2
    After adding, run:

    bash
    pihole -g

    Expected output:

    text
    [i] Neutrino emissions detected...
      [✓] Pulling blocklist source list into range
      [✓] Preparing new gravity database
      [✓] Storing downloaded domains in new gravity database
      [✓] Building tree
      [✓] Swapping databases

    Set up a weekly update cron if you want fresh lists without manual runs — Pi-hole already creates one under /etc/cron.d/pihole.

    For per-client rules, use Groups: assign specific clients (by IP or MAC) to groups with different blocklists. This is how you implement parental controls — the kids' tablets get a strict group, adults get the standard group.

    Troubleshooting

    ProblemCauseSolution
    [✗] DNS resolution is currently unavailable during installsystemd-resolved is holding port 53sudo systemctl disable --now systemd-resolved && sudo rm /etc/resolv.conf && echo "nameserver 1.1.1.1" \</td><td>sudo tee /etc/resolv.conf, then re-run installer
    Clients get "DNS_PROBE_FINISHED_NXDOMAIN"UFW blocking port 53 from the client IPsudo ufw allow from <client-ip> to any port 53 or widen to your WireGuard subnet
    Admin UI returns 403 from Nginxlighttpd access-control rulesEdit /etc/lighttpd/external.conf and allow the proxy IP, or switch to the Docker install
    Unbound returns SERVFAIL for every queryMissing root.hints or DNSSEC trust anchorsudo unbound-anchor -a /var/lib/unbound/root.key && sudo systemctl restart unbound
    Pi-hole dashboard shows 0 clientsAll queries arriving from the router IPDisable the router's DNS relay; point clients directly at Pi-hole, or enable Conditional Forwarding
    pihole -up fails with git errorsPartial install or permission driftsudo pihole -r and choose Reconfigure to repair without losing settings
    High CPU spikes every few minutesQuery logging rotation on slow diskMove /etc/pihole/pihole-FTL.db to a tmpfs or disable long-term stats in Settings
    Docker container loses config on restartBind mounts not populatedEnsure ./etc-pihole and ./etc-dnsmasq.d exist before first docker compose up; fix with docker compose down && docker compose up -d

    Useful Commands

    bash
    # Service status
    pihole status

    Live query log

    pihole -t

    Flush the query database

    pihole flush

    Update Pi-hole itself

    sudo pihole -up

    Update blocklists now

    pihole -g

    Disable blocking temporarily (e.g. 5 minutes)

    pihole disable 5m

    FAQ

    Is it safe to run Pi-hole on a public VPS?

    Yes, if you restrict DNS (port 53) to your own devices via UFW or a WireGuard tunnel. Never leave port 53 open to 0.0.0.0/0 on the public internet — open resolvers are abused for DNS amplification attacks and your provider will send abuse complaints. The recommended setup in this guide is to bind Pi-hole to the WireGuard interface and only accept queries from VPN peers.

    Pi-hole vs AdGuard Home — which should I pick?

    Both are excellent. Pi-hole has a more mature ecosystem, more community blocklists, and a slightly lighter footprint. AdGuard Home has DNS-over-HTTPS/TLS/QUIC built in, per-client settings out of the box, and a more modern UI. If you want the classic rock-solid tool that integrates cleanly with Unbound and a Linux admin workflow, install Pi-hole. If you want encrypted DNS and per-device filtering without extra components, see our AdGuard Home guide.

    Do I need Unbound or can I just use Cloudflare 1.1.1.1?

    Cloudflare, Quad9, and Google DNS all work fine as upstreams, but every query still leaks to a third party. Unbound runs a local recursive resolver that talks directly to the DNS root servers, so no single provider sees your full query history. For maximum privacy, pair Pi-hole with Unbound. For maximum speed on a low-traffic VPS with a shared Cloudflare cache, any of the big public resolvers is fine.

    Can Pi-hole replace my home router's DHCP?

    Yes, and it gives the best client-level visibility because Pi-hole then sees each device by hostname. However, running DHCP on a VPS only makes sense if the VPS is on the same L2 network as your clients, which is rare. On a public VPS, the realistic approach is to leave DHCP on your local router and point that router's DNS at the VPS (or use the WireGuard approach from Step 9).

    How much does Pi-hole save vs NextDNS or Control D?

    NextDNS Pro is around $20/year per account with a 300k queries/month soft cap, Control D Full Control is around $40/year. A CloudCore Starter VPS at EUR 7.99/month (~EUR 60/year) is more expensive in raw dollars, but you get unlimited queries, unlimited devices, a full Linux VPS you can reuse for other workloads (WireGuard, Nginx, Uptime Kuma), and zero third-party logging.

    How many devices can one Pi-hole instance handle?

    A single-core VPS with 1 GB of RAM comfortably serves 50-100 devices and easily over a million queries per day. The bottleneck is rarely CPU — it is usually network round-trip time to the upstream resolver, which is why running Unbound locally makes a noticeable latency difference. For enterprise workloads (thousands of clients), run two Pi-hole instances with a floating IP or anycast.

    Does Pi-hole block YouTube ads?

    Only partially. YouTube serves ads from the same domains as video content (googlevideo.com), so DNS-level blocking cannot separate ads from playback without breaking video. For full YouTube ad blocking, pair Pi-hole with browser-level solutions like uBlock Origin or a SmartTV app like SmartTube. Pi-hole does block most other web and mobile ad/tracking networks very effectively.

    Next Steps

    Now that Pi-hole is protecting your network, here are worthwhile follow-ups:

    • Lock down queries over WireGuard only — If you followed Step 9, remove the public UFW rules for port 53 so only tunneled peers can query. Your VPS becomes invisible to DNS scanners.
    • Add AdGuard Home as a secondary — Run both on the same VPS with different ports, and point different client groups at each. Lets you compare blocklist coverage in production.
    • Deploy Unbound with DNSSEC — Full DNSSEC validation ensures no upstream resolver can lie to you about a domain.
    • Set up status monitoring with Uptime Kuma — Add an HTTPS ping on the admin UI and a "DNS" probe that resolves example.com via your Pi-hole. Get alerted before users notice.
    • Front the admin UI with Nginx — Covered in Step 10; gives you HTTPS, HTTP/2, and per-IP rate limits.
    • Backup your blocklists and clients — pihole -a -t creates a teleporter archive of all settings. Store it off-box so you can rebuild in 2 minutes.
    • Read the official Pi-hole documentation — The upstream docs are excellent and cover advanced topics like conditional forwarding, regex blocking, and the FTL API.

    Prefer a VPS that is ready for self-hosted infrastructure?
    >
    CloudCore's Starter plan at EUR 7.99/month gives you 2 vCPU, 4 GB RAM, 50 GB NVMe, and unmetered bandwidth — everything Pi-hole, Unbound, and WireGuard need with room to spare.
    >
    - Ubuntu 24.04 LTS image in under 60 seconds
    - Full root SSH access and snapshots
    - Upgrade to Professional as your client count grows
    >
    Launch your Starter VPS and start blocking ads network-wide today.

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket