如何为 ssl_certificate 动态设置域

How to dynamically set the domain for ssl_certificate

我正在通过 openresty 使用 lua 并设置一个环境变量来动态设置域名。我有:

user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 768;
}

env MYDOMAIN;

http {
    server {
        listen 80;
        listen 443 ssl;
        set_by_lua $MYDOMAIN 'return os.getenv("MYDOMAIN")';
        server_name $MYDOMAIN www.$MYDOMAIN;
        location / {
          proxy_pass http://127.0.0.1:5000;
          index  index.html index.htm;
        }
        ssl_certificate /etc/letsencrypt/live/$MYDOMAIN/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/$MYDOMAIN/privkey.pem;    
    }
}

我收到一个错误:

nginx: [emerg] BIO_new_file("/etc/letsencrypt/live/$MYDOMAIN/fullchain.pem") failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen('/etc/letsencrypt/live/$MYDOMAIN/fullchain.pem','r') error:2006D080:BIO routines:BIO_new_file:no such file)

设置 server_name 工作正常,但在 ssl_certificate 和 ssl_certificate_key 的情况下,它按字面意思取 $MYDOMAIN 的值。

并非每个 nginx 指令都允许嵌入变量。 ssl_certificatessl_certificate_key 不支持。

但是你可以使用ssl_certificate_by_lua_block and ngx.ssl

主要工作流程:

  1. 在 nginx 配置中指定任何有效的存根证书。
  2. 按照ngx.ssl synopsis,需要进行一些证书格式转换。 使用 os.getenv("MYDOMAIN") 构建文件路径以打开和读取证书。文件内容。
  3. 缓存转换后的密钥以避免在每次请求时对同一域进行文件读取和转换。

You can always use libraries like lua-resty-lrucache and/or ngx_lua APIs like lua_shared_dict to do the caching of the DER-formatted results, for example.

如您所知,环境变量未在 nginx 配置中解析,并非每个指令都支持变量。

我早就写过一篇文章了

https://tarunlalwani.com/post/simple-parameterized-config-files-docker/

想法是在 运行 nginx 之前更新您的配置文件。所以你会有一个启动脚本

#!/bin/bash

envsubst < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf
exec nginx "-g" "daemon off;"

这会让事情变得容易很多。更严格的方法是使用 ssl_certificate_by_lua_block 动态加载证书。

https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md

Nginx 版本 1.15.9 支持 "ssl_certificate" 和 "ssl_certificate_key" 指令中的变量。

来自文档:从 1.15.9 版开始,使用 OpenSSL 1.0.2 或更高版本时,可以在文件名中使用变量

示例:

ssl_certificate     $ssl_server_name.crt;
ssl_certificate_key $ssl_server_name.key;