golang基于Digital Ocean DNS的个人动态域名解析插件DDNS的使用
Golang基于Digital Ocean DNS的个人动态域名解析插件DDNS的使用
什么是DDNS
动态DNS(DDNS)是一种自动更新域名系统(DNS)中名称服务器的方法,通常实时更新其配置的主机名、地址或其他信息。
动机
虽然有DynDNS、No-IP等服务可以远程访问PC,但我们真的需要它们吗?这是一个免费的DDNS解决方案(感谢Digital Ocean Networking DNS)。
安装
从发布页面下载二进制文件,并启动它:
ddns
或者使用Docker镜像:
docker run \
-v /path/to/config.yml:/config/ddns.yml \
skibish/ddns -conf-file /config/ddns.yml
文档
运行ddns -h
查看帮助,输出如下:
Usage of ./ddns:
-conf-file string
Location of the configuration file. If not provided, searches current directory, then $HOME for ddns.yml file
-ver
Show version
你需要在Digital Ocean Networks面板中设置你的域名,并在域名提供商配置中将域名指向Digital Ocean NS记录。
配置文件示例
ddns.yml
配置文件示例:
# DDNS configuration file.
# Mandatory, DigitalOcean API token.
# It can be also set using environment variable DDNS_TOKEN.
token: ""
# By default, IP check occurs every 5 minutes.
# It can be also set using environment variable DDNS_CHECKPERIOD.
checkPeriod: "5m"
# By default, timeout to external resources is set to 10 seconds.
# It can be also set using environment variable DDNS_REQUESTTIMEOUT.
requestTimeout: "10s"
# By default, IPv6 address is not requested.
# IPv6 address can be forced by setting it to `true`.
# It can be also set using environment variable DDNS_IPV6.
ipv6: false
# List of domains and their records to update.
domains:
example.com:
# More details about the fields can be found here:
# https://developers.digitalocean.com/documentation/v2/#create-a-new-domain-record
- type: "A"
name: "www"
- type: "TXT"
name: "demo"
# By default, is set to "{{.IP}}" (key .IP is reserved).
# Supports Go template engine.
# Additional keys can be set in "params" block below.
data: "My IP is {{.IP}} and I am {{.mood}}"
# By default, 1800 seconds (5 minutes).
ttl: 1800
# By default, params is empty.
params:
mood: "cool"
# By default, notifications is empty.
notifications:
# Gotify (https://gotify.net)
- type: "gotify"
app_url: "https://gotify.example.com"
app_token: ""
title: "DDNS"
# SMTP
- type: "smtp"
user: "foo@bar.com"
password: "1234"
host: "localhost"
port: "468"
from: "bar@foo.com"
to: "foo@foo.com"
subject: "My DDNS sending me a message"
# Telegram (https://telegram.org)
- type: "telegram"
token: "telegram bot token"
chat_id: "1234"
Go代码示例
以下是一个简单的Go代码示例,展示如何使用Digital Ocean API更新DNS记录:
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/digitalocean/godo"
"golang.org/x/oauth2"
)
// TokenSource 实现了oauth2.TokenSource接口
type TokenSource struct {
AccessToken string
}
// Token 返回一个oauth2.Token
func (t *TokenSource) Token() (*oauth2.Token, error) {
token := &oauth2.Token{
AccessToken: t.AccessToken,
}
return token, nil
}
func main() {
// 设置Digital Ocean API token
token := "your_digital_ocean_token"
// 创建OAuth2 token源
tokenSource := &TokenSource{
AccessToken: token,
}
// 创建OAuth2客户端
oauthClient := oauth2.NewClient(context.Background(), tokenSource)
// 创建Digital Ocean客户端
client := godo.NewClient(oauthClient)
// 设置域名和记录
domain := "example.com"
recordName := "www"
recordType := "A"
recordData := "192.168.1.1" // 这里应该是你的当前IP地址
recordTTL := 1800
// 创建DNS记录
createRequest := &godo.DomainRecordEditRequest{
Type: recordType,
Name: recordName,
Data: recordData,
TTL: recordTTL,
}
// 调用API创建记录
ctx := context.TODO()
record, _, err := client.Domains.CreateRecord(ctx, domain, createRequest)
if err != nil {
log.Fatalf("Error creating DNS record: %v", err)
}
fmt.Printf("Created DNS record: %+v\n", record)
// 定期检查并更新IP
ticker := time.NewTicker(5 * time.Minute)
defer ticker.Stop()
for range ticker.C {
// 这里应该获取当前IP地址
newIP := "192.168.1.1" // 替换为获取当前IP的逻辑
// 更新DNS记录
updateRequest := &godo.DomainRecordEditRequest{
Type: recordType,
Name: recordName,
Data: newIP,
TTL: recordTTL,
}
_, _, err := client.Domains.EditRecord(ctx, domain, record.ID, updateRequest)
if err != nil {
log.Printf("Error updating DNS record: %v", err)
continue
}
fmt.Printf("Updated DNS record with new IP: %s\n", newIP)
}
}
这个示例展示了如何使用Digital Ocean的Go客户端库创建和更新DNS记录。在实际应用中,你需要添加获取当前IP地址的逻辑,并处理错误情况。
更多关于golang基于Digital Ocean DNS的个人动态域名解析插件DDNS的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang基于Digital Ocean DNS的个人动态域名解析插件DDNS的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
基于Digital Ocean DNS的Golang动态域名解析插件(DDNS)
概述
动态域名解析(DDNS)允许你将动态IP地址映射到一个固定的域名上。下面我将介绍如何使用Golang开发一个基于Digital Ocean DNS的DDNS插件。
实现原理
- 定期检测本机公网IP
- 与DNS记录中的IP对比
- 如果不同则更新DNS记录
代码实现
package main
import (
"context"
"fmt"
"io/ioutil"
"net/http"
"time"
"github.com/digitalocean/godo"
"golang.org/x/oauth2"
)
// 配置参数
const (
doToken = "your_digitalocean_api_token" // DigitalOcean API令牌
domain = "example.com" // 你的域名
recordName = "home" // 记录名称(如home.example.com)
checkPeriod = 5 * time.Minute // 检查间隔
)
// TokenSource 用于DigitalOcean API认证
type TokenSource struct {
AccessToken string
}
func (t *TokenSource) Token() (*oauth2.Token, error) {
token := &oauth2.Token{
AccessToken: t.AccessToken,
}
return token, nil
}
// 获取当前公网IP
func getPublicIP() (string, error) {
resp, err := http.Get("https://api.ipify.org?format=text")
if err != nil {
return "", err
}
defer resp.Body.Close()
ip, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(ip), nil
}
// 获取DNS记录ID
func getDNSRecordID(client *godo.Client, domain, name string) (int, string, error) {
records, _, err := client.Domains.Records(context.Background(), domain, nil)
if err != nil {
return 0, "", err
}
for _, record := range records {
if record.Name == name && record.Type == "A" {
return record.ID, record.Data, nil
}
}
return 0, "", fmt.Errorf("record not found")
}
// 更新DNS记录
func updateDNSRecord(client *godo.Client, domain string, recordID int, ip string) error {
editRequest := &godo.DomainRecordEditRequest{
Type: "A",
Name: recordName,
Data: ip,
}
_, _, err := client.Domains.EditRecord(context.Background(), domain, recordID, editRequest)
return err
}
func main() {
// 创建DigitalOcean客户端
tokenSource := &TokenSource{
AccessToken: doToken,
}
oauthClient := oauth2.NewClient(context.Background(), tokenSource)
client := godo.NewClient(oauthClient)
// 获取初始记录ID
recordID, currentIP, err := getDNSRecordID(client, domain, recordName)
if err != nil {
fmt.Printf("Error getting DNS record: %v\n", err)
return
}
fmt.Printf("Initial DNS record: ID=%d, IP=%s\n", recordID, currentIP)
// 定时检查并更新
ticker := time.NewTicker(checkPeriod)
defer ticker.Stop()
for range ticker.C {
publicIP, err := getPublicIP()
if err != nil {
fmt.Printf("Error getting public IP: %v\n", err)
continue
}
if publicIP == currentIP {
fmt.Printf("IP unchanged (%s), skipping update\n", publicIP)
continue
}
fmt.Printf("IP changed from %s to %s, updating...\n", currentIP, publicIP)
err = updateDNSRecord(client, domain, recordID, publicIP)
if err != nil {
fmt.Printf("Error updating DNS record: %v\n", err)
continue
}
currentIP = publicIP
fmt.Println("DNS record updated successfully")
}
}
使用说明
- 安装依赖:
go get github.com/digitalocean/godo
go get golang.org/x/oauth2
-
修改配置参数:
doToken
: 你的DigitalOcean API令牌domain
: 你的域名recordName
: 要更新的记录名称(如"home"对应home.example.com)
-
运行程序:
go run ddns.go
进阶功能
- 配置持久化:可以将配置存储在配置文件中
- 多记录支持:支持同时更新多个DNS记录
- 通知功能:当IP变更时发送邮件或短信通知
- 日志记录:将变更历史记录到文件中
部署建议
- 在服务器上以后台服务方式运行
- 使用systemd或supervisor管理进程
- 设置合理的检查间隔(建议5-10分钟)
这个简单的DDNS实现可以满足基本需求,根据实际情况可以进一步扩展功能。