On the fly SSL certificate issue and renewal inside OpenResty with Let's Encrypt
Switch branches/tags
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.



On the fly free SSL registration and renewal inside OpenResty/nginx with Let's Encrypt.

This OpenResty plugin automatically and transparently issues SSL certificates from Let's Encrypt as requests are received.

This uses the ssl_certificate_by_lua functionality in OpenResty

By using ssl-cert-server to register SSL certificates with Let's Encrypt, you agree to the Let's Encrypt Subscriber Agreement.

I got inspires and stole some code from the awesome project lua-resty-auto-ssl and Golang's autocert package, many thanks 😀


Considered ALPHA. This is an spare-time project, anyone interested with this project are HIGHLY RECOMMENDED to do testing in your environment.


The release version 0.1.x has a bug which may cause dead loop in OCSP stapling updater after months long running. The bug has not much impact on CPU usage, but will blow up the logging files.

If anyone is using the 0.1.x release, please consider upgrade to 0.2.x release as soon as possible.


The lua library is published with OPM, the following command will install the ssl-cert-server library, as well as it's dependency "lua-resty-http".

opm get jxskiss/ssl-cert-server

If you do not have opm, you can install the lua libraries manually, take OpenResty installed under "/usr/local/openresty" as example (you may need to use sudo to grant proper permission):

mkdir -p /usr/local/openresty/site/lualib/resty
cd /usr/local/openresty/site/lualib/resty
wget https://raw.githubusercontent.com/pintsized/lua-resty-http/master/lib/resty/http.lua
wget https://raw.githubusercontent.com/pintsized/lua-resty-http/master/lib/resty/http_headers.lua
wget https://raw.githubusercontent.com/jxskiss/ssl-cert-server/master/lib/resty/ssl-cert-server.lua

Then download the cert server service binary file, either build by yourself:

go get github.com/jxskiss/ssl-cert-server

Or, download prebuilt binaries from the release page.

Run your cert server (eg: for any sub-domain of example.com):

/path/to/ssl-cert-server --listen= \
    --email=admin@example.com \

For all available options for ssl-cert-server service, please see the "Available options" section.

Now you can configure your OpenResty to use the cert server for SSL certificates, see the following configuration example.

Configuration Example

events {
    worker_connections 1024;

http {
    include       mime.types;
    default_type  application/octet-stream;

    lua_shared_dict ssl_certs_cache 1m;

    init_by_lua_block {
        -- Define a funcction to determine which SNI domains to automatically
        -- handle and register new certificates for. Defaults to not allowing
        -- any domain, so this must be configured.
        function allow_domain(domain)
            if domain:find("example.com$") then
                return true
            return false

        -- Initialize backend certificate server instance.
        cert_server = (require "resty.ssl-cert-server").new({
            backend = '',
            allow_domain = allow_domain

    # HTTPS Server
    server {
        listen 443 ssl;

        # Works also with non-default HTTPS port.
        listen 8443 ssl;

        server_name hello.example.com;

        # Dynamic handler for issuing or returning certs for SNI domains.
        ssl_certificate_by_lua_block {

        # Fallback certificate required by nginx, self-signed is ok.
        # openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 \
        #   -subj '/CN=sni-support-required-for-valid-ssl' \
        #   -keyout /etc/nginx/certs/fallback-self-signed.key \
        #   -out /etc/nginx/certs/fallback-self-signed.crt
        ssl_certificate /etc/nginx/certs/fallback-self-signed.crt;
        ssl_certificate_key /etc/nginx/certs/fallback-self-signed.key;

        location / {
            content_by_lua_block {
                ngx.say("It works!")

    # HTTP Server
    server {
        listen 80;
        server_name example.com;

        # Endpoint used for performing domain verification with Let's Encrypt.
        location /.well-known/acme-challenge/ {
            content_by_lua_block {


Available options for cert server

Usage of ssl-cert-server:
  -listen string
        listen address, be sure DON't open to the world (default "")
  -email string
        contact email, if Let's Encrypt client's key is already registered, this is not used
        generate certificates with 2048-bit RSA keys (default false)
  -before int
        renew certificates before how many days (default 30)
  -cache-dir string
        which directory to cache certificates (default "./secret-dir")
  -domain value
        allowed domain names (may be given multiple times)
  -pattern value
        allowed domain regex pattern using POSIX ERE (egrep) syntax, (may be given multiple times,
        will be ignored when domain parameters supplied)
        use Let's Encrypt staging directory (default false)
        print version string and quit



v0.2.0 @ 2018-08-11

  • fix: dead loop in OCSP stapling updater after months long running
  • change: remove unnecessary golang dependencies (gocraft/web, jxskiss/glog), resulting smaller binary size and easier installation
  • change: since glog dependency has been removed, the flags provided by glog are not available anymore
  • change: use official acme/autocert package instead of forking, makes code clearer and allows easier tracking of upstream changes
  • new: use glide to manage golang dependencies

v0.1.2 @ 2018-06-20

  • fix: 408 Request Time-out from OCSP stapling server

v0.1.1 @ 2018-01-06

Initial public release.


  1. Implement better cache strategy;
  2. Handle backend server failure more robustly;
  3. Test case for both cert-server and openresty library (The acme-related work is done by golang's acme/autocert package, which is well tested. Any error in the lua library and golang request handlers are carefully handled.)