├── Gemfile ├── Gemfile.lock ├── Procfile ├── README.md ├── config.ru └── lib └── heroku_nginx_headers_middleware.rb /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'sinatra', '~> 2.2.0' 3 | gem 'passenger', '>= 6.0.27' 4 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | mustermann (2.0.2) 5 | ruby2_keywords (~> 0.0.1) 6 | passenger (6.0.27) 7 | rack 8 | rake (>= 0.8.1) 9 | rack (2.2.8) 10 | rack-protection (2.2.4) 11 | rack 12 | rake (13.1.0) 13 | ruby2_keywords (0.0.5) 14 | sinatra (2.2.4) 15 | mustermann (~> 2.0) 16 | rack (~> 2.2) 17 | rack-protection (= 2.2.4) 18 | tilt (~> 2.0) 19 | tilt (2.3.0) 20 | 21 | PLATFORMS 22 | x86_64-darwin-22 23 | 24 | DEPENDENCIES 25 | passenger (>= 6.0.27) 26 | sinatra (~> 2.2.0) 27 | 28 | BUNDLED WITH 29 | 2.4.15 30 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: bundle exec passenger start -p $PORT 2 | 3 | # -OR- 4 | # Use the following line instead of the above 'web' line if you want 5 | # to use the Passenger Status Service. More information: 6 | # https://status-service.phusionpassenger.com/ 7 | 8 | # web: ./passenger-status-service-agent & bundle exec passenger start -p $PORT 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Running a Ruby app on Heroku with Phusion Passenger 2 | 3 | [Phusion Passenger](https://www.phusionpassenger.com/) is an application server, designed to be fast, robust and lightweight. By combining Heroku with Phusion Passenger, you can boost the performance of your apps, utilize the available resources on your dynos much more efficiently and increase its stability. 4 | 5 | Phusion Passenger for Heroku brings *the power of Nginx* to your dynos. Nginx is an extremely fast and lightweight web server that powers 10% of the Internet. All the cool guys are rapidly switching to Nginx. Phusion Passenger *replaces Thin and Unicorn*, and makes full use of Nginx to serve your Ruby apps faster and better. 6 | 7 |
8 | 9 |
10 | 11 | Here's a list of the benefits that using Phusion Passenger will bring you: 12 | 13 | * **Static asset acceleration through Nginx** - Don't let your Ruby app serve static assets, let Nginx do it for you and offload your app for the really important tasks. Nginx will do a much better job. 14 | * **Multiple worker processes** - Instead of running only one worker on a dyno, Phusion Passenger runs multiple worker on a single dyno, thus utilizing its resources to its fullest and **giving you more bang for the buck**. This approach is similar to Unicorn's. But unlike Unicorn, Phusion Passenger dynamically scales the number of worker processes based on current traffic, thus freeing up resources when they're not necessary. 15 | * **Memory optimizations** - Phusion Passenger uses less memory than Thin and Unicorn. It also supports copy-on-write virtual memory in combination with code preloading, thus making your app use even less memory when run on Ruby 2.0. 16 | * **Request/response buffering** - The included Nginx buffers requests and responses, thus protecting your app against slow clients (e.g. mobile devices on mobile networks) and improving performance. 17 | * **Out-of-band garbage collection** - Ruby's garbage collector is slow, but why bother your visitors with long response times? Fix this by running garbage collection outside of the normal request-response cycle! This concept, first introduced by Unicorn, has been improved upon: Phusion Passenger ensures that only one request at the same time is running out-of-band garbage collection, thus eliminating all the problems Unicorn's out-of-band garbage collection has. 18 | * **JRuby support** - Unicorn's a better choice than Thin, but it doesn't support JRuby. Phusion Passenger does. 19 | 20 | More information about Phusion Passenger: 21 | 22 | * [Website](https://www.phusionpassenger.com/) 23 | * [Documentation](https://www.phusionpassenger.com/library/) 24 | * [Support](https://www.phusionpassenger.com/support/) 25 | * [Source code](https://github.com/phusion/passenger) 26 | * [Community discussion forum](https://groups.google.com/d/forum/phusion-passenger) 27 | * [Issue tracker](https://github.com/phusion/passenger/issues) 28 | 29 | ## What people say 30 | 31 | 32 | 33 | 34 | 35 | [Tweet about us too](https://twitter.com/share) or [follow us on Twitter](https://twitter.com/phusion_nl). 36 | 37 | ## Creating a new app 38 | 39 | Clone this repository and push it to Heroku: 40 | 41 | git clone https://github.com/phusion/passenger-ruby-heroku-demo.git 42 | cd passenger-ruby-heroku-demo 43 | heroku create 44 | git push heroku master 45 | heroku open 46 | 47 | Your app is now powered by Phusion Passenger! 48 | 49 | ## Switching an existing app to Phusion Passenger 50 | 51 | Phusion Passenger is a drop-in replacement for Thin and Unicorn and very easy to install. 52 | 53 | Open your app's Gemfile. Remove the following lines if they exist: 54 | 55 | gem "unicorn" 56 | gem "thin" 57 | gem "puma" 58 | 59 | Insert: 60 | 61 | gem "passenger" 62 | 63 | Open your app's Procfile, or create one if you don't already have one. Remove lines like this: 64 | 65 | web: bundle exec ruby web.rb -p $PORT 66 | web: bundle exec unicorn -p $PORT 67 | web: bundle exec thin start -p $PORT 68 | web: bundle exec puma -p $PORT 69 | 70 | If you depend on Omniauth to authenticate with Facebook, G+, etc you must add the following lines to your `config/application.rb`: 71 | 72 | config.autoload_paths += Dir["#{config.root}/lib"] 73 | config.middleware.insert_before Rails::Rack::Logger, "HerokuNginxHeadersMiddleware" 74 | 75 | Copy the `lib/heroku_nginx_headers_middleware.rb` to the `lib` directory in your Rails app. 76 | 77 | Insert: 78 | 79 | web: bundle exec passenger start -p $PORT --max-pool-size 3 80 | 81 | Finally, bundle install, commit and deploy: 82 | 83 | bundle install 84 | git commit -a -m "Switch to Phusion Passenger" 85 | git push heroku master 86 | 87 | Congratulations, you're now running on Phusion Passenger! 88 | 89 | ## Configuration 90 | 91 | Any configuration is done by customizing the arguments passed to the `passenger` command. The most important ones are: 92 | 93 | * `--max-pool-size` - The maximum number of worker processes to run. The maximum number that you can run depends on the amount of memory your dyno has. 94 | * `--min-instances` - If you don't want the number of worker processes to scale dynamically, then use this option to set it to a value equal to `--max-pool-size`. 95 | * `--spawn-method` - By default, Phusion Passenger preloads your app and utilizes copy-on-write (the "smart" spawning method). You can disable this by setting this option to `direct`. 96 | * `--no-friendly-error-pages` - If your app fails to start, Phusion Passenger will tell you by showing a friendly error page in the browser. This option disables it. 97 | 98 | Please refer to the [configuration reference](https://www.phusionpassenger.com/library/config/standalone/reference/) for more information. 99 | 100 | ## Status service 101 | 102 | Passenger provides [the `passenger-status` command](https://www.phusionpassenger.com/library/admin/standalone/overall_status_report.html), which displays a status report that tells you what application processes are currently running, how much memory and CPU they use, how many requests are being handled, etc. 103 | 104 | However, `passenger-status` doesn't work out-of-the-box on Heroku because Heroku does not allow SSH access to its servers. For this reason, we have created the [Passenger Status Service](https://status-service.phusionpassenger.com/) for making Passenger status reports work. 105 | 106 | Please visit [https://status-service.phusionpassenger.com/](https://status-service.phusionpassenger.com/) for more information. 107 | 108 | ## Passenger Enterprise 109 | 110 | You can also use [Phusion Passenger Enterprise](https://www.phusionpassenger.com/enterprise) on Heroku, but with a caveat: 111 | 112 | * Passenger Enterprise's rolling restarts don't work. You need to use [Heroku's preboot facility](https://devcenter.heroku.com/articles/preboot) for that. 113 | 114 | Here are the instructions for running Passenger Enterprise on Heroku: 115 | 116 | 1. Add the Enterprise repo and gem to your Gemfile: 117 | 118 | source "https://download:#{your_download_key}@www.phusionpassenger.com/enterprise_gems" 119 | gem 'passenger-enterprise-server', '>= 5.0.22' 120 | 121 | 'your_download_key' can be found in the [Customer Area](https://www.phusionpassenger.com/orders). 122 | 123 | 2. Download the license key to your local workstation. Save it somewhere, e.g. to ~/passenger-enterprise-license. 124 | 3. Transfer the contents of the license key to a Heroku environment variable: 125 | 126 | heroku config:set PASSENGER_ENTERPRISE_LICENSE_DATA="`cat ~/passenger-enterprise-license`" 127 | 128 | 4. Commit and push to Heroku: 129 | 130 | git commit -a -m "Use Phusion Passenger Enterprise" 131 | git push heroku master 132 | 133 | ### Using Passenger open source in development, Enterprise in staging and production 134 | 135 | It is possible to use Passenger open source in development, while using Passenger Enterprise in staging production. This works by creating a binstub `bin/passenger` which will start either Passenger open source or Passenger enterprise, depending on the value of the `RAILS_ENV` environment variable. Then the user must use the `bin/passenger` binstub instead of using the `passenger` command directly. 136 | 137 | First, ensure that your Gemfile contains both 'passenger' and 'passenger-enterprise-server' but in different groups, like this: 138 | 139 | source 'https://rubygems.org' 140 | source "https://download:#{your_download_key}@www.phusionpassenger.com/enterprise_gems" 141 | 142 | group :development do 143 | gem 'passenger', '>= 5.0.22' 144 | end 145 | 146 | group :staging, :production do 147 | gem 'passenger-enterprise-server', '>= 5.0.22' 148 | end 149 | 150 | Second, create a binstub `bin/passenger`. This binstub will start Passenger open source in development, Passenger Enterprise in staging and production. The binstub must contain: 151 | 152 | #!/usr/bin/env ruby 153 | 154 | require 'pathname' 155 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", 156 | Pathname.new(__FILE__).realpath) 157 | 158 | require 'rubygems' 159 | require 'bundler/setup' 160 | 161 | if ENV['RAILS_ENV'] == 'staging' || ENV['RAILS_ENV'] == 'production' 162 | gem_name = 'passenger-enterprise-server' 163 | else 164 | gem_name = 'passenger' 165 | end 166 | 167 | bin_dir = Gem.loaded_specs[gem_name].bin_dir 168 | load File.join(bin_dir, 'passenger') 169 | 170 | Make it executable: 171 | 172 | chmod +x bin/passenger 173 | 174 | Third, modify your Procfile to use `./bin/passenger` instead of `passenger`. Replace this... 175 | 176 | web: bundle exec passenger start -p $PORT ... 177 | 178 | ...with this: 179 | 180 | web: bundle exec ./bin/passenger start -p $PORT ... 181 | 182 | Install the gem bundle and commit the result: 183 | 184 | bundle install 185 | git add Gemfile Gemfile.lock Procfile bin/passenger 186 | git commit -a -m "Use Passenger Enterprise only in staging and production" 187 | 188 | You can test the binstub locally as follows: 189 | 190 | $ ./bin/passenger --version 191 | Phusion Passenger 5.0.22 192 | $ RAILS_ENV=production ./bin/passenger --version 193 | Phusion Passenger Enterprise 5.0.22 194 | 195 | ## Next steps 196 | 197 | * Using Phusion Passenger on Heroku? [Tweet about us](https://twitter.com/share), [follow us on Twitter](https://twitter.com/phusion_nl) or [fork us on Github](https://github.com/phusion/passenger). 198 | * Having problems? Please post a message at [the community discussion forum](https://groups.google.com/d/forum/phusion-passenger). 199 | 200 | [](http://www.phusion.nl/) 201 | 202 | Please enjoy Phusion Passenger, a product by [Phusion](http://www.phusion.nl/). :-) 203 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | require 'sinatra/base' 2 | 3 | class MyApp < Sinatra::Base 4 | get '/' do 5 | "Hello, Phusion Passenger #{PhusionPassenger::VERSION_STRING}!" 6 | end 7 | end 8 | 9 | run MyApp 10 | -------------------------------------------------------------------------------- /lib/heroku_nginx_headers_middleware.rb: -------------------------------------------------------------------------------- 1 | # Fixes up headers based on information given by the Heroku router. 2 | # by @honglilai 3 | class HerokuNginxHeadersMiddleware 4 | def initialize(app) 5 | @app = app 6 | end 7 | 8 | def call(env) 9 | env["SERVER_PORT"] = env["HTTP_X_FORWARDED_PORT"] 10 | env["REMOTE_ADDR"] = env["HTTP_X_FORWARDED_FOR"] 11 | @app.call(env) 12 | end 13 | end 14 | --------------------------------------------------------------------------------