使用acme.sh撸一个免费且自动更新的HTTPS证书

2,643 阅读5分钟

原文: www.fengxianqi.com/index.php/a…

前言

一直想撸一下https,最近刚好有点空,就实现了一下。之前看过一篇教你快速撸一个免费HTTPS证书的文章,通过Certbot来管理Let's Encrypt的证书,使用前需要安装一堆库,觉得不太友好。所谓条条大路通罗马,肯定还有其他方法可以做这个事情。

经过一番研究,发现了 acme.sh 这个库,这个是用Shell脚本编写的,不需要安装其他东西,比较纯净,觉得比较适合自己,记录一下过程。

准备工作

  1. 一个已解析好的域名(可以用http来访问)。
  2. 开启服务器的443端口防火墙。

步骤

一、安装acme.sh

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

这个命令后会将acme.sh安装到~/.acme.sh/目录下 重新载入~/.bashrc

source ~/.bashrc 

二、生成证书

acme.sh  --issue -d www.your-domin.com  --webroot  /srv/your-domin.com/

这个命令的意思是用http方式将www.your-domin.com生成一个证书,/srv/your-domin.com/是你的网站根目录。(这个过程中acme.sh 会全自动的生成验证文件, 并放到网站的根目录, 然后自动完成验证. 最后又自动删除验证文件.)

三、安装或copy证书到nginx目录

默认生成的证书都放在安装目录下: ~/.acme.sh/,这个目录一般来说不能让nginx或Apache直接使用。所以我们需要将证书放到一个指定的目录,习惯是放在/etc/nginx/ssl/目录下。acme提供了--installcert来安装证书,只需指定目标位置, 然后证书文件会被copy到相应的位置。 先确保存在/etc/nginx/ssl/目录

mkdir /etc/nginx/ssl

copy证书并指定nginx reload命令

acme.sh  --installcert  -d  www.your-domin.com   \
        --key-file   /etc/nginx/ssl/www.your-domin.com.key \
        --fullchain-file /etc/nginx/ssl/fullchain.cer \
        --reloadcmd  "service nginx force-reload"

service nginx force-reload是为了在让acme自动更新时候能够重启nginx使得证书生效。执行完命令可以在/etc/nginx/ssl/看到多了www.your-domin.com.keywww.your-domin.com.cer的文件。

四、生成 dhparam.pem 文件

openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048

这一步不是必须,但最好加上,后面配置好后会通过 ssllabs.com 来验证一下,如果这一步ssl_dhparam 未配置,将导致 ssllabs.com 的评分降到 B。A+是最好。

五、配置nginx

证书已安装完毕,接下来就是让nginx来使用这个证书了。由于我这个服务器有几个站点,而目前只是一个站点配置了证书,因此只修改当前站点的conf即可

server {
    listen       80;
    server_name www.your-domin.com;
    listen       443 ssl http2 default_server;
    listen       [::]:443 ssl http2 default_server;
    ssl_certificate /etc/nginx/ssl/www.your-domin.com.cer;
    ssl_certificate_key /etc/nginx/ssl/www.your-domin.com.key;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;
    ...
}

ssl_prefer_server_ciphers on; 这个配置能提高证书的评分。 ssl_dhparam /etc/nginx/ssl/dhparam.pem; 能提高证书评分,这个文件是在第四步时生成的,若没有做则不需要写这句。 nginx -t验证一下nginx配置是否正确,然后systemctl restart nginx重启一下nginx,就可以用www.your-domin.com测试一下你的站点啦。

六、证书更新

Let's Encrypt 的证书有效期是 90 天的,需要定期重新申请,不过acme在安装的时候就已经设置了自动更新,所以这一步不用关心,很省心。 这里了解一下acme.sh的自动更新:安装acme时会自动为你创建 cronjob, 每天 0:00 点自动检测所有的证书, 如果快过期了, 需要更新, 则会自动更新证书. 查看任务

# crontab -l
47 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null

手动renew一下证书可以通过这个命令

acme.sh --cron -f

七、设置软件自动更新

目前由于 acme 协议和 letsencrypt CA 都在频繁的更新, 因此 acme.sh 也经常更新以保持同步.所以为了省心省力,最好还是设置一下软件的自动更新,执行下面的命令就可以了。

acme.sh  --upgrade  --auto-upgrade

其他

在这个网站可以验证一下你的证书级别,根据我上面的配置可以评级为A。 www.ssllabs.com/ssltest/ana…

使用docker安装acme.sh(202011补充)

如果想要使用docker安装证书,可以看下下面的步骤。

开始先理清楚限制:由于acme.sh是需要定时更新的,每次更新后需要重启nginx。我们回顾一下上面安装证书时的命令:

acme.sh  --installcert  -d  www.your-domin.com   \
        --key-file   /etc/nginx/ssl/www.your-domin.com.key \
        --fullchain-file /etc/nginx/ssl/fullchain.cer \
        --reloadcmd  "service nginx force-reload"

注意到--reloadcmd "service nginx force-reload"这句,这里就是重启nginx,如果acme.sh是运行在容器中的话,就得想办法解决如何在容器中运行宿主机命令,这相当于逃逸了docker环境,有违docker的初衷,因此不建议这样做。

参照官方的教程deploy-to-docker-containers,我们将acme.shnginx都用上docker,然后acme通过label来操作nginx容器进行重启。操作步骤:

  1. 给nginx容器加上label,从而acme.sh容器可以通过label找到nginx容器进行重启。
docker run \
--label=sh.acme.autoload.domain=example.com \
-p 80:80 -p 443:443 \
--mount type=bind,source=/data/nginx/conf.d,target=/etc/nginx/conf.d \
--mount type=bind,source=/data/nginx/ssl,target=/data/nginx/ssl \
--mount type=bind,source=/data/solution,target=/data/solution \
 -d \
--name nginx nginx
  • example.com是该nginx的标签,一般用网站域名就可以了。
  • --mount是映射宿主机和容器的文件目录,参考笔者的另一篇文章Centos8使用docker迁移typecho博客
  1. 启动acme.sh容器
docker run --rm  -itd  \
  -v "$(pwd)/out":/acme.sh  \
  --net=host \
  --name=acme.sh \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /data/nginx/ssl:/data/nginx/ssl \
  neilpang/acme.sh daemon

  • 挂载了/var/run/docker.sock到容器上,是为了acme.sh容器能够操作nginx容器。
  • /data/nginx/ssl是为了后面将生成的证书放到这个位置。
  1. 生成证书

生成证书有好多种模式,详情可看How to issue a cert,笔者这里使用了standalone模式,该模式会启动一个server完成证书签发,默认会占用80端口,因此我们最好先停止上面已经占用了80端口的nginx,docker stop nginx,然后再签发证书。

docker exec acme.sh  --issue  -d example.com  --standalone

example.com是你的网站域名,要先dns解析到你的服务器。

  1. 部署证书
docker  exec \
    -e DEPLOY_DOCKER_CONTAINER_LABEL=sh.acme.autoload.domain=example.com  \
    -e DEPLOY_DOCKER_CONTAINER_KEY_FILE=/data/nginx/ssl/example.com/key.pem   \
    -e DEPLOY_DOCKER_CONTAINER_CERT_FILE="/data/nginx/ssl/example.com/cert.pem"  \
    -e DEPLOY_DOCKER_CONTAINER_CA_FILE="/data/nginx/ssl/example.com/ca.pem"   \
    -e DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="/data/nginx/ssl/example.com/full.pem"  \
    -e DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="service nginx force-reload"   \
    acme.sh --deploy -d example.com  --deploy-hook docker

这里还是要注意将example.com改为你自己的域名,DEPLOY_DOCKER_CONTAINER_LABEL这里就是上面我们指定的nginx标签,注意要保持一致。

跑完该命令后,就会在/data/nginx/ssl目录下生成example.com的证书文件啦,接下来配置nginx然后重启就可以了。配置参考:

server {
    listen       80;
    server_name localhost example.com;
    return 301 https://example.com$request_uri;
}


server {
    server_name  example.com;
    listen       443 ssl http2 default_server;
    listen       [::]:443 ssl http2 default_server;
    ssl_certificate /data/nginx/ssl/example/full.pem;
    ssl_certificate_key /data/nginx/ssl/example/key.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_dhparam /data/nginx/ssl/dhparam.pem; # 需要生成
    location / {
        root   /data/solution/typecho;
        index  index.html index.php;
        try_files $uri $uri/ /index.php?$args;
    }
}

dhparam.pem文件需要跑openssl dhparam -out /data/nginx/ssl/dhparam.pem 2048来生成。

自此,配置结束,可以开始验证了。

参考文章