Skip to content

Latest commit

 

History

History
500 lines (384 loc) · 11.7 KB

File metadata and controls

500 lines (384 loc) · 11.7 KB

goddns - 动态 DNS 客户端

Go Version License

goddns 是一个用 Go 编写的轻量级动态 DNS (DDNS) 客户端,支持多域名、多服务商、IPv6,具备跨平台能力和丰富的日志输出。


目录


特性

功能 说明
🌐 多域名支持 一条配置可更新多个 DNS 记录
☁️ 多服务商 支持 Cloudflare、阿里云 DNS
🔒 安全性 强制使用环境变量,禁止明文密钥
🚀 并发更新 多个域名并行更新,提高效率
📦 IPv6 支持 原生支持 IPv6,多平台接口获取
🔄 IP 缓存 避免重复 API 调用
🎨 彩色日志 终端下日志分级彩色显示,支持文件输出
🌍 代理支持 HTTP(S)/SOCKS5 代理,记录级控制

快速开始

1. 构建

# 基础构建
go build -o goddns ./cmd/goddns

# 带版本信息构建
go build -ldflags "-X main.version=v2.0.0" -o goddns ./cmd/goddns

# 使用构建脚本
chmod +x build.sh
./build.sh v2.0.0

2. 配置

创建 config.json

{
    "general": {
        "get_ip": {
            "interface": "eth0",
            "urls": ["https://ipv6.icanhazip.com"]
        },
        "work_dir": "/var/lib/goddns",
        "log_output": "shell"
    },
    "records": [
        {
            "provider": "cloudflare",
            "zone": "example.com",
            "record": "dev",
            "cloudflare": {
                "api_token": "${CLOUDFLARE_API_TOKEN}"
            }
        }
    ]
}

3. 设置环境变量

export CLOUDFLARE_API_TOKEN="your_api_token_here"

4. 运行

# 运行
./goddns run -f config.json

# 忽略缓存强制更新
./goddns run -f config.json -i

# 查看版本
./goddns version

配置指南

安全性要求

⚠️ 重要:出于安全考虑,goddns 禁止在配置文件中明文存储密钥信息。所有敏感信息必须使用环境变量引用。

错误示例(会被拒绝执行):

{
    "cloudflare": {
        "api_token": "your_actual_token_here"
    }
}

正确示例

{
    "cloudflare": {
        "api_token": "${CLOUDFLARE_API_TOKEN}",
        "zone_id": "${CLOUDFLARE_ZONE_ID:-}"
    }
}

完整配置示例

{
    "general": {
        "get_ip": {
            "interface": "eth0",
            "urls": [
                "https://ipv6.icanhazip.com",
                "https://6.ipw.cn"
            ]
        },
        "work_dir": "/var/lib/goddns",
        "log_output": "shell",
        "proxy": ""
    },
    "records": [
        {
            "provider": "cloudflare",
            "zone": "example.com",
            "record": "dev",
            "ttl": 180,
            "proxied": false,
            "use_proxy": false,
            "cloudflare": {
                "api_token": "${CLOUDFLARE_API_TOKEN}",
                "zone_id": "${CLOUDFLARE_ZONE_ID:-}"
            }
        },
        {
            "provider": "aliyun",
            "zone": "example.cn",
            "record": "www",
            "ttl": 600,
            "aliyun": {
                "access_key_id": "${ALIYUN_ACCESS_KEY_ID}",
                "access_key_secret": "${ALIYUN_ACCESS_KEY_SECRET}"
            }
        }
    ]
}

配置字段说明

general(全局配置)

字段 类型 说明 示例
get_ip.interface string 本地网卡名(优先使用) eth0
get_ip.urls []string 外部 IP 检测 API 列表(降级) ["https://ipv6.icanhazip.com"]
work_dir string 缓存文件目录 /var/lib/goddns
log_output string 日志输出,shell 表示终端 shell 或文件路径
proxy string 全局代理(可选) socks5://127.0.0.1:1080

records(记录数组)

