Skip to content

Instantly share code, notes, and snippets.

@IanVS
Last active August 29, 2015 14:24
Show Gist options
  • Save IanVS/1b8e5c37f2430ed77a2b to your computer and use it in GitHub Desktop.
Save IanVS/1b8e5c37f2430ed77a2b to your computer and use it in GitHub Desktop.

Revisions

  1. IanVS revised this gist Jul 13, 2015. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions 01-single-ec2-instance.md
    Original file line number Diff line number Diff line change
    @@ -115,6 +115,7 @@ The EC2 box is built, the application code is deployed, and now we are ready to
    Notice the two sets of double dashes. The sails option for production is `--prod`, but in order for pm2 to pass arguments to the app, you need another set of `--`.

    1. Start App on server boot

    Congratulations, you just deployed your app. You should be able to visit the public IP given to your EC2 instance and see the app. Technically this is all you need to do. But wouldn't it be nice if the app would start up automatically if the server reboots? Maybe you're still testing and you want to start and stop the EC2 instance to save cost. If so, this is what you want:

    ```
  2. IanVS renamed this gist Jul 13, 2015. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. IanVS renamed this gist Jul 13, 2015. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  4. IanVS revised this gist Jul 13, 2015. 2 changed files with 0 additions and 0 deletions.
    File renamed without changes.
    File renamed without changes.
  5. IanVS revised this gist Jul 13, 2015. 2 changed files with 3 additions and 4 deletions.
    3 changes: 3 additions & 0 deletions 01-intro
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    # SANE deployment

    You’ve created a web app using the SANE stack (using an Ember.js client and a Sails.js API), and now you’re ready to get it out there for the world to see. There are many ways to handle deployments, with varying complexity and tradeoffs. This series of posts will present a few of those methods, with increasing levels of complexity, for deploying your app to AWS. There are many options of where to deploy your app, including Heroku, Firebase, DigitalOcean, AWS, and others. I’ve chosen to use AWS as it is currently the largest and most well-known.
    4 changes: 0 additions & 4 deletions single-ec2-instance.md
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,3 @@
    # SANE deployment

    You’ve created a web app using the SANE stack (using an Ember.js client and a Sails.js API), and now you’re ready to get it out there for the world to see. There are many ways to handle deployments, with varying complexity and tradeoffs. This series of posts will present a few of those methods, with increasing levels of complexity, for deploying your app to AWS. There are many options of where to deploy your app, including Heroku, Firebase, DigitalOcean, AWS, and others. I’ve chosen to use AWS as it is currently the largest and most well-known.

    ## Setting up a single EC2 Instance

    When your app is young and you have between 0 and 100 users, it makes sense to keep the architecture as simple as possible. This means running all the pieces of your app (web server, database, API server, etc.) on a single EC2 instance.
  6. IanVS renamed this gist Jul 13, 2015. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  7. IanVS created this gist Jul 13, 2015.
    130 changes: 130 additions & 0 deletions single-ec2-instance
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,130 @@
    # SANE deployment

    You’ve created a web app using the SANE stack (using an Ember.js client and a Sails.js API), and now you’re ready to get it out there for the world to see. There are many ways to handle deployments, with varying complexity and tradeoffs. This series of posts will present a few of those methods, with increasing levels of complexity, for deploying your app to AWS. There are many options of where to deploy your app, including Heroku, Firebase, DigitalOcean, AWS, and others. I’ve chosen to use AWS as it is currently the largest and most well-known.

    ## Setting up a single EC2 Instance

    When your app is young and you have between 0 and 100 users, it makes sense to keep the architecture as simple as possible. This means running all the pieces of your app (web server, database, API server, etc.) on a single EC2 instance.

    ### Step 1: Choose and Create EC2 Instance

    The first thing to do is pick out a base image to use for your instance. As of July, 2015, the image I’ve chosen to use is “Ubuntu Trusty 14.04 LTS hvm (x64)” with SSD disk storage. You can use http://cloud-images.ubuntu.com/locator/ec2/ to find the image you want to use, which will depend on your region. I’m in us-east-1, so I will use "ami-c135f3aa". This isn’t intended to be an in-depth guide on AWS itself, so I won’t get into the step-by-step of how to create the instance, but there are plenty of resources out there to take you through that process.

    ### Step 2: Configure

    Once your EC2 instance is up and running, you will need to SSH in so that you can make some changes. In more advanced methods, you will never need to manually log in to an individual instance, but that will come later. After you are logged in, perform the following actions:

    1. Update apt-get repository and installed packages

    ```
    sudo apt-get update
    sudo apt-get -y upgrade
    ```

    1. Install node

    There are many ways to install node.js on a system. Feel free to use whatever way you are comfortable with. The simplest and quickest way I have found is with using [Nave](https://www.npmjs.com/package/nave) from Isaac Schlueter. The method below will take ownership of some directories in `/usr/local`, which is fine as long as you don't plan to run the EC2 instance with a user other than the default `ubuntu`. It will install the latest stable version of node.js, but you may also specify a version in place of `stable` on the last line.

    ```
    mkdir ~/.nave
    cd ~/.nave
    wget http://github.com/isaacs/nave/raw/master/nave.sh
    chmod u+x nave.sh
    sudo ln -s $PWD/nave.sh /usr/local/bin/nave
    sudo mkdir -p /usr/local/{share/man,bin,lib/node,lib/node_modules,include/node}
    sudo chown -R $USER /usr/local/{share/man,bin,lib/node,lib/node_modules,include/node}
    nave usemain stable
    ```

    To verify node installed correctly, use `node --version`

    1. Install NPM

    ```
    wget -O - http://npmjs.com/install.sh | sh
    ```

    1. Install Ember, Sails, and other dependencies and tools

    ```
    npm i -g sails
    npm i -g ember-cli
    npm i -g bower
    npm i -g pm2

    sudo apt-get install -y git
    ```

    Additionally, you will need to install the database you are using (MySQL, PostgreSQL, MongoDB, etc.), as well as any other packages you may need like `make` and `g++`.


    ### Step 3: Deploy App Code

    Now that your EC2 instance is set up with the necessary environment, you need some way to get your application code to the server. There are many ways to do this, and I will be exploring other methods in future posts, but as a simple first step you can just clone it from your git repository. In this section, that's what we will do, and we will get the application to the point where it is ready to start.

    1. Clone project into a directory

    ```
    cd ~
    git clone <git repo url>
    ```

    1. Install project dependencies

    If you've gotten to the point of deploying your app, you likely know how all this goes, but I'm including it here for the sake of completeness. Assuming you use the default SANE structure of using `client` and `server` directories, it will look like this:

    ```
    cd <project-dir>
    npm i
    cd server
    npm i
    cd ../client
    bower install
    npm i
    ```

    1. Build your ember app for production

    You now need to run your Ember app through a production build to concatenate, minify, etc. From the client directory, run:

    ```
    ember build --environment=production --output-path=../server/assets/
    ```

    This will replace the default index.html which Sails comes with, so that users will get the Ember app instead.

    ### Start the App

    The EC2 box is built, the application code is deployed, and now we are ready to fire it up. As always, there is a little yak shaving to get out of the way first.

    1. Allow Node to listen on low ports

    In Linux systems, root permissions are usually required in order for a process to listen on a port below 1024. We want our web app to listen on port 80 (HTTP) and possibly 443 (SSL), so we will need to make some changes. There are two main ways to handle this. The most robust is to add a web server like Nginx as a reverse proxy which forwards requests to the Node.js app. I'll cover that in a future blog post, but in the interest of keeping things simple for now, we will just give the sails app permissions to listen on low ports.

    ```
    sudo apt-get install -y libcap2-bin
    sudo setcap cap_net_bind_service=+ep /usr/local/bin/node
    ```

    See http://technosophos.com/2012/12/17/run-nodejs-apps-low-ports-without-running-root.html for more details on what we're doing here.

    1. Start App

    You could just start your Sails app in production mode at this point, and you would have a working app. However, if it ever died for some reason, your site would go down and you would manually have to start it back up. Ain't nobody got time for that, so we are going to use PM2 instead. From within your `server` directory:

    ```
    pm2 start app.js -- --prod
    ```

    Notice the two sets of double dashes. The sails option for production is `--prod`, but in order for pm2 to pass arguments to the app, you need another set of `--`.

    1. Start App on server boot
    Congratulations, you just deployed your app. You should be able to visit the public IP given to your EC2 instance and see the app. Technically this is all you need to do. But wouldn't it be nice if the app would start up automatically if the server reboots? Maybe you're still testing and you want to start and stop the EC2 instance to save cost. If so, this is what you want:

    ```
    sudo env PATH=$PATH:/usr/local/bin pm2 startup -u $USER
    ```

    ## Summary

    You have a running application with a little bit of fanciness like autorestart. But once you start getting users you're going to want to improve the architecture to make it easier to deploy, scale, and manage. In future posts we will discuss adding a reverse proxy and load balancer, as well as configuration management and continuous deployment techniques.