Search code examples
dockernginxluaopenresty

How to dynamically set the domain for ssl_certificate


I am using lua via openresty and setting an environmental variable to dynamically set the domain name. I have:

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;    
    }
}

I get an error:

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)

Setting server_name works fine but in the case of ssl_certificate and ssl_certificate_key it is taking the value of $MYDOMAIN literally.


Solution

  • Not every nginx directive allow embedded variables. ssl_certificate and ssl_certificate_key don't support it.

    But you may use ssl_certificate_by_lua_block and ngx.ssl

    The main workflow:

    1. Specify any valid stub certificate within nginx config.
    2. Follow ngx.ssl synopsis, it would need some certificate format conversions. Use os.getenv("MYDOMAIN") to build the file path to open and read the cert. files contents.
    3. Cache converted keys to avoid file read and conversions for the same domain upon every request.

    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.