Skip to content

Commit

Permalink
Refactor plugin / Add instructions for non-chroot
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan Broer committed Dec 15, 2015
1 parent 22059d7 commit d55d065
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 31 deletions.
19 changes: 10 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ The plugin is compatible with ACME clients supporting webroot authentication for
### Zero-Downtime

No need to take HAProxy offline to issue or reissue certificates.
### Self-Contained & Lean
### Self-Contained

No need to leverage a backend webserver for the trivial task of serving a key authorization from a file.
No need to leverage a backend webserver for the trivial task of serving a key authorization file once every three months per domain.

## Installation instructions

Expand All @@ -31,26 +31,26 @@ If there is a line similar to this you are good to go:

Built with Lua support

If your binary doesn't come with Lua bindings, you can download Debian and Ubuntu packages of the latest v1.6 release from the [Debian HAProxy packaging team](http://haproxy.debian.net/).
If your binary doesn't come with Lua bindings, you can download Debian/Ubuntu packages of the latest v1.6 release from the [Debian HAProxy packaging team](http://haproxy.debian.net/).

### HAProxy configuration

Copy `acme-http01-webroot.lua` to a location accessible by HAProxy.
Copy `acme-http01-webroot.lua` to a location accessible by HAProxy. In case that you don't run HAProxy chrooted (`chroot` config option), you need to edit the plugin and set the `non_chroot_webroot` parameter to the path of the directory you want to use as 'webroot'.

Only minimal changes to your existing `haproxy.cfg` are necessary. In fact you just need to add **three lines**:
To activate the plugin you just need to add **three lines** to your `haproxy.cfg`:

In the `global` section insert

lua-load /etc/haproxy/acme-http01-webroot.lua

to invoke the Lua plugin.

In the `frontend` section serving the domain(s) for which you want to create/renew certificates insert
In the `frontend` section serving the domain(s) for which you want to create/renew certificates insert:

acl url_acme_http01 path_beg /.well-known/acme-challenge/
http-request use-service lua.acme-http01 if METH_GET url_acme_http01

to pass ACME http-01 validation requests to the Lua plugin.
This will pass ACME http-01 validation requests to the Lua plugin handler.

*Note:* ACME protocol stipulates validation on port 80. If your HTTP frontend listens on a non-standard port, make sure to add a port 80 bind directive.

Expand Down Expand Up @@ -83,10 +83,11 @@ Follow the [official guide](https://letsencrypt.readthedocs.org/en/latest/using.

We are ready to create our certificate. Let's roll!

What happens here is, we invoke the `letsencrypt` client with the [webroot method](https://letsencrypt.readthedocs.org/en/latest/using.html#webroot) and pass our email address and the `WEBROOT` path configured in the Lua plugin. The domain validation is then be performed against the running HAProxy instance.
We invoke the `letsencrypt` client with the [webroot method](https://letsencrypt.readthedocs.org/en/latest/using.html#webroot).
`--webroot-path` must be set to the value of the `chroot` parameter in your `haproxy.cfg`. If you are not running HAProxy chrooted you need to set it to the value of the `non_chroot_webroot` parameter configured in the Lua plugin.

$ sudo ./letsencrypt-auto certonly --text --webroot --webroot-path \
/var/temp -d www.example.com --renew-by-default --agree-tos \
/var/lib/haproxy -d www.example.com --renew-by-default --agree-tos \
--email your@email.com

Next, concat the certificate chain and private key to a `PEM` file suitable for HAProxy:
Expand Down
47 changes: 28 additions & 19 deletions acme-http01-webroot.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,30 @@
-- ./letsencrypt-auto certonly --text --webroot --webroot-path /var/tmp -d blah.example.com --renew-by-default --agree-tos --email my@email.com
--

--
-- Configuration begin
--

-- Path passed to letsencrypt via the '--webroot-path' parameter must match this
WEBROOT = "/var/tmp"
acme = {}
acme.version = "0.1.0"

--
-- Configuration end
-- Configuration
--
-- When HAProxy is *not* configured with the 'chroot' option you must set an absolute path here and pass
-- that as 'webroot-path' to the letsencrypt client

VERSION = "0.1.0"
acme.conf = {
["non_chroot_webroot"] = ""
}

core.Info("[acme] http-01 plugin v." .. VERSION .. " loaded");
--
-- Startup
--
acme.startup = function()
core.Info("[acme] http-01 plugin v" .. acme.version);
end

--
-- ACME http-01 validation endpoint
--
core.register_service("acme-http01", "http", function(applet)
acme.http01 = function(applet)
local response = ""
local reqPath = applet.sf:path()
local src = applet.sf:src()
Expand Down Expand Up @@ -72,7 +77,7 @@ core.register_service("acme-http01", "http", function(applet)
applet:add_header("Content-Type", "text/plain")
applet:start_response()
applet:send(response)
end)
end

--
-- strip chars that are not in the URL-safe Base64 alphabet
Expand All @@ -88,11 +93,15 @@ end
-- get key auth from token file
--
function getKeyAuth(token)
local keyAuth = ""
local f = io.open(WEBROOT .. "/.well-known/acme-challenge/" .. token, "rb")
if f ~= nil then
keyAuth = f:read("*all")
f:close()
end
return keyAuth
end
local keyAuth = ""
local path = acme.conf.non_chroot_webroot .. "/.well-known/acme-challenge/" .. token
local f = io.open(path, "rb")
if f ~= nil then
keyAuth = f:read("*all")
f:close()
end
return keyAuth
end

core.register_init(acme.startup)
core.register_service("acme-http01", "http", acme.http01)
2 changes: 1 addition & 1 deletion cert-renewal-haproxy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ LE_CLIENT="/path/to/letsencrypt-auto"

HAPROXY_RELOAD_CMD="service haproxy reload"

WEBROOT="/var/tmp"
WEBROOT="/var/lib/haproxy"

# Enable to redirect output to logfile (for silent cron jobs)
# LOGFILE="/var/log/certrenewal.log"
Expand Down
9 changes: 7 additions & 2 deletions haproxy.cfg.example
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
global
#daemon
#log /dev/log local0
user haproxy
group haproxy
daemon
log /dev/log local0
log /dev/log local1 info
chroot /var/lib/haproxy
crt-base /etc/letsencrypt/live
lua-load /etc/haproxy/acme-http01-webroot.lua

defaults
log global
mode http
option httplog
timeout connect 5000
Expand Down

0 comments on commit d55d065

Please sign in to comment.