Skip to main content

Ruby 3.2.10 with Rails 8.1.2 and Node.js 16 (Amazon Linux 2) AMI Administrator Guide

1. Quick Start Information

Connection Methods:

  • Access the instance via SSH using the ec2-user user. Use sudo to run commands requiring root privileges. To switch to the root user, use sudo su - root.

Install Information:

  • OS: Amazon Linux 2
  • Ruby version: 3.2.10
  • Rails version: 8.1.2
  • Node.js version: 16.20.2 (via nvm)
  • OpenSSL version: 1.1.1 (TLS 1.3 ready)
  • Ruby Install Directory: /usr/local/

Quick Verification Commands:

  • Check Ruby version: ruby -v
  • Check Rails version: rails -v
  • Check Node.js version: node -v
  • Check OpenSSL support: ruby -r openssl -e "puts OpenSSL::OPENSSL_VERSION"

Development Tools Included:

  • Ruby: 3.2.10 compiled from source
  • RubyGems: Gem package manager
  • Bundler: Dependency manager
  • Rails: 8.1.2 web framework
  • Node.js: 16.20.2 (JavaScript runtime)
  • npm: 8.19.4 (Node package manager)
  • nvm: Node Version Manager

Firewall Configuration:

  • Please allow SSH port 22.
  • For production Rails apps, allow port 3000 (development) or 80/443 (production with Nginx/Apache).
  • For security, it is recommended to limit SSH access to trusted IPs only.

2. Overview

Welcome to this Ruby 3.2.10 + Rails 8.1.2 + Node.js 16 AMI. This image is based on Amazon Linux 2 and provides a complete, production-ready environment for building modern Ruby on Rails web applications.

This guide explains how to use this AMI and details its internal configuration.

What is Ruby?

Ruby is a dynamic, object-oriented programming language focused on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write. Ruby is the foundation of the Rails framework and is widely used for web development, automation, and DevOps tools.

What is Rails?

Ruby on Rails (often called Rails) is a server-side web application framework written in Ruby. It follows the Model-View-Controller (MVC) pattern and emphasizes convention over configuration, making it possible to build database-backed web applications rapidly.

What is Node.js?

Node.js is a JavaScript runtime built on Chrome's V8 engine. In Rails applications, Node.js powers the asset pipeline (via Webpacker or esbuild) for compiling modern JavaScript, CSS, and other frontend assets.

Core Features of This AMI:

  • Ruby 3.2.10: Compiled from source with OpenSSL 1.1.1 support
  • OpenSSL 1.1.1: TLS 1.3 ready for secure HTTPS connections
  • Rails 8.1.2: Latest Rails framework with modern features
  • Node.js 16.20.2: LTS version via nvm for frontend asset management
  • Bundler: Gem dependency manager pre-installed
  • System-wide Installation: Ruby accessible to all users

Target Use Cases:

  • Building full-stack web applications with Rails
  • Creating RESTful APIs with Rails API mode
  • Developing e-commerce platforms (Spree, Solidus)
  • Building CMS systems (Refinery CMS, Comfortable Mexican Sofa)
  • Rapid prototyping and MVPs
  • Microservices with Rails

3. First Launch & Verification

Step 1: Connect to Your Instance

  1. Launch your instance in your cloud provider's console (e.g., AWS EC2)
  2. Ensure SSH port 22 is allowed in your security group
  3. Connect via SSH:
    ssh -i your-key.pem ec2-user@YOUR_PUBLIC_IP

Step 2: Verify Ruby Installation

Check Ruby version:

ruby -v

Expected Output:

ruby 3.2.10 (2025-01-07 revision ...) [x86_64-linux]

Check Ruby location:

which ruby

Expected Output:

/usr/local/bin/ruby

Step 3: Verify OpenSSL Support (Critical)

Check OpenSSL version:

ruby -r openssl -e "puts OpenSSL::OPENSSL_VERSION"

