Let's encrypt is a very promising new initiative aimed at becoming a new standard how SSL certificates are provided. No more hassle with having to manually send in certificate requests, remembering you forgot to forward your postmaster mail address, getting the certificate out of the mail and manually converting it and finally getting it imported. As per their website: "Let's Encrypt is a new Certificate Authority: It's free, automated, and open". And they don't disappoint.

Currently letsencrypt is built around an open API and uses online validation through your existing webserver to ensure that you are the owner of the domain. Apache and nginx are supported, and more servers are being added as the product matures. In addition, additional validation options exist such as building your own webroot, using standalone validation or manual validation, and through the plugin system it is possible to write your own plugins for your own product. So, all in all, very promising.

The reason for looking into letsencrypt is that I help manage a non-profit public cloud provider, and a bit over a year ago we made the decision to switch to NSX for our networking needs. We also use the NSX edge as a loadbalancer for our website, the vSphere web client and some other services such as irc and a shell host. Recently, our certificate expired and - because we all love cool new technologies - we all agreed to consider letsencrypt. However, since letsencrypt doesn't support NSX out of the box and we didn't want to play around with manual domain validation, some custom work needed to be done.

Setting up the environment

To start, we'll need a server that will run the letsencrypt application. In our case we decided to install it on our webserver, but you can also create a dedicated server in case you're worried about having your certificates and private keys on a server that's also running web services. It ultimately doesn't matter where letsencrypt is ran, as long as it can serve static files through a webserver.