字段 类型 说明 必填
provider string 服务商:cloudflarealiyun
zone string 主域名
record string 子域名/记录名(@ 表示根域)
ttl int DNS 记录 TTL(秒)
proxied bool Cloudflare 代理模式
use_proxy bool 是否使用全局代理

Cloudflare 配置

字段 类型 说明
cloudflare.api_token string API Token(环境变量引用)
cloudflare.zone_id string Zone ID(可选,留空自动获取)
cloudflare.ttl int TTL(可选,覆盖记录级)
cloudflare.proxied bool 代理模式(可选,覆盖记录级)

阿里云配置

字段 类型 说明
aliyun.access_key_id string AccessKey ID(环境变量引用)
aliyun.access_key_secret string AccessKey Secret(环境变量引用)
aliyun.ttl int TTL(可选,覆盖记录级)

服务商对比

特性 Cloudflare 阿里云
IPv6 支持
代理支持
自动获取 ZoneID
API 认证 API Token AccessKey

环境变量

支持的环境变量

变量名 说明 示例
CLOUDFLARE_API_TOKEN Cloudflare API Token your_token_here
CLOUDFLARE_ZONE_ID Cloudflare Zone ID(可选) abc123xyz
ALIYUN_ACCESS_KEY_ID 阿里云 AccessKey ID LTAI1234567890
ALIYUN_ACCESS_KEY_SECRET 阿里云 AccessKey Secret your_secret_here

使用方式

# 设置环境变量
export CLOUDFLARE_API_TOKEN="your_token_here"
export ALIYUN_ACCESS_KEY_ID="LTAI1234567890"
export ALIYUN_ACCESS_KEY_SECRET="your_secret_here"

# 运行
./goddns run -f config.json

环境变量默认值

支持 ${VAR:-default} 语法:

{
    "cloudflare": {
        "zone_id": "${CLOUDFLARE_ZONE_ID:-}"
    }
}
  • ${VAR} - 使用环境变量值
  • ${VAR:-default} - 未设置或为空时使用默认值
  • ${VAR-default} - 未设置时使用默认值

自动运行

systemd 定时(推荐)

1. 创建环境变量文件

# /etc/goddns/goddns.env
CLOUDFLARE_API_TOKEN="your_token_here"
ALIYUN_ACCESS_KEY_ID="LTAI1234567890"
ALIYUN_ACCESS_KEY_SECRET="your_secret_here"

# 设置权限(仅 root 可读)
chmod 600 /etc/goddns/goddns.env

2. 创建 service 文件

# /etc/systemd/system/goddns.service
[Unit]
Description=Dynamic DNS client
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/goddns run -f /etc/goddns/config.json
EnvironmentFile=/etc/goddns/goddns.env

3. 创建 timer 文件

# /etc/systemd/system/goddns.timer
[Unit]
Description=Run goddns every 5 minutes

[Timer]
OnBootSec=5min
OnUnitActiveSec=5min
Persistent=true

[Install]
WantedBy=timers.target

4. 启用

sudo systemctl daemon-reload
sudo systemctl enable --now goddns.timer

cron 定时

方式一:使用脚本(推荐)

创建运行脚本:

#!/bin/bash
# /etc/goddns/run-goddns.sh

# 设置 PATH 环境变量(cron 环境中可能需要)
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# 配置路径
GODDNS_BIN="/usr/local/bin/goddns"
GODDNS_CONFIG="/etc/goddns/config.json"
GODDNS_ENV="/etc/goddns/goddns.env"
LOG_FILE="/var/log/goddns-cron.log"

# 加载环境变量文件(如果存在)
if [ -f "$GODDNS_ENV" ]; then
    set -a
    source "$GODDNS_ENV"
    set +a
fi

# 运行 goddns
"$GODDNS_BIN" run -f "$GODDNS_CONFIG"

# 记录退出状态
EXIT_CODE=$?
if [ $EXIT_CODE -eq 0 ]; then
    echo "$(date): goddns executed successfully" >> "$LOG_FILE"
