Back-end Engineering Articles

I write and talk about backend stuff like Ruby, Ruby On Rails, Databases, Testing, Architecture / Infrastructure / System Design, Cloud, DevOps, Backgroud Jobs, and more...



Ruby Installation in Ubuntu Using RVM

Previously we've been talking about the Differences Between RVM, Rbenv, and RubyInstaller, and also I wrote a post about Creating a Linux Virtual Machine in AWS. We'll have to use these entries as the necessary context for this post to install Ruby on a Linux environment using RVM. So, I'll assume on this post that you have:

  • * A Linux-based local machine (a virtual or physical one), where you can install Ruby via RVM
  • * You have root access (admin access) to that machine, and you know how to use the Console or Terminal
  • * You know the differences between RVM, Rbenv, and RubyInstaller, so you know about what we're talking about here

Step #1 - Access to the Linux Machine

Because we're using a virtual environment for this post, and we're giving continuity to this post: Creating a Linux Virtual Machine in AWS, we have to first access this machine using our terminal and SSH:

$ ssh -p 22 -i ~/.ssh/ubuntu-webserver-rails.pem [email protected]  

Note: here is where we finished in the post mentioned above

Step #2- Update Linux packages and build the environment

This step helps us to update Linux and create the environment.

$ sudo apt-get update

apt-get update command downloads the package lists from the repositories and "updates" them to get information on packages' newest versions and dependencies. It will do this for all repositories and PPAs. Learn more about this here

$ sudo apt-get install -y curl gnupg build-essential

The build-essentials packages are meta-packages necessary for compiling software. They include the GNU debugger, g++/GNU compiler collection, and some more tools and libraries required to compile a program. For example, if you need to work on a C/C++ compiler, you must install essential meta-packages on your system before starting the C compiler installation. When installing the build-essential packages, some other packages such as G++, dpkg-dev, GCC and make, etc., are also installed on your system.

Step #3- Install GPG Keys

As a next step, install GPG keys used to verify the installation package:

$ sudo gpg --keyserver --recv-key 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB

GPG is the Gnu Privacy Guard, and it is an implementation of OpenPGP (Open Pretty Good Privacy). It is an encryption technique initially developed for use in e-mail exchanges. However, it is now used in several applications, such as code signing for Linux code repositories and source code repositories like GitHub. 

OpenPGP is a hybrid of the two-key cryptography approach where the message to be exchanged (called plaintext) is first compressed, and then a session key is created as a one-time use secret key. The compressed plaintext is then encrypted with the session key. The session key is then encrypted with the destination's public key and bundled with the encrypted message (called ciphertext). The destination can decrypt the session key with their private key then decompress it to recover the original plaintext.

There are several different ways to create a GPG key. The easiest is with the "gpg" or "gpg2" commands available on many major operating systems. Many commercial encryption programs also include a way to generate a GPG key. You can then store the public version on a public key server so folks can start sending you encrypted files/message traffic. Only you will decrypt it because only you have the associated private key.

Step #4- Install RVM

Curl is used for transferring data using various network protocols. The name stands for "Client URL." Using this tool, we can access the RVM webpage to get the latest and most stable version of RVM.

$ curl -sSL | sudo bash -s stable

Then we can add the current/root user to a group with the command.

$ sudo usermod -a -G rvm `whoami`

whoami It is a concatenation of the words "Who am I?" and prints the effective username of the current user when invoked. More info here:

$ if sudo grep -q secure_path /etc/sudoers; then sudo sh -c "echo export rvmsudo_secure_path=1 >> /etc/profile.d/" && echo Environment variable installed; fi

This last command seems a little bit more cryptic than the other ones, so I'll try to explain it: In Linux and other Unix-like operating systems, only the root user can run all commands and perform certain critical operations on the system such as install and update, remove packages, create users and groups, modify important system configuration files and so on.

However, a system administrator who assumes the role of the root user can permit other normal system users with the help of the sudo command and a few configurations to run some commands and carry out many vital system operations, including the ones mentioned above.

Alternatively, the system administrator can share the root user password (which is not recommended) so that routine system users can access the root user account via the su command.

