项目主页:https://github.com/Neilpang/acme.sh
acme.sh是一个纯 unix shell 兼容的 脚本, 实现了 acme 协议, 可以从 letsencrypt 自动生成并更新 ssl 证书.可以通过多种方式验证域名所有者,支持众多dns api。
安装直接看README.md
https://github.com/Neilpang/acme.sh#1-how-to-install

最近帮 linuxgame 几台下载服务器弄了下 https,发现这篇记录有些配置需要完善的地方,现在更新一下吧。

letsencrypt 的证书申请本来很简单的,但是因为我当时没有 DNS 权限,不能通过 DNS api 方式全自动化申请,顺便把其他的方式一并记录于此。

安装 acme.sh

1
curl https://get.acme.sh | sh

输出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
root@debian:~# curl https://get.acme.sh | sh
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 705 100 705 0 0 675 0 0:00:01 0:00:01 --:--:-- 675
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 164k 100 164k 0 0 2157k 0 --:--:-- --:--:-- --:--:-- 2188k
[Tue Apr 24 16:08:44 CEST 2018] Installing from online archive.
[Tue Apr 24 16:08:44 CEST 2018] Downloading https://github.com/Neilpang/acme.sh/archive/master.tar.gz
[Tue Apr 24 16:08:45 CEST 2018] Extracting master.tar.gz
[Tue Apr 24 16:08:45 CEST 2018] It is recommended to install socat first.
[Tue Apr 24 16:08:45 CEST 2018] We use socat for standalone server if you use standalone mode.
[Tue Apr 24 16:08:45 CEST 2018] If you dont use standalone mode, just ignore this warning.
[Tue Apr 24 16:08:45 CEST 2018] Installing to /root/.acme.sh
[Tue Apr 24 16:08:45 CEST 2018] Installed to /root/.acme.sh/acme.sh
[Tue Apr 24 16:08:45 CEST 2018] Installing alias to '/root/.bashrc'
[Tue Apr 24 16:08:45 CEST 2018] OK, Close and reopen your terminal to start using acme.sh
[Tue Apr 24 16:08:45 CEST 2018] Installing cron job
no crontab for root
no crontab for root
[Tue Apr 24 16:08:45 CEST 2018] Good, bash is found, so change the shebang to use bash as preferred.
[Tue Apr 24 16:08:45 CEST 2018] OK
[Tue Apr 24 16:08:45 CEST 2018] Install success!

这里有个 warning:如果你是用 standalone 模式验证域名,建议安装 socat;如果不用这个模式,就忽略掉吧。

1
apt install socat

关于 standalone 模式,稍后会介绍。

安装会默认添加一条 alias,在 ~/.bashrc

1
. "/root/.acme.sh/acme.sh.env"

内容是

1
2
export LE_WORKING_DIR="/root/.acme.sh"
alias acme.sh="/root/.acme.sh/acme.sh"

但是,这个时候 alias 还没有生效,
如果你的英文稍好一点,可以看到安装过程的提示:

[Tue Apr 24 16:08:45 CEST 2018] OK, Close and reopen your terminal to start using acme.sh

官方推荐是:可以退出 shell 重新进入使之生效。
或者手动生效

1
source ~/.bashrc

申请证书

申请证书有多种方式,不同在于证明域名是你的方式不同。

以下方式各有利弊,选择一种即可。

比如我的域名是 domain.com

DNS API(推荐)

我的域名是用的 cloudflare,所以我使用 CF 的 API key申请

导入到环境变量,为了方便后续续订证书,建议放到环境变量文件中,而不是在当前 shell 临时导入

1
2
3
export CF_Key="*******************"
export CF_Email="********@****.com"
acme.sh --issue -d domain.com -d *.domain.com --dns dns_cf

其中有个需要等待120秒验证记录的过程

申请好了后,证书文件会在/root/.acme.sh/domain.com/

手工 DNS 方式

如果你不信任 acme.sh 程序,或者你使用的 DNS 不提供 API 等等原因,你可以使用此方式,手动添加 TXT 记录来完成域名所属验证。

