OpenLiteSpeed ile Ruby on Rails Uygulaması Sunumu
Ruby on Rails uygulamalarını production ortamında ayağa kaldırmak, özellikle doğru web sunucusu seçimi yapıldığında hem performans hem de yönetim kolaylığı açısından büyük fark yaratıyor. Apache veya Nginx’e alışkın olan çoğu sysadmin, OpenLiteSpeed’i atlıyor. Oysa OLS’nin event-driven mimarisi, built-in cache mekanizması ve düşük kaynak tüketimi, Rails uygulamaları için son derece uygun bir zemin sunuyor. Bu yazıda sıfırdan başlayarak, gerçek bir Rails uygulamasını OpenLiteSpeed arkasında nasıl production-ready hale getireceğimizi adım adım inceleyeceğiz.
Neden OpenLiteSpeed ve Rails Birlikte?
Rails uygulamaları genellikle Nginx + Puma veya Nginx + Unicorn kombinasyonuyla çalıştırılır. Bu kurulum sağlamdır, ancak OpenLiteSpeed bu tabloya birkaç önemli avantaj ekler.
LSCache modülü sayesinde dinamik içerikleri bile önbelleğe alabilirsiniz. Statik dosyalar için ayrı bir CDN veya Nginx katmanı kurmak zorunda kalmadan, OLS’nin kendi içinde gzip sıkıştırma ve HTTP/2 desteğiyle yüksek throughput elde edebilirsiniz. Bunun yanı sıra web tabanlı admin paneli, konfigürasyon hatalarını minimuma indirir ve takım üyelerinin sunucuya doğrudan SSH bağlantısı olmadan bazı ayarları değiştirmesine olanak tanır.
Rails tarafında ise Puma, multi-threaded mimarisiyle OLS’nin reverse proxy yapısıyla mükemmel uyum sağlar. OLS, gelen istekleri Puma’ya iletir, statik dosyaları kendisi karşılar ve SSL termination görevini üstlenir.
Ortam Hazırlığı
Ubuntu 22.04 LTS üzerinde çalışacağız. Sunucunuzda en az 2GB RAM ve 2 CPU core olmasını öneririm.
Sistem Güncellemesi ve Temel Paketler
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget git build-essential libssl-dev libreadline-dev
zlib1g-dev libsqlite3-dev libpq-dev nodejs yarn
OpenLiteSpeed Kurulumu
OLS’yi resmi LiteSpeed deposundan kuruyoruz:
wget -O - https://repo.litespeed.sh | sudo bash
sudo apt install -y openlitespeed
sudo systemctl enable lsws
sudo systemctl start lsws
Kurulum tamamlandıktan sonra admin paneline erişmek için şifreyi ayarlayalım:
sudo /usr/local/lsws/admin/misc/admpass.sh
Bu komut size kullanıcı adı ve şifre belirleme imkanı sunar. Panel varsayılan olarak https://sunucu-ip:7080 adresinde çalışır. Tarayıcıdan bu adrese gittiğinizde self-signed sertifika uyarısı alacaksınız, bunu geçebilirsiniz.
Ruby Kurulumu (rbenv ile)
Sistem Ruby’si yerine rbenv kullanacağız. Bu sayede farklı projelerde farklı Ruby sürümleri yönetmek çok daha kolay hale gelir:
curl -fsSL https://github.com/rbenv/rbenv-installer/raw/HEAD/bin/rbenv-installer | bash
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
source ~/.bashrc
rbenv install 3.2.2
rbenv global 3.2.2
ruby --version
Gem kurulumlarında dokümantasyonu atlayarak hız kazanalım:
echo "gem: --no-document" >> ~/.gemrc
gem install bundler rails
Rails Uygulaması Oluşturma
Gerçek dünya senaryosu olarak bir blog uygulaması hazırlayacağız. PostgreSQL kullanacağız, çünkü production ortamlarında SQLite önerilmez.
sudo apt install -y postgresql postgresql-contrib
sudo systemctl start postgresql
sudo systemctl enable postgresql
sudo -u postgres psql -c "CREATE USER railsapp WITH PASSWORD 'guclu_sifre_123';"
sudo -u postgres psql -c "CREATE DATABASE railsblog_production OWNER railsapp;"
Rails uygulamasını oluşturalım:
cd /var/www
sudo mkdir rails_apps
sudo chown $USER:$USER rails_apps
cd rails_apps
rails new myblog --database=postgresql
cd myblog
config/database.yml dosyasını production için düzenleyin:
production:
adapter: postgresql
encoding: unicode
database: railsblog_production
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: railsapp
password: <%= ENV["DATABASE_PASSWORD"] %>
host: localhost
Puma Konfigürasyonu
config/puma.rb dosyasını production ortamına göre optimize edelim:
# config/puma.rb
max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
threads min_threads_count, max_threads_count
worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development"
port ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
workers ENV.fetch("WEB_CONCURRENCY") { 2 }
preload_app!
on_worker_boot do
ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
end
plugin :tmp_restart
Bu konfigürasyonda workers 2 ile 2 Puma worker process başlatıyoruz. Her worker RAILS_MAX_THREADS kadar thread kullanacak. 2 CPU core’lu bir sunucu için bu değerler makul başlangıç noktalarıdır.
Systemd Servisi Oluşturma
Uygulamanın sistem başlangıcında otomatik çalışması ve çökmesi durumunda yeniden başlaması için bir systemd unit dosyası oluşturuyoruz:
sudo nano /etc/systemd/system/myblog.service
[Unit]
Description=MyBlog Rails Application
Requires=network.target
After=network.target postgresql.service
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/rails_apps/myblog
ExecStart=/home/ubuntu/.rbenv/shims/bundle exec puma -C config/puma.rb
ExecStop=/bin/kill -SIGTERM $MAINPID
Restart=always
RestartSec=1
Environment=RAILS_ENV=production
Environment=DATABASE_PASSWORD=guclu_sifre_123
Environment=RAILS_MASTER_KEY=master_key_buraya
Environment=PORT=3000
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=myblog
[Install]
WantedBy=multi-user.target
Önemli not: Ortam değişkenlerini doğrudan service dosyasına yazmak küçük projeler için kabul edilebilir olsa da, hassas bilgileri /etc/myblog.env gibi ayrı bir dosyada saklayıp EnvironmentFile=/etc/myblog.env direktifiyle okumak daha güvenli bir yaklaşımdır.
sudo chown -R www-data:www-data /var/www/rails_apps/myblog
sudo systemctl daemon-reload
sudo systemctl enable myblog
sudo systemctl start myblog
sudo systemctl status myblog
OpenLiteSpeed’de Virtual Host Konfigürasyonu
Şimdi OLS’yi Rails uygulamamıza proxy yapacak şekilde ayarlayacağız. Bu işlemi hem admin panelinden hem de konfigürasyon dosyaları üzerinden yapabilirsiniz. Ben dosya tabanlı yaklaşımı tercih ediyorum çünkü bu yöntem version control’e daha uygun.
Virtual host konfigürasyon dizinini oluşturalım:
sudo mkdir -p /usr/local/lsws/conf/vhosts/myblog
sudo nano /usr/local/lsws/conf/vhosts/myblog/vhost.conf
virtualHost myblog {
vhRoot /var/www/rails_apps/myblog/public
configFile $SERVER_ROOT/conf/vhosts/myblog/vhost.conf
allowSymbolLink 1
enableScript 0
restrained 0
setUIDMode 0
}
Ana konfigürasyon dosyası olan /usr/local/lsws/conf/httpd_config.conf dosyasına virtual host tanımını ve listener’ı eklememiz gerekiyor. Admin paneli üzerinden gitmek burada daha pratik:
Admin Paneli adımları:
Virtual Hosts > Addile yeni virtual host ekleyinDocument Rootolarak/var/www/rails_apps/myblog/publicgirinVirtual Host Name: myblog
Asıl kritik kısım, external application tanımıdır. Admin panelinde Virtual Hosts > myblog > External Apps bölümüne gidin:
- Type: Web Server
- Name: RailsPuma
- Address:
localhost:3000 - Max Connections: 35
- Connection Keepalive Timeout: 60
- Response Buffering: Yes
Ardından Context bölümünde yeni bir context ekleyin:
- Type: Proxy
- URI:
/ - Web Server: RailsPuma
Statik dosyalar için ayrı bir context daha ekleyin:
- Type: Static
- URI:
/assets - Location:
/var/www/rails_apps/myblog/public/assets
Bu sayede CSS, JavaScript ve resim dosyaları doğrudan OLS tarafından servis edilir, Puma’ya hiç uğramaz.
SSL Sertifikası ile HTTPS Kurulumu
Let’s Encrypt ile ücretsiz SSL sertifikası alacağız. Certbot’u kuralım:
sudo apt install -y certbot
sudo certbot certonly --standalone -d myblog.example.com
OLS admin panelinde Listeners > Add ile yeni bir HTTPS listener ekleyin:
- Listener Name: HTTPS
- IP Address: ANY
- Port: 443
- Secure: Yes
- Certificate File:
/etc/letsencrypt/live/myblog.example.com/fullchain.pem - Key File:
/etc/letsencrypt/live/myblog.example.com/privkey.pem
HTTP’den HTTPS’e otomatik yönlendirme için 80 portunu dinleyen listener’a rewrite rule ekleyin:
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
Sertifika yenileme için cron job ekleyelim:
sudo crontab -e
0 12 * * * /usr/bin/certbot renew --quiet && /usr/local/lsws/bin/lswsctrl restart
Production Ortamına Hazırlık
Assets derleme ve veritabanı migration işlemleri:
cd /var/www/rails_apps/myblog
RAILS_ENV=production bundle exec rails db:create
RAILS_ENV=production bundle exec rails db:migrate
RAILS_ENV=production bundle exec rails assets:precompile
sudo systemctl restart myblog
config/environments/production.rb dosyasında bazı ayarları gözden geçirin:
# Statik dosyaları Rails serve etmesin, OLS halleder
config.public_file_server.enabled = true
config.public_file_server.headers = {
'Cache-Control' => 'public, max-age=31536000'
}
# Log seviyesi
config.log_level = :warn
# Force SSL
config.force_ssl = true
Performans Tuning ve Cache Ayarları
OLS’nin en güçlü özelliklerinden biri LSCache’dir. Rails uygulamanız için temel cache headers ayarlayalım. app/controllers/application_controller.rb dosyasına:
class ApplicationController < ActionController::Base
before_action :set_cache_headers
private
def set_cache_headers
if request.get? && !current_user
response.headers['X-LiteSpeed-Cache-Control'] = 'public, max-age=3600'
else
response.headers['X-LiteSpeed-Cache-Control'] = 'no-cache'
end
end
end
Oturum açmış kullanıcılar için cache’i devre dışı bırakmak kritik önem taşır. Aksi halde bir kullanıcının görüntülediği sayfa başka bir kullanıcıya gösterilebilir.
OLS’nin Gzip konfigürasyonunu admin panelinden optimize edin:
- Server Configuration > Tuning > GZIP Compression: Enabled
- Compression Level: 6
- Auto Update Static File: Yes
- MIME Types:
text/html, text/css, application/javascript, application/json
Loglar ve Monitoring
Sorunları hızlıca tespit etmek için log yapısını anlayalım:
# OLS access logları
tail -f /usr/local/lsws/logs/access.log
# OLS error logları
tail -f /usr/local/lsws/logs/error.log
# Rails uygulama logları (systemd journal üzerinden)
sudo journalctl -u myblog -f
# Puma process kontrolü
sudo systemctl status myblog
Bir sorun anında ilk bakacağınız yerler sırasıyla şunlar: önce journalctl -u myblog --since "1 hour ago" ile Rails tarafındaki hataları kontrol edin, sonra OLS error loguna bakın. Genellikle 502 Bad Gateway hataları Puma’nın cevap vermediğini, 503 hataları ise bağlantı havuzunun dolduğunu gösterir.
Basit bir health check endpoint eklemek de izleme açısından faydalıdır:
# config/routes.rb
get '/health', to: proc { [200, {}, ['OK']] }
Bu endpoint’i bir monitoring aracı ile her dakika kontrol edebilir, Puma’nın ayakta olup olmadığını doğrulayabilirsiniz.
Deployment Workflow
Capistrano veya manuel deployment ile her güncelleme sırasında izlenecek adımlar:
cd /var/www/rails_apps/myblog
# Kodu çek
git pull origin main
# Gem bağımlılıklarını güncelle
bundle install --deployment --without development test
# Veritabanı güncellemelerini uygula
RAILS_ENV=production bundle exec rails db:migrate
# Assets yeniden derle
RAILS_ENV=production bundle exec rails assets:precompile
# Puma'ya sıfır downtime restart sinyali gönder
sudo kill -SIGUSR1 $(cat tmp/pids/server.pid)
# Ya da systemd ile yeniden başlat
sudo systemctl reload myblog
SIGUSR1 sinyali Puma’ya “mevcut istekleri bitir, sonra yeniden başla” der. Bu sayede kullanıcılar deployment sırasında 502 hatası görmez. Ancak bu yalnızca kod değişiklikleri için geçerlidir; yeni worker veya thread ayarı değişikliklerinde tam restart gerekir.
Güvenlik Sıkılaştırma
OLS ve Rails tarafında temel güvenlik önlemleri:
# Güvenlik duvarı ayarları
sudo ufw enable
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 7080/tcp # Sadece yönetim IP'niz için açın
OLS admin paneline erişimi kısıtlamak için Server Configuration > Security > Allowed List bölümünden yalnızca kendi IP adresinizi ekleyin. 7080 portunu herkese açık bırakmak ciddi bir güvenlik açığıdır.
config/initializers/security_headers.rb dosyası oluşturun:
Rails.application.config.action_dispatch.default_headers = {
'X-Frame-Options' => 'SAMEORIGIN',
'X-XSS-Protection' => '1; mode=block',
'X-Content-Type-Options' => 'nosniff',
'Referrer-Policy' => 'strict-origin-when-cross-origin',
'Permissions-Policy' => 'geolocation=(), microphone=()'
}
Yaygın Sorunlar ve Çözümleri
502 Bad Gateway: Puma’nın çalışıp çalışmadığını kontrol edin. sudo systemctl status myblog ve curl localhost:3000 komutlarıyla doğrulayın.
Assets yüklenmiyor: public/assets dizininin mevcut olduğundan ve OLS’nin bu dizini okuyabildiğinden emin olun. sudo chown -R www-data:www-data public/ komutu genellikle sorunu çözer.
Database connection errors: PostgreSQL servisinin çalıştığını ve database.yml dosyasındaki kimlik bilgilerinin doğru olduğunu kontrol edin.
Slow response times: İlk olarak Puma worker sayısını artırmayı deneyin. Sonra N+1 query sorunlarını bullet gem’iyle tespit edin. OLS tarafında connection keepalive ayarlarını gözden geçirin.
Permission denied hataları: tmp/, log/ ve public/ dizinlerinin www-data kullanıcısına ait olması gerekir.
Sonuç
OpenLiteSpeed ile Ruby on Rails birlikteliği, doğru yapılandırıldığında oldukça güçlü bir production ortamı ortaya çıkarıyor. Nginx’in statik dosya servis gücünü, LiteSpeed’in cache yetenekleriyle birleştiren bu kurulum, orta ölçekli Rails uygulamaları için ek bir reverse proxy veya CDN kurma ihtiyacını önemli ölçüde azaltıyor.
Bu yazıda anlattığımız kurulumun özeti şu şekilde:
- rbenv ile izole Ruby ortamı
- Puma’yı systemd servisi olarak çalıştırma
- OLS’yi reverse proxy ve statik dosya sunucusu olarak yapılandırma
- Let’s Encrypt ile SSL entegrasyonu
- LSCache ile temel önbellekleme
- Sıfır downtime deployment akışı
Uygulamanız büyüdükçe bu kurulumu horizontal scaling için genişletmek mümkündür. OLS’nin load balancer özelliğiyle birden fazla Puma instance’ını, hatta farklı sunuculardaki worker’ları yönetebilirsiniz. Ama başlangıç için tek sunucuda bu mimari, çoğu küçük ve orta ölçekli uygulama için yeterli performans ve güvenilirliği sağlayacaktır.