sudo allows a permitted user to execute a command as root (or another user), as specified by the security policy:

  • * It reads and parses /etc/sudoers, looks up the invoking user and its permissions,
  • * then prompts the invoking user for a password (usually the user's password, but it can as well be the target * user's password. Or it can be skipped with NOPASSWD tag),
  • * after that, sudo creates a child process in which it calls setuid() to switch to the target user
  • * next, it executes a shell or the command given as arguments in the child process above.

Below are ten /etc/sudoers file configurations to modify the behavior of the sudo command using Defaults entries.

$ sudo cat /etc/sudoers
# This file MUST be edited with the 'visudo' command as root.
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
# See the man page for details on how to write a sudoers file.
Defaults env_reset
Defaults mail_badpass
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"

# Host alias specification

# User alias specification

# Cmnd alias specification

# User privilege specification

# Members of the admin group may gain root privileges
%admin ALL=(ALL) ALL

# Allow members of group sudo to execute any command

# See sudoers(5) for more information on "#include" directives:

#includedir /etc/sudoers.d

We can now see that we have a secure path to execute RVM. It's mandatory now to exit the system, and with that, we can have the environment ready to install Ruby.

$ exit

And then, we enter again to the virtual machine.

$ ssh -p 22 -i ~/.ssh/ubuntu-webserver-rails.pem [email protected]  

Step #5- Install Ruby

Now we can use the command rvm

$ rvm install ruby-2.6.8

You can replace the version number for whatever you want or need. After a while, we can check the installation of ruby with the following commands.

$ rvm list
$ ruby -v
$ irb

The "rvm list" command will list all the ruby versions on the machine. Now we've just version 2.6.8. Finally, the instruction given in the terminal by the command irb will enter you to the Interactive Ruby Console. In a later post, we'll talk about IRB in detail: Interactive Ruby Console or IRB.

Let's install the other 2 versions of Ruby to see the real advantages and behavior of a tool like RVM. Because so far, we've just installed one version of Ruby, but we mentioned that you'll be dealing with more than one version of Ruby in your career as a Ruby developer, that's for sure.

Step #6- Install other Ruby Versions and Switch between those versions

Let's install the other 2 Ruby versions on the same machine.

$ rvm install ruby-2.7.0
$ rvm install ruby-3.0.3

As you can see, we've installed the other 2 versions of ruby 2.7.0 and 3.0.3. So the question now is how to deal with these versions according to the project you're working on?

Let's execute a couple of other commands.

$ rvm list
 * ruby-2.6.8 [ x86_64 ]
   ruby-2.7.0 [ x86_64 ]
=> ruby-3.0.3 [ x86_64 ]

# => - current
# =* - current && default
#  * - default

When we execute the rvm list, we can see at the final of the output these symbols:

# => - current
# =* - current && default
#  * - default

In our current state, we have the default ruby version in * ruby-2.6.8 [ x86_64 ] (the first that we've been installed) and the current version in => ruby-3.0.3 [ x86_64 ] (the last we've been seated)

Now, what happens if we run

$ ruby -v

The output will be something like this: 

ruby 3.0.3p157 (2021-11-24 revision 3fb7d2cadc) [x86_64-linux]

That means that any project we create now will be done with the current version (3.0.3). The default version (2.6.8) is loaded when we restart the machine again. Let's say now that we want to create a project with the latest version we have in the machine, and at the same time, we want this version as the default version. So we have to do this:

$ rvm --default use ruby-3.0.3
Using /usr/local/rvm/gems/ruby-3.0.3

Now let's recheck the list.

$ rvm list
   ruby-2.6.8 [ x86_64 ]
   ruby-2.7.0 [ x86_64 ]
=* ruby-3.0.3 [ x86_64 ]

# => - current
# =* - current && default
#  * - default

Do you see something different? Yes, we have now =* ruby-3.0.3 [ x86_64 ] as current && default

As you can see, it is relatively easy to switch between Ruby versions; you just have to take care of the current and the default version.

Step #7- Other RVM commands

Type following commands to change just the current version (not the default version).

$ rvm use 2.7.0


$ rvm list known
$ rvm version
$ rvm current
$ rvm list rails

I encourage you to explore these latest commands and answer what they are doing? 

I hope you enjoyed this post and learned a lot... next time, we'll see how to install Ruby in Windows.

Thanks for reading
Daniel Morales