├── .gitignore ├── config ├── stack │ ├── essential.rb │ ├── scm.rb │ ├── memcached.rb │ ├── mysql.rb │ ├── postgresql.rb │ ├── ruby_enterprise.rb │ ├── nginx.rb │ ├── nginx │ │ └── init.d │ └── apache.rb ├── deploy.rb.example └── install.rb ├── Capfile └── README.markdown /.gitignore: -------------------------------------------------------------------------------- 1 | config/deploy.rb 2 | -------------------------------------------------------------------------------- /config/stack/essential.rb: -------------------------------------------------------------------------------- 1 | package :build_essential do 2 | description 'Build tools' 3 | apt 'build-essential' do 4 | pre :install, 'apt-get update' 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /Capfile: -------------------------------------------------------------------------------- 1 | default_run_options[:pty] = true 2 | 3 | load 'deploy' if respond_to?(:namespace) # cap2 differentiator 4 | Dir['vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) } 5 | load 'config/deploy' -------------------------------------------------------------------------------- /config/deploy.rb.example: -------------------------------------------------------------------------------- 1 | # Rename this file to deploy.rb 2 | 3 | # Fill slice_url in - where you're installing your stack to 4 | role :app, "your-app-server.com" 5 | 6 | # Fill user in - if remote user is different to your local user 7 | # set :user, "username" 8 | 9 | default_run_options[:pty] = true 10 | -------------------------------------------------------------------------------- /config/stack/scm.rb: -------------------------------------------------------------------------------- 1 | package :git, :provides => :scm do 2 | description 'Git Distributed Version Control' 3 | version '1.6.1' 4 | source "http://kernel.org/pub/software/scm/git/git-#{version}.tar.gz" 5 | requires :git_dependencies 6 | 7 | verify do 8 | has_file '/usr/local/bin/git' 9 | end 10 | end 11 | 12 | package :git_dependencies do 13 | description 'Git Build Dependencies' 14 | apt 'git-core', :dependencies_only => true 15 | end 16 | -------------------------------------------------------------------------------- /config/stack/memcached.rb: -------------------------------------------------------------------------------- 1 | package :memcached_daemon, :provides => :memcached do 2 | description 'Memcached, a distributed memory object store' 3 | apt %w( memcached ) 4 | 5 | post :install, "/etc/init.d/memcached start" 6 | post :install, "sudo ldconfig" 7 | 8 | verify do 9 | has_executable 'memcached' 10 | end 11 | end 12 | 13 | package :libmemcached do 14 | source 'http://download.tangent.org/libmemcached-0.25.tar.gz' 15 | requires :memcached_daemon 16 | end -------------------------------------------------------------------------------- /config/stack/mysql.rb: -------------------------------------------------------------------------------- 1 | package :mysql, :provides => :database do 2 | description 'MySQL Database' 3 | apt %w( mysql-server mysql-client libmysqlclient-dev ) 4 | 5 | verify do 6 | has_executable 'mysql' 7 | end 8 | 9 | optional :mysql_driver 10 | end 11 | 12 | package :mysql_driver, :provides => :ruby_database_driver do 13 | description 'Ruby MySQL database driver' 14 | gem 'mysql' 15 | 16 | verify do 17 | has_gem 'mysql' 18 | end 19 | 20 | requires :ruby_enterprise 21 | end 22 | -------------------------------------------------------------------------------- /config/stack/postgresql.rb: -------------------------------------------------------------------------------- 1 | package :postgres, :provides => :database do 2 | description 'PostgreSQL database' 3 | apt %w( postgresql postgresql-client libpq-dev ) 4 | 5 | verify do 6 | has_executable 'psql' 7 | end 8 | 9 | optional :postgresql_driver 10 | end 11 | 12 | package :postgresql_driver, :provides => :ruby_database_driver do 13 | description 'Ruby PostgreSQL database driver' 14 | gem 'postgres' 15 | 16 | verify do 17 | has_gem 'postgres' 18 | end 19 | 20 | requires :ruby_enterprise 21 | end 22 | -------------------------------------------------------------------------------- /config/stack/ruby_enterprise.rb: -------------------------------------------------------------------------------- 1 | package :ruby_enterprise do 2 | description 'Ruby Enterprise Edition' 3 | version '1.8.7-2010.01' 4 | REE_PATH = "/usr/local/ruby-enterprise" 5 | 6 | binaries = %w(erb gem irb rackup rails rake rdoc ree-version ri ruby testrb) 7 | source "http://rubyforge.org/frs/download.php/68719/ruby-enterprise-#{version}.tar.gz" do 8 | custom_install 'sudo ./installer --auto=/usr/local/ruby-enterprise' 9 | binaries.each {|bin| post :install, "ln -s #{REE_PATH}/bin/#{bin} /usr/local/bin/#{bin}" } 10 | end 11 | 12 | verify do 13 | has_directory install_path 14 | has_executable "#{REE_PATH}/bin/ruby" 15 | binaries.each {|bin| has_symlink "/usr/local/bin/#{bin}", "#{REE_PATH}/bin/#{bin}" } 16 | end 17 | 18 | requires :ree_dependencies 19 | end 20 | 21 | package :ree_dependencies do 22 | apt %w(zlib1g-dev libreadline5-dev libssl-dev) 23 | requires :build_essential 24 | end -------------------------------------------------------------------------------- /config/stack/nginx.rb: -------------------------------------------------------------------------------- 1 | # ========= 2 | # = Notes = 3 | # ========= 4 | 5 | # The phusion guys have made it so that you can install nginx and passenger in one 6 | # fell swoop, it is for this reason and cleanliness that I haven't decided to install 7 | # nginx and passenger separately, otherwise nginx ends up being dependent on passenger 8 | # so that it can call --add-module within its configure statement - That in itself would 9 | # be strange. 10 | 11 | package :nginx, :provides => :webserver do 12 | puts "** Nginx installed by passenger gem **" 13 | requires :passenger 14 | 15 | push_text File.read(File.join(File.dirname(__FILE__), 'nginx', 'init.d')), "/etc/init.d/nginx", :sudo => true do 16 | post :install, "sudo chmod +x /etc/init.d/nginx" 17 | post :install, "sudo /usr/sbin/update-rc.d -f nginx defaults" 18 | post :install, "sudo /etc/init.d/nginx start" 19 | end 20 | 21 | verify do 22 | has_executable "/usr/local/nginx/sbin/nginx" 23 | has_file "/etc/init.d/nginx" 24 | end 25 | end 26 | 27 | package :passenger, :provides => :appserver do 28 | description 'Phusion Passenger (mod_rails)' 29 | version '2.2.10' 30 | binaries = %w(passenger-config passenger-install-nginx-module passenger-install-apache2-module passenger-make-enterprisey passenger-memory-stats passenger-spawn-server passenger-status passenger-stress-test) 31 | 32 | gem 'passenger', :version => version do 33 | # Install nginx and the module 34 | binaries.each {|bin| post :install, "ln -s #{REE_PATH}/bin/#{bin} /usr/local/bin/#{bin}"} 35 | post :install, "sudo passenger-install-nginx-module --auto --auto-download --prefix=/usr/local/nginx" 36 | end 37 | 38 | requires :ruby_enterprise 39 | 40 | verify do 41 | has_gem "passenger", version 42 | binaries.each {|bin| has_symlink "/usr/local/bin/#{bin}", "#{REE_PATH}/bin/#{bin}" } 43 | end 44 | end -------------------------------------------------------------------------------- /config/install.rb: -------------------------------------------------------------------------------- 1 | $:<< File.join(File.dirname(__FILE__), 'stack') 2 | 3 | # Require the stack base 4 | %w(essential scm ruby_enterprise memcached postgresql mysql).each do |lib| 5 | require lib 6 | end 7 | 8 | # =============== 9 | # = Web servers = 10 | # =============== 11 | 12 | # Apache and Nginx are interchangable simply by choosing which file should be included to the stack 13 | 14 | # Apache has some extra installers for etags, gzip/deflate compression and expires headers. 15 | # These are enabled by default when you choose Apache, you can remove these dependencies within 16 | # stack/apache.rb 17 | 18 | require 'apache' 19 | # require 'nginx' 20 | 21 | # What we're installing to your server 22 | # Take what you want, leave what you don't 23 | # Build up your own and strip down your server until you get it right. 24 | policy :stack, :roles => :app do 25 | requires :webserver # Apache or Nginx 26 | requires :appserver # Passenger 27 | requires :ruby_enterprise # Ruby Enterprise edition 28 | requires :database # MySQL or Postgres, also installs rubygems for each 29 | requires :scm # Git 30 | #requires :memcached # Memcached 31 | #requires :libmemcached # Libmemcached 32 | end 33 | 34 | deployment do 35 | # mechanism for deployment 36 | delivery :capistrano do 37 | begin 38 | recipes 'Capfile' 39 | rescue LoadError 40 | recipes 'deploy' 41 | end 42 | end 43 | 44 | # source based package installer defaults 45 | source do 46 | prefix '/usr/local' 47 | archives '/usr/local/sources' 48 | builds '/usr/local/build' 49 | end 50 | end 51 | 52 | # Depend on a specific version of sprinkle 53 | begin 54 | gem 'sprinkle', ">= 0.2.3" 55 | rescue Gem::LoadError 56 | puts "sprinkle 0.2.3 required.\n Run: `sudo gem install sprinkle`" 57 | exit 58 | end -------------------------------------------------------------------------------- /config/stack/nginx/init.d: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | ### BEGIN INIT INFO 4 | # Provides: nginx 5 | # Required-Start: $all 6 | # Required-Stop: $all 7 | # Default-Start: 2 3 4 5 8 | # Default-Stop: 0 1 6 9 | # Short-Description: starts the nginx web server 10 | # Description: starts nginx using start-stop-daemon 11 | ### END INIT INFO 12 | 13 | 14 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 15 | DAEMON=/usr/local/nginx/sbin/nginx 16 | NAME=nginx 17 | DESC=nginx 18 | 19 | test -x $DAEMON || exit 0 20 | 21 | # Include nginx defaults if available 22 | if [ -f /etc/default/nginx ] ; then 23 | . /etc/default/nginx 24 | fi 25 | 26 | set -e 27 | 28 | case "$1" in 29 | start) 30 | echo -n "Starting $DESC: " 31 | start-stop-daemon --start --quiet --pidfile /usr/local/nginx/logs/$NAME.pid \ 32 | --exec $DAEMON -- $DAEMON_OPTS 33 | echo "$NAME." 34 | ;; 35 | stop) 36 | echo -n "Stopping $DESC: " 37 | start-stop-daemon --stop --quiet --pidfile /usr/local/nginx/logs/$NAME.pid \ 38 | --exec $DAEMON 39 | echo "$NAME." 40 | ;; 41 | restart|force-reload) 42 | echo -n "Restarting $DESC: " 43 | start-stop-daemon --stop --quiet --pidfile \ 44 | /usr/local/nginx/logs/$NAME.pid --exec $DAEMON 45 | sleep 1 46 | start-stop-daemon --start --quiet --pidfile \ 47 | /usr/local/nginx/logs/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS 48 | echo "$NAME." 49 | ;; 50 | reload) 51 | echo -n "Reloading $DESC configuration: " 52 | start-stop-daemon --stop --signal HUP --quiet --pidfile /usr/local/nginx/logs/$NAME.pid \ 53 | --exec $DAEMON 54 | echo "$NAME." 55 | ;; 56 | *) 57 | N=/etc/init.d/$NAME 58 | echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 59 | exit 1 60 | ;; 61 | esac 62 | 63 | exit 0 -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Passenger stack, zero to hero in under five minutes 2 | Scripts for [Sprinkle](http://github.com/crafterm/sprinkle/ "Sprinkle"), the provisioning tool 3 | 4 | [Watch the demo screen cast](http://www.vimeo.com/2888665) of passenger-stack. 5 | 6 | ## How to get your sprinkle on: 7 | 8 | * Get a brand spanking new slice / host (Debian or Ubuntu please, other apt-based sytems might work too) 9 | * Install sudo if you are on Debian 10 | * Create yourself a user (use `adduser`), add yourself to the /etc/sudoers file 11 | * Set your slices url / ip address in deploy.rb (config/deploy.rb.example provided) 12 | * Set username in config/deploy.rb if it isn't the same as your local machine (config/deploy.rb.example provided) 13 | 14 | From your local system (from the passenger-stack directory), run: 15 | 16 | sprinkle -c -s config/install.rb 17 | 18 | After you've waited for everything to run, you should have a provisioned slice. 19 | Go forth and install your custom configurations, add vhosts and other VPS paraphernalia. 20 | 21 | ### My app isn't running!? 22 | 23 | No superfluous configuation is included, these scripts focus purely on slice installation. 24 | Having said that passenger is configured to work with apache, your application should pretty much be a 'drop in' install. 25 | 26 | Read [these tips](http://github.com/benschwarz/passenger-stack/wikis/my-app-isnt-running) to get you humming 27 | 28 | Other things you should probably consider: 29 | 30 | * Close everything except for port 80 and 22 31 | * Disallow password logins and use a passphrased RSA key 32 | 33 | #### "Connection reset by peer" 34 | 35 | You can work around this issue by tweaking `/etc/ssh/sshd_config` to include the following on the server: 36 | 37 | ClientAliveInterval 60 38 | ClientAliveCountMax 15 39 | 40 | ### Wait, what does all this install? 41 | 42 | * Apache (Apt) 43 | * Scripts and stylesheets are compressed using mod_deflate 44 | * ETags are applied to static assets 45 | * Expires headers are applied to static assets 46 | 47 | or 48 | 49 | * Nginx (Source) 50 | 51 | * Ruby Enterprise (Source) [includes rubygems] 52 | * Passenger (Rubygem) 53 | * Memcached (Apt) 54 | * Libmemcached (Source) 55 | * MySQL (Apt) or PostgreSQL (Apt) 56 | * MySQL or PostgreSQL ruby database drivers (Rubygem) 57 | * Git (Apt) 58 | 59 | ## Requirements 60 | * Ruby 61 | * Capistrano 62 | * Sprinkle (github.com/crafterm/sprinkle) 63 | * An Ubuntu or Debian based VPS 64 | 65 | If you're interested in using Fedora or RedHat then maybe you should checkout one of these: 66 | 67 | * http://github.com/nwp/passenger-stack 68 | * http://github.com/l15n/yummy-sprinkles 69 | * http://github.com/kjwierenga/passenger-stack 70 | 71 | ## Thanks 72 | 73 | * [Marcus Crafter](http://github.com/crafterm) and other Sprinkle contributors 74 | * [Slicehost](http://slicehost.com), for giving a free slice for testing passenger stack 75 | * [Nathan de Vries](http://github.com/atnan) for Postgres support 76 | * [Anthony Kolber](http://aestheticallyloyal.com) for the github pages design 77 | * [Stephen Eley](http://github.com/SFEley) for some sanity checks on git dependencies 78 | * [James Chen](http://github.com/ashchan) for finishing the nginx-module support that I never got to. Awesome! 79 | 80 | ## Disclaimer 81 | 82 | Don't run this on a system that has already been deemed "in production", its not malicious, but there is a fair chance 83 | that you'll ass something up monumentally. You have been warned. -------------------------------------------------------------------------------- /config/stack/apache.rb: -------------------------------------------------------------------------------- 1 | package :apache, :provides => :webserver do 2 | description 'Apache2 web server.' 3 | apt 'apache2 apache2.2-common apache2-mpm-prefork apache2-utils libexpat1 ssl-cert' do 4 | post :install, 'a2enmod rewrite' 5 | end 6 | 7 | verify do 8 | has_executable '/usr/sbin/apache2' 9 | end 10 | 11 | requires :build_essential 12 | optional :apache_etag_support, :apache_deflate_support, :apache_expires_support 13 | end 14 | 15 | package :apache2_prefork_dev do 16 | description 'A dependency required by some packages.' 17 | apt 'apache2-prefork-dev' 18 | end 19 | 20 | package :passenger, :provides => :appserver do 21 | description 'Phusion Passenger (mod_rails)' 22 | version '2.2.4' 23 | binaries = %w(passenger-config passenger-install-nginx-module passenger-install-apache2-module passenger-make-enterprisey passenger-memory-stats passenger-spawn-server passenger-status passenger-stress-test) 24 | 25 | gem 'passenger', :version => version do 26 | binaries.each {|bin| post :install, "ln -s #{REE_PATH}/bin/#{bin} /usr/local/bin/#{bin}"} 27 | 28 | post :install, 'echo -en "\n\n\n\n" | sudo passenger-install-apache2-module' 29 | 30 | # Create the passenger conf file 31 | post :install, 'mkdir -p /etc/apache2/extras' 32 | post :install, 'touch /etc/apache2/extras/passenger.conf' 33 | post :install, 'echo "Include /etc/apache2/extras/passenger.conf"|sudo tee -a /etc/apache2/apache2.conf' 34 | 35 | [%Q(LoadModule passenger_module /usr/local/ruby-enterprise/lib/ruby/gems/1.8/gems/passenger-#{version}/ext/apache2/mod_passenger.so), 36 | %Q(PassengerRoot /usr/local/ruby-enterprise/lib/ruby/gems/1.8/gems/passenger-#{version}), 37 | %q(PassengerRuby /usr/local/bin/ruby), 38 | %q(RailsEnv production)].each do |line| 39 | post :install, "echo '#{line}' |sudo tee -a /etc/apache2/extras/passenger.conf" 40 | end 41 | 42 | # Restart apache to note changes 43 | post :install, '/etc/init.d/apache2 restart' 44 | end 45 | 46 | verify do 47 | has_file "/etc/apache2/extras/passenger.conf" 48 | has_file "#{REE_PATH}/ext/apache2/mod_passenger.so" 49 | binaries.each {|bin| has_symlink "/usr/local/bin/#{bin}", "#{REE_PATH}/bin/#{bin}" } 50 | end 51 | 52 | requires :apache, :apache2_prefork_dev, :ruby_enterprise 53 | end 54 | 55 | # These "installers" are strictly optional, I believe 56 | # that everyone should be doing this to serve sites more quickly. 57 | 58 | # Enable ETags 59 | package :apache_etag_support do 60 | apache_conf = "/etc/apache2/apache2.conf" 61 | config = < true 67 | verify { file_contains apache_conf, "Passenger-stack-etags"} 68 | end 69 | 70 | # mod_deflate, compress scripts before serving. 71 | package :apache_deflate_support do 72 | apache_conf = "/etc/apache2/apache2.conf" 73 | config = < 76 | # compress content with type html, text, and css 77 | AddOutputFilterByType DEFLATE text/css text/html text/javascript application/javascript application/x-javascript text/js text/plain text/xml 78 | 79 | # properly handle requests coming from behind proxies 80 | Header append Vary User-Agent 81 | 82 | 83 | eol 84 | 85 | push_text config, apache_conf, :sudo => true 86 | verify { file_contains apache_conf, "Passenger-stack-deflate"} 87 | end 88 | 89 | # mod_expires, add long expiry headers to css, js and image files 90 | package :apache_expires_support do 91 | apache_conf = "/etc/apache2/apache2.conf" 92 | 93 | config = < 96 | 97 | ExpiresActive on 98 | ExpiresDefault "access plus 1 year" 99 | 100 | 101 | eol 102 | 103 | push_text config, apache_conf, :sudo => true 104 | verify { file_contains apache_conf, "Passenger-stack-expires"} 105 | end 106 | --------------------------------------------------------------------------------