直接参考教程吧:https://github.com/Neilpang/acme.sh/wiki/%E8%AF%B4%E6%98%8E#2-%E6%89%8B%E5%8A%A8-dns-%E6%96%B9%E5%BC%8F-%E6%89%8B%E5%8A%A8%E5%9C%A8%E5%9F%9F%E5%90%8D%E4%B8%8A%E6%B7%BB%E5%8A%A0%E4%B8%80%E6%9D%A1-txt-%E8%A7%A3%E6%9E%90%E8%AE%B0%E5%BD%95-%E9%AA%8C%E8%AF%81%E5%9F%9F%E5%90%8D%E6%89%80%E6%9C%89%E6%9D%83

文件验证

适合无法配置 DNS 的时候(当然,服务器的 A 记录要配置好呀)

还未运行 web 程序(standalone)

如果你还没有运行任何 web 服务, 80 端口是空闲的, 那么 acme.sh 还能假装自己是一个webserver, 临时监听在 80 端口, 完成验证,这叫做 standalone 模式:

1
acme.sh  --issue -d mydomain.com   --standalone

已经运行 web 程序

如果你的 web 程序已经运行了,你得知道你的服务器根目录在哪,一般 nginx/apache 的配置文件里面能够看到。

1
acme.sh  --issue -d www.domain.com  --webroot  /home/wwwroot/domain.com/

-d 指定域名
–webroot 指定网站根目录

acme.sh 会全自动的生成验证文件, 并放到网站的根目录, 然后自动完成验证. 最后会聪明的删除验证文件. 整个过程没有任何副作用.

验证链接大概这样:http://www.doamin.com/.well-known/acme-challenge/NAb_XQD4Y-*******************

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
root@debian:~# acme.sh --issue -d www.domain.com --webroot /var/www/html
[Sat Oct 26 09:12:28 UTC 2019] Create account key ok.
[Sat Oct 26 09:12:28 UTC 2019] Registering account
[Sat Oct 26 09:12:29 UTC 2019] Registered
[Sat Oct 26 09:12:29 UTC 2019] ACCOUNT_THUMBPRINT='P***************FCaY'
[Sat Oct 26 09:12:30 UTC 2019] Creating domain key
[Sat Oct 26 09:12:30 UTC 2019] The domain key is here: /root/.acme.sh/www.domain.com/www.domain.com.key
[Sat Oct 26 09:12:30 UTC 2019] Single domain='www.domain.com'
[Sat Oct 26 09:12:30 UTC 2019] Getting domain auth token for each domain
[Sat Oct 26 09:12:32 UTC 2019] Getting webroot for domain='www.domain.com'
[Sat Oct 26 09:12:32 UTC 2019] Verifying: www.domain.com
[Sat Oct 26 09:12:36 UTC 2019] Success
[Sat Oct 26 09:12:36 UTC 2019] Verify finished, start to sign.
[Sat Oct 26 09:12:36 UTC 2019] Lets finalize the order, Le_OrderFinalize: https://acme-v02.api.letsencrypt.org/acme/finalize/<Redacted>/<Redacted>
[Sat Oct 26 09:12:37 UTC 2019] Download cert, Le_LinkCert: https://acme-v02.api.letsencrypt.org/acme/cert/<Redacted>
[Sat Oct 26 09:12:38 UTC 2019] Cert success.
-----BEGIN CERTIFICATE-----
<Redacted>
-----END CERTIFICATE-----
[Sat Oct 26 09:12:38 UTC 2019] Your cert is in /root/.acme.sh/www.domain.com/www.domain.com.cer
[Sat Oct 26 09:12:38 UTC 2019] Your cert key is in /root/.acme.sh/www.domain.com/www.domain.com.key
[Sat Oct 26 09:12:38 UTC 2019] The intermediate CA cert is in /root/.acme.sh/www.domain.com/ca.cer
[Sat Oct 26 09:12:38 UTC 2019] And the full chain certs is there: /root/.acme.sh/www.domain.com/fullchain.cer

拷贝证书文件

安装官方文档的说法

注意, 默认生成的证书都放在安装目录下: ~/.acme.sh/, 请不要直接使用此目录下的文件, 例如: 不要直接让 nginx/apache 的配置文件使用这下面的文件. 这里面的文件都是内部使用, 而且目录结构可能会变化.

(然鹅我以前一直这么干的【捂脸】)

如果直接使用,重启 nginx 后,可能会得到如下错误【这台是 CentOS,没关 SElinux,有点严格

1
SSL_CTX_use_certificate_chain_file("/etc/nginx/demo.crt") failed (SSL: error:0200100D:system     library:fopen:Permission denied...e:system lib)

参考:https://stackoverflow.com/questions/37994513/nginx-ssl-certificate-permission-ssl-error-0200100dsystem

你可能会很纳闷,为什么我们必须要用 acme 来拷贝证书,我自己手动拷贝一份不就好了吗?

因为证书过期,acme 会自动为证书续期,那么到时候 ~/.acme.sh/ 目录下的证书文件更新了,但是你手动拷贝的证书文件却不会更新。使用 acme 来拷贝,acme 会智能的记住这些位置,更新证书时会一并更新。

正确的做法:

先 创建目录 /etc/nginx/ssl

1
mkdir /etc/nginx/ssl

使用 acme.sh --installcert 来拷贝证书文件

1
2
3
4
acme.sh  --installcert  -d  <domain>.com   \
--key-file /etc/nginx/ssl/<domain>.key \
--fullchain-file /etc/nginx/ssl/fullchain.cer \
--reloadcmd "service nginx force-reload"

注意:

Nginx 的配置 ssl_certificate 使用 /etc/nginx/ssl/fullchain.cer ,而非 /etc/nginx/ssl/<domain>.cer ,否则 SSL Labs 的测试会报 Chain issues Incomplete 错误。

如果你是一台服务器有多个域名,fullchain.cer 又不能重命名,怎么办呢?

新建个目录。。

比如:www.<domain>.comftp.<domain>.com 两个域名

对于 www.<domain>.com

1
2
3
4
acme.sh  --installcert  -d  www.<domain>.com   \
--key-file /etc/nginx/ssl/www.<domain>.com/www.<domain>.com.key \
--fullchain-file /etc/nginx/ssl/www.<domain>.com/fullchain.cer \
--reloadcmd "service nginx force-reload"

对于 ftp.<domain>.com

1
2
3
4
acme.sh  --installcert  -d  ftp.<domain>.com   \
--key-file /etc/nginx/ssl/ftp.<domain>.com/ftp.<domain>.com.key \
--fullchain-file /etc/nginx/ssl/ftp.<domain>.com/fullchain.cer \
--reloadcmd "service nginx force-reload"

nginx 的配置

在 nginx 上使用证书

错误的案例,这是我以前的配置

1
2
3
4
5
6
7
8
9
server{
listen 443;
server_name www.domain.com;
ssl on;
ssl_certificate /root/.acme.sh/www.domain.com/fullchain.cer;
ssl_certificate_key /root/.acme.sh/www.domain.com/www.domain.com.key;
root /var/www/html/;
index index.html index.htm;
}

修正:

  1. 如果上面这样配置,nginx -t测试配置是否可用时会提示
    1
    nginx: [warn] the "ssl" directive is deprecated, use the "listen ... ssl" directive instead in /usr/local/etc/nginx/sites-enabled/confid-file-name:8

使用

1
2
listen 443;
ssl on;

是以前的配置方式,目前的配置方式应该是

1
listen 443 ssl;

  1. 直接使用 /root/.acme.sh/ 目录下的证书是不恰当的

具体请参考上一段文字

正确的配置:

1
2
3
4
5
6
7
8
9
10
11
12
server{
listen 443 ssl;
server_name www.domain.com;
ssl_certificate /etc/nginx/ssl/www.domain.com/fullchain.cer;
ssl_certificate_key /etc/nginx/ssl/www.domain.com/www.domain.com.key;
root /var/www/html;
index index.html index.htm;
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
charset utf-8,gbk;
}

刚刚发现,还有对群晖的设置,非常贴心了
https://github.com/Neilpang/acme.sh/wiki/Synology-NAS-Guide

更多的教程请查看
https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials