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 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 and here. 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:
- We will need 2 locations
- One where we
git clone
openssl. - One where we will
install
the cloned version to (we will install it but not for system, just for our usage). - For
git clone
we will use/tmp
. - For
install
location we will use a/opt/openssla (for this you can createtmp
folder somewhere e.g.~/tmp
, or you can use/opt/tmp
or/opt
, just don’t use something that the system would use) - 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:
- 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
.
- You have to build/compile openssl as
shared
library, otherwiservm
will complain. And for that we haveshared
option in line:RUN ./config shared — prefix=$OPENSSL_PREFIX — openssldir=$OPENSSL_PREFIX/ssl
- You can do build against a bit higher version of
openssl
like1.1.1
, in that case just doRUN git clone — branch OpenSSL_1_1_1 https://github.com/openssl/openssl.git
instead.
Cheers!
Top comments (2)
Nice post on this! I had encountered a similar issue recently when trying to install Ruby v3.0 on a Mac M3 chipset using rvm. Quite often I have to flip between what openssl version my system is using, I think for legacy versions its requiring v1.1.1 and for more recent versions it uses the native v3.x.x version.
When I encountered this problem it was difficult to find users detailing the explanation online, great to see a post on dev about it like yours!
I know you can use a specific command to specify your openssl version during installation i.e.
rvm install 2.4 --with-openssl-dir=$HOME/.rvm/usr
but if I recall even with this I had to modify my .zshrc file to source similar directories to your post correctly.Nice informative post!
Thx!