Learn Passenger: Full Guide for All Skill Levels

Complete Passenger + Rails Guide | Randomize Blog

Complete Beginner’s Guide to Passenger + Rails on Apache

Learn how to deploy Ruby on Rails with Passenger and Apache – from setup to advanced production tips.

πŸ“š Table of Contents

πŸ—οΈ Key Terms & Concepts

TermDescription
PassengerApplication server for Ruby, Node.js, and Python apps, integrates with Apache/Nginx.
PumaMulti-threaded Ruby/Rails application server, often used with Nginx or Apache as a reverse proxy.
RailsPopular web application framework written in Ruby.
Virtual HostApache config to host multiple sites on one server.
mod_passengerApache module that runs Passenger apps.
GemfileFile listing Ruby gems (dependencies) for a Rails app.
Environment VariablesVariables for secrets/config, set outside code for security.
SSL/TLSEncryption for secure HTTP (HTTPS).
SystemdLinux service manager, used for process control.
Reverse ProxyServer that forwards requests to backend apps.
AssetsStatic files (JS, CSS, images) served by Rails.
DockerContainerization platform for packaging and running applications in isolated environments.
ThreadLightweight process for handling multiple requests concurrently.
WorkerSeparate process for handling requests; more workers = more concurrency.
PoolGroup of worker processes managed by Passenger or Puma.

πŸ” What is Passenger?

Passenger (also known as Phusion Passenger) is an application server that makes it easy to deploy Ruby, Node.js, and Python web apps. It integrates directly with Apache (or Nginx), handling process management, scaling, and more.

Simple Analogy: Passenger is like a smart traffic controller for your Rails app, making sure requests are handled efficiently and reliably.

βœ… Why Use Passenger with Rails?

FeatureBenefit
Easy IntegrationWorks out-of-the-box with Apache and Rails
Process ManagementHandles app restarts, scaling, and memory automatically
PerformanceEfficient, supports multiple concurrent requests
SecurityRuns apps as non-root users, supports SSL
MonitoringBuilt-in status and monitoring tools

🚦 Puma vs Passenger: Comparison

FeaturePassengerPuma
IntegrationDirect with Apache/Nginx (module)Reverse proxy via Apache/Nginx
Process ModelMulti-process, can be multi-threadedMulti-threaded, multi-worker
Zero-downtime DeploysYes (built-in)Yes (with phased restart)
Monitoring Toolspassenger-status, passenger-memory-statspumactl, systemd, external tools
Ease of UseVery easy, auto-detects Rails appRequires manual config, more control
Docker SupportOfficial images, but less commonVery common, official images
ScalingAutomatic process managementManual tuning of workers/threads
Memory UsageEfficient, but more overhead than Puma for small appsVery efficient for threaded workloads
Best ForSimple, stable, production Rails hostingHigh concurrency, API, microservices

Summary:
Passenger is best for easy, stable, and secure Rails hosting with Apache/Nginx, especially for traditional web apps and teams who want less manual tuning.
Puma is best for high-concurrency, API-heavy, or microservice Rails apps, and is the default for new Rails projects.

πŸ‘ Pros & Cons: Passenger vs Puma

PassengerPuma
Pros
  • Easy Apache/Nginx integration
  • Automatic process management
  • Great for shared hosting
  • Zero-downtime deploys
  • Good monitoring tools
  • High concurrency (threads)
  • Great for APIs and real-time apps
  • Lightweight, fast
  • Flexible config
  • Excellent Docker support
Cons
  • More memory overhead for small apps
  • Less control over threading
  • Not as common in Dockerized microservices
  • Manual tuning required for best performance
  • More complex for beginners
  • Reverse proxy setup needed

❓ Why Use Passenger Over Puma?

  • Seamless Apache/Nginx integration (no reverse proxy config needed)
  • Automatic process management and scaling
  • Zero-downtime deploys out of the box
  • Great for teams who want stability and less manual tuning
  • Easy to monitor and debug with built-in tools
  • Ideal for shared hosting and traditional web apps

When to choose Passenger: If you want a “just works” Rails deployment with Apache or Nginx, especially for monolithic or traditional web apps, Passenger is a great choice.

πŸ› οΈ How to Install Passenger & Rails

Install on Ubuntu/Debian

# Install dependencies
sudo apt update
sudo apt install -y dirmngr gnupg apt-transport-https ca-certificates
sudo apt install -y curl

