How To Use JRuby to Run a Rails Application on Apache Tomcat 7 and Ubuntu 14.04
Ruby on Rails (RoR) is a very popular framework that enables developers to quickly create web applications that adhere to modern design patterns. Using Rails, with just a few commands, you can build a production-ready vanilla CRUD (Create, Read, Update, Delete) application without having to write any code at all. Apache Phusion Passenger, Unicorn, and Puma are some of the popular servers which are used to run Rails applications.
The performance of Ruby MRI has improved considerably over the years. However, it is still slow compared to languages like Java or C. If you are interested in faster write times, which is necessary for critical, concurrent, distributed, and enterprise-grade applications, you should use JRuby instead, a Java implementation of Ruby.
Some Advantages of JRuby over Ruby MRI
Concurrency — Ruby MRI uses GIL (Global Interpreter Lock), and consequently has limited concurrency. JRuby, on the other hand, is able to use JVM's threads, allowing you to achieve much higher levels of concurrency. This is usually the most important reason why JRuby is chosen over other Rubies.
Thread safety — Most of Ruby's core classes are not thread-safe. Using such classes in multi-threaded applications is error-prone. JRuby is capable of using Java's classes instead, which are designed for parallel processing.
More libraries — When you use JRuby, you have at your disposal not only a repertoire of Ruby gems but also all Java and Scala libraries. This lets you focus more on your application's core functionality.
Ease of deployment — A JRuby on Rails application can be packaged into a single WAR file, which can be trivially deployed to any Java EE server. A lot of them even have browser-based interfaces to manage applications.
What This Tutorial Covers
In this tutorial you will learn to:
- Create a simple CRUD application with Rails (one that uses Ruby MRI)
- Convert our Ruby on Rails application to a JRuby on Rails application
- Generate a WAR file for the application
- Install Apache Tomcat 7
- Deploy the WAR file to the Tomcat server
At the end of the tutorial, you'll have a working JRuby on Rails application deployed.
Deploy a 32-bit Ubuntu 14.04 Droplet. Tomcat and JRuby will run on a 64-bit server, but will likely be slower.
Create a sudo user.
If your Droplet has less than 2 GB of RAM, you should add at least 1 GB of swap space. Refer to the following tutorial for more information: How To Add Swap on Ubuntu 14.04.
Install the latest version of RVM on your machine. Refer to Step One of the following tutorial: How To Install Ruby on Rails on Ubuntu 12.04 LTS (Precise Pangolin) with RVM. You might need to add the key before you can install RVM:
gpg --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3
Follow that tutorial through the rvm requirements command.
Step 1 — Create a Simple CRUD RoR Application
Initialize RVM. This initialization is necessary for every new terminal you open.
Note: If you already have a Rails application that uses Ruby 1.9.3, you can now skip to Step 2.
Create a directory to house all your Rails applications, and enter that directory.
mkdir ~/my_applications cd ~/my_applications
We use Ruby 1.9.3 for this tutorial, because that is the latest version of Ruby that JRuby supports.
rvm install 1.9.3 rvm use 1.9.3
gem install rails -N
Create a new Rails application, called simple.
rails new simple
Enter the application's directory.
Ignoring the comments, your updated file should look like this:
source 'https://rubygems.org' gem 'rails', '4.1.7' gem 'sqlite3' gem 'sass-rails', '~> 4.0.3' gem 'uglifier', '>= 1.3.0' gem 'coffee-rails', '~> 4.0.0' gem 'therubyracer' gem 'jquery-rails' gem 'turbolinks' gem 'jbuilder', '~> 2.0' gem 'sdoc', '~> 0.4.0', group: :doc gem 'spring', group: :development
You'll want to remove the
, platforms: :ruby portion of the commented
therubyracer line, because eventually we'll be using JRuby rather than Ruby.
Install all the gems listed in the Gemfile.
Add a few pages to the application using Rails' scaffolding feature.
rails g scaffold Employee name:string age:integer address:text
rails g scaffold command generates a few migrations. Apply them:
Change the root of the application to show the list of all employees. Use nano to edit
~/my_applications/simple/config/routes.rb and change its contents to what's shown below, minus the comments:
Rails.application.routes.draw do resources :employees root 'employees#index' end
Your Rails application that uses Ruby MRI is now ready. Run it on the development server by typing in:
This will take a minute or two to start up.
You can visit the application in your browser by visiting http://<server-IP>:3000. Create a couple of records to make sure everything is working as expected.
Return to your console, and stop the server by pressing Ctrl+C.
Step 2 — Install Java 8
In order to install and use JRuby, a JDK is required. Oracle JDK 8 can be installed using apt-get after adding the
Add the repository by typing in the following:
sudo add-apt-repository ppa:webupd8team/java
Press Enter to accept the new repository.
Update apt-get's package index files.
sudo apt-get update
Install Oracle JDK 8.
sudo apt-get install oracle-java8-installer
Note: You will be prompted to accept a license agreement before the actual installation begins.
Select <Ok> and press Enter, then select <Yes> and press Enter.
After the installation is complete, run the command:
You should be able to see the following output, which means Java was installed correctly:
java version "1.8.0_25" Java(TM) SE Runtime Environment (build 1.8.0_25-b17) Java HotSpot(TM) Client VM (build 25.25-b02, mixed mode)
Step 3 — Install JRuby and JRuby on Rails
Use RVM to install and use JRuby.
rvm install jruby rvm use jruby
The latest version of JRuby (184.108.40.206 as of November 2014) is now ready to be used. Check the version:
This shows you your server is using Oracle JDK 8. You should see output similar to this:
jruby 220.127.116.11 (1.9.3p392) 2014-10-28 4e93f31 on Java HotSpot(TM) Client VM 1.8.0_25-b17 +jit [linux-i386]
Install JRuby on Rails.
gem install rails -N
JRuby on Rails is now installed.
Step 4 — Configure the Application to Use JRuby
While a lot of Ruby MRI gems are supported by JRuby seamlessly, some gems that have native code aren't. Most gems that are interfaces to databases fall into this category. Our application currently uses the sqlite3 gem, which is not supported by JRuby. activerecord-jdbcsqlite3-adapter should be used instead.
Use nano to edit
~/my_applications/simple/Gemfile to make this change.
Your file should look like this after updating the two lines, minus the comments:
source 'https://rubygems.org' gem 'rails', '4.1.7' gem 'activerecord-jdbcsqlite3-adapter' gem 'sass-rails', '~> 4.0.3' gem 'uglifier', '>= 1.3.0' gem 'coffee-rails', '~> 4.0.0' gem 'therubyrhino' gem 'jquery-rails' gem 'turbolinks' gem 'jbuilder', '~> 2.0' gem 'sdoc', '~> 0.4.0', group: :doc gem 'spring', group: :development
If you didn't before, now you need to remove the
platform setting from the therubyrhino line.
Some of our gems require native extensions. Type in the following to allow JRuby to support C extensions.
echo "cext.enabled=true" >> ~/.jrubyrc
You can now install the newly-added gems.
If you are not using SQLite3 as a database, you might need one of these gems:
- For Derby: activerecord-jdbcderby-adapter
- For MySQL: activerecord-jdbcmysql-adapter
- For Postgres: activerecord-jdbcpostgresql-adapter
Step 5 — Update Java's Policy Files
Using a browser, download the JCE Unlimited Strength Jurisdiction policy files. You will have to accept Oracle's License Agreement first.
(You can't wget the files because you have to accept the agreement.)
On your local computer, upload the file to your server using scp:
scp Downloads/jce_policy-8.zip user@server-ip:~
On your server, install the unzip utility:
sudo apt-get install unzip
Unzip the file in a directory in /tmp.
cd /tmp unzip ~/jce_policy-8.zip
Copy the policy files to the JRE's lib/security directory.
cd /tmp/UnlimitedJCEPolicyJDK8 sudo cp *.jar /usr/lib/jvm/java-8-oracle/jre/lib/security/
Go back to your application's directory.
Execute the following command to speed up the JVM startup. This is necessary because virtual server environments tend to generate very little randomness on their own.
At this point, our Rails application is fully configured to use JRuby. Start the development server:
This server might take several seconds to start. Wait till you see the following output before proceeding:
=> Booting WEBrick => Rails 4.1.7 application starting in development on http://0.0.0.0:3000 => Run `rails server -h` for more startup options => Notice: server is listening on all interfaces (0.0.0.0). Consider using 127.0.0.1 (--binding option) => Ctrl-C to shutdown server [2014-11-06 04:38:15] INFO WEBrick 1.3.1 [2014-11-06 04:38:15] INFO ruby 1.9.3 (2014-09-25) [java] [2014-11-06 04:38:15] INFO WEBrick::HTTPServer#start: pid=2620 port=3000
Use a browser to visit http://<server-ip>:3000 and test your application. Except for the fact that it is currently running on the JVM instead of using Ruby MRI, you should find nothing different about the application.
Return to the terminal and press Ctrl+C to stop the server.
Step 6 — Package the Application as a Deployable WAR File
To run the JRuby on Rails application on a servlet container like Tomcat, it should first be packaged into a WAR (Web application ARchive) file. This can be done using the warbler gem.
gem install warbler
The SQLite database that our application uses is currently present in the application's directory. When the WAR file is generated, the database in its current state will be placed inside the WAR file. We do not want this, because any changes that are made to the database after deployment will be overwritten if the application is redeployed.
Therefore, the SQLite database files should be moved to a location outside the application's directory.
Create a new directory for the databases:
mkdir -p ~/databases/simple
In this tutorial, we are only concerned about the development database. Therefore, move the development database file to the newly-created directory:
mv ~/my_applications/simple/db/development.sqlite3 ~/databases/simple
Edit the database.yml file using nano.
Update the path of the development database. You can also remove the details for other environments, because you won't be needing them for this tutorial. After the changes, your file should look like this:
default: &default adapter: sqlite3 pool: 5 timeout: 5000 development: <<: *default database: ~/databases/simple/development.sqlite3
Warbler also needs to know the Rails environment of the WAR. In this tutorial, we stick to the development environment. This is specified using a
Use nano to create a new file named warble.rb
Add the following to the file:
Warbler::Config.new do |config| config.webxml.rails.env = 'development' end
Our application is now ready to be packaged into a WAR file. Run the following command to generate the file:
warble executable war
This will take a few moments.
Successful output should look like:
Downloading winstone-0.9.10-jenkins-43.jar rm -f simple.war Creating simple.war
At this point, there will be a file named simple.war in your application's directory. Adding the argument executable to the command generates a WAR file that has a tiny embedded server (called Winstone) in it. This file can be used indepedently (without any external server) as follows:
java -jar simple.war
This is a good way to check for any problems with your WAR file. You can now use a browser to visit http://<server-ip>:8080. After a few minutes, you should be able see your application working correctly. All the entries you made in the database application earlier should be visible here.
You should wait until you see output similar to the following, to let you know that the server has started:
Nov 13, 2014 12:24:37 PM winstone.Logger logInternal INFO: Started GET "/assets/application.js?body=1" for 18.104.22.168 at 2014-11-13 12:24:37 -0500
Return to the terminal, and press Ctrl+C to stop the embedded server.
Now that you have confirmed that the application is working as a WAR, generate a new WAR for Tomcat using the following command:
It will replace the old executable WAR with a new WAR file that doesn't have any embedded server in it.
Step 7 — Install and Start Tomcat
Download the latest version of Tomcat.
cd ~ wget http://mirror.cc.columbia.edu/pub/software/apache/tomcat/tomcat-7/v7.0.56/bin/apache-tomcat-7.0.56.tar.gz
Create a new directory for Tomcat and enter that directory.
mkdir ~/Tomcat cd ~/Tomcat
Extract the archive:
tar -xvzf ~/apache-tomcat-7.0.56.tar.gz
Set the maximum heap size available to Tomcat to 512m to avoid
java.lang.OutOfMemoryError. This export has to be done every time you start the Tomcat server.
As before, set the randomness generation:
This server too takes several seconds to start. To monitor its logs, type in:
tail -f ~/Tomcat/apache-tomcat-7.0.56/logs/catalina.out
When the server is ready, you will see log messages like these:
Nov 10, 2014 4:12:32 AM org.apache.catalina.startup.HostConfig deployDirectory INFO: Deployment of web application directory ~/Tomcat/apache-tomcat-7.0.56/webapps/manager has finished in 210 ms Nov 10, 2014 4:12:32 AM org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler ["http-bio-8080"] Nov 10, 2014 4:12:32 AM org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler ["ajp-bio-8009"] Nov 10, 2014 4:12:32 AM org.apache.catalina.startup.Catalina start INFO: Server startup in 3390 ms
Press Ctrl+C to end the tail command.
Tomcat is now installed and running. You can use a browser to visit http://<server-ip>:8080. You should be able to see Tomcat's welcome page.
Step 8 — Deploy the Application to Tomcat
To deploy a WAR to Tomcat, all you have to do is copy it to Tomcat's webapps folder.
cp ~/my_applications/simple/simple.war ~/Tomcat/apache-tomcat-7.0.56/webapps
It might take a minute or so for your application to be automatically deployed. While you are waiting, you can monitor the contents of Tomcat's log file using:
tail -f ~/Tomcat/apache-tomcat-7.0.56/logs/catalina.out
When your application is ready to be used, you will see log messages like these:
INFO: Deploying web application archive ~/Tomcat/apache-tomcat-7.0.56/webapps/simple.war Oct 30, 2014 4:42:35 AM org.apache.catalina.startup.HostConfig deployWAR INFO: Deployment of web application archive ~/Tomcat/apache-tomcat-7.0.56/webapps/simple.war has finished in 47,131 ms
Press Ctrl+C to end the
You can now use a browser to visit http://<server-ip>:8080/simple/ and see your JRuby on Rails application running on Tomcat.
Restarting Your Session
If you disconnect from your SSH session at any time, you should run the following three commands:
cd ~/my_applications/simple . ~/.rvm/scripts/rvm rvm use jruby
And if you need to restart Tomcat, run the previous three commands, and make sure you set the two environment variables before starting the server:
export CATALINA_OPTS="-Xmx512m" export JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom" ~/Tomcat/apache-tomcat-7.0.56/bin/catalina.sh start
Thus, a Ruby on Rails application can be converted into a JRuby on Rails application with just a few configuration changes. JRuby on Rails applications can run on almost all servlet containers. In this tutorial, you have already seen how to run one on Apache Tomcat and Winstone.