Expected Output:

OpenSSL 1.1.1w  11 Sep 2024

Critical: Must show 1.1.1 or higher, NOT 1.0.2.

Verify TLS 1.3 support:

ruby -r openssl -e "puts OpenSSL::SSL::SSLContext.new.min_version = OpenSSL::SSL::TLS1_3"

Expected Output:

772

What This Means:

  • 772 is the protocol code for TLS 1.3
  • This confirms Ruby can handle modern encrypted connections
  • Essential for gems that communicate with HTTPS APIs

Step 4: Verify RubyGems and Bundler

Check Bundler:

bundle -v

Expected Output:

Bundler version 2.5.x

Check gem command:

gem -v

Expected Output:

3.5.x

Step 5: Verify Rails Installation

Check Rails version:

rails -v

Expected Output:

Rails 8.1.2

Step 6: Verify Node.js Installation

Check Node.js version:

node -v

Expected Output:

v16.20.2

Check npm version:

npm -v

Expected Output:

8.19.4

Check nvm:

nvm --version

Expected Output:

0.40.3

Step 7: Create and Run a Test Script

Create a simple Ruby script:

cat > hello.rb << 'EOF'
puts "Hello from Ruby 3.2.10!"
puts "OpenSSL: #{OpenSSL::OPENSSL_VERSION}"
puts "Rails: #{`rails -v`.strip}"
EOF

Run it:

ruby hello.rb

Expected Output:

Hello from Ruby 3.2.10!
OpenSSL: OpenSSL 1.1.1w 11 Sep 2024
Rails: Rails 8.1.2

Clean up:

rm hello.rb

4. Architecture & Detailed Configuration

4.1. Component Locations

ComponentInstallation PathPurpose
Ruby Binary/usr/local/bin/rubyRuby interpreter
Ruby Symlink/usr/bin/rubyPoints to /usr/local/bin/ruby
Gem Binary/usr/local/bin/gemRubyGems package manager
Bundle Binary/usr/local/bin/bundleBundler dependency manager
Rails Binary/usr/local/bin/railsRails command-line tool
System Gems/usr/local/lib/ruby/gems/3.2.0/Globally installed gems
nvm Directory~/.nvm/Node Version Manager
Node.js~/.nvm/versions/node/v16.20.2/Node.js installation
OpenSSL 1.1/usr/OpenSSL 1.1 libraries and headers

4.2. Why OpenSSL 1.1 Matters

The Problem:

Amazon Linux 2 ships with OpenSSL 1.0.2 by default. This version:

  • Does NOT support TLS 1.3
  • Is considered obsolete for modern web security
  • Causes SSL errors with many modern APIs and services

The Solution:

This AMI uses OpenSSL 1.1.1, which provides:

  • TLS 1.3 support (latest encryption standard)
  • Modern cipher suites
  • Better performance and security

How It Was Achieved:

Ruby was compiled with --with-openssl-dir=/usr pointing to the openssl11 package, forcing it to link against OpenSSL 1.1 instead of the system default.

Ruby binaries are linked for system-wide access:

/usr/bin/ruby -> /usr/local/bin/ruby
/usr/bin/gem -> /usr/local/bin/gem
/usr/bin/bundle -> /usr/local/bin/bundle

Why This Matters:

  • Allows sudo ruby to work
  • Makes Ruby accessible from any PATH
  • Standard for system-wide language installations

4.4. Gem Installation Paths

System Gems (installed with sudo gem install):

/usr/local/lib/ruby/gems/3.2.0/gems/

User Gems (installed with gem install without sudo):

~/.gem/ruby/3.2.0/gems/

Best Practice:

  • Use sudo gem install for global tools (rails, bundler)
  • Use bundle install for project dependencies (installs to vendor/bundle or ~/.bundle)

4.5. Node.js via nvm

