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 your config.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:

  1. Create the app: rails new myapp --database=postgresql.
  2. Put it under /var/www/myapp.
  3. Run bundle install --deployment --without development test inside.
  4. RAILS_ENV=production bundle exec rails db:migrate.
  5. RAILS_ENV=production bundle exec rails assets:precompile.
  6. Make sure the config.ru Rails ships is untouched (it already loads the Rack app).
  7. Set environment variables in the OpenLiteSpeed Context (RAILS_ENV=production, SECRET_KEY_BASE, database URLs).
  8. 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.

Sidekiq, ActiveJob, WebSockets

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.