ab8d472b7b
之前的探测顺序优先 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 不会加载。
335 lines
11 KiB
Markdown
335 lines
11 KiB
Markdown
# 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 / Ubuntu(bind9)
|
||
|
||
默认路径:`/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.conf(bind9 包默认就是这套,确认一下即可)
|
||
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 服务器留空默认查询本地 BIND(127.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
|