dns主从服务配置主服务器shell脚本#!/bin/bash set -euo pipefail #configuration parameters MASTER_IP192.168.153.131 DOMAINweb.com REV_ZONE153.168.192.in-addr.arpa SLAVE_IP192.168.153.132 #tool parameters info(){ echo -e \033[32m[info] $1\033[0m; } warn() { echo -e \033[33m[WARN] $1\033[0m; } error() { echo -e \033[31m[ERROR] $1\033[0m; exit 1; } #dynamic cursor spinner(){ local pid$1 local msg$2 local spin\|/- local i0 while kill -0 $pid 2/dev/null; do i$(( (i1) %4 )) echo -ne \r[${spin:$i:1}] $msg sleep 0.1 done echo -ne \r[√] $msg\n } #main clear info DNS primary server configuration script info 主服务器IP: $MASTER_IP info 域名: $DOMAIN info 反向区域: $REV_ZONE info 从服务器IP: $SLAVE_IP info #check if the user is the root user if [ $(id -u) -ne 0 ]; then error please run the script as the root usersudo -i 或 su - fi # 1. install bind package info step1/6Installing bind package... dnf install -y bind bind-utils /dev/null || error Failed to install bind package. Check your repository. # 2. Configure named.conf info step2/6Configuring /etc/named.conf... cat /etc/named.conf EOF options { listen-on port 53 { $MASTER_IP; 127.0.0.1; }; directory /var/named; dump-file /var/named/data/cache_dump.db; statistics-file /var/named/data/named_stats.txt; memstatistics-file /var/named/data/named_mem_stats.txt; allow-query { any; }; allow-transfer { $SLAVE_IP; }; dnssec-validation no; recursion no; }; # forward resolution zone zone $DOMAIN IN { type master; file $DOMAIN.zone; }; # reverse resolution zone zone $REV_ZONE IN { type master; file $REV_ZONE.zone; }; EOF # 立即设置 named.conf 的权限 info Setting permissions for /etc/named.conf... chown root:named /etc/named.conf || error Failed to change owner of /etc/named.conf chmod 640 /etc/named.conf || error Failed to change permissions of /etc/named.conf # 3. Configure forward zone file info step3/6Configuring forward zone file ($DOMAIN.zone)... cat /var/named/$DOMAIN.zone EOF \$TTL 1D IN SOA ns1.$DOMAIN. admin.$DOMAIN. ( $(date %Y%m%d%H) 1D 1H 1W 3H ) NS ns1.$DOMAIN. NS ns2.$DOMAIN. ns1 A $MASTER_IP ns2 A $SLAVE_IP www A $MASTER_IP EOF # 4. Configure reverse zone file info step4/6Configuring reverse zone file ($REV_ZONE.zone)... MASTER_IP_LAST$(echo $MASTER_IP | awk -F. {print $4}) cat /var/named/$REV_ZONE.zone EOF \$TTL 1D IN SOA ns1.$DOMAIN. admin.$DOMAIN. ( $(date %Y%m%d%H) 1D 1H 1W 3H ) NS ns1.$DOMAIN. NS ns2.$DOMAIN. $MASTER_IP_LAST PTR ns1.$DOMAIN. $MASTER_IP_LAST PTR www.$DOMAIN. EOF # 立即设置区域文件的权限 info Setting permissions for zone files... chown root:named /var/named/$DOMAIN.zone /var/named/$REV_ZONE.zone || error Failed to change owner of zone files chmod 640 /var/named/$DOMAIN.zone /var/named/$REV_ZONE.zone || error Failed to change permissions of zone files # 5. Final permission and SELinux configuration info step5/6Finalizing permissions and SELinux... # 强制确保 /var/named 目录的权限和上下文正确 info Securing /var/named directory... chown root:named /var/named || error Failed to change owner of /var/named chmod 770 /var/named || error Failed to change permissions of /var/named # 配置防火墙 info Configuring firewall... (firewall-cmd --add-port53/tcp --add-port53/udp --permanent firewall-cmd --reload) /dev/null spinner $! Firewall configuration in progress... # 配置SELinux if [ $(getenforce) Enforcing ]; then info Configuring SELinux... (setsebool -P named_write_master_zones on setsebool -P named_read_master_zones on) /dev/null spinner $! SELinux booleans in progress... info Restoring SELinux contexts... (restorecon -Rv /var/named restorecon /etc/named.conf) /dev/null spinner $! SELinux context restoration in progress... fi # 6. Start and verify the named service info step6/6Starting named service... systemctl enable --now named /dev/null || error Failed to start named service. Check logs with: journalctl -u named # 验证服务状态 if systemctl is-active --quiet named; then info The named service started successfully! else error The named service failed to start. Please check the log: journalctl -u named fi # 最终提示 info info Master DNS server configuration completed successfully! info Verification command: dig $MASTER_IP www.$DOMAIN info Slave server configuration: Please run the setup_dns_slave.sh script on the slave server. info 从服务器shell脚本#!/bin/bash set -euo pipefail # 开启严格模式出错立即退出 # 配置参数根据实际环境修改 SLAVE_IP192.168.153.132 # 从服务器IP MASTER_IP192.168.153.131 # 主服务器IP用于同步区域文件 DOMAINweb.com # 要解析的域名与主服务器一致 REV_ZONE153.168.192.in-addr.arpa # 反向解析区域与主服务器一致 # # 工具函数 info() { echo -e \033[32m[INFO] $1\033[0m } warn() { echo -e \033[33m[WARN] $1\033[0m } error() { echo -e \033[31m[ERROR] $1\033[0m exit 1 } spinner() { local pid$1 local msg$2 local spin\|/- local i0 while kill -0 $pid 2/dev/null; do i$(( (i1) %4 )) echo -ne \r[${spin:$i:1}] $msg sleep 0.1 done echo -ne \r[√] $msg\n } # # 主逻辑 clear info DNS 从服务器配置脚本 info 从服务器IP: $SLAVE_IP info 主服务器IP: $MASTER_IP info 域名: $DOMAIN info 反向区域: $REV_ZONE info # 1. 检查是否为root用户 if [ $(id -u) -ne 0 ]; then error 请以root用户执行脚本sudo -i 或 su - fi # 2. 安装BIND软件 info 步骤1/6安装BIND软件... dnf install -y bind bind-utils /dev/null spinner $! 正在安装bind包... # 3. 配置named.conf info 步骤2/6配置named.conf... cat /etc/named.conf EOF options { listen-on port 53 { $SLAVE_IP; 127.0.0.1; }; directory /var/named; dump-file /var/named/data/cache_dump.db; statistics-file /var/named/data/named_stats.txt; memstatistics-file /var/named/data/named_mem_stats.txt; allow-query { any; }; dnssec-validation no; recursion no; }; # 正向解析区域从服务器 zone $DOMAIN IN { type slave; masters { $MASTER_IP; }; file slaves/$DOMAIN.zone; }; # 反向解析区域从服务器 zone $REV_ZONE IN { type slave; masters { $MASTER_IP; }; file slaves/$REV_ZONE.zone; }; EOF # 立即设置 named.conf 的权限 info 步骤3/6调整文件和目录权限... chown root:named /etc/named.conf || error Failed to change owner of /etc/named.conf chmod 640 /etc/named.conf || error Failed to change permissions of /etc/named.conf # 确保 /var/named 和 slaves 目录权限正确 chown root:named /var/named || error Failed to change owner of /var/named chmod 770 /var/named || error Failed to change permissions of /var/named # 检查named.conf语法 named-checkconf /etc/named.conf || error named.conf配置语法错误请检查脚本配置参数 # 4. 配置防火墙和SELinux info 步骤4/6配置防火墙和SELinux... # 配置防火墙开放53端口 (firewall-cmd --add-port53/tcp --add-port53/udp --permanent firewall-cmd --reload) /dev/null spinner $! 正在配置防火墙... # 处理SELinux若开启 if [ $(getenforce) Enforcing ]; then info 正在配置SELinux... (setsebool -P named_write_slave_zones on setsebool -P named_read_slave_zones on) /dev/null spinner $! 正在设置SELinux布尔值... info 正在恢复SELinux上下文... (restorecon -Rv /var/named restorecon /etc/named.conf) /dev/null spinner $! 正在恢复文件SELinux上下文... fi # 5. 启动named服务 info 步骤5/6启动named服务... systemctl enable --now named /dev/null || error named服务启动失败请检查日志journalctl -u named # 验证服务状态 if systemctl is-active --quiet named; then info named服务启动成功 else error named服务启动失败状态异常 fi # 6. 等待并验证区域文件同步 info 步骤6/6等待从主服务器同步区域文件... SYNC_TIMEOUT20 SYNC_INTERVAL2 SYNC_COUNT0 while [ $SYNC_COUNT -lt $((SYNC_TIMEOUT / SYNC_INTERVAL)) ]; do if [ -f /var/named/slaves/$DOMAIN.zone ] [ -f /var/named/slaves/$REV_ZONE.zone ]; then info 区域文件同步成功 break fi SYNC_COUNT$((SYNC_COUNT 1)) echo -ne \r[INFO] 正在等待同步...${SYNC_COUNT}s/${SYNC_TIMEOUT}s sleep $SYNC_INTERVAL done echo -ne \r # 清除等待行 # 同步失败处理 if [ $SYNC_COUNT -ge $((SYNC_TIMEOUT / SYNC_INTERVAL)) ]; then warn 区域文件同步超时请检查 warn 1. 主从服务器网络连通性ping $MASTER_IP warn 2. 主服务器named服务是否正常运行 warn 3. 主服务器named.conf中allow-transfer是否包含从服务器IP$SLAVE_IP warn 4. 查看从服务器日志journalctl -u named | grep -i transfer fi # 最终提示 info info 从服务器配置完成 info 验证命令查询从服务器dig $SLAVE_IP www.$DOMAIN info 高可用测试停止主服务器named服务systemctl stop named再查询从服务器验证解析 info DNS 主从服务器自动化配置脚本笔记一、脚本概述1. 核心用途基于CentOS/RHEL 8系统自动化部署BINDDNS主从架构实现域名正向 / 反向解析及高可用主服务器配置正向 / 反向解析区域、开放从服务器同步权限、配置防火墙 / SELinux从服务器同步主服务器区域文件、提供备用解析服务、主服务器故障时自动接管2. 适用环境操作系统CentOS 8/RHEL 8依赖dnf包管理器、firewalld、SELinux网络要求主从服务器网络互通TCP/UDP 53 端口开放、root 权限执行软件依赖bindDNS 服务、bind-utilsDNS 测试工具如dig3. 架构核心逻辑主服务器192.168.153.131 从服务器192.168.153.132 ├─ 配置正向区域web.com.zone ├─ 配置slave类型区域 ├─ 配置反向区域153.168.192.zone ├─ 从主服务器同步区域文件 ├─ 允许从服务器同步allow-transfer ├─ 提供查询服务与主服务器解析结果一致 └─ 监听53端口接收查询/同步请求 └─ 主服务器故障时自动响应客户端查询二、脚本结构解析两个脚本均遵循「配置参数→工具函数→主逻辑」的结构核心模块如下1. 通用模块主从脚本共用模块功能说明配置参数集中定义 IP、域名、反向区域等核心变量如MASTER_IP、DOMAIN便于修改工具函数info/warn/error日志输出带颜色区分spinner动态进度条提升体验权限检查强制要求 root 用户执行id -u ! 0则退出服务验证启动named后检查服务状态systemctl is-active2. 主服务器脚本核心逻辑6 步步骤关键操作安装依赖用dnf安装bind、bind-utils配置named.conf监听主服务器 IP、允许从服务器同步、关闭 DNSSEC / 递归正向区域文件创建web.com.zone定义ns1/ns2解析、www记录反向区域文件创建153.168.192.in-addr.arpa.zone定义PTR反向解析记录权限 / 安全配置修正named.conf、区域文件、/var/named目录权限配置防火墙 / SELinux启动验证启用并启动named输出验证命令dig 主IP www.web.com3. 从服务器脚本核心逻辑6 步步骤关键操作安装依赖与主服务器一致安装bind、bind-utils配置named.conf监听从服务器 IP、定义slave类型区域、指向主服务器 IP权限调整修正named.conf、/var/named目录权限确保同步文件可写安全配置开放防火墙 53 端口、配置 SELinux 允许从服务器同步启动服务启用并启动named自动向主服务器请求区域同步同步验证等待 20 秒检查同步文件是否存在超时输出排查建议三、使用说明1. 执行前提主从服务器均安装CentOS 8/RHEL 8且网络互通ping测试主从服务器均配置好yum/dnf源确保能安装bind执行用户为root或通过sudo -i切换2. 执行步骤主服务器执行# 上传主服务器脚本如 setup_dns_master.sh chmod x setup_dns_master.sh ./setup_dns_master.sh从服务器执行# 上传从服务器脚本如 setup_dns_slave.sh chmod x setup_dns_slave.sh ./setup_dns_slave.sh3. 验证方法验证场景命令主服务器正向解析dig 192.168.153.131 www.web.com返回192.168.153.131主服务器反向解析dig 192.168.153.131 -x 192.168.153.131返回ns1.web.com从服务器同步验证dig 192.168.153.132 www.web.com返回与主服务器一致结果高可用测试主服务器执行systemctl stop named再查询从服务器解析正常四、核心改进建1. 兼容性优化解决跨版本 / 环境问题问题当前脚本仅支持CentOS 8依赖dnf不兼容CentOS 7yum包管理器未检查firewalld/bind依赖是否已安装。解决方案增加 OS 版本检测自动适配yum/dnf# 在脚本开头添加OS检测 detect_package_manager() { if [ -f /etc/redhat-release ]; then if grep -q CentOS Linux 7 /etc/redhat-release; then PKG_MGRyum else PKG_MGRdnf fi else error 不支持的操作系统 fi } # 安装依赖时使用 $PKG_MGR $PKG_MGR install -y bind bind-utils /dev/null 检查firewalld是否安装未安装则自动安装# 防火墙配置前添加检查 if ! command -v firewall-cmd /dev/null; then info firewalld未安装正在安装... $PKG_MGR install -y firewalld /dev/null spinner $! firewalld安装中... systemctl enable --now firewalld /dev/null fi2. 错误处理增强降低排查难度问题当前脚本通过/dev/null屏蔽了大部分操作的详细输出报错时仅提示 “失败”无法定位具体原因如区域文件语法错误、权限修改失败。解决方案保留关键操作的错误输出如named-checkzone/named-checkconf# 原代码屏蔽输出 named-checkzone $DOMAIN /var/named/$DOMAIN.zone || error 正向区域文件语法错误 # 改进后显示详细错误 if ! named-checkzone $DOMAIN /var/named/$DOMAIN.zone; then error 正向区域文件语法错误详细信息$(named-checkzone $DOMAIN /var/named/$DOMAIN.zone 21) fi检查后台进程退出码spinner显示失败状态# 改进spinner函数支持失败标识 spinner(){ local pid$1 local msg$2 local spin\|/- local i0 while kill -0 $pid 2/dev/null; do i$(( (i1) %4 )) echo -ne \r[${spin:$i:1}] $msg sleep 0.1 done # 检查进程退出码 wait $pid if [ $? -eq 0 ]; then echo -ne \r[√] $msg\n else echo -ne \r[×] $msg失败\n error $msg 执行失败请查看日志 fi }3. 幂等性优化支持重复执行问题当前脚本用cat 覆盖式创建文件如named.conf、区域文件重复执行会覆盖原有配置Serial号$(date %Y%m%d%H)可能因同一小时内重复执行导致同步失败。解决方案先备份原有文件再创建新配置# 配置named.conf前备份 if [ -f /etc/named.conf ]; then cp /etc/named.conf /etc/named.conf.bak.$(date %Y%m%d%H%M%S) /dev/null info 已备份原有named.conf到 /etc/named.conf.bak.$(date %Y%m%d%H%M%S) fi自动递增Serial号避免重复# 主服务器正向区域文件Serial号改进 # 读取现有Serial号无则用当前时间有则1 CURRENT_SERIAL$(date %Y%m%d%H) if [ -f /var/named/$DOMAIN.zone ]; then EXIST_SERIAL$(grep -E ^[[:space:]][0-9]{10,} /var/named/$DOMAIN.zone | awk {print $1}) if [ -n $EXIST_SERIAL ] [ $EXIST_SERIAL -ge $CURRENT_SERIAL ]; then CURRENT_SERIAL$((EXIST_SERIAL 1)) fi fi # 区域文件中替换为 $CURRENT_SERIAL4. 安全性增强适配生产环境问题allow-query {any;}开放所有客户端查询生产环境存在安全风险防火墙开放 53 端口给所有主机未限制合法查询网段SELinux 配置过于宽泛setsebool named_write_master_zones on解决方案限制允许查询的网段如公司内网192.168.153.0/24# named.conf 中修改 allow-query allow-query { 192.168.153.0/24; 127.0.0.1; };防火墙规则限制网段# 原代码开放给any firewall-cmd --add-port53/tcp --add-port53/udp --permanent # 改进后仅允许内网网段 firewall-cmd --add-rich-rulerule familyipv4 source address192.168.153.0/24 port port53 protocoltcp accept --permanent firewall-cmd --add-rich-rulerule familyipv4 source address192.168.153.0/24 port port53 protocoludp accept --permanent精细化 SELinux 配置替代宽泛的setsebool# 主服务器区域文件上下文配置 semanage fcontext -a -t named_zone_t /var/named/($DOMAIN|$REV_ZONE).zone restorecon -v /var/named/($DOMAIN|$REV_ZONE).zone5. 可维护性优化降低二次开发成本问题主从脚本存在大量重复代码工具函数、权限配置、防火墙逻辑配置参数内嵌在脚本中批量修改时需编辑两个文件解决方案抽离公共模块为独立脚本如common.sh# common.sh工具函数公共配置 info(){ echo -e \033[32m[info] $1\033[0m; } warn() { echo -e \033[33m[WARN] $1\033[0m; } error() { echo -e \033[31m[ERROR] $1\033[0m; exit 1; } spinner(){ ... } # 公共进度条函数 # 主从脚本引用 source ./common.sh配置参数抽离为独立配置文件如dns_config.sh# dns_config.sh MASTER_IP192.168.153.131 SLAVE_IP192.168.153.132 DOMAINweb.com REV_ZONE153.168.192.in-addr.arpa ALLOW_QUERY192.168.153.0/24 # 允许查询的网段 # 主从脚本引用 source ./dns_config.sh6. 易用性优化提升用户体验问题无参数校验如 IP 格式错误、域名非法时脚本直接执行失败无帮助信息新用户无法快速了解脚本用法从服务器同步超时后需手动排查未提供自动修复机制解决方案增加参数校验IP 格式、域名合法性# IP格式校验函数 validate_ip() { local ip$1 if ! [[ $ip ~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then error IP格式错误$ip fi } # 执行参数校验 validate_ip $MASTER_IP validate_ip $SLAVE_IP增加帮助选项-hif [ $1 -h ] || [ $1 --help ]; then echo 用法$0 [选项] echo -h, --help显示帮助信息 echo -c, --config指定配置文件路径默认./dns_config.sh exit 0 fi从服务器同步超时自动修复# 同步超时后尝试手动触发同步 if [ $SYNC_COUNT -ge $((SYNC_TIMEOUT / SYNC_INTERVAL)) ]; then warn 区域文件同步超时尝试手动触发同步... if ! rndc retransfer $DOMAIN /dev/null; then warn 手动同步失败请执行 journalctl -u named | grep -i transfer 排查 else info 手动同步触发成功等待3秒后验证... sleep 3 if [ -f /var/named/slaves/$DOMAIN.zone ]; then info 区域文件同步成功 fi fi fi7. 功能补充增强生产可用性增加日志记录将所有操作输出到/var/log/dns_setup.log方便排查# 脚本开头添加日志重定向 LOG_FILE/var/log/dns_setup.log exec (tee -a $LOG_FILE) 21服务健康监控配置定时任务crontab检查named服务状态异常时自动重启# 新增健康检查函数 check_named_health() { if ! systemctl is-active --quiet named; then warn named服务异常正在重启... systemctl restart named /dev/null fi } # 添加到crontab每5分钟检查一次 (crontab -l 2/dev/null; echo */5 * * * * /bin/bash $0 --check-health) | crontab -邮件通知配置完成或失败后发送邮件给管理员依赖mailx# 配置完成后发送邮件 send_notify() { echo DNS主服务器配置完成验证命令dig $MASTER_IP www.$DOMAIN | mailx -s DNS配置结果 adminweb.com }五、总结1. 脚本优势自动化程度高一键完成主从 DNS 配置无需手动修改配置文件安全性基础保障配置了最小权限、SELinux / 防火墙规则用户体验友好动态进度条、清晰的日志提示、同步失败排查建议2. 核心改进优先级兼容性优化支持 CentOS 7/8→ 2. 错误处理增强降低排查难度→ 3. 幂等性优化支持重复执行→ 4. 安全性增强适配生产→ 5. 可维护性 / 易用性优化