目录

Auto Deploy Ssl Cert With Lego Without 80 Port

在没有 80 端口的情况下自动从 let’s encrypt 下载 ssl 证书

代码可以在 gitee.com 找到:https://gitee.com/dereking/lego-renew-letsecrypt.sh

要求

  • linux (Ubuntu)
  • lego
  • dns 解析服务商的 key

安装lego

方法一:源码安装

1
2
3
4
git clone https://github.com/go-acme/lego
cd lego
go build
sudo cp lego /usr/local/bin

方法二:直接下载预编译的可执行文件

下载页面:https://github.com/go-acme/lego/releases/tag/v4.14.2

1
2
3
4
wget https://github.com/go-acme/lego/releases/download/v4.14.2/lego_v4.14.2_linux_amd64.tar.gz
tar xvf lego_v4.14.2_linux_amd64.tar.gz
cd lego 
sudo cp lego /usr/local/bin

创建自动下载脚本 renew.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
#!/bin/bash

CONF_FILE=domains.yaml

# 判断当前用户是否有sudo权限
uid=`id -u`
if [ $uid != 0 ]; then
  echo "$(whoami) is not sudo user"
  exit -1 
fi 

#args: file, key 
function read_yaml_array(){

	# echo "aaa$1 "
	# echo $2
    flag=0
	attr=$2
    # 逐行读取内容
    cat $1 | awk '{print $0}'| while read LINE
    do 
		# echo $LINE
        if [ $flag == 0 ];then
            # 属性开始标志 ips
            if [ "$(echo $LINE | grep "$attr:")" != "" ];then
                flag=1
                continue
            fi
        fi
        if [ $flag == 1 ];then
            # 这行开始为 $attr 下的数组属性,以‘- ’开头
            if [ "$(echo $LINE | grep -E "^- ")" != "" ];then

				#echo "($LINE)"
            	# 截取出数组属性内容
                echo "$LINE" | awk -F " " '{print $2}'
                continue
            else
            	# 不是以‘- ’开头则数组属性结束
                break
            fi
        fi
    done
}

#args: file , key, 
function read_yaml_key(){
    flag=0
	key=$2
    # 逐行读取内容
    cat $1 | while read LINE
    do 
        if [ $flag == 0 ];then
            # 属性开始标志 vehicle_type:
            if [ "$(echo $LINE | grep "$key: ")" != "" ];then
            		# 截取出key值
                	echo "$LINE" | awk -F " " '{print $2}'
                	continue
			else
				# 如果关键词后面没有空格,则跳出继续查找
				continue 
            fi
        fi
    done
}
 
# args: certname, email, DOMAINS, copyTargetDir, user,api_key
function gen_cloudflare_cert(){

	certname=$1
	email=$2
	DOMAINS=$3
	copyTargetDir=$4
	user=$5
	api_key=$6

	CF_API_EMAIL=$user \
	CF_API_KEY=$api_key \
	lego --email "$email" --dns cloudflare --pem --domains $DOMAINS --filename $certname run
	if [ $? -eq 0 ]; then

		echo "证书适用以下域名:"
		openssl x509 -in .lego/certificates/$certname.pem -noout -text|grep " DNS:"

		if [ ! -d $copyTargetDir ]
		then
			sudo mkdir $copyTargetDir
		fi
		sudo cp .lego/certificates/$certname.pem $copyTargetDir/$certname.pem
		sudo cp .lego/certificates/$certname.key $copyTargetDir/$certname.key
		return 0
	else
		echo "lego failed"
	   	return 1
	fi
	
}

# args: certname, email, DOMAINS, copyTargetDir, access_key,secret_key
function gen_alidns_cert(){

	certname=$1
	email=$2
	DOMAINS=$3
	copyTargetDir=$4
	access_key=$5
	secret_key=$6


	ALICLOUD_ACCESS_KEY=$access_key \
	ALICLOUD_SECRET_KEY=$secret_key \
	lego --email "$email" --dns alidns --pem --domains $DOMAINS --filename $certname run
	if [ $? -eq 0 ]; then

		echo "证书适用以下域名:"
		openssl x509 -in .lego/certificates/$certname.pem -noout -text|grep " DNS:"

		if [ ! -d $copyTargetDir ]
		then
			sudo mkdir $copyTargetDir
		fi
		sudo cp .lego/certificates/$certname.pem $copyTargetDir/$certname.pem
		sudo cp .lego/certificates/$certname.key $copyTargetDir/$certname.key
		return 0
	else
		echo "lego failed"
	   	return 1
	fi
}

function trim_tail_char(){
	var=$1
	echo ${var%?}
}

