Skip to content
pekman edited this page Mar 26, 2012 · 21 revisions

The deployment system is implemented with Vlad. The script is in config/deploy.rb. This file contains server settings, deployment path and the git repository URL at the start.

The script currently uses Ruby through rbenv, which allows installation of several Ruby versions and easy switching between them. The different versions are under the directory ~/.rbenv/versions on the server and the version the application uses is specified in the file .rbenv-version in the git repository. Please note that Phusion Passenger doesn't support rbenv and if the application's Ruby version is changed, Passenger's configuration (in /opt/nginx/conf/nginx.conf) must be changed to reflect the change.

When everything is set up, the deployment is done with the following command:

rake vlad:deploy

Current settings (at Soberit)

You need a private ssh key to access the Amazon EC2 server (e.g. in ~/.ssh/aapps).

Ssh in the local computer needs to be set up to use the correct ssh key to when connecting to EC2 server. This can be done by adding the following lines to ~/.ssh/config:

Host aaltoapps.fi aaltoapps.com aaltoapps.net
    IdentityFile ~/.ssh/aapps
    User aaltoapps
    ForwardAgent yes

Server setup

This guide is for Ubuntu 11.10 running in an Amazon EC2 server.

  1. Create a new user account. The application will run under this account and the account will be used for deployment. The following steps are done as this user. The user needs sudo privileges for this to work.

  2. Install the following packages (sudo apt-get install package1 package2 ...):

    • gcc
    • g++
    • make
    • automake1.9
    • git
    • postgresql
    • nodejs or some other Javascript runtime that works with ExecJS
    • imagemagick
      • it's probably best to install this with the apt-get flag --no-install-recommends
    • zlib1g-dev
    • libcurl4-openssl-dev or libcurl4-gnutls-dev
    • libssl-dev
    • libpq-dev
    • language-pack-en and other language packs you might use
      • PostgreSQL uses these for collation and other locale-specific string handling
      • install these with the apt-get flag --no-install-recommends to prevent the installation of Firefox language packs

    If some of the -dev-packages are not installed, ruby-build may silently skip building some of its core modules, which some gems may require.

  3. Install ruby-build:

    git clone git://github.com/sstephenson/ruby-build.git
    cd ruby-build
    sudo ./install.sh
  4. Install rbenv:

    cd
    git clone git://github.com/sstephenson/rbenv.git .rbenv
    echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> .profile
    echo 'eval "$(rbenv init -)"' >> .profile
  5. Install the latest stable Ruby under ~/.rbenv/versions/ and set it as the default ruby:

    ruby-build 1.9.2-p290 $HOME/.rbenv/versions/1.9.2-p290
    rbenv rehash
    rbenv global 1.9.2-p290

    Note: As of version 3.0.11 Phusion Passenger doesn't seem to work with Ruby 1.9.3.

  6. Install Nginx and Phusion Passenger:

    gem install passenger --no-rdoc --no-ri
    rbenv rehash
    sudo sh -c "PATH=\"$PATH\" passenger-install-nginx-module \
        --auto \
        --prefix=/opt/nginx \
        --auto-download \
        --extra-configure-flags='\
            --with-http_gzip_static_module \
            --with-http_ssl_module'"

    The option --with-http_ssl_module is optional.

    • Create a directory for the application and give yourself write permissions to it:

      sudo mkdir -p /deployment_path
      sudo chown your_username:your_groupname /deployment_path

      In Ubuntu your_groupname is typically the same as your_username.

    • Edit Nginx configuration in file /opt/nginx/conf/nginx.conf. For basic installation replace server section with the following:

      server {
          listen 80;
          server_name domain.name.of.the.server alternate.domain.name ...;
          root /deployment_path/current/public;
          passenger_enabled on;
          
          location ~ ^/assets/ {
              # Some browsers still send conditional-GET requests if there's a
              # Last-Modified header even if they haven't reached the expiry
              # date sent in the Expires header. The same applies to ETag
              # headers, but Nginx does't generate them.
              add_header Last-Modified "";
              
              gzip_static on;  # serve pre-gzipped versions of files
              expires max;
              add_header Cache-Control public;
          }
      }
    • passenger-install-nginx-module doesn't seem to create init script for Nginx, so we have to do it ourselves:

      1. Create file /etc/init.d/nginx as root with the following contents:

        #!/bin/sh
        
        ### BEGIN INIT INFO
        # Provides:          nginx
        # Required-Start:    $all
        # Required-Stop:     $all
        # Default-Start:     2 3 4 5
        # Default-Stop:      0 1 6
        # Short-Description: starts the nginx web server
        # Description:       starts nginx using start-stop-daemon
        ### END INIT INFO
        
        PATH=/opt/nginx/sbin:/sbin:/bin:/usr/sbin:/usr/bin
        DAEMON=/opt/nginx/sbin/nginx
        NAME=nginx
        DESC=nginx
        
        test -x $DAEMON || exit 0
        
        # Include nginx defaults if available
        if [ -f /etc/default/nginx ] ; then
                . /etc/default/nginx
        fi
        
        set -e
        
        case "$1" in
          start)
                echo -n "Starting $DESC: "
                start-stop-daemon --start --quiet --pidfile /opt/nginx/logs/$NAME.pid \
                        --exec $DAEMON -- $DAEMON_OPTS
                echo "$NAME."
                ;;
          stop)
                echo -n "Stopping $DESC: "
                start-stop-daemon --stop --quiet --pidfile /opt/nginx/logs/$NAME.pid \
                        --exec $DAEMON
                echo "$NAME."
                ;;
          restart|force-reload)
                echo -n "Restarting $DESC: "
                start-stop-daemon --stop --quiet --pidfile \
                        /opt/nginx/logs/$NAME.pid --exec $DAEMON
                sleep 1
                start-stop-daemon --start --quiet --pidfile \
                        /opt/nginx/logs/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS
                echo "$NAME."
                ;;
          reload)
                  echo -n "Reloading $DESC configuration: "
                  start-stop-daemon --stop --signal HUP --quiet --pidfile     /opt/nginx/logs/$NAME.pid \
                      --exec $DAEMON
                  echo "$NAME."
                  ;;
              *)
                    N=/etc/init.d/$NAME
                    echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
                    exit 1
                    ;;
        esac
        
        exit 0

        (copied from http://library.linode.com/frameworks/ruby-on-rails-nginx/ubuntu-10.10-maverick)

      2. sudo chmod +x /etc/init.d/nginx

      3. Run the command: sudo update-rc.d -f nginx defaults

      4. Start Nginx: sudo /etc/init.d/nginx start

  7. Set up PostgreSQL database

    • Edit /etc/postgresql/9.1/main/pg_hba.conf as root and add the line:

      local   all         all                               md5
      
    • Restart PostgreSQL (sudo /etc/init.d/postgresql restart)

    • sudo -u postgres psql postgres:

      postgres=# CREATE ROLE aaltoapps WITH LOGIN PASSWORD 'database_password';
      postgres=# CREATE DATABASE aaltoapps OWNER aaltoapps;
      postgres=# \q
      
  8. Set up mail server

    The application needs a mail server to send notification emails. The sending of these emails is a blocking operation, which means that when a user performs an action that causes an email to be sent, the rendering of the page is delayed until the email has been sent or an error or a timeout occurs. Therefore it is recommended that a local email server is installed even if it just sends all the emails to another mail server.

    To install Postfix and configure it to only send mail run the following command:

    sudo apt-get install postfix

    Select "Satellite system". If the emails are to be sent directly to the recipient's server, set "SMTP relay host" to blank. Double-check that the mail server listens for connections only from the loopback interface.

  9. Configure and deploy the application

    • do the following on your computer (not on the server):

      1. Set up a development environment
      2. Make sure that settings in the file config/deploy.rb are correct and that you have ssh access to the server
      3. Run the following command in the development directory: bundle exec rake vlad:setup
    • do the following on the server:

      1. run these commands:

        cd /deployment_path
        mkdir shared/config
        touch shared/config/{aaltoapps_config.yml,database.yml}
        chmod go= shared/config/{aaltoapps_config.yml,database.yml}
      2. edit shared/config/database.yml:

        production:
          username: aaltoapps
          password: database_password
          database: aaltoapps
          adapter: postgresql
        
      3. Copy config/aaltoapps_config.yml or config/aaltoapps_config_example.yml in your development directory to shared/config/aaltoapps_config.yml and edit it to suit your needs

      4. install Bundler:

        gem install bundler --no-rdoc --no-ri
    • on your computer in the development directory:

      bundle exec rake vlad:deploy

      If the deployment fails, it may be because of a missing library. In that case install the library on the server and try again.

  10. Create an administrator account

    • do the following in a web browser:

      1. Go to the application's main page.

      2. Either create a new user or log in as an existing user.

      3. Look at the user information page URL (The link in "Logged in as "). It contains the numerical user id.

    • do the following on the server replacing <id> with the numerical user id:

      cd /deployment_path
      env RAILS_ENV=production bundle exec rake role:grant:admin[<id>]

      (see Managing admin roles from command line for further information)

    • now you can give other users administrator privileges using the web interface

Upgrading Nginx and Phusion Passenger

If you have multiple ruby versions installed with rbenv, select the version that the rails application is using:

rbenv shell 1.9.2-p290

Run the same commands as in installing Nginx and Phusion Passenger except that instead of the gem install command run the update command:

gem update passenger --no-rdoc --no-ri

The install/update script asks you to change configuration settings in /opt/nginx/conf/nginx.conf. Follow the instructions.