B4J Tutorial [Server] Using Let's Encrypt on Ubuntu VPS


Well-Known Member
Licensed User
So I have created a few JRDC2 apps. I put them on a VPS as live demo. It is running on Ubuntu 18.04 64 bit. Today I wanted to make the app more secure by enabling SSL certificate. I have chosen to use Let's Encrypt. There are many tutorials here but I am confused with the steps. Especially for people who are not familiar with Linux path and commands.
The steps explained in http://wiki.eclipse.org/Jetty/Howto/Configure_SSL#Generating_Keys_and_Certificates_with_JDK_keytool (updated link: Generating Key Pairs and Certificates) is confusing and I have read many times tried to understand which parts are required. After spending a few hours, I have finally able to put all the puzzles together.

To summarize what I have learned,
I can enable SSL (or https in the URL) in my app without purchasing an SSL certificate (since my app is for demo/testing purpose and not considered critical). Let's Encrypt is a popular choice. I found it is easy to install on Ubuntu. Once installed, my website is now SSL enabled (served by Apache on port 80).

#1 How to: Install Let's Encrypt on Ubuntu Linux VPS to Create SSL Certificates

Downloading and Installing Let's Encrypt
. Update the server's packages
apt-get update & sudo apt-get upgrade
2. Install the GIT package
apt-get install git
3. Download a clone of Let's Encrypt from the GitHub repository to /opt
git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt
4. Navigate to the new /opt/letsencrypt directory
cd /opt/letsencrypt
Creating an SSL Certificate
. Run Let's Encrypt (api.puterise.com is my domain)*
./letsencrypt-auto certonly --standalone -d api.puterise.com
2. Follow the steps
3. Agree to the Terms of Service
4. If everything worked properly, you should receive a message similar to the following
- If you lose your account credentials, you can recover them through e-mails sent to somebody@example.com.
- Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/api.puterise.com/fullchain.pem. Your cert will expire on 2021-01-31. To obtain a new version of the certificate in the future, simply run Let's Encrypt again.
- Your account credentials have been saved in your Let's Encrypt configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Let's Encrypt, so making regular backups of this folder is ideal.
- If you like Let's Encrypt, please consider supporting our work by
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

Now, to make it work on B4J JRDC2 app:

#2 How to use Letsencrypt certificate & private key with Jetty (xkr47/letsencrypt-jetty.sh)

root@computer:/etc/letsencrypt/live/api.puterise.com# openssl pkcs12 -export -out keystore.pkcs12 -in fullchain.pem -inkey privkey.pem
root@computer:/etc/letsencrypt/live/api.puterise.com# keytool -importkeystore -srckeystore keystore.pkcs12 -srcstoretype PKCS12 -destkeystore keystore.jks
root@computer:/etc/letsencrypt/live/api.puterise.com# rm keystore.pkcs12
Enter and verify the source and destination password.


Now I can use the keystore file in B4J server code.
ssl.SetKeyStorePath("/etc/letsencrypt/live/api.puterise.com", "keystore.jks") 'path to keystore file

The above steps explained how I can enable SSL in hosted VPS server with certificates already generated by Let's Encrypt.
For local development machine, it is easier to follow the steps to generate the keystore file from Generating Key Pairs and Certificates.


ssl.SetKeyStorePath("/etc/letsencrypt/live/api.puterise.com", "keystore.jks") 'path to keystore file
ssl.SetKeyStorePath("C:\SSL", "jetty.keystore") 'path to keystore file
#End If


Well-Known Member
Licensed User
Using self signed certificates (generated by keytool or openssl) in localhost causing my client B4X apps unable to connect using OKHttp so I gave up and just use normal http connection.
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
To avoid the above errors, I only use SSL during production with Let's Encrypt.
    Dim ssl As SslConfiguration
    ssl.SetKeyStorePath("/etc/letsencrypt/live/api.puterise.com", "keystore.jks") 'path to keystore file
    ssl.KeyStorePassword = "123456"
    'ssl.KeyManagerPassword = "654321"
    srvr.SetSslConfiguration(ssl, SslPort)
    'add filter to redirect all traffic from http to https (optional)
    srvr.AddFilter("/*", "HttpsFilter", False)
#End If


Well-Known Member
Licensed User
@aeric have you looked at certbot? https://certbot.eff.org/

I use this as it sends reminders when the cetificate is about to expire.

Steps are pretty simple too;

sudo apt-get install software-properties-common
sudo add-apt-repository universe
sudo apt-get update

sudo apt-get install certbot

certbot certonly --standalone
Follow the prompts, use a real email as it will remind you when the cert is about to expire.

Then to renew just run this;

cerbot renew
The renew command is great as you can run it as often as you want and it will only renew when its time - so for example you can run this on startup of your server.

To convert to a Java keystore I use this script (run from my app directory - note this replaces the entire keystore);

rm jetty.keystore

# convert certificate chain + private key to the PKCS#12 file format
openssl pkcs12 -export -out keystore.pkcs12 -in /etc/letsencrypt/live/yourdomain.com/fullchain.pem -inkey /etc/letsencrypt/live/yourdomain.com/privkey.pem -name jetty -passout pass:keystorepassword

# convert PKCS#12 file into Java keystore format
/opt/jdk/jdk-11.0.2/bin/keytool -importkeystore -srckeystore keystore.pkcs12 -srcstoretype PKCS12 -destkeystore jetty.keystore -storepass keystorepassword -srcstorepass keystorepassword

# don't need the PKCS#12 file anymore
rm keystore.pkcs12