Bring-your-own SSL Certs with VNS3

Bring-your-own SSL Certs

One of the (few) issues some customers have with VNS3 is the use of self-signed certificates. There are arguments to be made that self-signed certs can be as secure than those provided by third-party trusted signing certificate authorities (CAs), when implemented properly. But these arguments are often more hassle than many IT departments want, especially as most browsers have increased their scary warnings, and when an end user sees those the last thing they want is a debate on the relative security of CAs versus their own local infrastructure.

As of version 4.0 of VNS3 it is possible to upload your own SSL certs. These can be self-signed certs or those provided by a CA.

In this post we’re going to show how to create and upload a signed certificate to VNS3 by using EFF’s Certbot and certificates generated by Let’s Encrypt . Certbot is a part of EFF’s efforts to encrypt the entire Internet. It acts as a client to the Let’s Encrypt open CA, which is a service provided by the Internet Security Research Group (ISRG).

From the perspective of VNS3, an issue with Certbot is that by default it needs to be installed on the instance. It requires this so the certificates can be automatically renewed every 3 months. As VNS3 is a self-contained software appliance, access to the system is strictly limited and the only way to install new software is via the plugin container system, but as the plugin system doesn’t have access to the host’s web server this isn’t a viable approach.

A workable solution, however, is to use the manual options of Certbot and create the certificates separate from the instance, then upload them using VNS3’s UI.

Creating and Installing Your Let’s Encrypt Certificates

The rest of this tutorial assumes the following:

  • You have ownership of a specific domain,
  • You are naming your VNS3 instance
  • You have access to the DNS records for

Given the above requirements, you can run the Certbot process on a separate server and have the certs generated, ready to be uploaded to VNS3.

The approach is:

Running Certbot looks similar to the following:

$ sudo certbot certonly –manual –preferred-challenges dns

Saving debug log to /var/log/letsencrypt/letsencrypt.log

Please enter in your domain name(s) (comma and/or space separated)  (Enter ‘c’

to cancel):

Obtaining a new certificate

Performing the following challenges:

dns-01 challenge for


NOTE: The IP of this machine will be publicly logged as having requested this

certificate. If you’re running certbot in manual mode on a machine that is not

your server, please ensure you’re okay with that.

Are you OK with your IP being logged?


(Y)es/(N)o: Y


Please deploy a DNS TXT record under the name with the following value:


Before continuing, verify the record is deployed.


Press Enter to Continue

At this point you will have to wait for your DNS records to push the TXT record out. This should be fairly quick. To see if your TXT record has appeared you can use the “dig” command (in a separate tab/window), which should return the contents of the TXT record. For example:

$ dig txt

; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> txt

;; global options: +cmd

;; Got answer:

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64903

;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1


; EDNS: version: 0, flags:; udp: 512


;    IN TXT

;; ANSWER SECTION: 1799 IN TXT “hZo-MWdsBlAhwbbYAVyzada3LSLlpDTTu752T3XxthU”

;; Query time: 46 msec


;; WHEN: Thu Sep 07 11:37:23 CDT 2017

;; MSG SIZE  rcvd: 123

Back to Certbot, press Enter to Continue:

Waiting for verification…

Cleaning up challenges


 – Congratulations! Your certificate and chain have been saved at:


   Your key file has been saved at:


   Your cert will expire on 2017-12-06. To obtain a new or tweaked

   version of this certificate in the future, simply run certbot

   again. To non-interactively renew *all* of your certificates, run

   “certbot renew”

 – If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let’s Encrypt:

   Donating to EFF:          

Congratulations, your certs have been created and they are valid for 3 months.

For VNS3 we need the following files:



To update via the UI, connect to your instance and navigate to the “HTTPS Certs” option in the Admin section of the menu. 

The file, cert.pem, is your SSL certificate, and privkey.pem is your SSL key file. Upon clicking the “Upload and Install” button you will receive the message, “HTTPS certs validated and installed”. (If you receive “Error validating key/cert files” it’s possible the order of the files was reversed, with the private key as the cert and vice versa). Once installed the system will restart the web server and your new certificates should be protecting your VNS3 instance.

Automating Certificate Renewal

An SSL certificate from Let’s Encrypt CA expires in 3 months. This is actually a very good thing as it means that in the event of another Heartbleed-type bug, the maximum amount of time that the weakened certs will remain active is 90 days. The problem is that it means that someone will need to rerun Certbot and update the certs on the VNS3 instances every 90 days. A better way is to automate the process.

A detailed analysis of the certificate renewal process is beyond this post. Instead we’ll just touch on some details. Certbot supports a way of running non-interactively but a plugin is required when combining with manual use. It is also possible to run semi-interactively, like so:

$ sudo bash -c “yes | certbot certonly –manual –cert-name

To automate the uploading of the new certs to the VNS3 instance requires use of the API. Here is an example of some basic, hastily written Ruby code that can be used to upload and install the certs:

require ‘rest_client’

require ‘json’

@user     = ‘api’

@password = ‘vnscubed’

base_path = ‘’

cert      =‘cert.pem’)

key       =‘cert.key’)

def put(url, payload = {})

  rc =, user: @user, password: @password, verify_ssl: OpenSSL::SSL::VERIFY_NONE)

  JSON.parse(rc.put(payload.to_json, content_type: ‘application/json’))


def get(url)

  rc =, user: @user, password: @password, verify_ssl: OpenSSL::SSL::VERIFY_NONE)

  JSON.parse(rc.get(content_type: ‘application/json’))



  response = put(“#{base_path}/keypair”, { cert: cert, key: key })

  response = put(“#{base_path}/install”)

  uuid = response[‘response’][‘uuid’]

  response = get(“#{base_path}/install/#{uuid}”)

  while response[‘response’][‘state’] == ‘pending’

    puts “Job #{uuid} : status #{response[‘response’][‘status’]}”

    sleep 3

    response = get(“#{base_path}/install/#{uuid}”)


  puts “Job #{uuid} : status #{response[‘response’][‘status’]}”

rescue => e

  puts “Error: #{e.message}”


The above Ruby code should not be used in production. It doesn’t test well for errors, it has global variables, it loops in an unchecked way and it’s not verifying the existing SSL certs. But on the positive side, it does demonstrate how easy it can be to upload newly generated certs to a VNS3 instance.

Taking the two separate steps and wrapping them in a script is trivial and having either a Jenkins task or a cron job run the process every month or two should be easy to ensure that the certificates on your VNS3 instances are up-to-date.


In this post we’ve shown you how to create and upload an SSL certificate for your VNS3 instance using Let’s Encrypt and Certbot. We’ve also given a quick overview on how to begin to automate the certificate update process. Hopefully another item on the ever-lengthening IT security to-do list can now be checked off.


By: Nicholas Clements