Why nvm:

  • Allows multiple Node.js versions side-by-side
  • Easy version switching per project
  • User-specific (no sudo required)
  • Standard in Rails/JavaScript development

nvm Directory Structure:

~/.nvm/
├── versions/
│ └── node/
│ └── v16.20.2/
│ ├── bin/ # node, npm
│ └── lib/
├── nvm.sh # nvm script
└── nvm-exec # nvm executor

5. How-To-Create: Building This AMI from Scratch

This section explains exactly how this AMI was created, allowing you to:

  • Understand the configuration
  • Reproduce the setup on other systems
  • Customize the installation

Step 1: Environment Preparation

Update the system:

sudo yum update -y

Remove old OpenSSL development headers:

sudo yum remove -y openssl-devel

Why Remove:

Amazon Linux 2 has both openssl-devel (1.0.2) and openssl11-devel (1.1.1). Removing the old one ensures Ruby compiles against 1.1.1.

Critical: This only removes header files, NOT the system openssl-libs. Your system remains functional.

Step 2: Install Dependencies

Install compilation tools and OpenSSL 1.1:

sudo yum install -y gcc make \
openssl11 openssl11-devel \
readline-devel zlib-devel \
libyaml-devel libffi-devel \
wget tar gzip

Package Breakdown:

  • gcc, make: C compiler and build tools
  • openssl11, openssl11-devel: OpenSSL 1.1 runtime and headers
  • readline-devel: For interactive Ruby shell (irb)
  • zlib-devel: Compression library
  • libyaml-devel: YAML parser (required by Rails)
  • libffi-devel: Foreign Function Interface (for native extensions)
  • wget, tar, gzip: Download and extraction tools

Step 3: Download Ruby Source

Download Ruby 3.2.10:

sudo wget https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.10.tar.gz

Why This Version:

  • Ruby 3.2 is the current stable series
  • 3.2.10 is the latest patch release (security fixes)
  • Fully compatible with Rails 8.x

Extract:

sudo tar -zxvf ruby-3.2.10.tar.gz
cd ruby-3.2.10

Step 4: Configure Ruby Build

Configure with OpenSSL 1.1:

sudo ./configure --prefix=/usr/local --with-openssl-dir=/usr --disable-install-doc

Configuration Options Explained:

  • --prefix=/usr/local: Install to /usr/local/ (standard for locally-compiled software)
  • --with-openssl-dir=/usr: Force Ruby to use OpenSSL 1.1 from /usr/
  • --disable-install-doc: Skip documentation to save space (~50 MB)

What --with-openssl-dir Does:

Without this flag, Ruby might find OpenSSL 1.0.2 first and link against it. This flag explicitly tells Ruby where to find OpenSSL 1.1.

Step 5: Compile Ruby

Compile using all CPU cores:

sudo make -j$(nproc)

Compilation Time:

  • t3.micro (1 vCPU): ~8 minutes
  • t3.small (2 vCPU): ~5 minutes
  • t3.medium (4 vCPU): ~3 minutes

What Gets Built:

  • Ruby interpreter (ruby)
  • Standard library
  • Native C extensions
  • OpenSSL bindings (linked to 1.1.1)

Install to system:

sudo make install

Result: Ruby is installed to /usr/local/bin/ruby

Link Ruby to /usr/bin:

sudo ln -sf /usr/local/bin/ruby /usr/bin/ruby
sudo ln -sf /usr/local/bin/gem /usr/bin/gem
sudo ln -sf /usr/local/bin/bundle /usr/bin/bundle

Why:

  • Makes sudo ruby work
  • Standard location for executables
  • No need to modify PATH

Step 7: Install Bundler

Install Bundler gem manager:

sudo gem install bundler

Update RubyGems:

sudo gem update --system

What is Bundler:

Bundler manages gem dependencies for Ruby projects. It reads Gemfile and installs exact versions, ensuring consistent environments across development, staging, and production.

Step 8: Install Rails

