Awesome
Name
lua-resty-letsencrypt - Automatically fetch and renew TLS certificates on the fly using LetsEncrypt CA.
Table of Contents
Status
This software is considered experimental and still under active development.
Description
On the fly SSL registration and renewal inside OpenResty/nginx using Let's Encrypt.
In practice this means that on first HTTPS connection from a web client to the web server, this software will:
- Make an account for LetsEncrypt
- Create CSR and send to LetsEncrypt
- Put challenges on a well known URL and serve that
- Get signed cert from LetsEncrypt and store it on the filesystem
- Continue SSL handshake with client using the newly issued cert
On subsequent requests the certs will be loaded from filesystem and cached in nginx mem, and if expiry date is less than a week a new certificate will be requested from LetsEncrypt.
This software uses the ssl_certificate_by_lua functionality in OpenResty 1.9.7.2+. This software requires an nginx build with OpenSSL version at least 1.0.2e. the ngx_lua module, and LuaJIT 2.0.
It is built using Kim Alvefur's ACME implementation for Lua, and the only dependency for that is luaopenssl http://25thandclement.com/~william/projects/luaossl.html which can be installed using LuaRocks
Installation
Requirements:
Install OpenResty, and Luarocks. Install lua-openssl:
sudo luarocks install luaossl
Create directory for storing certificates and letsencrypt data.
mkdir -p /etc/nginx/letsencrypt/
# Make it writable by nginx user (often www-data)
chown www-data /etc/nginx/letsencrypt/
Put letsencrypt.lua
somewhere in the lua_package_path.
Configuration
Example nginx.conf
# HTTP client needs a resolver. Use google as an example:
resolver 8.8.8.8;
# Storage for challenge token and cert cache
lua_shared_dict acme 1m;
server {
# Non-HTTPS server for serving challenges
listen 80;
listen [::]:80;
location /.well-known {
content_by_lua_block {
letsencrypt:challenge()
}
}
}
init_by_lua_block {
-- Using staging dir by default, please test by using that first.
-- Once you feel ready you can uncomment the second line
local conf = {
domains = {'www.example.com', 'example.com'}, -- domains that we should fetch certs for
root = '/etc/nginx/letsencrypt/', -- Trailing slash is important. Must be included.
directory_url = "https://acme-staging.api.letsencrypt.org/directory",
--directory_url ="https://acme-v01.api.letsencrypt.org/directory"
contact = 'mailto:my@email.gg',
agreement = 'https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf',
}
letsencrypt = (require 'letsencrypt').new(conf)
}
server {
listen 443 http2 ssl;
# Fallback, needs to be a valid file, can be self signed.
# openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 \
# -subj '/CN=resty-auto-ssl-fallback' \
# -keyout /etc/ssl/letsencrypt-fallback.key \
# -out /etc/ssl/letsencrypt-fallback.crt
ssl_certificate /etc/ssl/letsencrypt-fallback.crt;
ssl_certificate_key /etc/ssl/letsencrypt-falllback.key;
ssl_certificate_by_lua_block {
letsencrypt:ssl()
}
... more conf here ...
}
Start nginx and pay attention to error.log for any messages.
TODO
- Request multiple domains in certs.
- Alternative storage for certs/account (i.e. redis)
- Extensible caching
- Rate limits so we ensure we don't send too many requests to LetsEncrypt
- Cache cert conversion
- Configurable logging
- Use Squish to generate one big file: http://matthewwild.co.uk/projects/squish/readme.html or https://code.zash.se/luaunbound/file/tip/squish.sh
- Write FFI to openssl to have one less dependency?
Copyright and License
This module is licensed under the MIT license.
Copyright (c) 2016 Tor Hveem
Copyright (c) 2016 Kim Alvefur
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
See Also
- the ngx_lua module: http://wiki.nginx.org/HttpLuaModule
- lua-acme readme https://www.zash.se/lua-acme.html
- lua-acme repo https://code.zash.se/lua-acme/
- lua-jwc repo https://code.zash.se/lua-jwc/
- Alternative implementation, lua-resty-auto-ssl https://github.com/GUI/lua-resty-auto-ssl