A self-hosted web GUI to view, add, edit, delete Cloudflare DNS records (A, AAAA, CNAME, TXT, MX, PTR) — all in one container. Includes light/dark mode, error popups, and record protections.
- List DNS records (A, AAAA, CNAME, TXT, MX, PTR)
- Add / Edit / Delete records (except read-only Cloudflare-managed entries)
- Proxy toggle support (A / AAAA / CNAME)
- Comments on records (tooltip icon)
- Search / filter by type & free-text
- Bulk delete with “Delete Selected”
- Error handling via toast popups
- Dark mode toggle (persistent)
- Clean UI with modals, tooltips, hover effects
- Single container (React + Express), multi-stage Docker build
- Debug logging for all upstream API calls
- Go to My Profile → API Tokens → Create Custom Token
- Grant Zone:Read + DNS:Edit permissions
- Restrict to specific zones if needed
- Copy the token (starts with
cf…
) - Get your Zone ID from your domain’s Overview page
Create a .env
file in the project root (or use .env.example
):
Name | Required | Example | Description |
---|---|---|---|
APP_PASSWORD |
✅ | s3cr3tPass |
Password for UI / API access |
CF_API_TOKEN |
✅ | cfabcd1234… |
Cloudflare API token |
PORT |
❌ | 8080 (default) |
Server port |
APP_PASSWORD=your_ui_password
CF_API_TOKEN=your_cloudflare_api_token
PORT=8080
This uses a multi-stage Docker build to bundle backend and frontend.
Create a docker-compose.yml
file in your project root:
version: '3.8'
services:
cf-dns-manager:
build:
context: .
dockerfile: Dockerfile
container_name: cf-dns-manager
ports:
- "8080:8080"
environment:
- APP_PASSWORD=${APP_PASSWORD}
- CF_API_TOKEN=${CF_API_TOKEN}
- PORT=${PORT:-8080}
env_file:
- .env
restart: unless-stopped
Then run:
docker-compose up --build -d
docker build -t cf-dns-manager .
docker run -d -p 8080:8080 \
-e APP_PASSWORD=${APP_PASSWORD} \
-e CF_API_TOKEN=${CF_API_TOKEN} \
cf-dns-manager
Access the UI at: http://localhost:8080
- Logging: Express logs Cloudflare API calls via morgan + console
- CSS: No Tailwind/Bootstrap; uses CSS variables
- Theme: Toggle switch in footer, saved via localStorage
- Tooltips: Truncation + ellipsis for long fields
- Blank page / 401 → Check
APP_PASSWORD
in.env
- 403 / 9007 errors → Validate record fields (CNAME, TXT)
- Missing zones → Check token scope and zone access
- “Delete Selected” always enabled → Bug in selection logic
.
├── backend/
│ └── server.js
│ └── package.json
├── frontend/
│ ├── src/
│ │ ├── components/
│ │ │ ├── DnsManager.jsx
│ │ │ ├── ZoneSelect.jsx
│ │ │ ├── Login.jsx
│ │ │ ├── Toast.jsx
│ ├── styles.css
│ ├── package.json
│ └── vite.config.js
├── Dockerfile
├── docker-compose.yml
└── .env.example / README.md
Powered by Cloudflare DNS API • © iAmSaugata
Built with Node.js (Express) + React + Vite + CSS.