Install Rails framework:

sudo gem install rails

Installation Size: ~50 MB (includes all dependencies)

Verify:

rails -v

Expected: Rails 8.1.2

Step 9: Install Node.js via nvm

Download and install nvm:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash

What This Does:

  1. Downloads nvm installation script
  2. Installs nvm to ~/.nvm/
  3. Adds nvm initialization to ~/.bashrc

Load nvm in current session:

\. "$HOME/.nvm/nvm.sh"

Install Node.js 16:

nvm install 16

Why Node.js 16:

  • LTS (Long-Term Support) version
  • Required by Rails for asset compilation (esbuild, importmaps)
  • Compatible with most Rails frontend tools

Verify:

node -v  # Should show v16.20.2
npm -v # Should show 8.19.4

Step 10: Cleanup (Critical for AMI)

Remove source code and archive:

cd ~
sudo rm -rf ruby-3.2.10
sudo rm -f ruby-3.2.10.tar.gz

Space Saved: ~60 MB

Clean yum cache:

sudo yum clean all

Space Saved: ~100 MB

Total Space Saved: ~160 MB

This cleanup is essential before creating AMI snapshots.


6. Using the Development Environment

6.1. Creating a New Rails Application

Create a new Rails app:

rails new myapp
cd myapp

What Gets Created:

myapp/
├── app/ # Application code (models, views, controllers)
├── bin/ # Executables (rails, bundle, rake)
├── config/ # Configuration files
├── db/ # Database migrations and schema
├── Gemfile # Gem dependencies
├── public/ # Static files
└── test/ # Test files

Start the development server:

bin/rails server

Expected Output:

=> Booting Puma
=> Rails 8.1.2 application starting in development
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Listening on http://127.0.0.1:3000

Access the app:

Stop the server: Press Ctrl+C

6.2. Creating a Rails API

Create an API-only Rails app (no views, no asset pipeline):

rails new myapi --api
cd myapi

Benefits of API mode:

  • Lighter weight (no view layer)
  • Faster startup
  • Perfect for backends serving JSON to React/Vue/mobile apps

6.3. Managing Gem Dependencies

Edit Gemfile to add gems:

# Add a gem
gem 'devise' # Authentication
gem 'pundit' # Authorization
gem 'sidekiq' # Background jobs

Install dependencies:

bundle install

What This Does:

  1. Resolves dependencies
  2. Downloads gems
  3. Creates Gemfile.lock with exact versions

Update all gems:

bundle update

Show outdated gems:

bundle outdated

6.4. Database Setup

Rails supports PostgreSQL, MySQL, SQLite out of the box.

For PostgreSQL:

Edit Gemfile:

gem 'pg'

Run:

bundle install

Edit config/database.yml:

development:
adapter: postgresql
database: myapp_development
username: postgres
password: password
host: localhost

Create database:

bin/rails db:create

Run migrations:

bin/rails db:migrate

6.5. Generating Scaffolds

Generate a complete resource (model, views, controller, migration):

bin/rails generate scaffold Article title:string body:text

Run the migration:

bin/rails db:migrate

Start server and visit:

http://localhost:3000/articles

What This Creates:

  • Model: app/models/article.rb
  • Controller: app/controllers/articles_controller.rb
  • Views: app/views/articles/ (index, show, new, edit)
  • Migration: db/migrate/xxx_create_articles.rb
  • Routes: Added to config/routes.rb

6.6. Running the Rails Console

Start interactive console:

bin/rails console

Example Usage:

# Create a record
article = Article.create(title: "Hello", body: "World")

# Query
Article.all
Article.find(1)
Article.where(title: "Hello")

# Update
article.update(title: "Updated")

# Delete
article.destroy

# Exit
exit

6.7. Running Tests

Run all tests:

bin/rails test

Run specific test:

bin/rails test test/models/article_test.rb

6.8. Asset Compilation