# args dnsprovider,certName,certEmail,domains,targetDir
function gen_cert(){
dnsprovider=$1 
certName=$2
certEmail=$3
domains=$4
targetDir=$5
case $dnsprovider in
	cloudflare) 
		user=`read_yaml_key "$CONF_FILE" "CLOUDFLARE_EMAIL"`
		api_key=`read_yaml_key "$CONF_FILE" "CLOUDFLARE_API_KEY"`
		if [  -z  "$user" ]; then
			echo "need CLOUDFLARE_EMAIL in $CONF_FILE"
			return 1
		fi 
		if [  -z  "$api_key" ]; then
			echo "need CLOUDFLARE_API_KEY in $CONF_FILE"
			return 1
		fi 


		if [ $domains ]; then
			gen_cloudflare_cert "$certName" "$certEmail"   "$domains"  "$targetDir" "$user" "$api_key"
		fi 
		;;
	alidns)
		access_key=`read_yaml_key "$CONF_FILE" "ALICLOUD_ACCESS_KEY"`
		secret_key=`read_yaml_key "$CONF_FILE" "ALICLOUD_SECRET_KEY"`
		if [  -z  "$access_key" ]; then
			echo "need ALICLOUD_ACCESS_KEY in $CONF_FILE"
			return 1
		fi 
		if [  -z  "$secret_key" ]; then
			echo "need ALICLOUD_SECRET_KEY in $CONF_FILE"
			return 1
		fi 


		if [ $domains ]; then
			gen_alidns_cert "$certName" "$certEmail"   "$domains"  "$targetDir" "$access_key" "$secret_key"
		fi
		;;
	*) 
		echo  "????" 
		;;
esac

}



dnsprovider=($(read_yaml_key "$CONF_FILE" "DNSProvider"))
if [  -z  "$dnsprovider" ]; then
	echo "need DNSProvider in $CONF_FILE"
	exit 1
fi 
 

certEmail=($(read_yaml_key "$CONF_FILE" "LETS_EMAIL"))
targetDir=($(read_yaml_key "$CONF_FILE" "targetDir"))
	echo $certEmail
	echo $targetDir

groups=($(read_yaml_array "$CONF_FILE" "groups")) 

echo "start generte cert for groups:"
for group in ${groups[@]}
do
	echo "*. $group"
done

for group in ${groups[@]}
do
	echo "============================ $group ============================"

	g_name=($(read_yaml_key "$CONF_FILE" "${group}_name"))
	dms=($(read_yaml_array "$CONF_FILE" ${group}))
	printf -v domains '%s,' "${dms[@]}"
	domains=`trim_tail_char $domains`
	echo "域名: $domains" 

	# start call let's encrypt api
	gen_cert $dnsprovider $g_name $certEmail $domains $targetDir 
	if [ $? -eq 0 ]; then
	   echo "ERROR: $group failed"
	fi
done

sudo nginx -s reload

准备配置文件

在 renew.sh 同目录下增加 domains.yaml

 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

LETS_EMAIL: [email protected]  # LETS encrypt 的账户
targetDir: /etc/nginx/cert  # 存放 证书的目录


DNSProvider: cloudflare   # dns解析使用的 服务商,清单见下一章节。

#cloudflare api 账户信息,需要 global api key
CLOUDFLARE_EMAIL: [email protected]
CLOUDFLARE_API_KEY: xxxxxxxx

#alidns api 账户信息
ALICLOUD_ACCESS_KEY: xxxxxxx
ALICLOUD_SECRET_KEY:  xxxxxxxx

# 可以获取多个证书,比如不同的域名用不同证书。
groups:
  - aaaa_com
  - b_com

# key为 证书的 名字 “aaaa_com” + “_name”, 
# 值为保存证书的文件名字
aaaa_com_name: a_com
# 第1个证书的域名清单:
aaaa_com:
  - a.com
  - aa.a.com

# key为 证书的 名字 b_com + “_name”, 
# 值为保存证书的文件名字
b_com_name: b_com_cert
# 第2个证书的域名清单:
b_com:
  - a.b.com
  - xxxx.b.com
  - 333.b.com

yaml 文件说明

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
DNSProvider: cloudflare 
# 可以取以下服务商:根据你自己的实际情况选择;目前 renew.sh 只支持 alidns 和 cloudflare 两个服务商。
# acme-dns, alidns, allinkl, arvancloud, auroradns, autodns, azure, azuredns, 
# bindman, bluecat, brandit, bunny, checkdomain, civo, clouddns, cloudflare, 
# cloudns, cloudru, cloudxns, conoha, constellix, derak, desec, designate, 
# digitalocean, dnshomede, dnsimple, dnsmadeeasy, dnspod, dode, domeneshop, 
# dreamhost, duckdns, dyn, dynu, easydns, edgedns, efficientip, epik, exec, exoscale,
# freemyip, gandi, gandiv5, gcloud, gcore, glesys, godaddy, googledomains, hetzner, 
# hostingde, hosttech, httpreq, hurricane, hyperone, ibmcloud, iij, iijdpf, infoblox, 
# infomaniak, internetbs, inwx, ionos, ipv64, iwantmyname, joker, liara, lightsail, 
# linode, liquidweb, loopia, luadns, manual, metaname, mydnsjp, mythicbeasts, namecheap, 
# namedotcom, namesilo, nearlyfreespeech, netcup, netlify, nicmanager, nifcloud, njalla,
# nodion, ns1, oraclecloud, otc, ovh, pdns, plesk, porkbun, rackspace, rcodezero, regru, 
# rfc2136, rimuhosting, route53, safedns, sakuracloud, scaleway, selectel, servercow, simply,
# sonic, stackpath, tencentcloud, transip, ultradns, variomedia, vegadns, vercel, versio,
# vinyldns, vkcloud, vscale, vultr, websupport, wedos, yandex, yandex360, yandexcloud, zoneee, zonomi

DNSProvider 相关文档见: https://go-acme.github.io/lego/dns/

获取新证书

1
./renew.sh