问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

搭建自己的DDNS服务器教程

创作时间:
作者:
@小白创作中心

搭建自己的DDNS服务器教程

引用
1
来源
1.
https://www.cnblogs.com/darkchen/p/18044915

DDNS(动态域名系统)可以解决ADSL拨号和内网服务器无法提供稳定互联网IP的问题,通过域名绑定动态IP地址,实现域名与IP地址的动态解析。

前置条件

  1. 拥有公网地址:查看路由器WAN口地址是否是公网地址
  2. 在GoDaddy上注册一个自己的域名
  3. 一台海外主机

申请GoDaddy的API密钥

访问GoDaddy开发者平台申请API密钥,并复制保存。


GoDaddy API文档

参考GoDaddy API文档。API请求示例如下:

PUT https://api.godaddy.com/v1/domains/yourdomain.com/records/A/yoursubdomain
Content-Type: application/json
Authorization: sso-key yourkey:yoursecret

[
 {
 "data": "1.1.1.1",
 "port": 65535,
 "priority": 0,
 "protocol": "string",
 "service": "string",
 "ttl": 600,
 "weight": 0
 }
]

Python实现方案

设计思路

  • 服务端使用海外主机监听客户端发送的数据,并调用GoDaddy API更新域名解析
  • 客户端定期连接服务器的socket,发送需要添加解析的域名
  • 服务端验证客户端合法性和socket的源IP是否发生变动,变动后调用API更新解析记录

服务端代码

import requests
import socket
import logging
import os
import sys
import json

def logger():
    log_name = os.path.join(base_dir, 'ddns.log')
    logger = logging.getLogger()
    fh = logging.FileHandler(log_name)
    formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
    fh.setFormatter(formatter)
    logger.setLevel(logging.WARNING)
    logger.addHandler(fh)
    return logger

def sock():
    host = '0.0.0.0'
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    address = ('your_server_address', your_port)
    s.bind(address)
    s.listen(200)
    while True:
        try:
            conn, addr = s.accept()
            client_data = conn.recv(1024)
            data = json.loads(client_data.decode('utf-8'))
            key, domain = data['key'], data['domain']
            print(key, domain)
        except Exception as e:
            log.warning(e)
            continue
        finally:
            conn.close()
        if key == 'your_custom_key':
            newhost, port = addr
            if newhost != host:
                host = newhost
                ddns(host, domain)
        else:
            pass

def ddns(host, domain):
    try:
        url = f'https://api.godaddy.com/v1/domains/yourdomain.com/records/A/{domain}'
        headers = {
            'accept': 'application/json',
            'Content-Type': 'application/json',
            'Authorization': 'sso-key yourkey:yoursecret'
        }
        data = [
            {
                "data": host,
                "port": 65535,
                "priority": 0,
                "ttl": 600,
                "weight": 0
            }
        ]
        response = requests.put(url, json=data, headers=headers)
        log.warning(response)
    except Exception as e:
        log.warning(str(e))

if __name__ == '__main__':
    base_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
    log = logger()
    sock()

客户端代码

import socket
import time
import logging
import os
import sys

def logger():
    log_name = os.path.join(base_dir, 'ddns.log')
    logger = logging.getLogger()
    fh = logging.FileHandler(log_name)
    formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
    fh.setFormatter(formatter)
    logger.setLevel(logging.WARNING)
    logger.addHandler(fh)
    return logger

def client(data):
    while True:
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.settimeout(3)
            s.connect(('your_server_address', your_port))
            s.sendall(data.encode())
        except Exception as e:
            log.warning(str(e))
            time.sleep(10)

if __name__ == '__main__':
    base_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
    data = '{"key":"your_custom_key","domain":"your_subdomain"}'
    log = logger()
    client(data)

注意事项

  1. 请将代码中的yourdomain.comyour_subdomainyourkeyyoursecretyour_custom_keyyour_server_addressyour_port等占位符替换为实际值。
  2. 确保海外主机能够访问GoDaddy API。
  3. 客户端需要定期运行,建议使用定时任务(如cron)来实现。
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号