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-useruser. Usesudoto run commands requiring root privileges. To switch to the root user, usesudo 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
- Launch your instance in your cloud provider's console (e.g., AWS EC2)
- Ensure SSH port 22 is allowed in your security group
- 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:
772is 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
| Component | Installation Path | Purpose |
|---|---|---|
| Ruby Binary | /usr/local/bin/ruby | Ruby interpreter |
| Ruby Symlink | /usr/bin/ruby | Points to /usr/local/bin/ruby |
| Gem Binary | /usr/local/bin/gem | RubyGems package manager |
| Bundle Binary | /usr/local/bin/bundle | Bundler dependency manager |
| Rails Binary | /usr/local/bin/rails | Rails 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.
4.3. Symbolic Link Strategy
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 rubyto 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 installfor global tools (rails, bundler) - Use
bundle installfor 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 toolsopenssl11, openssl11-devel: OpenSSL 1.1 runtime and headersreadline-devel: For interactive Ruby shell (irb)zlib-devel: Compression librarylibyaml-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
Step 6: Create Symbolic Links
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 rubywork - 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:
- Downloads nvm installation script
- Installs nvm to
~/.nvm/ - 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:
- Locally: http://localhost:3000
- Remotely: http://YOUR_PUBLIC_IP:3000 (open port 3000 in security group)
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:
- Resolves dependencies
- Downloads gems
- Creates
Gemfile.lockwith 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
| Path | Purpose | Notes |
|---|---|---|
/usr/local/bin/ruby | Ruby interpreter | Compiled from source |
/usr/local/bin/gem | RubyGems package manager | For installing gems |
/usr/local/bin/bundle | Bundler dependency manager | For project dependencies |
/usr/local/bin/rails | Rails command-line tool | For generating apps, servers |
/usr/local/lib/ruby/gems/3.2.0/ | System gems directory | Globally installed gems |
/usr/bin/ruby | Ruby symlink | Points to /usr/local/bin/ruby |
~/.nvm/ | nvm directory | Node Version Manager |
~/.nvm/versions/node/v16.20.2/ | Node.js installation | Node.js 16 LTS |
~/.gem/ | User gems | Per-user gem installations |
Gemfile | Project dependencies | In each Rails project |
Gemfile.lock | Locked versions | Ensures consistent installs |
vendor/bundle/ | Bundled gems | Project-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
Recommended Next Steps
-
Learn Ruby Basics:
- Ruby in 20 Minutes: https://www.ruby-lang.org/en/documentation/quickstart/
- Try Ruby: https://try.ruby-lang.org/
-
Learn Rails:
- Rails Guides: https://guides.rubyonrails.org/
- Rails Tutorial: https://www.railstutorial.org/
-
Deploy Your App:
-
Join the Community:
- Ruby Forum: https://www.ruby-forum.com/
- Rails Forum: https://discuss.rubyonrails.org/
- Stack Overflow: https://stackoverflow.com/questions/tagged/ruby-on-rails
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! 💎