Emqx: Reloading Certificates

Created on 21 Jun 2017  路  4Comments  路  Source: emqx/emqx

Environment

  • OS: debian 8 - docker 17 - alpine:3.5
  • Erlang/OTP: 19
  • EMQ: 2.2

Description

We are using letsencrypt to get our certificates for the SSL connections. As letsencrypt wants us to renew the certificate at least every 90 days, it would be nice to have a solution for doing that without closing the listener (and dropping all active connections) every time.

I looked at esockd as well as mochiweb if there is any solution for this but didn't found anything.
Any suggestions to make that possible?


Thank you in advance

Support

All 4 comments

Just tried a few possible ways to achieve this without touching the code. The most promising and easiest solution I came up with is:

Childs = supervisor:which_children(esockd:listener({'mqtt:ssl',8883})),
[Listener] = lists:filtermap(fun(E) -> case E of {listener,P,_,_} -> {true, P}; _ -> false end end, Childs),
exit(Listener, kill).

Existing connections will not be terminated and all new connections use the new certificate.
However, if I use this solution in a one liner it often crashes the system - not sure whats the problem here but I assume that it could be the asynchronous exit?

It's not the cleanest solution but it works- still hope that it will be implemented a better way where the 'listener' process will be terminated and restarted cleanly.

Best,
baer

After some further investigations I found a pretty simple solution but it needs some additional code in the source. Adding the following code to 'emqttd_app':

restart_listener(ssl, ListenOn) ->
    restart_listener({'mqtt:ssl', ListenOn});

restart_listener(wss, ListenOn) ->
    restart_listener({'mqtt:wss', ListenOn});

restart_listener(Proto, ListenOn) ->
    restart_listener({Proto, ListenOn}).

restart_listener({Protocol, ListenOn}) ->
    % get supervisor pid & child specs
    ListenerSup = esockd:listener({Protocol, ListenOn}),
    {ok, Map} = supervisor:get_childspec(ListenerSup, listener),

    % stop and delete old child (cant be simply restart if transient)
    supervisor:terminate_child(ListenerSup, listener),
    supervisor:delete_child(ListenerSup, listener),

    % start child again
    supervisor:start_child(ListenerSup, {listener,
        maps:get(start, Map),
        maps:get(restart, Map), maps:get(shutdown, Map), maps:get(type, Map), maps:get(modules, Map)}).

As well as change the exported functions to:
-export([start_listener/1, stop_listener/1, restart_listener/2]).

This will work on both SSL connections (MQTT and WSS)! 馃

I hope it will find the way into the next release.

Cheers,
baer

@ baer Thanks for your contributions. I will review and merge the fix in next release if it works fine:)

@baer-devl restart_listener working in v2.2-rc.2

Was this page helpful?
0 / 5 - 0 ratings

Related issues

w3yyb picture w3yyb  路  3Comments

stefano055415 picture stefano055415  路  4Comments

andywang2014 picture andywang2014  路  5Comments

jbrzozoski picture jbrzozoski  路  4Comments

nerdial picture nerdial  路  3Comments