Files
dns-serrvice/README.md
T
Hermes ab8d472b7b fix: prefer RHEL paths in BIND path detection to avoid ambiguity
之前的探测顺序优先 Debian 路径 (/etc/bind/named.conf.local),
在某些混合/历史场景下会选错:当两个 named.conf.local 都存在时
(RHEL 默认 /etc/named.conf.local + 之前手动 touch 的 /etc/bind/named.conf.local),
named 实际只读其中一个,但代码会写到另一个,导致 zone 写出来了
但 named 不加载。

调整候选顺序,把 RHEL 路径(/etc/named.conf.local、/etc/named.conf)
放在 Debian 路径前面:

  BIND_CONF_LOCAL:   /etc/named.conf.local -> /etc/bind/named.conf.local
  BIND_CONF_OPTIONS: /etc/named.conf -> /etc/bind/named.conf.options

Dev 环境(Debian)行为不变(/etc/bind/named.conf.options 和
/etc/bind/named.conf.local 实际存在,依然命中 Debian 路径)。

README '配置 BIND' 一节明确两套发行版的差异,并强调 named 主配置
必须 include 对应的 named.conf.local 文件,否则 zone 文件存在但
named 不会加载。
2026-07-22 17:47:52 +08:00

335 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DNS Web Manager
基于 BIND9 的 DNS 服务器 Web 管理界面,使用 Flask + SQLite 构建。
## 功能概览
| 功能 | 说明 |
|------|------|
| 仪表盘 | BIND 服务状态、域名/记录统计、服务控制(启动/停止/重启/重载) |
| 域名管理 | 创建/删除 Zone(支持 master/slave)、查看 Zone 详情、编辑原始 zone 文件 |
| 记录管理 | 添加/删除 DNS 记录(A、AAAA、CNAME、MX、TXT、NS、PTR、SRV、CAA |
| DNS 查询 | 在线 dig 测试,支持所有记录类型 |
| 配置管理 | 在线编辑 `named.conf.options``named.conf.local`,带语法校验 |
| 操作日志 | 全部操作的审计日志,支持分页 |
| 用户认证 | 登录/登出/修改密码 |
## 截图
### 仪表盘
- BIND 服务状态卡片(运行状态、开机自启)
- 域名数量、记录总数统计
- 服务控制按钮(启动/停止/重启/重载)
- 域名概览表格
- 最近操作日志
### 域名管理
- 域名列表(域名、类型、Zone 文件、记录数)
- 创建域名表单(域名、类型、NS 服务器、管理员邮箱)
- Zone 详情页:SOA 信息、记录列表、添加记录表单、原始文件编辑
### DNS 查询
- 输入域名 + 记录类型 + DNS 服务器,执行 dig 查询
- 显示完整 dig 输出
## 技术栈
- **DNS 服务器**: BIND 9.18+named
- **Web 框架**: Flask 3.0
- **数据库**: SQLite(用户认证 + 审计日志)
- **前端**: Jinja2 模板 + 原生 CSS(无前端框架依赖)
- **WSGI 服务器**: Gunicorn
## 目录结构
```
dns-service/
├── app.py # Flask 应用主文件(路由、模型、BIND 操作)
├── wsgi.py # Gunicorn 入口
├── init_db.py # 数据库初始化脚本
├── requirements.txt # Python 依赖
├── README.md
├── templates/ # Jinja2 模板
│ ├── base.html # 布局模板(导航栏 + 页脚)
│ ├── login.html # 登录页
│ ├── dashboard.html # 仪表盘
│ ├── zones.html # 域名列表
│ ├── zone_form.html # 创建域名表单
│ ├── zone_detail.html # Zone 详情 + 记录管理
│ ├── zone_raw.html # 原始 Zone 文件编辑
│ ├── query.html # DNS 查询测试
│ ├── config.html # BIND 配置管理
│ ├── logs.html # 操作日志
│ ├── change_password.html
│ └── error.html # 错误页
├── static/
│ └── style.css # 全部样式
└── instance/ # SQLite 数据库(运行时生成)
└── dns_web.db
```
## BIND 配置文件
| 文件 | 用途 | 默认路径(Debian/Ubuntu |
|------|------|---------------------------|
| `named.conf` | 主配置 | `/etc/bind/named.conf` |
| `named.conf.options` | 全局选项(监听端口、转发器、查询权限) | `/etc/bind/named.conf.options` |
| `named.conf.local` | Zone 声明(由 Web UI 自动管理) | `/etc/bind/named.conf.local` |
| zone files | DNS 记录文件 | `/etc/bind/zones/db.*` |
> **路径自动探测**:服务启动时按常见路径顺序探测实际存在的目录/文件,覆盖 Debian/Ubuntu、RHEL/CentOS/Rocky、AlmaLinux、FreeBSD 等发行版默认布局。如需强制指定,可用环境变量覆盖(见"路径优先级")。
## 安装部署
### 1. 安装 BIND9
```bash
apt-get update
apt-get install -y bind9 bind9utils dnsutils
```
### 2. 配置 BIND
不同发行版默认路径、默认 include 的文件都不同,下面分别给出**全新机器**的初始化步骤。如果机器上已经有 BIND 在跑,只看对应小节的"追加 include"步骤即可。
**核心要点**Web UI 写入 zone 声明的文件(`named.conf.local`**必须**被 named 主配置 include,否则 zone 文件存在但 named 不会加载。
#### Debian / Ubuntubind9
默认路径:`/etc/bind/named.conf``/etc/bind/named.conf.options``/etc/bind/named.conf.local``/etc/bind/zones/`
```bash
apt-get update
apt-get install -y bind9 bind9utils dnsutils
# 创建 zone 文件目录(项目代码默认就写这里)
mkdir -p /etc/bind/zones
chown bind:bind /etc/bind/zones
# named.conf.options(监听 53 端口)
cat > /etc/bind/named.conf.options << 'EOF'
options {
directory "/var/cache/bind";
listen-on port 53 { any; };
listen-on-v6 { none; };
forwarders { 8.8.8.8; 8.8.4.4; };
allow-query { any; };
allow-recursion { 127.0.0.0/8; 10.168.1.0/24; };
dnssec-validation auto;
auth-nxdomain no;
};
EOF
# named.confbind9 包默认就是这套,确认一下即可)
grep -q '/etc/bind/named.conf.local' /etc/bind/named.conf || \
echo 'include "/etc/bind/named.conf.local";' >> /etc/bind/named.conf
# named.conf.local(空,由 Web UI 自动填充;首次部署建一个空文件)
touch /etc/bind/named.conf.local
chown bind:bind /etc/bind/named.conf.local
systemctl enable named
systemctl restart named
```
#### RHEL / CentOS 7 / Rocky Linux / AlmaLinux
默认路径:`/etc/named.conf``/var/named/``/etc/named.conf.local`(默认**不创建**)、`/etc/rndc.key`
```bash
yum install -y bind bind-utils
# /var/named 默认就有;如果没建过,手动建
mkdir -p /var/named
chown root:named /var/named
chmod 2770 /var/named
# 关键:RHEL 的 /etc/named.conf 默认不 include /etc/named.conf.local
# 必须手动追加,否则 Web UI 写的 zone 声明不会生效
grep -q '/etc/named.conf.local' /etc/named.conf || \
echo 'include "/etc/named.conf.local";' >> /etc/named.conf
# 空白入口文件,让 named 重启时不报"include 文件不存在"
touch /etc/named.conf.local
chown root:named /etc/named.conf.local
chmod 640 /etc/named.conf.local
systemctl enable named
systemctl restart named
```
### 3. 安装 Web 应用
```bash
git clone ssh://git@git.cnbugs.com:10022/AI-Agent/dns-service.git
cd dns-service
# 安装 Python 依赖
pip install -r requirements.txt
# 创建数据库目录
mkdir -p instance
# 初始化数据库(创建默认 admin/admin 账号)
python3 init_db.py
# 启动(开发模式)
python3 app.py
```
### 4. 生产部署(Gunicorn + Systemd
```bash
# 创建 systemd 服务
cat > /etc/systemd/system/dns-web.service << 'EOF'
[Unit]
Description=DNS Web Manager
After=network.target named.service
[Service]
Type=notify
User=root
WorkingDirectory=/root/dns-service
ExecStart=/usr/local/bin/gunicorn --workers 2 --bind 0.0.0.0:5300 wsgi:app
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable dns-web
systemctl start dns-web
```
### 5. 路径优先级
服务启动时按下面的顺序确定每个 BIND 路径:
1. **环境变量**(最高优先级,用于强制指定非默认路径)
2. **自动探测**(按常见路径顺序,找到第一个存在的目录/文件)
3. **内置默认值**(都没探测到时使用,主要为 Debian/Ubuntu
自动探测覆盖以下发行版默认布局:
| 变量 | 探测顺序 |
|------|----------|
| `BIND_CONF_DIR` | `/etc/bind``/etc``/etc/named` |
| `BIND_ZONES_DIR` | `/etc/bind/zones``/var/named``/var/named/data` |
| `BIND_CONF_LOCAL` | `/etc/named.conf.local``/etc/bind/named.conf.local` |
| `BIND_CONF_OPTIONS` | `/etc/named.conf``/etc/bind/named.conf.options` |
| `BIND_RNDC_KEY` | `/etc/bind/rndc.key``/etc/rndc.key``/var/named/key` |
| `BIND_SERVICE` | 固定 `named` |
> **`BIND_CONF_LOCAL` / `BIND_CONF_OPTIONS` 探测顺序说明**RHEL/CentOS 的 `/etc/named.conf` 默认 include 的是 `/etc/named.conf.local`Debian/Ubuntu 默认 include 的是 `/etc/bind/named.conf.local`。代码里**优先探测 RHEL 路径**——这样可以避免"两个文件都存在但 named 只读其中一个"的歧义场景(典型踩坑:zone 文件写出来了,但 named 不加载)。
大多数情况下**无需任何配置**——Debian 上自然走 `/etc/bind/*`CentOS/RHEL 上自然走 `/var/named` + `/etc/named.conf*`
只有以下两种场景需要用环境变量强制覆盖:
- BIND 装在非标准路径(比如容器里 mount 到 `/opt/bind`
- 同机多实例 / 测试场景,需要指向特定路径
覆盖示例(systemd):
```bash
cat > /etc/systemd/system/dns-web.service << 'EOF'
[Unit]
Description=DNS Web Manager
After=network.target named.service
[Service]
Type=notify
User=root
WorkingDirectory=/root/dns-service
Environment=BIND_ZONES_DIR=/opt/bind/zones
ExecStart=/usr/local/bin/gunicorn --workers 2 --bind 0.0.0.0:5300 wsgi:app
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl restart dns-web
```
> 注意:覆盖 `BIND_CONF_LOCAL` 后,**必须**让 named 主配置 include 这个文件。CentOS 7 的 `/etc/named.conf` 默认不会 include,需要按上面"配置 BIND / RHEL"一节里的命令追加 `include "/etc/named.conf.local";`。
## 使用说明
### 登录
- 访问 `http://<服务器IP>:5300`
- 默认账号: `admin` / 密码: `admin`
- 首次登录后请修改密码
### 创建域名
1. 进入「域名管理」→「+ 添加域名」
2. 填写域名(如 `example.com`)、选择类型(master/slave
3. 可选填写 NS 服务器和管理员邮箱(留空则自动生成)
4. 点击「创建域名」
### 添加 DNS 记录
1. 进入域名详情页
2. 点击「+ 添加记录」
3. 填写记录名称、类型、TTL、数据
4. 点击「添加」
**记录类型说明:**
| 类型 | 数据格式 | 示例 |
|------|----------|------|
| A | IPv4 地址 | `10.168.1.100` |
| AAAA | IPv6 地址 | `2001:db8::1` |
| CNAME | 别名(FQDN,以 `.` 结尾) | `www.example.com.` |
| MX | 优先级 + 邮件服务器(FQDN) | `10 mail.example.com.` |
| TXT | 文本内容 | `"v=spf1 ~all"` |
| NS | NS 服务器(FQDN | `ns1.example.com.` |
| PTR | 反向解析目标(FQDN | `host.example.com.` |
| SRV | 优先级 权重 端口 目标 | `10 5 5060 sip.example.com.` |
### DNS 查询测试
1. 进入「DNS 查询」页面
2. 输入域名和记录类型
3. DNS 服务器留空默认查询本地 BIND127.0.0.1:53
4. 点击「查询」查看结果
### 配置管理
1. 进入「配置管理」页面
2. 可在线编辑 `named.conf.options`(监听端口、转发器等)
3. 可在线编辑 `named.conf.local`Zone 声明)
4. 保存时自动执行 `named-checkconf` 校验,通过后自动 `rndc reload`
### 服务控制
在「仪表盘」页面可控制 BIND 服务:
- **启动** - `systemctl start named`
- **停止** - `systemctl stop named`
- **重启** - `systemctl restart named`
- **重载配置** - `rndc reload`(不中断服务,热加载 zone 变更)
## 注意事项
1. **权限要求**: Web 应用需要 root 权限运行(用于操作 BIND 配置文件和 systemctl 命令)
2. **端口冲突**: 如果 53 端口被其他服务占用(如 dnsmasq),需先停掉对应服务
3. **Zone 文件权限**: zone 文件需要 `bind:bind` 所有权,Web UI 自动设置
4. **Serial 自动递增**: 每次添加/删除记录时,SOA Serial 自动递增(YYYYMMDDNN 格式)
5. **配置备份**: 编辑配置文件时自动创建 `.bak` 备份
## API 接口
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/status` | 获取 BIND 服务状态(需登录) |
## License
MIT