Ruby on Rails ist ein produktives Webframework nach dem Convention-over-Configuration-Prinzip. Für den Produktionsbetrieb wird Puma als Application Server zusammen mit Nginx empfohlen.
Architektur
Client → Nginx (Port 80/443)
↓
Puma (Unix Socket)
↓
Rails App
↓
PostgreSQLRuby installieren
rbenv (empfohlen)
# Dependencies
apt install git curl autoconf bison build-essential \
libssl-dev libyaml-dev libreadline-dev zlib1g-dev \
libncurses5-dev libffi-dev libgdbm-dev
# rbenv installieren
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
source ~/.bashrc
# ruby-build
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
# Ruby installieren
rbenv install 3.3.0
rbenv global 3.3.0
# Prüfen
ruby -vSystem-Ruby (Alternative)
apt install ruby ruby-dev ruby-bundlerRails-Projekt
Neues Projekt
gem install rails
rails new myapp --database=postgresql
cd myappBestehendes Projekt
mkdir -p /var/www/myapp
cd /var/www/myapp
git clone https://github.com/user/myapp.git .Dependencies installieren
bundle install --deployment --without development testDatenbank
PostgreSQL einrichten
sudo -u postgres psql
CREATE DATABASE myapp_production;
CREATE USER myapp WITH PASSWORD 'sicheres_passwort';
GRANT ALL PRIVILEGES ON DATABASE myapp_production TO myapp;
\qdatabase.yml
# config/database.yml
production:
adapter: postgresql
encoding: unicode
database: <%= ENV['DATABASE_NAME'] %>
username: <%= ENV['DATABASE_USER'] %>
password: <%= ENV['DATABASE_PASSWORD'] %>
host: <%= ENV['DATABASE_HOST'] || 'localhost' %>
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>Migrationen
RAILS_ENV=production rails db:migratePuma-Konfiguration
config/puma.rb
# config/puma.rb
# Umgebung
rails_env = ENV.fetch("RAILS_ENV") { "production" }
environment rails_env
# Threads
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
threads threads_count, threads_count
# Workers (Multi-Process)
workers ENV.fetch("WEB_CONCURRENCY") { 2 }
# Socket
if rails_env == "production"
bind "unix:///run/puma/myapp.sock"
else
port ENV.fetch("PORT") { 3000 }
end
# Preload für Copy-on-Write
preload_app!
# Worker-Boot
on_worker_boot do
ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
end
# PID und State
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
state_path "tmp/pids/puma.state"
# Logging
if rails_env == "production"
stdout_redirect "/var/log/puma/myapp.stdout.log",
"/var/log/puma/myapp.stderr.log",
true
end
# Graceful Restart
plugin :tmp_restartSystemd-Service
puma.service
# /etc/systemd/system/puma-myapp.service
[Unit]
Description=Puma HTTP Server for myapp
After=network.target
[Service]
Type=notify
WatchdogSec=10
User=www-data
Group=www-data
WorkingDirectory=/var/www/myapp
RuntimeDirectory=puma
Environment=RAILS_ENV=production
Environment=RAILS_LOG_TO_STDOUT=true
EnvironmentFile=/var/www/myapp/.env
ExecStart=/home/deploy/.rbenv/shims/bundle exec puma -C config/puma.rb
ExecReload=/bin/kill -SIGUSR1 $MAINPID
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetService starten
mkdir -p /var/log/puma
chown www-data:www-data /var/log/puma
systemctl daemon-reload
systemctl enable puma-myapp
systemctl start puma-myappNginx-Konfiguration
# /etc/nginx/sites-available/myapp
upstream myapp {
server unix:/run/puma/myapp.sock fail_timeout=0;
}
server {
listen 80;
server_name example.de www.example.de;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name example.de www.example.de;
ssl_certificate /etc/letsencrypt/live/example.de/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.de/privkey.pem;
root /var/www/myapp/public;
client_max_body_size 10M;
access_log /var/log/nginx/myapp-access.log;
error_log /var/log/nginx/myapp-error.log;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
location ^~ /packs/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri @myapp;
location @myapp {
proxy_pass http://myapp;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
error_page 500 502 503 504 /500.html;
}ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginxUmgebungsvariablen
.env-Datei
# /var/www/myapp/.env
RAILS_ENV=production
SECRET_KEY_BASE=dein_sehr_langes_secret_hier
DATABASE_NAME=myapp_production
DATABASE_USER=myapp
DATABASE_PASSWORD=sicheres_passwort
DATABASE_HOST=localhost
RAILS_MAX_THREADS=5
WEB_CONCURRENCY=2
RAILS_SERVE_STATIC_FILES=trueSecret Key generieren
RAILS_ENV=production rails secretAsset-Pipeline
Assets kompilieren
RAILS_ENV=production rails assets:precompileMit Webpack
RAILS_ENV=production rails assets:precompile
# Oder mit Webpacker
RAILS_ENV=production rails webpacker:compileSidekiq (Background Jobs)
Installation
# Gemfile
gem 'sidekiq'bundle installKonfiguration
# config/sidekiq.yml
:concurrency: 5
:queues:
- default
- mailers
- critical# config/initializers/sidekiq.rb
Sidekiq.configure_server do |config|
config.redis = { url: ENV.fetch('REDIS_URL') { 'redis://localhost:6379/0' } }
end
Sidekiq.configure_client do |config|
config.redis = { url: ENV.fetch('REDIS_URL') { 'redis://localhost:6379/0' } }
endSidekiq-Service
# /etc/systemd/system/sidekiq-myapp.service
[Unit]
Description=Sidekiq for myapp
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/myapp
EnvironmentFile=/var/www/myapp/.env
ExecStart=/home/deploy/.rbenv/shims/bundle exec sidekiq -C config/sidekiq.yml
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetCapistrano Deployment
Installation
# Gemfile
group :development do
gem 'capistrano', '~> 3.17'
gem 'capistrano-rails', '~> 1.6'
gem 'capistrano-rbenv', '~> 2.2'
gem 'capistrano3-puma', '~> 5.2'
endbundle install
cap installCapfile
# Capfile
require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano/puma'
install_plugin Capistrano::Puma
install_plugin Capistrano::Puma::Systemddeploy.rb
# config/deploy.rb
set :application, 'myapp'
set :repo_url, 'git@github.com:user/myapp.git'
set :deploy_to, '/var/www/myapp'
set :branch, 'main'
set :rbenv_type, :user
set :rbenv_ruby, '3.3.0'
set :linked_files, %w[.env config/master.key]
set :linked_dirs, %w[log tmp/pids tmp/cache tmp/sockets public/system]
set :keep_releases, 5
set :puma_systemctl_user, :systemproduction.rb
# config/deploy/production.rb
server 'example.de', user: 'deploy', roles: %w[app db web]Deployment ausführen
cap production deployManuelles Deployment
#!/bin/bash
# /var/www/myapp/deploy.sh
set -e
cd /var/www/myapp
git pull origin main
bundle install --deployment --without development test
RAILS_ENV=production rails db:migrate
RAILS_ENV=production rails assets:precompile
sudo systemctl restart puma-myapp
sudo systemctl restart sidekiq-myapp
echo "Deployment abgeschlossen"Monitoring
Health Check Endpoint
# config/routes.rb
get '/health', to: proc { [200, {}, ['OK']] }Logs
# Puma
tail -f /var/log/puma/myapp.stdout.log
# Rails
tail -f /var/www/myapp/log/production.log
# Sidekiq
journalctl -u sidekiq-myapp -fZusammenfassung
| Komponente | Funktion | |------------|----------| | Ruby/rbenv | Runtime | | Rails | Framework | | Puma | Application Server | | Nginx | Reverse Proxy | | PostgreSQL | Datenbank | | Sidekiq | Background Jobs |
| Befehl | Funktion | |--------|----------| | rails db:migrate | Migrationen | | rails assets:precompile | Assets kompilieren | | cap production deploy | Capistrano Deploy |
| Datei | Funktion | |-------|----------| | config/puma.rb | Puma-Config | | config/database.yml | DB-Config | | .env | Umgebungsvariablen |
Fazit
Ruby on Rails bietet ein vollständiges Framework für Webentwicklung. Puma ist der Standard-Application-Server für Rails. Mit Capistrano lassen sich Deployments automatisieren. Sidekiq übernimmt Background Jobs zuverlässig. Die Asset-Pipeline optimiert Frontend-Ressourcen. Rails bleibt eine produktive Wahl für komplexe Webanwendungen.