Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Automate deployment with Capystrano Rails passenger

Setting up new Ubuntu 14.04 server with Nginx, Passenger, Postgresql, RVM, Ruby, Rails

Step 0: Setting up the new EC2 instance

NOTE: We can now use an AMI for this. Once you enter the launch wizard make sure that "My AMIs" and "Shared with me" is selected and then search for the term "Rotati". Select the Rotati Staging AMI and continue with the wizard. This AMI will have everything you need to run the staging application (so no need to run though the process below if everything is working on the AMI already!)

  • Launch the AWS instance in Singapore region (unless the client specially stated to launch in a different region). For Staging use t2.micro. For Production use t2.micro (and higher).
  • Configure the settings as per the wizard. Ensure to enable termination protection. Most other settings can remain unchanged.
  • Create a new security group for the server giving it a meaningful name (e.g. the name of the project). Open only the ports that are required which are generally HTTP, HTTPS and SSH. Ensure that SSH is only accessible from your current IP.
  • Verify the settings and launch the instance.
  • For Production servers only, create a new Elastic IP and accociate that to the new instance by right clicking on the new IP address and selecting 'Associate Address'
  • SSH into the server using the following command. Ensure that you have allowed your IP address in the SSH settings for the servers security group!
chmod 600 keypair.pem
ssh -i keypair.pem ubuntu@new.elasitic.ip
  • Add you and your admins SSH key(s) to the .ssh/authorized_keys file on the server. Log out of the server and then SSH back in using:
ssh ubuntu@new.elastic.ip

Everything from now on assumes that you have already SSH into your ubuntu server, and you are currently on the remote server machine.

Step 1: Creating a swap memory (Skip this if your server memory is larger than 2GB)

If your server memory (RAM) is low (2GB or less), it is a good practice to create another swap memory in case your memory is full.

sudo apt-get -y update
sudo /bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=2048
sudo /sbin/mkswap /var/swap.1
sudo /sbin/swapon /var/swap.1

then add this line of code in to your /etc/fstab:

/var/swap.1 swap swap defaults 0 0'

Rebooting your server

sudo reboot

Step 2: Installing the following software

sudo apt-get -y install curl git-core python-software-properties htop git-core curl build-essential zlib1g-dev libssl-dev libreadline6-dev libcurl4-openssl-dev

The above command will install git, curl, htop and some other required softwares.

Installing imagemagick

sudo apt-get install libmagickwand-dev imagemagick

Installing Postfix if your app need to send out email:

sudo apt-get -y install telnet postfix

Just select all the default options.

Installing NodeJS (for asset precompiling)
sudo apt-get install nodejs
sudo apt install nodejs-legacy

Step 3a: Installing PostgreSQL (STAGING ONLY)

sudo apt-get -y install postgresql libpq-dev

It's a good practice to add password to the postgres user:

Login to database console with user postgres

sudo -u postgres psql

In the database console, type the following command:

\password 

Input your password, then type \q to exit the console.

