A complete self-hosted DNS + reverse proxy stack using BIND9, Traefik, and Docker Compose, supporting both Cloudflare (default) and Namecheap for automated DNS-based SSL certificates via Let’s Encrypt (ACME).
Designed as a DevOps lab project for managing custom DNS, HTTPS, and containerized infrastructure.
This project simulates a production-grade DNS and reverse proxy setup:
- BIND9 acts as an authoritative DNS for your custom domain.
- Traefik handles HTTPS termination and automatic certificate generation.
- You can switch between Cloudflare or Namecheap as the DNS API provider without editing configuration files.
- Managed entirely with a single
deploy.shscript.
Built and tested on Ubuntu Server 24.04 LTS using Docker Compose, all services communicate on a shared frontend network.
| Component | Description |
|---|---|
| BIND9 | Authoritative DNS server for your internal or public domain (e.g. anganba.me) |
| Traefik v3.5 | Reverse proxy providing HTTPS with automatic certificate renewal |
| Let's Encrypt (ACME) | SSL/TLS certificate authority used via DNS challenge |
| Cloudflare / Namecheap | Supported DNS APIs for ACME DNS-01 challenge |
| Nginx | Example backend web service |
| Portainer | Web-based UI for Docker management |
┌─────────────────────┐
│ Client (Web) │
└─────────┬───────────┘
│ HTTPS (443)
▼
┌──────────────────────┐
│ Traefik │
│ Reverse Proxy + SSL │
└─────────┬────────────┘
│ Internal network (frontend)
┌───────────────┴───────────────┐
│ │
┌──────────────┐ ┌─────────────────┐
│ Nginx App │ │ Portainer UI │
└──────────────┘ └─────────────────┘
│ │
▼ ▼
nginx.alo.anganba.me portainer.alo.anganba.me
│ │
▼ ▼
┌────────────────────────────────────────────────────┐
│ BIND9 DNS │
│ ns.anganba.me (local) │
└────────────────────────────────────────────────────┘
- 🔄 Switch between Cloudflare and Namecheap DNS easily
- 🔐 Automated SSL via Let's Encrypt DNS-01 challenge
- 🧩 Modular services (Traefik, BIND9, Nginx, Portainer)
- 📜 Single deployment script (
deploy.sh) - 🧠 Local authoritative DNS management
- 🧱 Real-world DevOps lab setup
- A valid domain name (e.g.,
anganba.me) - API credentials for Cloudflare and/or Namecheap
- Installed dependencies:
sudo apt install docker.io docker-compose -y
- A Linux server or VM (tested on Ubuntu Server 24.04)
git clone https://github.com/Anganba/TraeDNS.git
cd TraeDNSYou can use either Cloudflare (default) or Namecheap.
sudo nano Traefik/.env.cloudflarePROVIDER=cloudflare
ACME_EMAIL=info@yourdomain
CF_DNS_API_TOKEN=your_cloudflare_api_tokensudo nano Traefik/.env.namecheapPROVIDER=namecheap
ACME_EMAIL=info@yourdomain
NAMECHEAP_API_USER=your_username
NAMECHEAP_API_KEY=your_api_key
NAMECHEAP_API_URL=https://api.namecheap.com/xml.responseUpdate the zone file for your domain in:
bind9/config/anganba-me.zone
Example:
ns IN A 192.168.68.129
alo IN A 192.168.68.129
*.alo IN A 192.168.68.129
Replace
192.168.68.129with your server’s IP address.
If you skip this step, DNS queries and SSL validation will fail.
Also Your Namecheap account must have: API access enabled under “Profile → Tools → Namecheap API Access”. Your host’s public IP added to the “API Whitelist IPs” section. If you don't have your local VMs' public IP or VPS IP get whitelisted in the Namecheap API section, TLS Handshake will fail.
Create a network called "frontend" since it is hardcoded in the script. Run:
sudo docker network create frontendMake the deploy script executable:
sudo chmod +x deploy.shThen start the full infrastructure:
sudo ./deploy.sh upTo switch providers:
sudo ./deploy.sh up namecheapCheck running status:
sudo ./deploy.sh statusUsage: sudo ./deploy.sh {up|down|restart|status} [cloudflare|namecheap]
Examples:
./deploy.sh up # Start stack using Cloudflare (default)
./deploy.sh up namecheap # Start stack using Namecheap
./deploy.sh restart cloudflare # Restart stack using Cloudflare
./deploy.sh status # Show running containers
| Service | URL | Description |
|---|---|---|
| Traefik Dashboard | https://traefik.alo.anganba.me | Reverse proxy UI (insecure mode ON for lab) |
| Portainer | https://portainer.alo.anganba.me | Docker management UI |
| Nginx Demo | https://nginx.alo.anganba.me | Example app |
Check your DNS server resolution:
dig @192.168.68.129 portainer.alo.anganba.meTest from client machine:
nslookup nginx.alo.anganba.me 192.168.68.129Certificates are automatically generated and renewed using Let’s Encrypt DNS challenge.
Stored in:
Traefik/data/certs/cloudflare-acme.json
Traefik/data/certs/namecheap-acme.json
Set permissions:
sudo chmod 600 Traefik/data/certs/*.json- Check file permissions for ACME files
- Verify DNS A-records resolve correctly
- Wait 5–10 minutes for DNS propagation
- Ensure correct API tokens or keys are in
.envfiles
- Confirm
named.confincludes your zone - Run:
to verify successful zone loading.
docker logs dns-bind9
- Ensure domain/subdomain exists in your DNS zone.
- Let’s Encrypt does not issue certificates for internal-only domains (e.g.,
.local).
If you want to access those https://traefik.yea.zenorahost.com in your windows or local machine, make sure to point your DNS settings preferred DNS to VM's IP where DNS server is running and as alternative DNS use 1.1.1.1 or 8.8.8.8.
dns-traefik-lab/
├── bind9/
│ ├── config/
│ │ ├── named.conf
│ │ └── anganba-me.zone
│ ├── cache/
│ ├── records/
│ └── docker-compose.yaml
├── Traefik/
│ ├── config/
│ │ └── traefik.yaml
│ ├── data/certs/
│ │ ├── cloudflare-acme.json
│ │ └── namecheap-acme.json
│ ├── .env.cloudflare
│ ├── .env.namecheap
│ └── docker-compose.yaml
├── nginx/
│ └── docker-compose.yaml
├── Portainer-Server/
│ └── docker-compose.yaml
├── deploy.sh
└── README.md
digDNS resolution showing correct IP mapping
- Traefik dashboard with routers + TLS certs

- NGINX Browser view with HTTPS padlock

- Portainer dashboard running behind Traefik

- Add HAProxy for load balancing
- Enable IPv6 for Traefik and BIND9
- Integrate Grafana + Prometheus monitoring
- Add Automatic DNS Sync with Cloudflare API
MIT License — Free for educational and demonstration use.
Anganba Singha
DevOps | Linux Server Administrator | Cybersecurity Enthusiast