目前已经全部搞妥了,有了泛域名证书之后我把之前所有的域名证书全部替换了一下,现在更方便管理了。


既然要开启全站HTTPS肯定离不开SSL证书这个话题。

我以前一直使用的腾讯的TrustAsia,也就是诚信亚洲的证书。但是腾讯的这个证书有个毛病就是不支持泛域名(不能说不支持,是要花钱,而且死贵),而且只能一年一年申请。上次我笔记服务Trilium的证书过期了就要重新申请并再次上传到服务器上替换掉旧的证书,那个时候觉的超级麻烦,这也是我一直没弄HTTPS的主要原因。

这次在给又拍云弄SSL证书的时候忽然就想着要不要查查看有没有免费的泛域名证书用,这一搜果然有—— acme.sh ,他可以支持自动化的从Let’s Encrypt获取免费的泛域名证书,而且还支持自动更新。我之前有一次想给Ghost博客搞全站HTTPS时还用过这个服务,当时Ghost支持一键调用acme.sh生成证书并启用HTTPS,不过当时没研究这个东西所以不太懂,后来出了些配置问题弄不懂我也就弃用了。

acme.sh介绍

acme.sh是个开源的shell证书生成脚本,他可以自动生成Let’s Encrypt的证书,而Let’s Encrypt 是一家免费、开放、自动化的证书颁发机构(CA),为公众的利益而运行。它是一项由 Internet Security Research Group(ISRG)提供的服务。我们以尽可能对用户友好的方式免费提供为网站启用 HTTPS(SSL/TLS)所需的数字证书。这是因为我们想要创建一个更安全,更尊重隐私的 Web 环境。

💡
It's probably the easiest & smartest shell script to automatically issue & renew the free certificates.
这可能是最简单和最智能的 shell 脚本自动发布和更新免费证书。
GitHub - acmesh-official/acme.sh: A pure Unix shell script implementing ACME client protocol
A pure Unix shell script implementing ACME client protocol - GitHub - acmesh-official/acme.sh: A pure Unix shell script implementing ACME client protocol

安装

我根据acme.sh的github上的中文说明安装好了这个证书,不过最开始我看的是网络上的其他教程踩了不少坑,很多教程要不就是太老,要不就是各种稀奇古怪的原因无法正常安装。

首先需要安装acme.sh。我们只需要执行很简单的一行命令即可安装该脚本。不过使用国内的腾讯轻量云服务器安装时会在安装过程中经常卡住,我看了一下sh脚本好像要请求Github的服务器,但是国内不挂梯子访问Github会很慢。所以我每次卡住就直接结束命令重新再执行一次,直到顺畅执行成功为止(反正就是碰运气。)

curl  https://get.acme.sh | sh -s email=my@example.com
ubuntu执行以上命令安装

这个命令会把 acme.sh 安装到你的用户目录下,并设为隐藏,你可以在安装完成之后通过 ls -a 来检查是否有名为 .acme.sh 目录。

安装成功,并自动设置了cron job

在安装完成之后你可能需要执行 alias acme.sh=~/.acme.sh/acme.sh 创建 一个 bash 的 alias,我安装的时候看的另外一个教程没有说这一部,导致一直提示 acme.sh: command not found ,无法执行acme.sh命令,卡了我好几个小时。

认证

官方提供的证书认证方式有三种

  • http 方式需要在你的网站根目录下放置一个文件, 来验证你的域名所有权,完成验证. 然后就可以生成证书了
  • 手动 dns 方式, 手动在域名上添加一条 txt 解析记录, 验证域名所有权.
  • 可以使用域名解析商提供的 api 自动添加 txt 记录完成验证.

前面两种都比较麻烦,我就直接使用了第三种:利用域名解析商提供的API让acme.sh自动进行相关的验证操作。acme.sh目前支持 cloudflare, dnspod, cloudxns, godaddy 以及 ovh 等数十种解析商的自动集成。

获取DNS服务商token

我用的是DNSPod,所以这里就详细说下DNSPod怎么获取token。

  • 登录DNSPod后台
  • 点击右上角自己的头像
  • 点击左侧选项卡伤的的 DNSPod Tokens
  • 点击 创建密钥 后起个名字,接着就能拿到ID和token值,另外注意,Token值只显示一次,请记好备份。

设置DNSPod token

通过在命令行里执行以下命令设置token,要严格按格式来, DP_Id 后的 = 号前后不能有空格。 DP_Id 为DNSPod里生成的 idDP_Key 为生成的 token

export DP_Id=""
export DP_Key=""

生成

生成证书,这里一定要先添加主域名,再添加泛域名。我们可以通过 -d 来添加多个域名。域名生成后证书文件会自动存放在 .acme.sh 目录里,文件夹名称为你添加的主域名。

acme.sh   --issue   --dns dns_dp   -d aa.com  -d *.aa.com

安装证书到指定目录

因为我用的Nginx,所以这里说一下怎么安装到Nginx里。

我之前看的教程是直接cp证书到nginx证书目录里,但是看了官方的说明和其他一些网友分享的经验才知道最好是通过命令来安装证书文件。

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

我们需要通过 --install-cert 来安装证书文件,使用官方的这种方式以后可以自动无感续期、自动更新等。官方安装说明reloadcmd使用的是:  service nginx force-reload ,我用的下面的,不知道会不会有什么问题。

acme.sh --install-cert -d example.com \
--key-file       /youdata/ssl/nginx/yourdomain.key  \
--fullchain-file /youdata/ssl/nginx/fullchain.cer \
--reloadcmd     "sudo nginx -s reload"
安装证书文件到指定目录,并设置重载命令

这样在指定目录会自动生成对应的证书文件,接下来我们在Nginx配置文件里进行引用就行了。

续期

我们前面在安装acme.sh的时候默认会自动生成一个 crontab 任务,我们可以通过 crontab -l 查看。默认的计划任务是每天检查一次是否需要续期,如果需要则会自动续期,当然你也可以自由设置任务,crontab示例配置如下:

56 * * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null

Nginx配置文件

我以前没有用代码片段来管理ssl证书,也不懂要怎么弄,这次在 这篇文章里 解锁了代码段的使用(但是这篇文章的其他部分都是坑,可能是因为比较老的缘故,4年前的文章了)

先在 /etc/nginx/snippets 目录下创建代码段文件 ssl-params.conf 专门拿来配置SSL相关的设置,内容如下,用的也是上面那位作者的设置,不知道4年前的东西现在是不是要改什么?如果有看到这里的大佬麻烦指点一下。

# /etc/nginx/snippets/ssl-params.conf

server_tokens   off;

ssl_session_cache        shared:SSL:10m;
ssl_session_timeout      60m;

ssl_session_tickets      on;

ssl_stapling             on;
ssl_stapling_verify      on;

resolver                 8.8.4.4 8.8.8.8  valid=300s;
resolver_timeout         10s;
ssl_prefer_server_ciphers on;

# 证书路径 绝对地址
ssl_certificate          /youdata/ssl/nginx/fullchain.cer;
ssl_certificate_key      /youdata/ssl/nginx/yourdomain.key;

ssl_protocols            TLSv1 TLSv1.1 TLSv1.2;

ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";

add_header Strict-Transport-Security "max-age=31536000;includeSubDomains;preload";
add_header  X-Frame-Options  deny;
add_header  X-Content-Type-Options  nosniff;
add_header x-xss-protection "1; mode=block";
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: https:; connect-src 'self' https:; img-src 'self' data: https: blob:; style-src 'unsafe-inline' https:; font-src https:";

接下来再新建一个nginx配置文件,并配置server项,并在server项里通过 include 命令导入我们之前写的ssl配置代码段即可。

server {
    listen 443 ssl;
    server_name test.yourdomain.com;
    
    include snippets/ssl-params.conf;

  location / {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header Host $http_host;
      proxy_pass http://127.0.0.1:15215;

      # 如果您要使用本地存储策略,请将下一行注释符删除,并更改大小为理论最大文件尺寸
      # client_max_body_size 20000m;
  }


    location ~ /.well-known {
        allow all;
    }

    client_max_body_size 50m;
}