RVM Ruby 2.6.0 — built with custom openssl version on Ubuntu 22.04
Tags: ruby, rails, openssl, sslcertificate
Published: 2024-04-26 12:11:45

Setup: Ubuntu 22.04, rvm, RoR (4.2.X), Ruby 2.1.7

Recently I had a task to update Ruby from `2.1.7` to `2.6.0` while keeping the RoR version to `4.2.X`.

After standard `rvm install 2.6.0` and `bundle install` command, I had to bump Rails to `4.2.8` due some incompatibility with gems, and then `bundle install` yielded some [errors](https://stackoverflow.com/questions/49674564/package-configuration-for-libxml2-is-not-found) for gems, which I had to resolve by installing `sudo apt-get install libxml12-dev libcurl14-openssl-dev` packages, which coincidently removed `libssl1`, and the build passed.

But when I ran the RoR app, I got SSL certification issue from the **3rd party service**, which was working fine with previous versions of Ruby and Rails: `SSL_connect returned=1 errno=0 state=error: certificate verify failed (unable to get local issuer certificate)`

So I removed `Ruby 2.6.0` and tried to build from scratch, and got issue during ruby install process, apparently I was missing `openssl` library files. `Ruby 2.6.0` was not compatible with the system `openssl` libs, which was strange since the first time it passed.

It turns out that `libssl1` , which was removed was crucial, and the `2.6.0` can’t be built with the new libs which were installed via `apt-get install` command, but I needed those libs to do `bundle install`. So it was closed loop.

###Solution #1 (which didn’t work)
After digging the web, the most common solution was to do following:
```
rvm pkg install openssl
rvm install 2.6.0 --with-openssl-dir=/usr/local/rvm/usr
```
And that passed, Ruby was built, but the problem with the SSL certificate when Rails up was started **was still present**.

The issue was that version of `openssl` that comes with `rvm` is `1.0.1i` and the `openssl` in the `libssl1` is `1.0.2n` , which can be seen [here](https://launchpad.net/ubuntu/bionic/+package/libssl1.0-dev) and [here](https://launchpad.net/ubuntu/+source/openssl1.0/1.0.2n-1ubuntu5.13). So there was some incompatibility with openssl version and the SSL certificate. By the way, SSL certificate was issued by **Let’s Encrypt**, so it wasn’t some custom certificate.

###Solution #2 (which worked)
I had to download `1.0.2n` openssl from Github and build it, install it and then rebuilt Ruby against it.

**Note here I was using Docker, but this can be done outside of the Docker of course.**

Here are the steps for building Ruby via `rvm` against custom version of openssl:

1. We will need 2 locations
2. One where we `git clone` openssl.
3. One where we will `install` the cloned version to (we will 
   install it but not for system, just for our usage).
4. For `git clone` we will use `/tmp`.
5. For `install` location we will use a/opt/openssla (for 
this you can create `tmp` folder somewhere e.g. `~/tmp`, or you can use `/opt/tmp` or `/opt`, just don’t use something that the system would use)
6. Run/Add following commands in Dockerfile:
```
ENV OPENSSL_PREFIX=/opt/openssl
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt

WORKDIR /tmp
RUN git clone --branch OpenSSL_1_0_2n https://github.com/openssl/openssl.git
RUN cd openssl
RUN ./config shared --prefix=$OPENSSL_PREFIX --openssldir=$OPENSSL_PREFIX/ssl
RUN make
RUN make install

RUN rvm install 2.6.0 -C --with-openssl-dir=$OPENSSL_PREFIX
ENV PATH /usr/local/rvm/bin:$PATH
RUN rvm --default use ruby-2.6.0
ENV PATH /usr/local/rvm/bin:/usr/local/rvm/rubies/ruby-2.6.0/bin:$PATH
ENV GEM_HOME /usr/local/rvm/rubies/ruby-2.6.0/lib/ruby/gems/2.6.0
```
And that’s it. If that was successful you have Ruby complied against custom `openssl` library.

### Important notes:
1. If you omit `ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt` the build process will not fail, but when you do bundle install it will give you:
```
Fetching source index from https://rubygems.org/
Could not verify the SSL certificate for
https://rubygems.org/quick/Marshal.4.8/nokogiri-1.13.10-x86_64-linux.gemspec.rz.
There is a chance you are experiencing a man-in-the-middle attack, but most
likely your system doesn't have the CA certificates needed for verification. For
information about OpenSSL certificates, see http://bit.ly/ruby-ssl. To connect
without using SSL, edit your Gemfile sources and change 'https' to 'http'
```
And you would try to fix this by doing `gem update — system` or whatever, but the problem is that it needs path to certs.

So don’t forget to add `ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt`.
2. You have to build/compile openssl as `shared` library, otherwise `rvm` will complain. And for that we have `shared` option in line: `RUN ./config shared — prefix=$OPENSSL_PREFIX — openssldir=$OPENSSL_PREFIX/ssl`
3. You can do build against a bit higher version of `openssl` like `1.1.1` , in that case just do `RUN git clone — branch OpenSSL_1_1_1 https://github.com/openssl/openssl.git` instead.

Cheers!