水一水,好快乐

Introduction

社团的 ssl 证书要过期了,但是自动更新证书的任务一直失败,感觉很奇怪。

我以为是一个小问题,重新配置一下就行了,但是我错了。

letsencrypt 的认证方式有多种,最好用的莫过于 dns 认证,只需要配置一下 dns 解析就可以申请,哪怕没有服务器也可以。

但是社团的情况有点特殊,没有 dns 管理权限,没有 80 端口。也因此,我对于之前如何申请的证书感到好奇。

原来是 letsencryt 还支持另外一种叫做 tls-alpn-01 的认证方式。

优点

  • 不需要 80 端口
  • 在 ssl 层面执行

其实之前还有过一个 TLS-SNI-01 认证方式, 不过因为有缺陷被禁用了。

缺点

  • It’s not supported by Apache, Nginx, or Certbot, and probably won’t be soon.
  • Like HTTP-01, if you have multiple servers they need to all answer with the same content.
  • This method cannot be used to validate wildcard domains.

看到这里,我心理都凉了,居然不支持 nginx?

我更加好奇了,于是询问了一下学长。

学长告诉我不要修改 socket 配置的相关内容。

啊这!

原来都是我的锅呀 ,难怪我感觉 nginx 的配置好生奇怪。

那就进入今天的正题

nginx tls-alpn-01(https)

我带着问题查了一下,好家伙,第一个就是学长的博客(膜拜一波大佬)

原理

Nginx 不仅是 HTTP/HTTPS 服务器,跟提供了全面的 TLS、UDP 甚至是邮件协议支持。

Nginx 的 ngx_stream_ssl_preread_module 模块提供了 ClientHello 访问。通过$ssl_preread_alpn_protocols 变量,即可实现不同协议的分流。

nginx 有一个模块可以根据协议进行分流,于是我们根据这一点来实现 letsencrypt 认证时候的流量转发,进而实现不停服务情况下进行 ssl 证书 renew。

nginx 之 map 作用

学习一下 map 指令

map 指令是由 ngx_http_map_module 模块提供的,默认情况下安装 nginx 都会安装该模块。

map 的主要作用是创建自定义变量,通过使用 nginx 的内置变量,去匹配某些特定规则,如果匹配成功则设置某个值给自定义变量。 而这个自定义变量又可以作于他用。

map 指令的三个参数

  • default : 指定源变量匹配不到任何表达式时将使用的默认值。当没有设置 default,将会用一个空的字符串作为默认的结果。
  • hostnames : 允许用前缀或者后缀掩码指定域名作为源变量值。这个参数必须写在值映射列表的最前面。
  • include : 包含一个或多个含有映射值的文件。
map $var1 $var2 {
    match1 value1;
    default default-value;
    ...
}

在 Nginx 配置文件中的作用段: http{}
注意 map 不能写在 server{} 否则会报错
map 的 $var1 为源变量,通常可以是 nginx 的内置变量,$var2 是自定义变量。 $var2 的值取决于 $var1 在对应表达式的匹配情况。 如果一个都匹配不到则 $var2 就是 default 对应的值。

配置

  • nginx 配置
stream {
    tcp_nodelay on;
    map $ssl_preread_alpn_protocols $tls_addr {
        ~\bacme-tls/1\b 127.0.0.1:10443; # TLS-ALPN-01验证服务的地址
        default 127.0.0.1:8443; # HTTPS服务地址,此处以本机8443为例
    }
    server {
      listen 443;
      listen [::]:443;
      proxy_pass $tls_addr; # 使用对应变量进行访问
      proxy_protocol on; # 开启PROXY protocol,见后文
      ssl_preread on;
    }
}

这里就把 ssl 的流量分成了两个一个是localhost:8443的提供 web 服务器的 ssl 流量,另一个就是letsencrypt tls-alpn-01 的认证流量,这个流量走localhost:10443

一切变得简单起来了,对于 web 服务,将端口修改成 8443 即可,对于认证 ssl 服务,监听10443端口即可。

注意,由于经过这个操作后,从 8443 端口来的流量就是代理的协议了,需要使用代理协议,即添加proxy_protocol
同时需要通过 proxy_protocol_addr来获取真实的 IP 地址。

acme.sh 配置

接下来就是配置 acme.sh 了,只需要修改 tls-apln 的监听端口即可。

示例

acme.sh --issue --domain your-domain.example --alpn --tlsport 10443

如果一切正常,通过上面的命令就可以完成 ssl 证书的申请了。

小插曲
在我完成配置修改的时候,直接使用nginx -s reload进行配置的更新
但是并没有卵用,这个更新无法涉及 socket 修改的变得
也因此,我一直卡在最后一步无法解决
就当我要放弃的时候突入来了一句systemctl restart nginx
然后,就申请成功了。 (我太菜了)

最后

其实我很早就像写这篇了,但是因为拖延症患者,导致现在才有机会写(还是占用上课时间写的)

好了,水了一篇博文好开心。

延伸链接

Last modification:December 11th, 2020 at 08:42 pm
要饭啦~