else
    echo "$(date): goddns failed with exit code $EXIT_CODE" >> "$LOG_FILE"
fi

exit $EXIT_CODE

设置权限并配置 crontab:

chmod +x /etc/goddns/run-goddns.sh
crontab -e
# 添加:*/5 * * * * /etc/goddns/run-goddns.sh >> /var/log/goddns-cron.log 2>&1

方式二:直接在 crontab 中设置

crontab -e
# 添加环境变量和任务
CLOUDFLARE_API_TOKEN="your_token_here"
ALIYUN_ACCESS_KEY_ID="LTAI1234567890"
ALIYUN_ACCESS_KEY_SECRET="your_secret_here"

# 每 5 分钟执行一次(推荐)
*/5 * * * * /usr/local/bin/goddns run -f /etc/goddns/config.json >> /var/log/goddns-cron.log 2>&1

# 每小时执行一次
# 0 * * * * /usr/local/bin/goddns run -f /etc/goddns/config.json >> /var/log/goddns-cron.log 2>&1

# 每天执行一次
# 0 0 * * * /usr/local/bin/goddns run -f /etc/goddns/config.json >> /var/log/goddns-cron.log 2>&1

Crontab 时间格式说明

# ┌───────────── 分钟 (0 - 59)
# │ ┌───────────── 小时 (0 - 23)
# │ │ ┌───────────── 日期 (1 - 31)
# │ │ │ ┌───────────── 月份 (1 - 12)
# │ │ │ │ ┌───────────── 星期几 (0 - 7) (星期日=0 或 7)
# │ │ │ │ │
# * * * * * 命令

常用配置示例:

  • */5 * * * * - 每 5 分钟
  • */10 * * * * - 每 10 分钟
  • 0 * * * * - 每小时整点
  • 0 */2 * * * - 每 2 小时
  • 0 0 * * * - 每天午夜
  • 0 0 * * 0 - 每周日凌晨
  • @reboot - 系统启动时执行

注意:cron 环境与交互式 shell 不同,建议使用绝对路径,并确保环境变量文件权限正确(chmod 600)。


平台支持

平台 状态 说明
Linux 使用 netlink 接口
FreeBSD 使用 ioctl 接口
OpenBSD 使用 ioctl 接口
macOS ⚠️ 暂无支持,欢迎提交 PR

项目结构

goddns/
├── cmd/goddns/           # 主程序入口
│   ├── main.go
│   └── cmd.go
├── internal/
│   ├── config/           # 配置管理
│   │   ├── config.go
│   │   └── config_test.go
│   ├── log/              # 日志系统
│   │   └── log.go
│   ├── platform/ifaddr/  # 平台相关网络工具
│   │   ├── linux_netlink.go
│   │   ├── freebsd_ioctl.go
│   │   ├── openbsd_ioctl.go
│   │   ├── shared.go
│   │   ├── shared_test.go
│   │   └── util.go
│   └── provider/         # DNS 服务商实现
│       ├── provider.go
│       ├── factory/
│       ├── cloudflare/
│       └── aliyun/
├── config.example.json   # 配置示例
├── .env.example          # 环境变量示例
├── build.sh              # 构建脚本
└── README.md

常见问题

1. 如何获取 Cloudflare API Token?

访问 Cloudflare Dashboard,创建具有 Zone:DNS:Edit 权限的 Token。

2. 如何获取阿里云 AccessKey?

访问 阿里云 RAM 控制台 创建 AccessKey。

3. Zone ID 如何获取?

  • Cloudflare:Dashboard → Overview 右侧,或留空自动获取
  • 阿里云:不需要

4. 代理如何配置?

{
    "general": {
        "proxy": "socks5://127.0.0.1:1080"
    },
    "records": [
        {
            "use_proxy": true
        }
    ]
}

注意:仅 Cloudflare 支持代理,阿里云不支持。


许可证

采用 BSD 3-Clause License - 详见 LICENSE 文件。


贡献

欢迎提交 Issue 和 Pull Request!