{"id":49606124,"url":"https://github.com/alvarezops/privacy-shield","last_synced_at":"2026-05-04T13:04:12.930Z","repository":{"id":329033565,"uuid":"1111418465","full_name":"alvarezops/privacy-shield","owner":"alvarezops","description":"DNS Infrastructure with AdBlocking and Recursive Resolution #Pihole #RaspberryPi #Unbound","archived":false,"fork":false,"pushed_at":"2026-01-07T13:36:46.000Z","size":14548,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-04T12:43:32.882Z","etag":null,"topics":["adblock","dns","docker","docker-compose","homelab","networking","pi-hole","privacy","raspberry-pi","recursive-dns","security","sovereignty","unbound"],"latest_commit_sha":null,"homepage":"https://www.linkedin.com/in/jadomin/","language":null,"has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alvarezops.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-06T22:31:09.000Z","updated_at":"2026-04-15T22:16:56.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/alvarezops/privacy-shield","commit_stats":null,"previous_names":["jalvarez-netdev/privacy-shield","alvarezdevnet/privacy-shield","alvarezops/privacy-shield"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/alvarezops/privacy-shield","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvarezops%2Fprivacy-shield","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvarezops%2Fprivacy-shield/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvarezops%2Fprivacy-shield/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvarezops%2Fprivacy-shield/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alvarezops","download_url":"https://codeload.github.com/alvarezops/privacy-shield/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvarezops%2Fprivacy-shield/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32608319,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-04T10:08:07.713Z","status":"ssl_error","status_checked_at":"2026-05-04T10:08:02.005Z","response_time":58,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["adblock","dns","docker","docker-compose","homelab","networking","pi-hole","privacy","raspberry-pi","recursive-dns","security","sovereignty","unbound"],"created_at":"2026-05-04T13:04:11.804Z","updated_at":"2026-05-04T13:04:12.922Z","avatar_url":"https://github.com/alvarezops.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🛡️ Pi-hole + Unbound (Docker Edition) - Power User\n\n![intropihole.png](assets/intropihole.png)\n\n\u003e \"You are the master of your own network.\"\n\nThis project deploys a professional **Ad Blocking** and **DNS Sovereignty** solution using **Docker** containers.\nIt replaces your ISP's or Google's DNS with a private, encrypted infrastructure that is 100% controlled by you.\n\n---\n\n### 🛑 STOP: READ BEFORE USE\n\n**This project is NOT \"Plug \u0026 Play\".**\nFor this to work on your home network, **you must** understand the basics of networking.\n\n**Mandatory Requirements:**\n1.  **Static IP:** Your Server (Raspberry Pi/PC) MUST have a static IP assigned by your Router (e.g., `192.168.88.88`).\n2.  **Time Synchronization:** The Host machine MUST have the correct time and date. DNSSEC relies on cryptographic timestamps; if your time is off, DNS resolution will fail.\n3.  **Persistence:** Use an external SSD (like Samsung T5) for the `/docker` folder to prevent microSD corruption.\n\n---\n\n### Software Architecture\n\n* **[Pi-hole v6](https://pi-hole.net/):** The Shield (\"DNS Sinkhole\"). It intercepts and blocks requests for ads, trackers, and telemetry at the network level.\n* **[Unbound](https://github.com/klutchell/unbound):** The Recursive Resolver. It queries the Internet Root Servers directly, ensuring data integrity and removing intermediaries.\n* **[Docker](https://www.docker.com/):** Ensures an isolated, reproducible, and clean deployment.\n\n---\n\n## Privacy \u0026 Sovereignty Philosophy\n\nThis project strictly adheres to the **Data Sovereignty** principle:\n\n* **Zero Reliance:** We do not rely on upstream providers like Google (`8.8.8.8`) or Cloudflare (`1.1.1.1`).\n* **Privacy by Design:** By using recursive resolution, no single entity centralizes your browsing history. You are your own DNS provider.\n* **Security:** DNSSEC validation is enforced to prevent DNS spoofing.\n\n---\n\n## Installation \u0026 Deployment\n\n### 1. Prerequisites\n\n* **Hardware:** Raspberry Pi 4 (4GB RAM) or higher recommended.\n* **Software:** Docker and Docker Compose installed.\n* **Network:** Port **53** must be free on the host machine.\n\n### 2. File Structure\n\nCreate the following folder structure.\n*Note: The `.gitignore` file is vital to avoid uploading logs and private data to GitHub.*\n\n```text\nprivacy-shield/\n├── .env                \u003c-- Local secrets (ignored by Git)\n├── .gitignore          \u003c-- Prevents leaking private data\n├── docker-compose.yml\n└── etc-unbound/\n    └── unbound.conf    \u003c-- Recursive configuration\n```\n\n**Recommended content for `.gitignore`:**\n```text\netc-pihole/\netc-dnsmasq.d/\netc-unbound/\n*.log\n.DS_Store\n.env\n```\n\n### 3. Service Definition (`docker-compose.yml`)\n\nWe use a static internal network (`10.10.10.0/24`).\n**CRITICAL:** This configuration includes `cap_add` and time volume mappings to prevent DNSSEC failures on modern Pi-hole versions.\n\n```yaml\nservices:\n  # Recursive DNS Resolver\n  unbound:\n    container_name: unbound\n    image: klutchell/unbound:latest\n    restart: unless-stopped\n    hostname: unbound\n    volumes:\n      - ./etc-unbound:/opt/unbound/etc/unbound/\n    networks:\n      privacy_net:\n        ipv4_address: 10.10.10.2\n    # Log Rotation Policy: Prevent disk saturation\n    logging:\n      driver: \"json-file\"\n      options:\n        max-size: \"10m\"\n        max-file: \"3\"\n\n  # DNS Sinkhole and Ad-blocker\n  pihole:\n    container_name: pihole\n    image: pihole/pihole:latest\n    restart: unless-stopped\n    hostname: pihole\n    depends_on:\n      - unbound\n    ports:\n      - \"53:53/tcp\"\n      - \"53:53/udp\"\n      - \"8080:80/tcp\"\n    cap_add:\n      - SYS_TIME\n      - SYS_NICE\n    environment:\n      - TZ=${TIMEZONE}\n      - WEBPASSWORD=${PIHOLE_WEB_PASSWORD}\n      - PIHOLE_DNS_=${PIHOLE_DNS_IP}#53\n      - DNSSEC=true\n      - DNSMASQ_LISTENING=all\n      - MAXDBDAYS=90 # Database retention limit (3 months)\n    volumes:\n      - ./etc-pihole:/etc/pihole\n      - ./etc-dnsmasq.d:/etc/dnsmasq.d\n      - /etc/localtime:/etc/localtime:ro\n      - /etc/timezone:/etc/timezone:ro\n    networks:\n      privacy_net:\n        ipv4_address: 10.10.10.3\n    # Log Rotation Policy: Prevent disk saturation\n    logging:\n      driver: \"json-file\"\n      options:\n        max-size: \"10m\"\n        max-file: \"3\"\n\nnetworks:\n  privacy_net:\n    driver: bridge\n    ipam:\n      config:\n        - subnet: 10.10.10.0/24\n```\n\n### 4. Deployment\n\nYou can use the included automated script or run it manually:\n\n```bash\ndocker compose up -d\n```\n\n---\n\n## Dashboard Access\n\n**URL Format:** `http://\u003cYOUR_LOCAL_IP\u003e:8080/admin`\n\n\n![image.png](assets/pihole-main.png)\n\n---\n\n## ⚙️ Critical Post-Install Configuration\n\nMandatory steps in the web dashboard:\n\n### 1. Link to Unbound (Upstream DNS)\n\n* Go to **Settings \u003e DNS**.\n* **Uncheck** all external providers (Google, OpenDNS, etc).\n* In **\"Custom 1 (IPv4)\"**, type: 👉 **`10.10.10.2#53`**\n* **IMPORTANT:** Ensure the **\"Use DNSSEC\"** box is **CHECKED**.\n\n![image.png](assets/image%201.png)\n\n### 2. Permit Docker Traffic (CRITICAL) ⚠️\n\n* In the same DNS tab, under **\"Interface Settings\"**.\n* Select the option: 👉 **\"Permit all origins\"** (Or verify `pihole.toml` listeningMode=\"all\").\n\n\u003e **Why?** Due to Docker's internal networking (NAT), requests appear to come from the internal Docker IP range, not your LAN. If you restrict this, Pi-hole will block valid queries. This is safe as long as port 53 is not exposed to the WAN (Internet).\n\n### 3. Add Blocklists\n\n1.  Go to **Group Management \u003e Adlists**.\n2.  Add recommended URLs (StevenBlack, Firebog, etc).\n3.  Go to **Tools \u003e Update Gravity** and click **Update**.\n\n---\n\n## Router Configuration\n\n⚠️ **ATTENTION:** Perform these steps **ONLY** after you have verified the dashboard works.\n\n1.  **IP Reservation:** Lock your Raspberry Pi's IP (e.g., `192.168.88.88`) in your Router's DHCP settings.\n2.  **DNS Assignment:** Change your Router's **Primary DNS** to your Raspberry Pi's IP. Leave Secondary DNS **EMPTY**.\n3.  **Disable IPv6 (Recommended):** To prevent leaks, disable IPv6 on your Router or individual clients if possible.\n\n### 🛰️ Advanced: MikroTik NAT Hijacking (Optional)\nIf you use a MikroTik router, apply these rules to force all devices to use Pi-hole (prevents hardcoded DNS bypass):\n\n```routeros\n# Redirect external DNS queries to Pi-hole\n/ip firewall nat\nadd chain=dstnat protocol=udp dst-port=53 src-address=!192.168.88.88 \\\n    action=dst-nat to-addresses=192.168.88.88 to-ports=53 comment=\"DNS Hijacking\"\n\n# Fix Hairpin NAT for internal resolution\n/ip firewall nat\nadd chain=srcnat protocol=udp src-address=192.168.88.0/24 dst-address=192.168.88.88 \\\n    dst-port=53 action=masquerade comment=\"Fix Hairpin NAT\"\n```\n\n---\n\n## Troubleshooting\n\n### \"BOGUS\" or \"Servfail\" on all domains\nThis usually means the time is out of sync.\n1. Check host time: `date`\n2. Check container time: `docker exec -it pihole date`\n3. If they differ, ensure `cap_add: SYS_TIME` is in your compose file and restart.\n\n### Port 53 Conflict (Ubuntu)\nIf `systemd-resolved` occupies port 53:\n1. `sudo nano /etc/systemd/resolved.conf` -\u003e set `DNSStubListener=no`\n2. `sudo systemctl restart systemd-resolved`\n\n### Password Reset\n```bash\ndocker exec -it pihole pihole -a -p\n```\n\n---\n\n## 📜 License\n\nMIT Licence\n\n---\n\n### 👤 Author\n\n**[José Álvarez Dominguez]**\n* [GitHub Profile](https://github.com/alvarezdevnet)\n* [LinkedIn](https://www.linkedin.com/in/jadomin/)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falvarezops%2Fprivacy-shield","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falvarezops%2Fprivacy-shield","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falvarezops%2Fprivacy-shield/lists"}