How do I use Let's Encrypt Certs with Boost.ASIO?


How do I use a DHE group with Apache?

I found the Ciphersuites, but what do I do with that whole thing? Is what I need just before each colon?



You would use that string as [all in one line]:


Without quotes or with quotes? Right now I have this:

<VirtualHost *:8000>
    ErrorLog "logs/"
    CustomLog "logs/" common
ProxyPass "/" ""
ProxyPass "/?q=accesskey" ""
SSLCertificateFile "C:/Users/Osman/"
SSLCertificateKeyFile "C:/Users/Osman/"
SSLEngine On
SSLProtocol "TLSv1.2"


That should work…
Have you tried it?


I removed the port forwarding rule for port 5051 on my router and added a rule for port 8000, and then I changed my .cpp code file back to the non-SSL version and recompiled it. But when I run the app, start Apache as a service, and try to visit , I get an error page saying that Edge can’t reach that page.

By the way, what do I with this?

<IfModule ssl_module>
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin

It’s the default setting.

My app itself is listening on port 5501, so I need set up the proxy so that requests sent to port 8000 are proxied to port 5501.


That is how you configured it:

From that same system:
curl -Iki
curl -Iki

[assuming the local IP is]


Visiting in my browser works, but doesn’t.

And on Command Prompt I get this:

curl -Iki
curl: (35) schannel: failed to receive handshake, SSL/TLS connection failed
curl -Iki
curl: (7) Failed to connect to port 8000: Connection refused


That test should be without the “S”
curl -Iki

Please show local IP:
ifconfig | grep -Ei 'add|inet'


Without the S, the test for port 5501 is stuck. Nothing’s happening.

ifconfig isn’t recognized, but running ipconfig gives me this:

Wireless LAN adapter Wi-Fi:

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::ce:d32:bd96:79e4%9
   IPv4 Address. . . . . . . . . . . :
   Subnet Mask . . . . . . . . . . . :
   Default Gateway . . . . . . . . . : fe80::e6a:bcff:fef6:a306%9


curl -Iki
curl: (7) Failed to connect to port 8000: Connection refused

The other one is still frozen, so I did this in another Command Prompt window.

What do you think could be the problem if the reverse proxy itself is configured correctly?

After doing this in the ProxyPass directives:

ProxyPass "/" ""
ProxyPass "/?q=accesskey" ""

I get this:

curl -Iki
curl: (7) Failed to connect to port 5501: Connection refused
curl -Iki
curl: (7) Failed to connect to port 8000: Timed out

I changed it back to the IP address in the .conf file.


@rg305 Because I’m having trouble with the reverse proxy anyway, I’m still going to try manually loading the server certificate into app directly via Boost.Asio itself. I’ve changed the C++ code for my server app to follow the sync HTTP server example for Beast that’s using SSL. I think it’s possible that I need to do this to get it to work with the reverse proxy too.

Also, how do I get the certificate password? Boost.Asio has a password callback method on the SSL context object, and the Beast example does it like this:

        return "test";

The callback must return the password as a string, and the samples use “test” as the password. And the example HTTP client (sync) example also has root certificates. I have code where I’m sending a request to the currency API that I’m using to get conversion rates, but I’m sending the request over port 80 because SSL isn’t allowed in the free plan.

Anyway, here’s the link to the app source code repository on GitHub again. The .cpp file is using the HTTP SSL server example (sync) and the HTTP non-SSL client (sync) example. If there are mistakes you can see, please tell me about it and help me fix it. Thanks in advance. [Hopefully there are others who can help me if you can’t for any reason.]

Edit: It works. I have HTTPS on the app now. I just need to fix the URL I’m sending CORS requests to in my JavaScript code in the app. I do have an error on the read call here that says that the stream was truncated:

// Read a request 
http::request<http::string_body> req;
http::read(stream, buffer, req, ec);
if (ec == http::error::end_of_stream)
if (ec)
	std::cerr << "Lines 591 and 592:\n";
	return fail(ec, "read");

I’ll try asking about this in the Boost users mailing list too, but what is this about and is it possible to fix it?


@rg305I found a currency API that accepts requests over HTTPS in the free subscription. I already know how to use the SSL certificate with the server, but I don’t know how to get the root certificate for the client. The Boost.Beast examples include an SSL-enabled synchronous HTTP client and it uses a root certificate. Here’s the header file root_certificates.hpp on GitHub and this is the C++ file using that header.

Anyway, I still need to know how to get the password.


The root cert is never provided by LE nor should it be included in the servers’ reponse.
The most you can get (by default) is the complete chain.
You can use something like this to see the cert and chain:

openssl s_client -connect -servername -showcerts

You will have to get creative to get the root cert from the (tail of) that chain.
[but that should NOT be required; as root certs are already included in all such packages]

Please show:
netstat -natp tcp
[only need to see the LISTENING lines]


I need it for the client code that’s making a request to the currency API in the C++ code. The Boost.Beast example uses a root certificate for the encryption. I’ll try running that command.