# Add Passenger APT repo
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 561F9B9CAC40B2F7
sudo sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger $(lsb_release -cs) main > /etc/apt/sources.list.d/passenger.list'
sudo apt update

# Install Passenger + Apache module
sudo apt install -y libapache2-mod-passenger
sudo apt install -y apache2

# Install Ruby, Rails, Bundler
sudo apt install -y ruby-full build-essential zlib1g-dev
sudo gem install rails bundler

Install on CentOS/RHEL

# See official docs for latest steps: https://www.phusionpassenger.com/library/install/apache/install/oss/el7/

βš™οΈ Basic Configuration

Create a Rails App

# Create a new Rails app (or clone your repo)
cd /var/www
rails new myapp -d postgresql
cd myapp
bundle install
RAILS_ENV=production rails db:setup
RAILS_ENV=production rails assets:precompile

Apache VirtualHost Example

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/myapp/public
    
        Allow from all
        Options -MultiViews
        Require all granted
    
    ErrorLog ${APACHE_LOG_DIR}/myapp_error.log
    CustomLog ${APACHE_LOG_DIR}/myapp_access.log combined

Note: Passenger automatically detects and runs your Rails app from the public directory. No need to run rails server or puma manually.

βš™οΈ Rails Application Settings for Passenger

  • Set RAILS_ENV=production for production deployments
  • Precompile assets: RAILS_ENV=production rails assets:precompile
  • Use config.force_ssl = true in config/environments/production.rb for HTTPS
  • Set secrets and DB credentials via environment variables or config/credentials.yml.enc
  • For large apps, tune config.threadsafe! and config.eager_load = true
  • Use SetEnv in Apache config to pass ENV vars to Rails
# Example: config/environments/production.rb
Rails.application.configure do
  config.cache_classes = true
  config.eager_load = true
  config.force_ssl = true
  config.log_level = :info
  # ...other production settings...
end

πŸš€ Full Implementation Example: Rails + Passenger + Apache + SSL

Step-by-Step Production Deployment

  1. Install all dependencies (see above)
  2. Clone/setup your Rails app:
    cd /var/www
    git clone https://github.com/youruser/myapp.git
    cd myapp
    bundle install
    RAILS_ENV=production rails db:setup
    RAILS_ENV=production rails assets:precompile
    
  3. Set permissions:
    sudo chown -R www-data:www-data /var/www/myapp
    sudo chmod -R 755 /var/www/myapp
  4. Configure Apache VirtualHost (HTTP & HTTPS):
    <VirtualHost *:80>
        ServerName example.com
        ServerAlias www.example.com
        RewriteEngine On
        RewriteCond %{HTTPS} off
        RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    </VirtualHost>
    
    <VirtualHost *:443>
        ServerName example.com
        ServerAlias www.example.com
        SSLEngine on
        SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
        Include /etc/letsencrypt/options-ssl-apache.conf
    
        DocumentRoot /var/www/myapp/public
        
            Allow from all
            Options -MultiViews
            Require all granted
        
        ErrorLog ${APACHE_LOG_DIR}/myapp_ssl_error.log
        CustomLog ${APACHE_LOG_DIR}/myapp_ssl_access.log combined
    </VirtualHost>
    
  5. Enable required modules and site:
    sudo a2enmod passenger rewrite ssl headers
    sudo a2ensite myapp.conf
    sudo systemctl reload apache2
  6. Obtain SSL certificate (Let’s Encrypt):
    sudo apt install certbot python3-certbot-apache
    sudo certbot --apache -d example.com -d www.example.com
  7. Set environment variables (production):
    # In /var/www/myapp/.env or via Apache config:
    export RAILS_ENV=production
    export SECRET_KEY_BASE=your_secret
    export DATABASE_URL=postgres://user:pass@localhost/dbname
    
  8. Test:
    • Visit https://example.com (should load your Rails app)
    • All HTTP is redirected to HTTPS

Troubleshooting Tips:

  • App not loading? Check /var/log/apache2/ error.log and log/production.log
  • Permission denied? Ensure public/ and tmp/ are writable by Apache
  • Assets not loading? Run RAILS_ENV=production rails assets:precompile
  • SSL not working? Check /etc/letsencrypt/ and run sudo certbot renew –dry-run
  • Environment variables? Use .env or set in Apache config with SetEnv

🌐 Passenger with Nginx

