外观
16 - 运维操作手册
本文是 TDNS 日常运维的操作手册,每一步都给到可直接复制的命令。按章节对号入座,照着做就行。
服务管理
systemd 部署
bash
# 启动 / 停止 / 重启
sudo systemctl start tdns
sudo systemctl stop tdns
sudo systemctl restart tdns
# 热重载(不中断现有查询,改配置首选)
sudo systemctl reload tdns
# 查看状态 + 最近日志
sudo systemctl status tdns
# 开机自启
sudo systemctl enable tdns
sudo systemctl disable tdns # 关闭自启
# 查看最近 100 行日志
journalctl -u tdns -n 100 --no-pager
# 实时跟踪日志
journalctl -u tdns -fDocker 部署
bash
# 启动
docker compose up -d
# 停止 / 重启
docker compose down
docker compose restart tdns
# 查看日志
docker compose logs -f tdns
# 进入容器排查
docker compose exec tdns sh
# 热重载(容器内发 SIGHUP)
docker compose exec tdns kill -HUP 1裸进程部署
bash
# 前台运行(调试首选,日志直接输出到终端)
tdns --config /etc/tdns/tdns.toml --log-level debug
# 后台运行
nohup tdns --config /etc/tdns/tdns.toml &
echo $! > /var/run/tdns/tdns.pid
# 优雅关闭(等现有查询处理完再退出)
kill -TERM $(cat /var/run/tdns/tdns.pid)
# 热重载
kill -HUP $(cat /var/run/tdns/tdns.pid)配置变更流程
标准变更步骤(4 步)
bash
# 1️⃣ 备份当前配置(永远先备份)
sudo cp /etc/tdns/tdns.toml /etc/tdns/tdns.toml.bak.$(date +%Y%m%d%H%M)
# 2️⃣ 编辑配置
sudo vi /etc/tdns/tdns.toml
# 3️⃣ 验证配置(语法 + 逻辑校验,不会启动服务)
tdns --validate --config /etc/tdns/tdns.toml
# 或用 CLI 工具
tdnsctl validate /etc/tdns/tdns.toml
# 4️⃣ 热重载,立即生效
sudo systemctl reload tdns
# 或
tdnsctl reload
# 确认状态
tdnsctl status哪些变更能热重载,哪些必须重启?
| 变更项 | 热重载 | 重启 | 说明 |
|---|---|---|---|
| Zone 文件内容 | ✅ | — | 原子替换,不中断查询 |
新增 / 删除 [[zones]] | ✅ | — | 区域加载 / 卸载 |
| ACL 地址列表 | ✅ | — | 访问控制即时更新 |
| 转发器列表 | ✅ | — | 上游变更即时生效 |
| 缓存配置(大小、TTL) | ✅ | — | 缓存参数更新 |
| 安全配置(RRL 等) | ✅ | — | 速率限制即时生效 |
server.listen-addrs / listen-port | — | ✅ | 监听地址变更需重新绑定 |
server.workers | — | ✅ | 线程数变更 |
[tls] / [doh] 启用 / 禁用 | — | ✅ | 监听器变更 |
[api] / [metrics] 启用 / 禁用 | — | ✅ | HTTP 服务器变更 |
| Feature flag 变更 | — | ✅ | 需重新编译 |
经验法则:改"内容"的走热重载,改"监听"的重启。不确定就先
--validate,过了再reload。
区域管理
添加新区域(Zone 文件方式,4 步)
bash
# 1️⃣ 创建 Zone 文件
sudo vi /etc/tdns/zones/newzone.com.zonetext
; /etc/tdns/zones/newzone.com.zone
$TTL 3600
@ IN SOA ns1.example.com. admin.example.com. (
2026081001 ; Serial —— 每次改记录递增
3600 ; Refresh
1800 ; Retry
604800 ; Expire
86400 ) ; Minimum TTL
IN NS ns1.example.com.
@ IN A 192.0.2.10
www IN A 192.0.2.20bash
# 2️⃣ 在配置中声明区域
sudo vi /etc/tdns/tdns.tomltoml
[[zones]]
name = "newzone.com"
file = "/etc/tdns/zones/newzone.com.zone"
type = "master"bash
# 3️⃣ 验证 + 热重载
tdnsctl validate /etc/tdns/tdns.toml
tdnsctl reload
# 4️⃣ 验证解析
dig @127.0.0.1 www.newzone.com A
dig @127.0.0.1 newzone.com SOA通过 REST API 添加记录(无需改 Zone 文件)
bash
TOKEN="your-secret-token"
BASE="http://127.0.0.1:8080"
# 添加 A 记录(区域不存在会自动创建)
curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"api.newzone.com","type":"A","ttl":300,"data":"192.0.2.30"}' \
"$BASE/api/v1/zones/newzone.com/records"
# 验证
dig @127.0.0.1 api.newzone.com A +short修改 Zone 文件后递增 Serial
BIND 格式要求每次修改 Zone 文件后递增 SOA Serial,否则次级服务器不会同步:
text
@ IN SOA ns1.example.com. admin.example.com. (
2026081001 ; Serial — 改记录后改成 2026081002Serial 推荐格式:YYYYMMDDNN(年月日 + 当日序号),如 2026081001 → 2026081002。
删除区域(3 步)
bash
# 1️⃣ 从配置中移除 [[zones]] 段
sudo vi /etc/tdns/tdns.toml
# 2️⃣ 可选:删除 Zone 文件
sudo rm /etc/tdns/zones/oldzone.com.zone
# 3️⃣ 验证 + 热重载
tdnsctl validate /etc/tdns/tdns.toml
tdnsctl reload缓存管理
查看缓存统计
bash
tdnsctl stats输出包含缓存条目数、命中率、正 / 负缓存数量等。
清空全部缓存
配置变更或区域更新后,清空缓存让变更立即生效:
bash
# CLI
tdnsctl flush
# API
curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:8080/api/v1/cache/flush清空指定域名缓存
bash
# CLI
tdnsctl flush-name www.example.com
# API
curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:8080/api/v1/cache/flush/www.example.com缓存调优建议
| 场景 | 推荐配置 |
|---|---|
| 高 QPS 公网 DNS | max-size = "4GB", prefetch-enabled = true |
| 内网 DNS | max-size = "512MB" |
| 权威 DNS(无递归) | cache.enabled = false 或小缓存 |
| 低延迟要求 | min-ttl = 30, prefetch-threshold = 0.9 |
| 防缓存投毒 | negative-ttl = 60, max-negative-entries = 10000 |
日志管理
日志轮转
systemd 自动管理 journald 日志。对于文件日志,配置 logrotate:
# /etc/logrotate.d/tdns
/var/log/tdns/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
copytruncate
}临时启用调试日志
bash
# 停止后台服务
sudo systemctl stop tdns
# 前台调试运行(日志直接输出到终端)
tdns --config /etc/tdns/tdns.toml --log-level debug
# 或 trace 级别(更详细)
tdns --config /etc/tdns/tdns.toml --log-level trace关键日志过滤
bash
# 递归解析失败
journalctl -u tdns | grep "recursive.*failed\|SERVFAIL"
# 上游超时
journalctl -u tdns | grep "upstream.*timeout"
# ACL 拒绝
journalctl -u tdns | grep "REFUSED\|ACL"
# Zone 加载失败
journalctl -u tdns | grep "zone.*error\|zone.*failed"
# TLS 握手失败
journalctl -u tdns | grep "handshake.*failed"备份与恢复
配置备份(定期 cron)
bash
# 手动备份配置 + Zone 文件
sudo tar -czf tdns-backup-$(date +%Y%m%d).tar.gz \
/etc/tdns/tdns.toml \
/etc/tdns/zones/ \
/etc/tdns/root.hints
# 每日凌晨 2 点自动备份
echo "0 2 * * * tar -czf /backup/tdns-$(date +\%Y\%m\%d).tar.gz /etc/tdns/" | sudo crontab -区域数据导出(通过 API)
bash
# 导出所有区域的记录为 JSON
curl -s -H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:8080/api/v1/zones | jq -r '.zones[].origin' | \
while read zone; do
curl -s -H "Authorization: Bearer $TOKEN" \
"http://127.0.0.1:8080/api/v1/zones/$zone/records" > "/backup/${zone}.json"
done恢复流程(5 步)
bash
# 1️⃣ 停止服务
sudo systemctl stop tdns
# 2️⃣ 恢复配置
sudo tar -xzf tdns-backup-20260810.tar.gz -C /
# 3️⃣ 验证配置
tdns --validate --config /etc/tdns/tdns.toml
# 4️⃣ 启动
sudo systemctl start tdns
# 5️⃣ 确认状态
tdnsctl status证书管理(DoT / DoH)
查看证书有效期
bash
openssl x509 -in /etc/tdns/tls/fullchain.pem -noout -dates证书续期(Let's Encrypt)
bash
# 续期
sudo certbot renew --quiet
# 续期后热重载 TDNS(重新加载证书)
sudo systemctl reload tdns证书过期告警(cron)
bash
# 每天检查,过期前 30 天告警
echo "0 9 * * * openssl x509 -in /etc/tdns/tls/fullchain.pem -checkend 2592000 -noout || echo 'TDNS certificate expiring soon!'" | crontab -root.hints 更新(递归模式)
递归模式需要定期更新 root.hints 文件:
bash
# 从 IANA 下载最新根提示
curl -o /etc/tdns/root.hints https://www.internic.net/domain/named.root
# 或用 dig 直接查询根服务器
dig @a.root-servers.net . NS > /etc/tdns/root.hints
# 热重载生效
sudo systemctl reload tdns建议每 3-6 个月更新一次。根服务器 IP 很少变更,但保持更新是好习惯。
性能调优
内核参数
bash
# /etc/sysctl.d/tdns.conf
# UDP 缓冲区(高 QPS 场景必调)
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.rmem_default = 4194304
net.core.wmem_default = 4194304
# 连接队列
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
# 端口范围(转发 / 递归模式)
net.ipv4.ip_local_port_range = 10240 65535
# 应用
sudo sysctl --system文件描述符限制
bash
# /etc/security/limits.d/tdns.conf
tdns soft nofile 65535
tdns hard nofile 65535systemd 服务文件中也设置:
ini
[Service]
LimitNOFILE=65535Worker 线程
toml
[server]
workers = 0 # 0 = 自动检测 CPU 核心数(推荐)手动设置:
toml
[server]
workers = 4 # 建议等于或小于物理核心数安全运维
API Token 轮换
bash
# 1️⃣ 生成新 Token
NEW_TOKEN=$(openssl rand -hex 32)
# 2️⃣ 更新配置(注意字段名是 auth-token)
sudo sed -i "s/^auth-token = .*/auth-token = \"$NEW_TOKEN\"/" /etc/tdns/tdns.toml
# 3️⃣ 热重载
tdnsctl reload
# 4️⃣ 更新客户端环境变量
export TDNS_API_TOKEN="$NEW_TOKEN"定期检查清单
| 检查项 | 频率 | 命令 |
|---|---|---|
| 证书有效期 | 每周 | openssl x509 -checkend 2592000 -noout |
| root.hints 更新 | 每 3-6 月 | 对比 IANA 版本 |
| 缓存命中率 | 每日 | tdnsctl stats |
| RRL 丢弃率 | 每日 | curl -s http://localhost:9090/metrics | grep rrl |
| 上游可用性 | 每日 | curl -s http://localhost:9090/metrics | grep upstream |
| 配置备份 | 每周 | tar 备份 |
| 日志清理 | 每月 | logrotate |
| Rust 安全公告 | 随时 | 关注 Rust 安全公告 |
下一步
- 17 - 故障排查指南 — 遇到问题怎么查
- 15 - 监控与可观测性 — Prometheus + 日志 + 健康检查
- 14 - CLI管理工具 — tdnsctl 命令速查