群晖-阿里云ddns

该方法适用于任何可以执行 .sh 脚本的环境下

  1. 首先需要一个阿里的域名
  2. 需要有阿里的操作AccessKey,没有的可以在阿里云控制台申请
  3. 下载文件 aliyun.sh (点击访问)
    或复制下面的代码保存为 aliyun.sh
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    #!/bin/sh

    set -e

    if [ $1 ]; then
    ApiId=$1
    fi

    if [ $2 ]; then
    ApiKey=$2
    fi

    if [ $3 ]; then
    Domain=$3
    fi

    if [ -z "$ApiId" -o -z "$ApiKey" -o -z "$Domain" ]; then
    echo "参数缺失"
    exit 1
    fi

    if [ $4 ]; then
    SubDomain=$4
    fi

    if [ -z "$SubDomain" ]; then
    SubDomain="@"
    fi

    Nonce=$(date -u "+%N") # 有bug?
    Timestamp=$(date -u "+%Y-%m-%dT%H%%3A%M%%3A%SZ") # SB 阿里云, 什么鬼时间格式
    Nonce=$Timestamp

    urlencode() {
    local raw="$1";
    local len="${#raw}"
    local encoded=""

    for i in `seq 1 $len`; do
    local j=$((i+1))
    local c=$(echo $raw | cut -c$i-$i)

    case $c in [a-zA-Z0-9.~_-]) ;;
    *)
    c=$(printf '%%%02X' "'$c") ;;
    esac

    encoded="$encoded$c"
    done

    echo $encoded
    }

    # $1 = query string
    getSignature() {
    local encodedQuery=$(urlencode $1)
    local message="GET&%2F&$encodedQuery"
    local sig=$(echo -n "$message" | openssl dgst -sha1 -hmac "$ApiKey&" -binary | openssl base64)
    echo $(urlencode $sig)
    }

    sendRequest() {
    local sig=$(getSignature $1)
    local result=$(wget -qO- --no-check-certificate --content-on-error "https://alidns.aliyuncs.com?$1&Signature=$sig")
    echo $result
    }

    getRecordId() {
    echo "获取 $SubDomain.$Domain 的 IP..." >&2
    local queryString="AccessKeyId=$ApiId&Action=DescribeSubDomainRecords&Format=JSON&SignatureMethod=HMAC-SHA1&SignatureNonce=$Nonce&SignatureVersion=1.0&SubDomain=$SubDomain.$Domain&Timestamp=$Timestamp&Type=A&Version=2015-01-09"
    local result=$(sendRequest "$queryString")
    local code=$(echo $result | sed 's/.*,"Code":"\([A-z]*\)",.*/\1/')
    local recordId=$(echo $result | sed 's/.*,"RecordId":"\([0-9]*\)",.*/\1/')

    if [ "$code" = "$result" ] && [ ! "$recordId" = "$result" ]; then
    local ip=$(echo $result | sed 's/.*,"Value":"\([0-9\.]*\)",.*/\1/')

    if [ "$ip" == "$NewIP" ]; then
    echo "IP 无变化, 退出脚本..." >&2
    echo "quit"
    else
    echo $recordId
    fi
    else
    echo "null"
    fi
    }

    # $1 = record ID, $2 = new IP
    updateRecord() {
    local queryString="AccessKeyId=$ApiId&Action=UpdateDomainRecord&DomainName=$Domain&Format=JSON&RR=$SubDomain&RecordId=$1&SignatureMethod=HMAC-SHA1&SignatureNonce=$Nonce&SignatureVersion=1.0&Timestamp=$Timestamp&Type=A&Value=$2&Version=2015-01-09"
    local result=$(sendRequest $queryString)
    local code=$(echo $result | sed 's/.*,"Code":"\([A-z]*\)",.*/\1/')

    if [ "$code" = "$result" ]; then
    echo "$SubDomain.$Domain 已指向 $NewIP." >&2
    else
    echo "更新失败." >&2
    echo $result >&2
    fi
    }

    # $1 = new IP
    addRecord() {
    local queryString="AccessKeyId=$ApiId&Action=AddDomainRecord&DomainName=$Domain&Format=JSON&RR=$SubDomain&SignatureMethod=HMAC-SHA1&SignatureNonce=$Nonce&SignatureVersion=1.0&Timestamp=$Timestamp&Type=A&Value=$1&Version=2015-01-09"
    local result=$(sendRequest $queryString)
    local code=$(echo $result | sed 's/.*,"Code":"\([A-z]*\)",.*/\1/')

    if [ "$code" = "$result" ]; then
    echo "$SubDomain.$Domain 已指向 $NewIP." >&2
    else
    echo "添加失败." >&2
    echo $result >&2
    fi
    }

    # Get new IP address
    echo "获取当前 IP..."
    NewIP=$(wget -qO- --no-check-certificate "http://members.3322.org/dyndns/getip")
    echo "当前 IP 为 $NewIP."

    # Get record ID of sub domain
    recordId=$(getRecordId)

    if [ ! "$recordId" = "quit" ]; then
    if [ "$recordId" = "null" ]; then
    echo "域名记录不存在, 添加 $SubDomain.$Domain 至 $NewIP..."
    addRecord $NewIP
    else
    echo "域名记录已存在, 更新 $SubDomain.$Domain 至 $NewIP..."
    updateRecord $recordId $NewIP
    fi
    fi
  4. 配置群晖内的计划任务

主要修改的是”用户定义脚本” 格式如下,多个域名每行一个
假设需要配置两个域名,一个是 www.domain.com,一个是cloud.domain.com
那么脚本内容就是

1
2
sh {绝对地址}aliyun.sh {AccessKeyId} {AccessKeySecret} domain.com www
sh {绝对地址}aliyun.sh {AccessKeyId} {AccessKeySecret} domain.com cloud

配置群晖计划任务
控制面板 》任务计划 》新增任务

设定好执行时间