# 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