Configuring HTTPs on a standalone Ardor installation
Introduction
This tutorial explains how to configure HTTPS on a standalone Ardor installation running on a Linux or macOS system.
It is provided an easy mechanism to configure HTTPS without using a reverse proxy and automation certificates renewal without having to restart the full node.
The steps below have been tested on macOS 10.14.6 and Linux system, Debian derivative like Ubuntu.
The challenges
If you want to configure HTTPS for you node's API and Wallet port you face two challenges:
- The certificate
- The listening port
The certificate proves that you are the domain that you claim to be and allows the browser and server to establish a secure channel for communications.
You probably want a certificate signed by a public CA (Certificate Authority) to avoid nasty security messages from browsers. In the past, that would mean buying one from a well-known company and following some technical steps. Fortunately, we currently have Let's Encrypt, a free, open, and automated certificate authority.
The listening port is where you point your browser to open the wallet, the 27876 in the usual http://localhost:27876. The challenge comes when you want to use the standard HTTPS port (443) so you can have some nice URI like https://ardor.myserver.com without a :port modifier. In order to use a port under 1024 you need to have special privileges. In the macOS and Linux world that means being root or using the authbind utility.
Using a Let's Encrypt cerficate with Ardor
Let's assume that you don't have a web server or any other service listening on port 80 (HTTP). The Let's Encrypt service uses that port to perform a challenge resolution in order to prove that you own a certain domain.
Actually the port 80 is only needed during the issue and renewal of certificates so if you have any other service you could, for example, just shut it down for a few seconds while you perform the operation.
Please follow the official documentation (https://certbot.eff.org) in order to install Certbot. In macOS, it will be needed some other packages such as homebrew (https://brew.sh), Ruby, and cURL.
Node configuration
You need to add a few properties to the nxt.properties file. At least these ones:
nxt.apiSSL=true
nxt.keyStorePath=keystore
nxt.keyStorePassword=PutHereLongPassword
nxt.keyStoreType=PKCS12
Take a look also at these properties: nxt.allowedBotHosts, nxt.apiServerHost, nxt.adminPassword
Certificate's first issuance
For the first generation of the certificate you can use a command like this:
sudo certbot certonly -d DOMAIN --standalone
Where DOMAIN is your domain name. If everything is correct you should have your certificate and private key under the Let's Encrypt directory. Usual locations are /etc/letsencrypt/live/DOMAIN and /usr/local/etc/letsencrypt/live/DOMAIN.
Afterwards you need to export the certificate to a java keystore. In order to do this operation you can use a command like this:
sudo openssl pkcs12 -export -in /etc/letsencrypt/live/DOMAIN/fullchain.pem -inkey /etc/letsencrypt/live/DOMAIN/privkey.pem -out KEYSTORE -name nrs -passout pass:KEYSTORE_PASS
Copy the java keystore to a folder with permissions from the Ardor user and finally configure the nxt.keyStorePath, nxt.keyStorePassword and nxt.keyStoreType=PKCS12 in the nxt.properties file.
Configuring a renewal hook to update the Ardor keystore
The Let's Encrypt certificates are issued with a relatively short expiry date. The recommended approach to renewal is to automate it and the Certbot software provides support for automatic renewal. But the NRS software doesn't use the Let's Encrypt certificate directly as we've seen in previous sections so we need to update the keystore with each renewal.
The standard installation provide a script to be used as a deploy hook for the Certbot software. You just need to configure it once:
sudo certbot certonly -d DOMAIN -n --standalone --deploy-hook "/PATH/TO/NRS_INSTALLATION/pem.to.pkcs12.keystore.certbot.hook.sh" --force-renewal
Replace DOMAIN with the domain name. That will force the renewal, execute the script, and also update the certbot configuration to use the script with every certificate renewal for that domain.
NOTE: The script pem.to.pkcs12.keystore.certbot.hook.sh is included with version 2.2.6 or later but you can check it in the following box:
#!/bin/sh
#######################################################################
## This script takes the pem files from a Let's Encrypt / Certbot
## directory and bundles them together for use by the current NRS
## installation, reading the corresponding properties from the
## nxt.properties file.
##
## It is designed to be run from the --deploy-hook Certbot option,
## meaning that it expects the RENEWED_LINEAGE environment variable
## to point to a directory with the PEM encoded files.
#######################################################################
PROPERTIES_PATH="conf/nxt.properties"
if [ -z $RENEWED_LINEAGE ]; then
echo "RENEWED_LINEAGE environtment variable not found, running from certbot --deploy-hook ?"
exit
fi
OLD_DIR="$(pwd)"
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
cd $SCRIPTPATH
if [ ! -r $PROPERTIES_PATH ]; then
echo "nxt.properties file not found"
exit
fi
KEYSTORE=$(grep "^nxt.keyStorePath=" $PROPERTIES_PATH | cut -d'=' -f2)
if [ -z $KEYSTORE ]; then
echo "You need to define nxt.keyStorePath on nxt.properties"
exit
fi
KEYSTORE_PASS=$(grep "^nxt.keyStorePassword=" $PROPERTIES_PATH | cut -d'=' -f2)
if [ -z $KEYSTORE_PASS ]; then
echo "You need to define nxt.keyStorePassword on nxt.properties"
exit
fi
KEYSTORE_TYPE=$(grep "^nxt.keyStoreType=" $PROPERTIES_PATH | cut -d'=' -f2)
if [ -z $KEYSTORE_TYPE ] || [ $KEYSTORE_TYPE != "PKCS12" ]; then
echo "You need to define the keystore type as PKCS12. Add \"nxt.keyStoreType=PKCS12\" to your nxt.properties file "
exit
fi
openssl pkcs12 -export -in $RENEWED_LINEAGE/fullchain.pem -inkey $RENEWED_LINEAGE/privkey.pem -out $KEYSTORE -name nrs -passout pass:$KEYSTORE_PASS
chmod a+r $KEYSTORE
cd $OLD_DIR
If you had the node running while performing these operations you need to restart it in order to pick up the new certificates. The next renewals will be picked up automatically if you are using Ardor version 2.2.6 or newer.
Automatic renewal of the certificates
Now we need to make sure that we're renewing the certificates at all. Some Certbot versions take care of that automatically so you don't need to do anything else. For example Ubuntu and Debian packages. Others require some one-time manual steps like the FreeBSD or CentOS version. You should check the documentation of Certbot for your specific platform.
For those platforms that require to set up a cron hook to renew the certificate, we suggest checking that the renewal works before adding the cron job using the command sudo certbot renew --dry-run
which does a test run of the renewal without making any changes.
Setting up Ardor to listen to a privileged port
If you want your node to listen on a privileged port, like the standard HTTPS port 443, you need root privileges or an alternative mechanism.
We do not recommend running your node, or any nonsystem software, as root.
Linux system
Here we will describe how to use authbind, a tool available in Ubuntu and other Debian derivates, to allow the Ardor software to listen to port 443 without running it as root.
First, make sure you have authbind installed:
sudo apt install authbind
Then, also as root, you need to create a file to tell authbind that binding to port 443 is allowed.
sudo touch /etc/authbind/byport/443
Authbind determines that a process can bind to that port if it has execute permissions to that file. Let's suppose you are running your node as the local user ardor. You need to execute these commands:
sudo chgrp ardor /etc/authbind/byport/443
sudo chmod g+x /etc/authbind/byport/443
Now authbind will provide a mechanism for any process run by that user to just bind to port 443. In order to use that mechanism you need to run your command inside a authbind execution. You can use the --authbind modifier of run.sh for that purpose.
You specify the HTTPS port in the nxt.properties file:
nxt.apiServerSSLPort=443
MacOS
Here we will describe how to use MacOSX-authbind. It is a tool available in https://github.com/Castaglia/MacOSX-authbind for Mac OSC 10.7 Lion and later versions, to allow the Ardor software to listen to port 443 without running it as root.
First download the software. Then simply do:
$ cd MacOSX-authbind
$ make`
$ sudo make install
Then, also as root, you need to create a file to tell authbind that binding to port 443 is allowed.
sudo touch /etc/authbind/byport/443
Authbind determines that a process can bind to that port if it has execute permissions to that file. Let's suppose you are running your node as the local user ardor. You need to execute these commands:
sudo touch /etc/authbind/byport/443
sudo chown ardor /etc/authbind/byport/443
sudo chmod 755 /etc/authbind/byport/443
You can test the correct installation and configuration of authbind using the following command:
authbind nc -l localhost 443
If it fails, please check the correct installation and configuration of authbind.
Now authbind will provide a mechanism for any process run by that user to just bind to port 443. In order to use that mechanism you need to run your command inside a authbind execution you can use the --authbind modifier of run.sh for that purpose.
Conclusion
We've seen how to, easily, overcome the two main challenges when setting up HTTPS support on a node. Of course there are alternative methods like using a standard certificate issued by a CA which use to have longer valid periods or using the firewall / NAT subsystem to solve the port problem. These instructions try to cover a general setup.
Monitoring certificate expiration and renewals
Using Let's Encrypt is free and quite easy. It's highly automated but any automation can fail. As the certificates are issued with short expiration dates it's important to make sure that the renewals are working correctly before facing a warning page from the browser.
The automated renewal mechanism of the cerbot utility renews automatically each certificate some days before the expiration date. So you can detect when a renewal is having a problem if a certificate expiration date is less than a number of days.
A useful service to monitor externally the renewal of certificates is Let's Monitor. It's free to use for just checking the certificate expiration date and it will send an email when a certificate is about to expire.
Internals about certbot and the certificates
This section dives into a bit more detail about how the certificate management works between certbot and the NRS. You don't need to read it unless you want to understand more details or are trying to troubleshoot problems with the process.
If you have any problem about the certificates you should check the certbot support site (https://certbot.eff.org/help/) and also the community forum (https://community.letsencrypt.org/).
When generating the certificates for your domain (let's call it DOMAIN) correctly you should have your certificate and private key in plain text (PEM) format under /etc/letsencrypt/live/DOMAIN.
If at any moment you need to troubleshoot the certbot execution it usually creates a log file on /var/log/letsencrypt/letsencrypt.log
You can track the invocation of pem.to.pkcs12.keystore.certbot.hook.sh
by looking for "Running deploy-hook command:" in this file. Check the Certbot documentation for your platform for more details.
The NRS software uses Jetty internally as the webserver. Unfortunately Jetty cannot directly use those files so we need to convert and pack them into a single "keystore" file. That's not hard, you can do that with a single OpenSSL command. The problem is that Let's Encrypt certificates expire in 90 days so you need some way to automate the renewal and "repacking" of your new keys.
The Certbot software automatically takes care of renewals and we can even instruct it to call a script every time a certificate gets renewed. So we are going to use a custom script that will convert the new certificates and keys to the proper format and location for the Ardor software to use.
That's the purpose of the pem.to.pkcs12.keystore.certbot.hook.sh
script from the root of the installation directory. And execute it every time the certificate is renewed. In order to instruct certbot to use it with every deployment, we need to do a manual renew with the configured hook.
Once the new keystore is in place the node needs to reload them. Since Ardor version 2.2.6 or newer the software will check for changes on the keystore every day. So that will be enough as certificates are renewed several days in advance. You can force it with a node restart.