https://github.com/allenhack638/self-hostable-private-dns
Private DNS resolver with Pi-hole + DoH/DoT + automatic HTTPS. Network-wide ad blocking and secure DNS in Docker.
https://github.com/allenhack638/self-hostable-private-dns
ad-blocking caddy dns dns-over-https dns-over-tls dnsdist docker docker-compose network-filtering pihole privacy private-dns security self-hosted
Last synced: 29 days ago
JSON representation
Private DNS resolver with Pi-hole + DoH/DoT + automatic HTTPS. Network-wide ad blocking and secure DNS in Docker.
- Host: GitHub
- URL: https://github.com/allenhack638/self-hostable-private-dns
- Owner: allenhack638
- Created: 2025-08-09T09:49:43.000Z (10 months ago)
- Default Branch: main
- Last Pushed: 2025-08-21T18:01:58.000Z (9 months ago)
- Last Synced: 2025-08-21T19:27:48.967Z (9 months ago)
- Topics: ad-blocking, caddy, dns, dns-over-https, dns-over-tls, dnsdist, docker, docker-compose, network-filtering, pihole, privacy, private-dns, security, self-hosted
- Homepage: https://github.com/allenhack638/self-hostable-private-dns
- Size: 481 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Self-hosted Private DNS (Pi-hole + Dnsdist + Caddy)

Run your own **private DNS resolver** with advanced filtering, DNS over HTTPS (DoH), and DNS over TLS (DoT) — all in a simple Docker setup.
Pi-hole provides customizable DNS filtering and query logging, dnsdist handles DNS/DoT/DoH backends, and Caddy manages HTTPS with automatic Let's Encrypt certificates.
## ✨ Features
- **Custom DNS filtering**: Centralized control over which domains are resolved
- **Secure DNS**: DoH at `https:///dns-query` and DoT on port `853`
- **Automatic TLS**: Caddy obtains and renews certificates via Let's Encrypt
- **Dashboard**: Full query visibility and management at `https:///admin/`
- **Persistence & health checks**: Data volumes and restart policies included
## 🔧 Prerequisites
### DNS Records
Set up **A/AAAA DNS records** pointing both domains to your server's public IP:
- `DOMAIN_DNS` → e.g., `dns.example.com`
- `DOMAIN_DASHBOARD` → e.g., `dashboard.example.com`
### Port Requirements
Ensure the following ports are available (no other services using them):
- `80, 443` → Caddy (HTTP/HTTPS)
- `53/tcp, 53/udp` → DNS (dnsdist → Pi-hole)
- `853/tcp` → DoT (dnsdist)
## 🚀 Quick Start
1. **Clone the repository:**
```bash
git clone --depth=1 https://github.com/allenhack638/self-hostable-private-dns.git
cd self-hostable-private-dns
```
2. **Configure environment:**
```bash
cp .env.example .env
# Edit .env with your domain names and password
```
3. **Start the stack:**
```bash
docker compose up -d
```
4. ⚠️ **If you see "port 53 already in use" errors, then disable systemd-resolved:**
```bash
# Stop the containers first
docker compose down
# Disable systemd-resolved
sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved
# Start the stack again
docker compose up -d
```
**To re-enable systemd-resolved later (if needed):**
```bash
docker compose down
sudo systemctl enable systemd-resolved
sudo systemctl start systemd-resolved
```
> **Why this order matters**: If you disable `systemd-resolved` first, your system will lose DNS resolution temporarily, preventing Docker from pulling images and Caddy from verifying certificates. Starting the stack first allows everything to download properly, then we only disable `systemd-resolved` if there's actually a conflict.
## ⚙️ Configuration
### Environment Variables
| Variable | Description | Example |
| -------------------------------- | ------------------------------------------------- | ----------------------- |
| `TZ` | Timezone in tz database format | `Asia/Kolkata` |
| `FTLCONF_webserver_api_password` | Dashboard login password (use a strong password!) | `your-secure-password` |
| `DOMAIN_DNS` | Public domain for DoH/DoT (TLS via Caddy) | `dns.example.com` |
| `DOMAIN_DASHBOARD` | Public domain for the dashboard | `dashboard.example.com` |
> **Timezone reference**: See the full list in [tz database time zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).
## 📡 Usage
### Service Endpoints
| Protocol | Address / URL | Port |
| --------- | ----------------------------------- | ---- |
| DNS | `` | 53 |
| DoT | `` | 853 |
| DoH | `https:///dns-query` | 443 |
| Dashboard | `https:///admin/` | 443 |
### Port Summary
| Port(s) | Service |
| -------------- | ----------------------- |
| 53/tcp, 53/udp | DNS (dnsdist → Pi-hole) |
| 80, 443 | Caddy (HTTP/HTTPS) |
| 853/tcp | DoT (dnsdist) |
## 💾 Data & Persistence
- **Pi-hole configuration**: Stored in `data/pihole/`
- **Caddy certificates**: Stored in `data/caddy-data/`
- **Shared certificates**: Copied to `data/shared-certs/` for dnsdist access
All data persists between container restarts and updates.
## 📜 Monitoring & Troubleshooting
### View Logs
**All services (live):**
```bash
docker compose logs -f
```
**Individual services:**
```bash
docker compose logs dns-pihole
docker compose logs dns-caddy
docker compose logs dns-dnsdist
```
### Health Checks
The stack includes built-in health checks and restart policies to ensure services stay running.
## 🙌 Credits
This project is built with these excellent open-source tools:
- [Pi-hole](https://pi-hole.net/) – Network-level DNS filtering and management
- [dnsdist](https://dnsdist.org/) – High-performance DNS load balancer with DoH/DoT support
- [Caddy](https://caddyserver.com/) – Modern web server with automatic HTTPS
## 🤝 Contributing
Issues, questions, and feature requests are welcome! Please open an issue or start a discussion in this repository.
## 📖 Advanced Configuration
Need custom configurations? I can help with:
- Custom ACLs and fine-grained access control
- Advanced dnsdist load-balancing strategies
- Conditional forwarding rules
- Integration with upstream/external resolvers
- Enterprise-grade scaling and security hardening
📬 **Contact**: [allenbenny038@gmail.com](mailto:allenbenny038@gmail.com)