For production, precompile assets:

RAILS_ENV=production bin/rails assets:precompile

This:

  • Compiles CSS/JS
  • Minifies files
  • Generates fingerprinted filenames
  • Places assets in public/assets/

7. Important File Locations

PathPurposeNotes
/usr/local/bin/rubyRuby interpreterCompiled from source
/usr/local/bin/gemRubyGems package managerFor installing gems
/usr/local/bin/bundleBundler dependency managerFor project dependencies
/usr/local/bin/railsRails command-line toolFor generating apps, servers
/usr/local/lib/ruby/gems/3.2.0/System gems directoryGlobally installed gems
/usr/bin/rubyRuby symlinkPoints to /usr/local/bin/ruby
~/.nvm/nvm directoryNode Version Manager
~/.nvm/versions/node/v16.20.2/Node.js installationNode.js 16 LTS
~/.gem/User gemsPer-user gem installations
GemfileProject dependenciesIn each Rails project
Gemfile.lockLocked versionsEnsures consistent installs
vendor/bundle/Bundled gemsProject-specific gem cache

8. Troubleshooting

Problem: SSL errors when installing gems

Cause: Ruby not linked to OpenSSL 1.1, or using old OpenSSL.

Solution:

# Check OpenSSL version Ruby is using
ruby -r openssl -e "puts OpenSSL::OPENSSL_VERSION"

# Should show 1.1.1, NOT 1.0.2

# If showing 1.0.2, Ruby needs recompilation
# Follow Step 4 in "How-To-Create" section

Problem: rails: command not found

Cause: Rails gem not installed or PATH issue.

Solution:

# Install Rails
sudo gem install rails

# Check if rails binary exists
ls -la /usr/local/bin/rails

# Verify PATH
echo $PATH | grep /usr/local/bin

# If missing, add to PATH
export PATH="/usr/local/bin:$PATH"

Problem: node: command not found in Rails app

Cause: nvm not loaded or Node.js not installed.

Solution:

# Load nvm
\. "$HOME/.nvm/nvm.sh"

# Check if Node.js is installed
nvm list

# If not installed
nvm install 16

# Add to .bashrc to auto-load
echo '\. "$HOME/.nvm/nvm.sh"' >> ~/.bashrc

Problem: Bundle install fails with native extension errors

Cause: Missing development libraries.

Solution:

# Install common development libraries
sudo yum install -y gcc make \
libxml2-devel libxslt-devel \
postgresql-devel mysql-devel \
sqlite-devel

# Retry
bundle install

Problem: Rails server won't start on port 3000

Cause: Port already in use.

Solution:

# Check what's using port 3000
sudo lsof -i :3000

# Kill the process
kill -9 <PID>

# Or start Rails on different port
bin/rails server -p 3001

Problem: Gem::FilePermissionError when installing gems

Cause: Trying to install to system gems without sudo.

Solution:

# For system gems, use sudo
sudo gem install gem_name

# Or install to user directory
gem install gem_name --user-install

# Or use Bundler for project dependencies
bundle install

9. Advanced Topics

9.1. Production Deployment with Puma

Configure Puma (Rails default web server) for production.

Create config/puma.rb:

# Puma configuration for production

# Number of workers (processes)
workers ENV.fetch("WEB_CONCURRENCY") { 2 }

# Threads per worker
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
threads threads_count, threads_count

# Port
port ENV.fetch("PORT") { 3000 }

# Environment
environment ENV.fetch("RAILS_ENV") { "production" }

# Preload app for better performance
preload_app!

# Allow puma to be restarted by `rails restart` command
plugin :tmp_restart

Start in production:

RAILS_ENV=production bin/rails server

9.2. Background Jobs with Sidekiq

Add to Gemfile:

gem 'sidekiq'
gem 'redis'

Install:

bundle install

Create a job:

bin/rails generate job SendEmail

Edit app/jobs/send_email_job.rb:

class SendEmailJob < ApplicationJob
queue_as :default

def perform(user_id)
user = User.find(user_id)
UserMailer.welcome_email(user).deliver_now
end
end

Enqueue job:

SendEmailJob.perform_later(user.id)

Start Sidekiq:

bundle exec sidekiq

9.3. Using Rails with Docker

Create Dockerfile:

FROM ruby:3.2.10-slim

RUN apt-get update -qq && apt-get install -y \
build-essential libpq-dev nodejs

WORKDIR /app

COPY Gemfile Gemfile.lock ./
RUN bundle install

COPY . .

EXPOSE 3000

CMD ["bin/rails", "server", "-b", "0.0.0.0"]

Build and run:

docker build -t myapp .
docker run -p 3000:3000 myapp

9.4. Caching with Redis

Add to Gemfile:

gem 'redis'

Configure in config/environments/production.rb:

config.cache_store = :redis_cache_store, { url: ENV['REDIS_URL'] }

Use caching:

Rails.cache.fetch("user_#{user.id}") do
user.expensive_calculation
end

9.5. Monitoring with New Relic

Add to Gemfile:

gem 'newrelic_rpm'

Create config/newrelic.yml:

production:
license_key: <%= ENV['NEW_RELIC_LICENSE_KEY'] %>
app_name: My App

New Relic will automatically monitor:

  • Response times
  • Database queries
  • Error rates
  • Throughput

10. Security Considerations

10.1. Gem Security

Check for vulnerable gems:

# Install bundler-audit
gem install bundler-audit

# Update vulnerability database
bundle audit --update

# Check for vulnerabilities
bundle audit

Keep gems updated:

bundle update --conservative

10.2. Rails Security Best Practices

Enable strong parameters:

# In controllers
def article_params
params.require(:article).permit(:title, :body)
end

Use encrypted credentials:

EDITOR=nano bin/rails credentials:edit

Never commit secrets to git:

Add to .gitignore:

/config/master.key
.env

Enable force_ssl in production:

# config/environments/production.rb
config.force_ssl = true

10.3. Firewall Best Practices

Only expose necessary ports:

# SSH (restrict to your IP)
Source: YOUR_IP/32, Port: 22

# Web application
Source: 0.0.0.0/0, Port: 80 (HTTP) or 443 (HTTPS)

# Do NOT expose:
# - Port 3000 (development server)
# - Port 6379 (Redis)
# - Port 5432 (PostgreSQL)

11. Final Notes

What You've Got

This AMI provides a complete, production-ready Ruby on Rails development environment:

  • ✅ Ruby 3.2.10 compiled from source with OpenSSL 1.1.1
  • ✅ Rails 8.1.2 latest framework
  • ✅ Node.js 16.20.2 via nvm for asset compilation
  • ✅ Bundler for dependency management
  • ✅ TLS 1.3 ready for modern HTTPS
  • ✅ System-wide installation for all users
  1. Learn Ruby Basics:

  2. Learn Rails:

  3. Deploy Your App:

  4. Join the Community:

Performance Expectations

Rails excels at:

  • Rapid Development: Build MVPs in days, not months
  • Convention Over Configuration: Less boilerplate code
  • Database Abstraction: ActiveRecord ORM for clean database code
  • RESTful APIs: Built-in support for JSON APIs
  • Modern Frontend: Hotwire, Turbo, Stimulus integration

Cost Optimization

For development:

  • t3.micro (1 vCPU, 1GB RAM): Learning and small apps
  • t3.small (2 vCPU, 2GB RAM): Medium Rails apps

For production:

  • t3.medium+ (2+ vCPU, 4GB+ RAM): Recommended minimum
  • c5.large+: For high-traffic applications
  • r5.large+: For memory-intensive apps (large datasets)

Rails applications generally use more memory than Go/Node but are very developer-productive.


Happy coding with Ruby on Rails! 💎