The installation of letsencrypt (found on http://letsencrypt.readthedocs.org/en/latest/using.html#installation) on Linux is as simple as running the following commands:

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt

Next up, we'll need to set up a webserver that will respond to all domains you want to request certificates for. In our case we use apache with the following vhost config:

<VirtualHost *:80>
 ServerAdmin [email protected]
 DocumentRoot /var/www/klauwd.com
 ServerName www.klauwd.com
 ServerAlias klauwd.com
 ServerAlias irc.klauwd.com
 ServerAlias vcsa.int.klauwd.com
ErrorLog ${APACHE_LOG_DIR}/error.log
 CustomLog ${APACHE_LOG_DIR}/access.log combined
 Alias /.well-known/acme-challenge/ "/var/www/letsencrypt/.well-known/acme-challenge/"

The important part is the Alias for /.well-known to the location of your letsencrypt validation directory. Of course, you could also publish these in the same directory as your webserver, but this allows you to use a single location for validation even if you have multiple virtualhosts.

Next up, we want to configure the NSX load balancer. First off, ensure that even if you just use HTTPS for your sites, HTTP is also served since the online validation takes place over HTTP.

In our NSX loadbalancer we'll need to create a pool for your letsencrypt server. If you reuse your existing webserver you might not need to, but lets assume that you have a dedicated machine.


We've created a "services" backend which is our server that manages all internal services, including letsencrypt.

Next up, for our loadbalancer we'll need to create some application rules:


As you can see, we have two rules. Now technically, only one rule would be required, but for completeness' sake i wanted to show the first rule as well.

Let's start off with the last rule first:

acl is_letsencrypt url_sub -i acme-challenge
use_backend services if is_letsencrypt

If you're familiar with NSX loadbalancig and/or HAProxy syntax, this might already be familiar for you, but for those who aren't, lets go through the implication of this rule.

acl is_letsencrypt creates an access list which checks (through the command url_sub) if acme-challenge is part of the requested url, while -i allows us to check case-insentitive. So if the url in our example would be www.domain.tld/.well-known/acme-challenge/ the acl would match. Now i know this could likely be a bit more strict, but due to time constraints i did not get around to doing this. Modify this rule at your liking.

use_backend services if is_letsencrypt means that if the acl is_letsencrypt matched in the request, the backend pool to be used should be the one named services instead of the preconfigured one. This means that - regardless of the original destination for the traffic - the request will be sent to our letsencrypt machine instead, but only if the url contains acme-challenge.

Now on to the next rule:

acl is_letsencrypt url_sub -i acme-challege
redirect scheme https code 301 if !is_letsencrypt !{ ssl_fc }

as we obviously love using our free new certificates as much as possible, all traffic coming in on http is redirected to the same url on https. However, this is not possible for letsencrypt which will use http for the online validation.

Again, we see the acl is_letsencrypt described in the previous rule. What we've added now is a redirect rule. Breaking down this rule, what is says is to change http to https with a HTTP 301 (Moved permanently) status code, but only if the protocol is not ssl encrypted already (The exclamation mark means that the rule should negate the condition). In addition, we've added a condition that it should only redirect to https if is_letsencrypt is not true.

This allows us to redirect all traffic to https, except when the url contains our letsencrypt certificate url.

Now that this is complete, we can continue on to the actual certificate requests.

Requesting the certificates

For all the details regarding certificate requests, I would like to redirect you to http://letsencrypt.readthedocs.org/en/latest/ for all the fine documentation that has been provided by the let's encrypt team. They can explain in all details what each option does, how to customize your requests and what other possibilities you have.

For our use case, we want to request a single SAN certificate which contains all our domain names, so after logging in to our services machine, the following command is ran in the directory where you installed letsencrypt:

./letsencrypt-auto certonly --webroot --email [email protected] --agree-tos -w /var/www/letsencrypt/ -d klauwd.com -d vcsa.int.klauwd.com -d www.klauwd.com -d irc.klauwd.com

What this does is request a certificate only, not install it (certonly), use the webroot plugin (--webroot), set our email address for support and recovery, agree to the terms of service, set our location for the challenge to /var/www/letsencrypt, and set our domains to all the domains we want to provide on the command line. Ensure that while you're still testing the product to use the --test-cert option which will provide you with a limited test certificate, since the amount of requests per domain is limited.

Alternatively you can set these options in a configuration file so you won't have to provide them on each run, which is what we'll use in the cronjob to automate this process. For more information, see http://letsencrypt.readthedocs.org/en/latest/using.html#configuration-file.

Now we should have our certificates generated in /etc/letsencrypt/live/<domain>/ where <domain> is the first domain option you entered on the request. In this directory, you'll find a number of files:

  • cert.pem - This is the certificate in PEM format.
  • chain.pem - This is the root CA's chain in PEM format.
  • fullchain.pem - This is the full chain of your root CA's chain and your certificate, again in pem format.
  • privateKey.pem - This is the private key for your certificate.

Now before we can use these, there is one last thing we must do. Since NSX doesn't support the private key format provided by letsencrypt, we need to convert this to a RSA private key first. For this, use the following command line:

openssl rsa -in privateKey.key -check

This provides you with the RSA enabled private key on the standard out, which can be copied for importing into NSX.

Now we'll open the NSX edge configuration again and go to Settings -> Certificates.


Click the +icon and add a CA certificate. In the following screen, paste the content of your chain.pem file. You should see the Let's encrypt Authority X1 being added to your certificate store.

Next, click the + icon again and select "Certificate".

This time, in the Certificate Contents, paste the content of your fullchain.pem. Ensure that you include the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- lines, and don't leave any whitespace before or after those.

Next, we need the private key. Remember the original key we converted to RSA? Copy the output of that command into the private key field.

Since the key is not password-encrypted, leave those fields blank. If you want to, you can add a description as well.

Now the only thing left to do is to change our load balancer application profile. in the NSX Edge, go to Load Balancer -> Application Profiles and edit the HTTPS application profile you should already have.


At the bottom, select "Virtual Server Certificates". Check "Configure Service Certificate" and select the certificate you generated. Next, select "CA Certificates" and check the Let's Encrypt Authority X1 certificate.

After saving the settings, your website should now be fully encrypted and have a valid certificate through the use of the Let's encrypt Public Key Infrastructure. And all of that without messing around with legacy systems like email validation or having to pay through the nose for multidomain certificates.

Now, since letsencrypt certificates are valid for 90 days only, our next step will be to run the request commands through vrealize Orchestrator or a cron job, and use the NSX api to automatically configure the newly requested certificate.

Happy Encrypting!


Let's talk!

Knowledge is key for our existence. This knowledge we use for disruptive innovation and changing organizations. Are you ready for change?

"*" indicates required fields

First name*
Last name*