Passenger can also be used with Nginx instead of Apache. This is a popular choice for high-performance Rails deployments, as Nginx is lightweight and efficient for serving static files and handling concurrent connections.

Why use Passenger + Nginx? Nginx is known for its speed and low memory usage. Combined with Passenger, it provides a robust, production-ready platform for Rails apps, especially for high-traffic or API-heavy workloads.

Install Passenger + Nginx (Ubuntu/Debian)

# Add Passenger APT repo
sudo apt update
sudo apt install -y dirmngr gnupg apt-transport-https ca-certificates
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 561F9B9CAC40B2F7
sudo sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger $(lsb_release -cs) main > /etc/apt/sources.list.d/passenger.list'
sudo apt update

# Install Passenger + Nginx module
sudo apt install -y libnginx-mod-http-passenger nginx

Sample Nginx Config for Rails + Passenger

server {
    listen 80;
    server_name example.com;
    root /var/www/myapp/public;

    passenger_enabled on;
    passenger_app_env production;

    # Static file serving
    location ~ ^/(assets|packs|uploads)/ {
        expires max;
        add_header Cache-Control public;
    }

    # Rails error pages
    error_page 500 502 503 504 /500.html;
    client_max_body_size 20M;
    keepalive_timeout 10;
}

SSL with Nginx + Passenger

server {
    listen 443 ssl;
    server_name example.com;
    root /var/www/myapp/public;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    passenger_enabled on;
    passenger_app_env production;
    # ...rest as above...
}

Environment Variables in Nginx + Passenger

passenger_env_var SECRET_KEY_BASE your_secret;
passenger_env_var DATABASE_URL postgres://user:pass@localhost/dbname;

Troubleshooting Tips:

  • App not loading? Check /var/log/nginx/ error.log and log/production.log
  • Permission denied? Ensure public/ and tmp/ are writable by the Nginx user (usually www-data).
  • Assets not loading? Check root path and precompile assets.
  • SSL not working? Check certificate paths and run sudo certbot renew –dry-run.
  • Environment variables? Use passenger_env_var in your Nginx config.

🐳 Passenger with Docker

Passenger can be run inside Docker containers for modern, containerized Rails deployments. Official images are available, but Puma is more common in the Docker world. Here’s a basic example:

# Dockerfile for Rails + Passenger + Apache
FROM phusion/passenger-ruby31:latest

# Install dependencies
RUN apt-get update && apt-get install -y nodejs yarn

# Set working directory
WORKDIR /app

# Copy app files
COPY . /app

# Install gems
RUN bundle install

# Precompile assets
RUN bundle exec rake assets:precompile

# Expose port 80
EXPOSE 80

# Start Apache + Passenger
CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

Tip: For production, use multi-stage builds and set environment variables securely. See Passenger Docker docs for more.

🏒 Best Settings for Large Scale Applications

  • Increase PassengerMaxPoolSize for more concurrent processes
  • Use PassengerMinInstances to keep workers warm
  • Enable config.cache_store with Memcached or Redis
  • Use a CDN for static assets
  • Enable Gzip compression (mod_deflate)
  • Monitor with passenger-status and external tools (New Relic, Datadog)
  • Set config.active_record.database_selector for DB load balancing (Rails 6+)
  • Use config.active_job.queue_adapter for background jobs (Sidekiq, Resque)
# Example: Apache Passenger tuning
PassengerMaxPoolSize 12
PassengerMinInstances 4
PassengerPoolIdleTime 300

Tip: For very large scale, consider horizontal scaling (multiple servers/load balancer) and database replication.

🌍 Real-World Case Study: Rails + Passenger Deployment

Company: Startup SaaS Platform

Stack: Rails 7 + Passenger + Apache + PostgreSQL + Redis + Sidekiq

Deployment: Ubuntu 22.04 VPS, Passenger as Apache module, SSL via Let’s Encrypt, assets on CDN, background jobs with Sidekiq.

Challenges: Needed zero-downtime deploys, easy scaling, and simple monitoring for a small team.

Solution: Used Passenger for process management and zero-downtime deploys, Apache for SSL and static files, passenger-status for monitoring, and capistrano for automated deploys. Switched to Redis cache store and CDN for assets as traffic grew.

Result: 99.99% uptime, easy deploys, and simple scaling as the team grew. Minimal manual tuning required.

🚨 Common Error Messages Table

