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


#1

I have a web server I made myself using example code from Boost.Beast which itself relies on Boost.ASIO. I’m using Boost version 1.69.0 (the version of Beast that comes with this version of Boost is older than the one on the master branch of the Boost.Beast GitHub repository, by the way). My application’s source code is here. The server_certificate.hpp file on the GitHub repository is here.

I host the app on my own computer, so I got a free subdomain name from dynu.com (dragonosman.dynu.net). And because I’m using a server I made, hosted on my own computer, I can’t use automated certificate renewal methods that depend on commercial servers like Ngnix or Apache. I’ll have to use a different method to automate renewal if one exists for my case.

I got a certificate for the domain from Let’s Encrypt using the TXT record method. I’m using Windows 10 and the client I used to get the certificates was acme.sh. On the Command Prompt. As you guys can see in the example server_certificate.hpp file on the Beast repository, there’s a DH parameter field in the SSL context that Boost.ASIO uses. Is there no way for me to get DH parameters for this certificate? I currently don’t have them.

I have ca.cer, dragonosman.dynu.net.cer, fullchain.cer and dragonosman.dynu.net.key files. I used fullchain.cer for the certificate.

I need help on getting it to work because right now whenever I visit the app in my browser (MS Edge in this case) I get an error page saying, “Can’t connect securely to this page”. And in my app’s console window (it being a C++ console application), I get an error saying, “handshake: The file handle supplied is not valid”. It’s generated by a function that uses a boost::system::error_code object to hold the error returned by the operation used (in this case the SSL handshake).


#2

Hi @DragonOsman,

DH parameters are not part of the certificate itself. You could generate some on your system with the openssl command line utility, among other possibilities.

A lot of people who are developing their own web apps with some kind of framework have been better served by having another application, like a reverse proxy, terminate incoming TLS connections and then proxy to the web app on localhost. I imagine that this would be the easiest option for you because then you wouldn’t have to configure HTTPS support in Boost at all. You could use nginx or Caddy this way, among other options; documentation for getting Let’s Encrypt to work with these tools is more readily available. You don’t have to use them to host your web site because they can pass everything through to another port (for example, with nginx’s proxy_pass directive).


#3

I tried to use Apache’s reverse proxy before with my current dynamic DNS domain name, but I had trouble with it and was also told that I’d need an actual domain name to get it to work. Are NGINX and Caddy different in this case? Mine is a free subdomain name, so it probably wouldn’t work in some cases.


#4

A free subdomain name is an actual domain name.
As long as the “name” is resolvable via Internet DNS and that IP is handled by your web server you can get a cert for that name*.

[* there may be some domain names that are blocked or restricted - but that would be a very rare case]


#5

I still had trouble with Apache when I tried to set up a reverse proxy on it and they told me on the mailing list that I couldn’t use a dynamic DNS. I don’t know. I also have some confusion about what port to set up port forwarding for and such (I have one port for my app itself, one for the proxy, and one for Apache itself–I also don’t know if I should use the same port for the latter two or not). And I can’t use port 80, 443, 8080, or 8443 because these are taken by the router.

Anyway, I do want to know how to set up HTTPS for my app on my own. I could install a client for Let’s Encrypt and have it renew the certificate if possible, though first I need to know if it’s possible for me to just bring in the certificate I already have so that it’d use that.


#6

The information you have been provided may have been out-of-context or incorrect.
You can get a cert for any real DNS name.

That said, you will need to use port 80 to authenticate the certificate validation request.
Or switch to a DNS name that your can control the DNS entries for and use that name to validate over DNS.


#7

I already have certificates, like I’ve said. I used the DNS method to get my certificates, where you verify ownership by putting TXT records in the domain name. I put TXT records in my account on dynu.com and verified ownership that way. I had to do this because port 80 is reserved by the router–same for port 8080 which is like alias apparently. I’m talking about being told that I couldn’t get a reverse proxy to work with a dynamic DNS.

Anyway, I do want to know how to set up HTTPS for my app on my own. I could install a client for Let’s Encrypt and have it renew the certificate if possible, though first I need to know if it’s possible for me to just bring in the certificate I already have so that it’d use that.


#8

Since you are able to get a cert…
On that subject then: You have been provided misinformation.
The Apache reverse proxy has no way to differentiate any name from any other name; be they dynamic, or forced by your own hosts file, or any other way an IP can be retrieved from a name.

Apache would NOT be able to use any ports that are already in use, nor would it be able to make available ports that can’t reach your server.

So, if your app can be accessed on any other port and that port can be reached from the Internet, you can secure that port with Apache reverse proxy and serve your app via https://your.dynamic.name:port-number/


#9

Do I use separate domain names for Apache itself and its reverse proxy, or can I use the same port for both?

Also, if I got the certificate using acme.sh, will it renew automatically after 60 days or do I have to do it manually? I cloned the GitHub repository.