@rg305 I just tried the command you suggested. The result is:

openssl s_client -connect -servername -showcerts
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN =
verify return:1
Certificate chain
 0 s:CN =
   i:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
 1 s:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
   i:O = Digital Signature Trust Co., CN = DST Root CA X3
Server certificate
subject=CN =

issuer=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3

No client certificate CA names sent
Peer signing digest: SHA512
Peer signature type: RSA
Server Temp Key: ECDH, P-256, 256 bits
SSL handshake has read 3077 bytes and written 453 bytes
Verification error: unable to get local issuer certificate
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
    Session-ID: E82398218D3F68AB9344A4646A2FDA65379813077741017CA640515FE81E8F9D
    Master-Key: 5F12660C7CA292B29E26CA1709947C1AC17A66F30348E5B2237F06C9116AF615012541850BF1C75DCA86CF7CE88AFCFA
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1552605120
    Timeout   : 7200 (sec)
    Verify return code: 20 (unable to get local issuer certificate)
    Extended master secret: no
HTTP/1.0 408 Request Time-out
Cache-Control: no-cache
Connection: close
Content-Type: text/html

<html><body><h1>408 Request Time-out</h1>
Your browser didn't send a complete request in time.

Is that meant to be the root certificate chain?

I need to make a GET request over HTTPS in my C++ code. I’m sending the request over port 443, but it doesn’t seem to be enough because I’m getting an empty response body. This is the root certificate header and this is the C++ file using it, in the Boost.Beast examples that I have to use as a reference.

Do I use MS Edge’s root certificate if I can find it? Because I don’t know how to find it. I’ve tried searching around for into on root certificates but I can’t find anything. Is it in the certificates I got from Let’s Encrypt when I got the server certificates? And if so, which one is it?

Edit: It does mention this is the root certificate, but do I need both of these or just one?

Edit2: This chain isn’t the same one I got for the server. I checked (by reading fullchain.cer into a file and writing an if condition to match the strings). Neither of them is the same as the one in either.


The Boost example is bad because it hard-codes a single GeoTrust trust anchor (root) into your application. This is the wrong thing to do in a real application. If you are writing a client that has to do x.509 verification, then you are meant to load the trust anchors from the operating system. These get updated from time to time, and you have to keep up to date with them.

On Linux, you would call ssl::context::add_verify_path on the standard directory for the distribution, e.g. /etc/ssl/certs/.

On Windows, I don’t know what the standard approach for this is. It’s pretty clear from the output of your openssl s_client command that your OpenSSL installation doesn’t know how to locate the root certificate store either. So you might have to get it from, or alternatively identify what the correct way to do it in Microsoft-land is.


Which certificate do I use out of those two as the root certificate, though? It mentions the words “CN = DST Root CA X3”, so is the one right above that the root certificate I need (because below the certificate that’s below that one, it says “Server Certificate”).

Anyway, I’ll try following the link you posted for


Choosing just one root to load is straight up wrong. Let’s Encrypt isn’t going to use DST Root CA X3 forever - it’s expiring rather soon and your application will break. Or it might get revoked.

You could just load DST Root CA X3, and it will work for a while sure, but it’s bad.

I checked, and on Windows you are meant to use CertOpenSystemStore(0, "ROOT") and load each root certificate from there. Or you can bundle cacert.pem with your application and load each certificate from there.

This type of thing doesn’t give you portable code, but if you’re using a library that is barely one level above from using raw OpenSSL, then you’re going to have to deal with it.

e: updated wrong link


Is there no way I can find out where the root certificate store is on Windows so I can enter that path when using the OpenSSL command to find the root certificates? And a cross-platform way to get the certs from the store if one exists.

In the documentation for CertOpenSystemStoreA (which is the function whose documentation you linked to) it says that it returns a handle to the cert store if it succeeds and NULL if it fails. So if it succeeds and gives me a handle, I need to know how to get the certificate out of the handle. I don’t know where to look for the info, so I’d try to ask on either the Microsoft Community or MSDN. But as I said before, I’d rather just use a cross-platform way so that my app can work no matter where the server app runs (even though I’m going to host the app on my own laptop only).


If you want this to be cross-platform, then individually passing each certificate from the curl cacert.pem bundle (which you’d have to include with your application) to ssl::context::add_certificate_authority would probably do a trick. But you take responsibility for updating that file over time.

The proper Windows way, you need to learn the Windows Crypto API. There is no root store on the filesystem. Use CertEnumCertificatesInStore on the store handle to loop over each entry, extract the certificate bytes, convert to PEM, pass it to the Boost SSL context … etc.


How often does Mozilla update the cacert.pem file? I could just try to stay up to date with Mozilla. I can just load the cacert.pem file into my app and use a loop or something to load each certificate into the Boost SSL context, right? I’ll just do it that way.

And if I can, I should probably write code to make a GET request to the place where the cacert.pem file is. That way, I could just get the updated file when it changes.