Error MessageWhereWhat it Means / How to Fix
Could not spawn process for applicationPassenger/Apache/NginxCheck permissions, Ruby version, and Gemfile.lock. Ensure all gems are installed and public/ is readable.
App 123 stdout: Missing secret_key_basePassenger/RailsSet SECRET_KEY_BASE in ENV or credentials.
Permission denied @ dir_s_mkdirRailsEnsure tmp/ and public/ are writable by web server user.
502 Bad GatewayNginx/BrowserPassenger or Rails app crashed or not starting. Check logs and restart.
503 Service Temporarily UnavailableApache/NginxApp is restarting or overloaded. Check passenger-status and logs.
Assets not loading (404)BrowserRun RAILS_ENV=production rails assets:precompile and check root path.
Database connection refusedRailsCheck DATABASE_URL and DB server status.
SSL certificate errorBrowser/Apache/NginxCheck certificate paths and renewal. Use sudo certbot renew –dry-run.

πŸ”„ .htaccess and Nginx Equivalent

.htaccess RuleNginx Equivalent
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
if ($scheme = http) {
  return 301 https://$host$request_uri;
}
ErrorDocument 404 /404.html
error_page 404 /404.html;
AuthType Basic
AuthName "Restricted"
AuthUserFile /path/to/.htpasswd
Require valid-user
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
Header set Access-Control-Allow-Origin "*"
add_header Access-Control-Allow-Origin *;
Options -Indexes
autoindex off;

πŸ”§ Troubleshooting

  • Check /var/log/apache2/ error.log for Passenger and Rails errors
  • Check log/production.log in your Rails app
  • Use passenger-status and passenger-memory-stats for diagnostics
  • Restart Apache after config changes: sudo systemctl reload apache2
  • Check permissions on public/ and tmp/

⚑ Performance Tuning

  • Use PassengerMaxPoolSize to control max app processes
  • Enable caching in Rails (config/environments/production.rb)
  • Use a CDN for static assets
  • Enable Gzip compression (mod_deflate)
  • Monitor memory usage with passenger-memory-stats

πŸ”’ Security Best Practices

  • Always use HTTPS (SSL/TLS)
  • Hide Apache version (ServerTokens Prod, ServerSignature Off)
  • Set proper file permissions (never run as root)
  • Use strong secrets and environment variables
  • Keep Rails, Passenger, and Apache updated
  • Enable firewalls and restrict SSH access

πŸ€– Automation

  • Automate deployment with Capistrano or Ansible
  • Use bash scripts for backups and log rotation
  • Automate SSL renewal with Certbot cron job
# Example: Capistrano deploy
bundle exec cap production deploy

πŸ“ˆ Monitoring

  • Use passenger-status and passenger-memory-stats
  • Monitor Apache logs and Rails logs
  • Integrate with external tools (New Relic, Datadog, etc.)

πŸ“ Passenger + Rails Cheat Sheet

TaskCommand/Config
Restart Apachesudo systemctl restart apache2
Reload Apachesudo systemctl reload apache2
Check Passenger statuspassenger-status
Check memory usagepassenger-memory-stats
Precompile Rails assetsRAILS_ENV=production rails assets:precompile
Set environment variableexport VAR=value or SetEnv VAR value in Apache config
View Rails logstail -f log/production.log

❓ FAQ

QuestionAnswer
What is Passenger?An application server for Ruby, Node.js, and Python that integrates with Apache/Nginx.
How do I restart my Rails app?Touch tmp/restart.txt in your app directory or reload Apache.
How do I set environment variables?Use SetEnv in Apache config or .env files.
How do I enable SSL?Use certbot to get a certificate and configure your VirtualHost for port 443.
How do I debug Passenger issues?Check /var/log/apache2/ error.log and use passenger-status.
How do I scale my app?Increase PassengerMaxPoolSize and use a load balancer if needed.

🌐 External Resources

βœ… Conclusion

Passenger + Apache is a powerful, production-ready way to deploy Ruby on Rails apps. With easy integration, strong security, and robust performance, it’s a top choice for Rails hosting.

  • Easy to set up and manage
  • Handles process management and scaling
  • Works seamlessly with Apache and SSL
  • Great for both beginners and advanced users

For more advanced Rails optimization, see Randomize Blog.

45 thoughts on “Learn Passenger: Full Guide for All Skill Levels”

Comments are closed.

Scroll to Top