#10

The Apache itself doesn’t require anything at all.

It will simply need to use the cert you have obtained for your dynamic DNS name to bind it to the reverse proxy block that connects the clients to your app.
Client side is HTTPS://your-ddns:port/ > Apache(reverse proxy)
Server side is Apache > your APP (presumably HTTP://localhost-or-other-local-system:some-app-port/)


#11

I thought I needed to bind Apache to a port and use another port for the reverse proxy itself. Is that wrong; do I only need a port for the reverse proxy itself?

And what about the certificate renewal? Will acme.sh renew it automatically once the 60 days are up or should I do it manually?


#12

Yes, you don’t need anymore than that.
Just one port that will be used to proxy to your app.

If acme.sh has a DNS plugin that works it can be automated.
If you had to do it manually, then you will have to continue doing it manually.


#13

Okay, so if Apache is listening on port 8081, the port for VirtualHost is 8000, and my app is on port 5501 (which it currently is, with port forwarding set up), what do I do? This is my rule for the VirtualHost:

<VirtualHost *:8000>
    ServerAdmin osmanzakir90@hotmail.com
    ServerName dragonosman.dynu.net
	ServerAlias www.dragonosman.dynu.net
    ErrorLog "logs/dragonosman.dynu.net-error.log"
    CustomLog "logs/dragonosman.dynu.net-access.log" common
	ProxyPass "/" "http://192.168.10.14:5501/"
	ProxyPass "/?q=accesskey" "http://192.168.10.14:5501/?q=accesskey"
</VirtualHost>

I’m asking here because I was apparently misinformed on the Apache mailing list. Sorry about this if it’s a bother or a problem. Anyway, aside from this and port forwarding, is there anything else I need to do to make it work? And can you see anything wrong in the above XML markup?

Don’t mind the weird indentation; it’s all lined up straight on disk.


#14

You need to include the lines for SSL:
SSLCertificateFile /path/to/cert.pem (or fullchain.pem)
SSLCertificateKeyFile /path/to/private.key
And maybe also: [depending on the apache version]
SSLCertificateChainFile /path/to/chain.pem

You may also need to ensure SSL is on:
SSLEngine On

And you may also need to provide ciphers and protocols to be used by SSL:
SSLProtocol …
SSLCipherSuite …
[I leave it to you to find and use whichever ones you may deem proper and/or necessary]


#15

The files are:
ca.cer
{DOMAIN}.cer
fullchain.cer
{DOMAIN}.key
{DOMAIN}.conf
{DOMAIN}.csr.conf

First I need to know what the .conf and .csr.conf ones are. All I can tell is that .conf is for some kind of configuration.

The fullchain.cer file consists of two certificates listed together back-to-back, and I’m using both in my cert object in my code like shown here: https://github.com/DragonOsman/currency_converter/blob/master/server_certificate.hpp . Is this wrong? And there’s also a “chain” mentioned, with ctx.use_certificate_chain(). What chain is this referring to? The chain I used in the const cert object, or something else (also assuming I may have done something wrong there)?

What do I do about the ports I mentioned? Notice I mentioned three different ones.

My Apache version is 2.4.34. I’ll go and get 2.4.38 real quick after posting this.


#16

.csr = Certificate Signing Request (you don’t need those for anything)

Apache 2.4.34 supports the fullchain.pem file - so that is correct.

You shouldn’t need to do anything with the chain file.

You can close them - except the one you decide to use for Apache (to proxy to your app).


#17

I can keep on my app on port 5501 but stop forwarding it, then, so that only the port that VirtualHost is listening on is forwarded?

Where can I find out what values, respectively, to use for SSLProtocol and SSLCipherSuite?

I’m installing version 2.4.38 now, so I need to about that. I’m assuming it supports fullchain.pem/fullchain.cer as well?


#18

Yes; that is the idea - to force access through the (secure) proxy.

You can start with a web search or use the Mozilla recommended: https://wiki.mozilla.org/Security/Server_Side_TLS

Yes; all versions since 2.4.8 support them.


#19

Do I just put the values for the Cipher Suite and SSL Protocol directly in httpd.conf file? And is it fine if I just provide the Cipher Suites? And what value do I put for the SSL Protocol if I’m using OpenSSL version 1.1.1b? Would TLSv1.2 be fine? And Mozilla recommends three DHE groups for the DH parameters. I guess I should use one of those, then?


#20

If you intend on using those setting “globally”, then yes.

Apache is very “forgiving”, anything it needs that may be missing it will generally use a “default” for.

Yes, TLSv1.2 is recommended and supported by OpenSSL v1.1.1b

This may be a “trial-and-error” phase as I can’t be certain which one(s) will be supported by your clients.
[for instance: I generally only use ECDHE ciphers - but it just happens to NOT conflict with my intended uses]