简述

趁着年底有点时间,把自己的服务器操作系统升级到了 16.04 。Let’s Encrypt 是早就听说过,只是一直没时间搞。前两天听朋友讲到在 nginx/openresty 下有自动化的 lua 脚本可以实现自动化的申请和证书更新,感觉非常有意思,顺便折腾了一把。

过程

Openresty

Openresty 是在 nginx core 的基础上集成了 LuaJIT 和许多第三方的 nginx 模块。除了 nginx 本身具备的功能外,还可以用来做 web application,web service。利用 lua 可以直接在 Openresty 里面构建动态服务。目前官方只提供 RPM 的预编译包,其它操作系统需要自行编译。 官方的安装说明 简明易懂,直接照猫画虎即可。

接下来要配置 systemd ,让 Openresty 可以自动启动。

1
$ sudo vim /etc/systemd/system/nginx.service

nginx.service

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[Unit]
Description=The nginx HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/usr/local/openresty/nginx/logs/nginx.pid
ExecStartPre=/usr/local/openresty/nginx/sbin/nginx -t
ExecStart=/usr/local/openresty/nginx/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

启用:

1
2
$ sudo systemctl enable nginx
$ sudo systemctl start nginx

附上几个调试技巧:

  • 通过 systemctl status nginx 可以看到 nginx 是不是正常启动了。若是失败这里也会输出用的日志信息,可以按左右键对界面进行横向滚动
  • 需要看到更多日志可以使用 journalctl -b _PID=上一步中输出的PID 查看更多的信息。
  • 通过 curl http://localhost 确认 nginx 已经可以正常工作。

LuaRocks

这个 lua 的包管理器,相当于 node.js 的 npm 。安装的方法 点这里 。 上面推荐安装的版本是 2.0.13 。但我装的是当时最新的 2.4.2 ,也许是这个原因导致我后面配置 lua-resty-auto-ssl 的时候踩了坑?

lua-resty-auto-ssl

装完 LuaRocks 之后,首先要配置一下 PATH,在 ~/.profile 中加入:

1
export PATH=/usr/local/openresty/luajit/bin:/usr/local/openresty/bin:/usr/local/openresty/nginx/sbin:$PATH

1
source ~/.profile

然后就可以使用它来安装 lua-resty-auto-ssl 了:

1
2
3
4
5
6
$ sudo luarocks install lua-resty-auto-ssl

# Create /etc/resty-auto-ssl and make sure it's writable by whichever user your
# nginx workers run as (in this example, "www-data").
$ sudo mkdir /etc/resty-auto-ssl
$ sudo chown www-data /etc/resty-auto-ssl

修正 lua-resty-auto-ssl 的脚本权限问题

1
2
$ sudo chmod +x /usr/local/openresty/luajit/share/lua/5.1/resty/auto-ssl/shell/*
$ sudo chmod +x /usr/local/openresty/luajit/share/lua/5.1/resty/auto-ssl/vendor/*

这就是上面我提到的坑,也许是 LuaRocks 的问题,也许不是。如果你找到了原因,欢迎 comment 给我,谢谢哈。

在 Openresty 中配置 lua-resty-auto-ssl

nginx 的 ssl 站点需要先指定一个静态的 ssl_certificate, 否则会报错,因此需要生成一个自签的证书,骗过 nginx 让它顺利启动之后,再由 lua-resty-auto-ssl 返回动态的证书。

1
2
3
4
$ sudo openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 \
   -subj '/CN=sni-support-required-for-valid-ssl' \
   -keyout /etc/ssl/resty-auto-ssl-fallback.key \
   -out /etc/ssl/resty-auto-ssl-fallback.crt

我习惯于将全局配置就放到 nginx.conf 里面,每个虚拟主机、网站或说应用独立一个配置文件 example.com.vh.conf 这样。

nginx 的全局配置 /usr/local/openresty/nginx/conf/nginx.conf

 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
http {
  # 配置 lua-resty-auto-ssl 的全局选项,并启动服务
  lua_shared_dict auto_ssl 1m;
  resolver 8.8.8.8;

  init_by_lua_block {
    auto_ssl = (require "resty.auto-ssl").new()

    # 这里你可以限定只给那些域名启用 auto ssl
    auto_ssl:set("allow_domain", function(domain)
      return true
    end)

    auto_ssl:init()
  }

  init_worker_by_lua_block {
    auto_ssl:init_worker()
  }

  server {
    listen 127.0.0.1:8999;
    location / {
      content_by_lua_block {
        auto_ssl:hook_server()
      }
    }
  }

  include /path/to/example.com.vh.conf;
}

example.com.vh.conf

 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
server {
  listen 80;
  server_name example.com;

  # Let's Encrypt 需要验证你对域名的控制权,这个就是用来应答的.
  location /.well-known/acme-challenge/ {
    content_by_lua_block {
      auto_ssl:challenge_server()
    }
  }
}

server {
  listen 443 ssl;
  server_name example.com;

  # lua-resty-auto-ssl 的精华部份,若当前还没有证书或已过期则自动申请,然后返回,证书有效就直接返回
  ssl_certificate_by_lua_block {
    auto_ssl:ssl_certificate()
  }

  # 这里配上之前我们生成的自签名证书,否则会报错
  ssl_certificate /etc/ssl/resty-auto-ssl-fallback.crt;
  ssl_certificate_key /etc/ssl/resty-auto-ssl-fallback.key;
}

我主要是演示这些配置放在哪些地方,参数的意义可以在 lua-resty-auto-ssl 主页上查询。

以上配置完成重启 nginx ,接着就可以看看 auto ssl 是否能正常工作了:

1
2
$ sudo systemctl restart nginx
$ curl https://example.com

若有错误,可以查看 nginx 的 error log, lua-resty-auto-ssl 会将错误信息输出到这上面。

总结

虽然早有 CertBot 这样的自动化工具,但 lua-resty-auto-ssl 显然是更加地方便,在新建站点的时候多加几行即可实现全自动化的 https 。