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 cloneopenssl. - One where we will
installthe cloned version to (we will install it but not for system, just for our usage). - For
git clonewe will use/tmp. - For
installlocation we will use a/opt/openssla (for this you can createtmpfolder somewhere e.g.~/tmp, or you can use/opt/tmpor/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.crtthe 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
sharedlibrary, otherwiservmwill complain. And for that we havesharedoption in line:RUN ./config shared — prefix=$OPENSSL_PREFIX — openssldir=$OPENSSL_PREFIX/ssl - You can do build against a bit higher version of
openssllike1.1.1, in that case just doRUN git clone — branch OpenSSL_1_1_1 https://github.com/openssl/openssl.gitinstead.
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/usrbut 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!