简体   繁体   中英

Erlang: inets httpd with SSL

It is asininely ridiculous how difficult this is to set up. I've been trying for 3 days now. Combed the internet and this site for help, but nothing has worked.

What I want is conceptually simple. I want an inets httpd server with ssl. Getting the server up and running is no issue... non-ssl anyway. It's when ssl is added in that it just doesn't work.

Don't ask what errors, there are multiple ones, and they shift depending on what change I make to the configuration. Mainly it's either a browser error saying the certificate doesn't give permission to do this or that, or if changes are made, a bunch of errors and process crashes in the erlang shell.

I simply want to know 1) what ssl certificates I will need, 2) what format they need to be in, and 3) on the httpd server side, exactly what ssl config options I will need.

No Apache-like config or config files. I want the config options for doing it programmatically.

If anyone can help with that, I'm all ears.

Using Erlang R16B03 the following setup works for me:

-module(inets_ssl).

-export([start/0]).

start() ->
  inets:start(),
  {ok, Pid} = inets:start(httpd, [
                                  {port, 22443},
                                  {server_name,"localhost"},
                                  {server_root,"./"},
                                  {document_root,"./"},
                                  {bind_address, any},
                                  {socket_type, {ssl, [{certfile, "./server.crt"}, 
                                                {keyfile, "./server.key"}]}},
                                  {mimetypes, [
                                               {"html", "text/html"}
                                              ]}
                                 ]),
  Pid.

The cert (server.crt) and key (server.key) files can be generated with:

$ openssl genrsa -des3 -passout pass:x -out server.pass.key 2048
$ openssl rsa -passin pass:x -in server.pass.key -out server.key
$ openssl req -new -key server.key -out server.csr
$ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Taken from https://devcenter.heroku.com/articles/ssl-certificate-self

Assuming a index.html file exists in document_root the url https://localhost:22443/index.html should be accessible.

This worked for me using linux OTP release 22 and windows OTP release 23:

https://127.0.0.1:9999/db/api:get

Of course my cert was not signed (had to add an exception for that in Firefox) and in windows it seems that my connection was just reset.

However curl worked for both cases and it managed to establish a connection

curl -v -k https://127.0.0.1:9999/db/api:get

-module(api).
-export([start/0, get/3, main_handler/1]).

start() -> 
    try 
        inets:start(),
        ssl:start()
    catch 
        _ -> erlang:exit("Failed to start inets")
    end,

    case lists:member(main_handler_pid, registered()) of
        false -> 
            MainPid = spawn_link(api, main_handler, [0]),
            register(main_handler_pid, MainPid);
        _ -> ok
    end,
    try start_api_response() of 
        {State,Pid} -> erlang:display({State,Pid}),
        case State of 
        ok ->
            ok;
        _ -> 
            erlang:display(State)
        end
    catch 
         _:_ -> {"Error starting server"}
    end.


start_api_response() ->
    {State,Pid} = inets:start(httpd, [{port, 9999}, 
        {server_name, "localhost"}, 
        {socket_type, {ssl,[{certfile, "./cert.pem"}, {keyfile, "./key.pem"}]}},
        {document_root, "./"}, 
        {modules,[mod_esi,ssl,crypto]},
        {server_root, "./"}, 
        {bind_address, any},
         {mimetypes, [
                                               {"html", "text/html"}
                                              ]},
        {erl_script_alias, {"/db", [api,io]}}]),
    {State,Pid}.


main_handler(N) ->
    receive
        Pid -> 
            erlang:display("ping main: " ++ integer_to_list(N)),
            Pid ! N
    end,
    main_handler(N+1).

get(Sid, _Env, Input) ->
    main_handler_pid ! self(),
    erlang:display(Input),
    receive
        N -> 
            mod_esi:deliver(Sid, integer_to_list(N))
    end.

It worked after I used 127.0.0.1 instead of localhost and added the modules part:

{modules,[mod_esi,ssl,crypto]}

After that I got some TLS notice reports from the server and the reason it doesn't seem to work in Windows is that:

TLS server: In state hello at tls_record.erl:539 generated SERVER ALERT: Fatal - Unexpected Message
 - {unsupported_record_type,71}

My small code just increments a counter.

EDIT:

ssl:cipher_suites(all,'tlsv1.3).

Will make it possible to do get commands through the webbrowser, seems it defaults to an old tls version.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM