Install rbenv system-wide
sudo apt update
sudo apt install -y autoconf bison build-essential libssl-dev libyaml-dev \
libreadline-dev zlib1g-dev libncurses-dev libffi-dev libgdbm-dev \
curl git dh-autoreconf
Clone rbenv and ruby-build to a shared location:
sudo git clone https://github.com/rbenv/rbenv.git /opt/rbenv
sudo git clone https://github.com/rbenv/ruby-build.git /opt/rbenv/plugins/ruby-build
sudo chown -R root:root /opt/rbenv
Make it visible to every user by putting the initialization in a system-wide profile file:
sudo tee /etc/profile.d/rbenv.sh <<'EOF'
export RBENV_ROOT=/opt/rbenv
export PATH=$RBENV_ROOT/bin:$PATH
eval "$(rbenv init -)"
EOF
# Reload the current shell
source /etc/profile.d/rbenv.sh
rbenv --version
Install Ruby
# Grab the latest stable release
LATEST=$(rbenv install -l 2>/dev/null | grep -v - | tail -1)
echo "Installing $LATEST"
sudo -E bash -c "source /etc/profile.d/rbenv.sh && rbenv install $LATEST"
sudo -E bash -c "source /etc/profile.d/rbenv.sh && rbenv global $LATEST"
rbenv version
ruby --version
The -E preserves your shell's environment so rbenv's PATH is visible inside sudo.
Install the gems LSAPI needs
sudo -E bash -c "source /etc/profile.d/rbenv.sh && gem update --system"
sudo -E bash -c "source /etc/profile.d/rbenv.sh && gem install rack ruby-lsapi bundler rails"
ruby-lsapi is the Ruby gem that bridges LSAPI requests into Rack. Rails is optional here; install whatever framework your app uses.
Configure OpenLiteSpeed to run Ruby
Log into WebAdmin at https://your-server:7080 and edit the vhost that'll host the Ruby app.
1. Enable SuExec
Basic → Security. Set:
- Run On Start Up: Yes
- Max Connections: 10 (a reasonable starting point)
- Environment: leave default
- Run As User: a non-root user that owns the app directory
2. Add a Rack/LSAPI Context
Context → Add. Type: App Server. Fill in:
- URI:
/(or the path you want the app to serve from) - Location:
/var/www/myapp(directory containing yourconfig.ru) - App Type: Rack
- Startup File:
config.ru - Rack Env:
production - Max Conns: 5
Save, graceful restart.
A working sample app
sudo mkdir -p /var/www/myapp
sudo chown "$USER":"$USER" /var/www/myapp
cd /var/www/myapp
cat > config.ru <<'EOF'
app = proc do |env|
body = "It works!\nRuby #{RUBY_VERSION}\nRack #{Rack.release}\n"
[200, {"Content-Type" => "text/plain"}, [body]]
end
run app
EOF
Reload the server and hit the vhost in a browser; you should see:
It works!
Ruby 3.x.y
Rack 3.x.y
Deploying a real Rails app
The pattern is identical:
- Create the app:
rails new myapp --database=postgresql. - Put it under
/var/www/myapp. - Run
bundle install --deployment --without development testinside. RAILS_ENV=production bundle exec rails db:migrate.RAILS_ENV=production bundle exec rails assets:precompile.- Make sure the config.ru Rails ships is untouched (it already loads the Rack app).
- Set environment variables in the OpenLiteSpeed Context (RAILS_ENV=production, SECRET_KEY_BASE, database URLs).
- Graceful restart.
In production I'd use Puma behind a proxy instead
The above is clean, but in 2026 the industry-standard Rails deployment is Puma (the app server that ships with Rails) behind nginx or Caddy. It has a larger community, better profiling tools, and Rails' own documentation is written assuming it. LSAPI works well but you're alone if something misbehaves.
The OpenLiteSpeed + LSAPI path makes most sense when you're already running OpenLiteSpeed for PHP and want one extra Ruby app running alongside without adding a second application server.
LSAPI handles HTTP requests, nothing else. Background jobs need a separate Sidekiq/Solid Queue process. ActionCable needs its own Puma or a Redis-backed alternative. LSAPI isn't a total replacement for the supporting cast of a real Rails deployment — it just replaces the HTTP-serving piece.