Create a new user for postgres database (skip this step if you don't need a new database user):

We would suggest to create a database user rather using postgres user, usually the user you will be using in your rails app

sudo -u postgres psql

In your database console, type the following command:

Note: replace the any_user to the username you want to created, and change the secret to any password to you want to use.

create user any_user with password 'secret';
ALTER USER any_user CREATEDB;

Step 3b: Installing PostgreSQL on RDS (PRODUCTION ONLY)

In the PRODUCTION environment we use RDS for the database so we DON'T need to install PostgresSQL on the EC2 application server instance, however we DO need the psql client tools which can be installed by running apt-get install postgresql-client and sudo apt-get install libpq-dev.

To install Postgres using RDS just follow the wizard in the RDS console and use the following settings:

  • DB Engine Version: Latest Version of Postgres
  • DB Instance Class: db.t2.micro
  • Multi-AZ Deployment: NO (unless there is budget)
  • Storage Type: General Purpose (SSD)
  • Allocated Storage*: 20GB
  • DB Instance Identifier: (Use the project name)
  • Availability Zone: (Use the same as the EC2 Instance that will connect to this database)
  • Backup Retention Period: 7 days
  • Auto Minor Version Upgrade: Yes
  • Public Accessibility: No
  • Enable Deletion Protection: Yes

Other settings, use your judgment!

NOTE You must make sure that security group in RDS accept your EC2 private IP (Not public IP).

Step 4: Creating a new deployer user

Type the following command then enter the password for the new user (change 'deployer' to the username you desire):

sudo adduser deployer --ingroup admin

Login to the deployer user:

sudo su deployer

Step 5: Installing RVM, Ruby, Rails, Passenger

With deployer user, now we could start installing RVM, Ruby, Rails and Passenger

Installing RVM
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3

curl -sSL https://get.rvm.io | bash -s stable

Reload .bash_profile by running: source ~/.bash_profile.

Installing Ruby
rvm install 2.2.0
rvm use --default 2.2.0
rvm rubygems current

Command above will install ruby version 2.2.0 and uses it as a default, and use rubygems.

_Note_ If you're using Ruby 2.2.3 . Run the below command, otherwise skip it!*

sudo apt-get install libgmp3-dev

Install PCRE for nginx regex syntax recognition

sudo apt-get install libpcre3 libpcre3-dev

Installing Nginx with Passenger

Installation
# Install PGP key and add HTTPS support for APT
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 561F9B9CAC40B2F7
sudo apt-get install -y apt-transport-https ca-certificates

# Add APT repository
sudo sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger xenial main > /etc/apt/sources.list.d/passenger.list'
sudo apt-get update

# Install Passenger + Nginx
sudo apt-get install -y nginx-extras passenger
Enable the Passenger Nginx module and restart Nginx

Edit /etc/nginx/nginx.conf and uncomment include /etc/nginx/passenger.conf;. For example, you may see this:

include /etc/nginx/passenger.conf;

Type the following command to start server

sudo service nginx start

You should be able to visit your website through your server public IP via any browser now. The Nginx Welcome page should appear.

Step 6: Configure Nginx, Passenger

Once nginx installed, all the configuration files should be located in /etc/nginx/sites-available

Open /etc/nginx/sites-available/default with sudo privilege using your favorite editor, in our case, we use Vim:

sudo vim /etc/nginx/sites-available/default

Replace the file content with the following content:

server {
  listen 80;
  server_name default _;

  location / {
    root /var/www/test_app/current/public;
    passenger_enabled on;
    rails_env staging;
  }

  location ~ \.(js|css|png|jpg|jpeg|gif|ico|html)$ {
    root /var/www/test_app/current/public;
    expires max;
    gzip_static on;
    add_header Cache-Control public;
    break;
  }

  location ^~ /assets/ {
    root /var/www/test_app/current/public;
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  # Drop requests to non-rails requests
  location ~ \.(aspx|php|jsp|cgi|asp) {
    return 410;
   }
}

Replace the test_app with your project directory name. You need to make sure that you clone your project and put it under /var/www/test_app

You need to create a /var/www/ directory

sudo mkdir /var/www

Then change the ownership of the directory to deployer

cd /var
sudo chown -R deployer:admin www

Clone your rails app into the /www directory.

cd www
git clone git@github.com:rotati/test_app.git

Create a restart.txt file in test_app tmp folder.

cd /test_app
mkdir tmp
touch tmp/restart.txt

Restart your Nginx Service (NOTE: this also restarts Passenger)

sudo service nginx restart

To reload Nginx configuration you may need to run:

sudo service nginx reload

Visit your public IP or domain and you should see your app is live.

Step 7: Setup upstart script using foreman gem

If your project requires, setup upstart files:

rvmsudo foreman export upstart /etc/init -a appname -u deployer --env=/var/.env --log=/var/log
cat /etc/init/...

Note that in the /var/.env file you need to put all the environment variables for the application so they are picked up by the upstart script. For example some environment variables might be:

export RACK_ENV=production
export RAILS_ENV=production
etc...

View production logs:

sudo tail /var/log/upstart/appname-web-1.log

Start appname service (other commands e.g. stop follow a similar pattern)

sudo service appname start

Step 8: Ensure that you have all the required monitoring services setup for the application

Suggested Services for an Application

Main services are:

  • Error management handling using Errbit
  • User profiling and statistics monitoring using Google Analytics
  • Application performance monitoring using NewRelic
  • Server performance monitoring using CloudWatch

Step 9: Ensure the server is locked down and secure!

Step 10: Ensure that all services restart when the server is rebooted

Go to init.d folder (place where linux execute when server started)

cd /etc/init.d

Create service file to run on boot

sudo vim service-name.sh

In service-name.sh file, place code we want to make it run Eg: ``` #!/bin/bash

  # this script starts the nginx process attached to passenger  

  sudo /opt/nginx/sbin/nginx

  ```

Make the file executable

sudo chmod +x /etc/init.d/service-name.sh

You can test if the file run correctly by running the script

sudo /etc/init.d/service-name.sh

Update it to make changes

sudo update-rc.d service-name.sh defaults

Final Step: Ensure that a Billing Alarm is set to determine when an agreed threshold is reached.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment