-
-
Notifications
You must be signed in to change notification settings - Fork 1
HOWTO devops rvm_openssl_issue
Any projects that adopts Ruby 3.1+ shouldn't face any issues with OpenSSL 3+ as it's now supported by Ruby itself.
Issues may arise when using Ruby 3.0 or older versions with RVM on Ubuntu 22+ due to the included OpenSSL 3.
When attempting to compile Ruby 3 with RVM on Ubuntu 22+, you might encounter issues due to the included OpenSSL version.
Here are some options for addressing the problem:
-
Downgrade OpenSSL and libssl-dev: downgrading the OpenSSL and libssl-dev packages can resolve the compilation issue. Use the following commands to downgrade:
sudo apt install libssl-dev=1.1.1l-1ubuntu1.4 openssl=1.1.1l-1ubuntu1.4
-
Install OpenSSL with RVM: You can install OpenSSL using RVM's package manager and then specify the OpenSSL directory during the Ruby installation. Use these commands:
rvm pkg install openssl rvm install ruby-3.0.0 --with-openssl-dir=$HOME/.rvm/usr
-
Reinstall RVM: If the above steps do not work, you might need to reinstall RVM. First, remove RVM and then reinstall it:
rm -rf ~/.rvm curl -L https://get.rvm.io | bash -s stable
-
Check RVM Version: Ensure you are using the latest version of RVM. Update RVM to the latest version with:
rvm get master
Note that there are some gems, specifically most DB drivers, that may throw a seg-fault when trying to access the DB due to the OpenSSL version mismatch.
Typical case: build the application bundle may succeed, but the application will crash as soon as it's trying to access the DB. (See more below.)
The content of this page is merely a developer workstation-oriented solution and differs from what may be needed to actually deploy the application.
But whenever the deploy is done using scripts that rely on rvm
and the target server is running on newer Ubuntu machines, changing the Ruby version manager needs some housekeeping.
Keep in mind that rvm
can't coexist easily with rbenv
or any other version manager, especially when installed at system level.
So, the best course of action is to remove rvm
and update the deploy scripts to use the chosen version manager instead. (Unless deploying to a legacy server that still uses rvm
or using other means like Docker or any other VMs.)
Remove rvm first with rvm implode
(when installed at user level) and update all deploy scripts to the alternative capistrano+rbenv ecosystem.
Update gem groups:
group :development do
gem 'capistrano', '~> 3.10' # or whatever
gem 'capistrano-rails', '~> 1.3'
gem 'capistrano-rbenv', '~> 2.1'
end
Edit the capfile
to include the dependencies:
require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
Possible deploy.rb
updates:
set :rbenv_type, :user
set :rbenv_ruby, '<2.x.x>' # the specific version you want to use
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
set :rbenv_map_bins, %w{rake gem bundle ruby rails}
set :rbenv_roles, :all
Any very-old legacy Ruby (e.g., any v2.x.x) can still be installed on newer Ubuntu versions even if they ship with a newer OpenSSL 3+, using rvm
as done for Ruby 3.0:
$ rvm pkg install openssl
$ rvm install ruby-2.7.4 --with-openssl-dir=$HOME/.rvm/usr
(REMINDER: NEVER do a system-wide install for rvm using the apt package and rely exclusively on user-level install with curl
so that rvm implode
may actually clean the setup in case issues arise.)
Unfortunately, any additional gem that relies on OpenSSL, as stated above, will either HALT the binstub compilation during bundle install
due to a library mismatch, or due to a misconfiguration (i.e.: legacy ruby w/ custom openssl v1 support VS system's openssl v3+) or, possibly, will complete the bundle anyway but throw a seg-fault as soon as the DB gets accessed using the compiled driver binaries.
Best alternatives for RVM are its "low-level" counterparts:
asdf
is slightly slower than rbenv
but, similarly to mise
, allows to isolate even JS & python through plugins and, allegedly, has a better install experience than rbenv
.
mise
is a sort of wrapper around asdf
and it seems to be faster.
In any case, choosing rbenv
here for reasons of personal experience.
References:
- https://github.com/rbenv/rbenv
- https://github.com/rbenv/rbenv#how-rbenv-hooks-into-your-shell
- https://github.com/rbenv/ruby-build#readme
- https://github.com/rbenv/ruby-build/wiki#suggested-build-environment
Install the latest rbenv
with its ruby-build
plugin:
$ git clone https://github.com/rbenv/rbenv.git ~/.rbenv
$ ~/.rbenv/bin/rbenv init
$ git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
Do plugin upgrades with git -C "$(rbenv root)"/plugins/ruby-build pull
and git -C ~/.rbenv pull
when needed.
On a typical system, these are the required build env libs dependencies:
$ sudo apt-get install autoconf patch build-essential rustc libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libgmp-dev libncurses5-dev libffi-dev libgdbm6 libgdbm-dev libdb-dev uuid-dev
Additional apt dependencies for building the binstubs:
(do a sudo apt install
for each additional library)
- Postgres/pg =>
postgres
,libpq-dev
- any globalization or Unicode libraries, like charlock-holmes =>
libicu-dev
- rmagick =>
libmagickcore-dev
- any JS VM engine, like execjs =>
nodejs
- Redis or resque =>
redis
- nokogiri =>
libxml2-dev
,libxslt1-dev
- mongo =>
mongodb
In any case, if the bundle halts during the binstub compilation, take note of the names of any missing libraries reported in the errors and add them (the -dev
version with the headers) to the required bindings of the new setup.
(This is true for any version manager, including the usual, RVM.)
References:
Running ruby-build
without any additional parameters will also download & install into a temporary folder the required version of openssl (1.1.1) needed by the ruby compilation (but this temporary install won't be reused during the bundle compilation later on).
This won't prevent possible errors during the bundle phase raised by drivers relying on a specific openssl version and, even less, won't prevent the application from throwing seg-faults later on.
The best approach is to use a "permanent" local build of OpenSSL, reused every time there's a new dependency binding for the gem bundle.
Do a local build for OpenSSL under ~/.openssl/openssl-1.1.1w with:
$ wget https://www.openssl.org/source/openssl-1.1.1w.tar.gz
$ tar zxvf openssl-1.1.1w.tar.gz
$ export OPENSSL=$HOME/.openssl/openssl-1.1.1w
$ cd openssl-1.1.1w
$ ./config --prefix=$OPENSSL --openssldir=$OPENSSL
$ make
$ make test
$ make install
As this doesn’t include any certificates, symlink the main (system-wide) OpenSSL certs folder into this version like so:
rm -rf $OPENSSL/certs
ln -s /etc/ssl/certs $OPENSSL/certs
Install Ruby with: (remember that $OPENSSL must be always set before this)
# Ruby 3.0
RUBY_CONFIGURE_OPTS=--with-openssl-dir=$OPENSSL rbenv install 3.0.7
# Ruby 2.7
RUBY_CONFIGURE_OPTS=--with-openssl-dir=$OPENSSL rbenv install 2.7.x
# Ruby 2.6
RUBY_CONFIGURE_OPTS=--with-openssl-dir=$OPENSSL rbenv install 2.6.10
# Ruby 2.5
RUBY_CONFIGURE_OPTS=--with-openssl-dir=$OPENSSL rbenv install 2.5.9
Set a Ruby version to finish installation and start using Ruby:
$ rbenv global 2.7.x # set the default Ruby version for this machine
# or:
$ cd <project_root>
$ rbenv local 2.7.x # set the Ruby version for this directory
# Verify versions:
$ cd <project_root>
$ ruby -v
# Check that the system's openssl is still v3:
$ openssl version
Check the location where gems are going to be installed with gem env:
$ gem env home
# => ~/.rbenv/versions/<version>/lib/ruby/gems/...
Proceed to install gems as you normally would (for 2.7.x):
$ gem install bundler -v 2.4.22
$ bundle install
Final reminders:
Note that a specific version of Bundler is needed for very-old Ruby versions like the 2.7.x.
In case rails -T
doesn't work yet, do a rbenv rehash
when changing to project folder.
Never ever use sudo
to install gems.