Deploying Reason on AWS Elastic Beanstalk with RDS
Tags: reason, aws, devops
Published: 2018-06-13 22:16:12

---
title: Deploying Reason on AWS Elastic Beanstalk with RDS
published: true
description: Notes on setting up Amazon Elastic Beanstalk to run a Node app written in Reason using an RDS database
tags: reasonml, aws, devops
---

This isn’t a step-by-step guide. It’s more like a selection of points that the author has just spent too much time getting all flamboozled over,  that have been written down now in hopes that some poor kindred spirit (including that same author) won’t have to re-experience the pain necessary just to get a Reason service running on AWS EBS.

The first thing to do is get the `eb` utility installed (`eb` standing for “Elastic Beanstalk”, of course). You can get it on either `homebrew` or `pip`. The details you can figure out all on your own (good luck!).

Run these commands and follow the prompts. Mostly the default values are okay.

- `eb init`
- `eb create`

That’s all normal stuff. Buckle up for the juicy details:

# Bundling
Compiled reason code depends on javascript that’s included in the `bs-platform` NPM package. The problem is that said package also will build an entire OCaml compiler, and if you’re trying to deploy code on anything smaller than a not-small server, you’re going to have a prohibitively hard time.

A relatively simple solution is to do a little bit of bundling before shipping your code. You’ll use `webpack` to bundle up your compiled Reason code into a little neat package before deploying to EBS.

On reading the mention of Webpack, you might be wiping sweat from your brow, anxiously telling yourself that you don’t feel an aching throb at the back of your skull at the thought of having to dig into yet another Webpack config. But don’t worry. It’s a tiny file that’s simple to understand:

*webpack.config.js* ->
```
var nodeExternals = require('webpack-node-externals');


module.exports = {
  entry: './src/index.js',
  target: "node",
  output: {
    filename: 'bundle.js',
    libraryTarget: 'commonjs2',
    path: __dirname
  },
  externals: [nodeExternals({
    whitelist: [/^bs-platform/, /\.bs\.js$/]
  })],
  mode: "development",
  devtool: "sourcemap"
};
```

You’ve included a Webpack plugin that automatically tells Webpack *not to bundle* anything at all that’s found in the `node_modules` folder. Which is good! Because most of that stuff will be provided when the deploy process runs `npm install`, and also good because some of the things in there won’t be happily bundled.

You’ll want to add that plugin to your project with the following command (assuming you’re using Yarn. If you’re using NPM you’re straight outta luck. Just kidding. You know what to do):

```
yarn add -D webpack-node-externals
```

![](https://thepracticaldev.s3.amazonaws.com/i/0ptcuig2u7zhbngat8w9.jpg)

but you’ll see that you’ve passed a config object when calling `nodeExternals(..)` with the key `whitelist`. This is an array of things that you *do want to be bundled*.

So, to repeat in simpler words, you set up Webpack, and used a plugin to say “don’t bundle anything in node_modules *except this list of things*.

That list of things looks like this:

`[/^bs-platform/, /\.bs\.js$/]`

Those are two regular expressions. The first includes any JS used from the `bs-platform` module, and the second is any file referenced inside of node_modules that uses the extension `.bs.js`.

That second entry is important, because when you run the `bsb` compiler while developing, the compiled JS artifacts get dropped inside of the `node_modules` folder (like `node_modules/bs-foo/lib/js/foo.bs.js` for example).

Now just :

```
yarn add -D webpack-command
#^ this is smaller and faster than webpack-cli AFAIK
```

Then `yarn webpack`, and you should get a generated `bundle.js` in the root of your project.

You can then add `node bundle.js` to your `start` command in your package json, and EBS should do what’s expected when you deploy. BTW, you’ll want to have your server code listen on `8081`, or whatever the `PORT` ENV var is set to.

## Cleaning up your deps
Now, open up your package.json, and move every package that isn’t a strict *runtime* dependency from `dependencies` to `devDependencies`. Including all the Bucklescript packages you’ve installed (because you bundled them already), and *especially* including `bs-platform`.

# Deploying
When I first tried a deploy, EBS was trying to zip up my whole code folder, including node modules, and ship it off for deployment. That’s obviously huge and unwieldy and not what we want at all for deployment. So do this instead:

Create a file called `.ebignore` and put inside:

`
node_modules/
`

Make sure the trailing slash is there!

After that, you should be able to `eb deploy`, and have a relatively quick deployment.

# RDS
The author of this post would still be trying to keep himself from bursting small blood vessels in his face if it weren’t for this Front-end Master’s course on Node and AWS EBS: https://frontendmasters.com/courses/production-node-aws. The information following is taken from that course. So if you have money and want to learn, consider giving some to those peeps.

First step, add an RDS database. That should be pretty simple to figure out on your own.

Here’s the more detailed stuff.

- When you deployed your EB application, a new security group was created for it, and you can find the name of that security group in the config console for your EB application.
- You need to add your RDS instance to that same security group in its configuration console.

Here’s the part that might seem surprising. It might seem that if the RDS instance and the EB instance are in the same security group, they should be intimate security buddies and open to all kinds of communication. But, nope.

- You need to edit the incoming permissions for that security group, and open up the port your database is listening on to incoming traffic *from the selfsame security group*. You need to tell it that it can access itself!

![](https://thepracticaldev.s3.amazonaws.com/i/p05voxx5uvldy8ul98ax.jpeg)

You’ll see in the snap above that security group `sg-9...` now specifies that it should allow traffic on port 5432 from security group `sg-9...` (the same group).

After you’ve done this, EB and RDS should be able to talk.

## S3
If your application uses S3, you might be worried that you’d have to do silly shenanigans to allow that connection, but it should “just work”(tm).
 
# Little tips for troubleshooting
- You can SSH into a running EB instance by typing `eb ssh`
- The process runs under the user `nodejs`,  but you can’t `su` to that user. Don’t try. Someone did, and they got rejected. And rejection hurts.
- The logs for the node process live in `/var/logs/nodejs/nodejs.log`
- You can tail those logs with this command `tail -f /var/logs/nodejs/nodejs.log`
- Trying to run things like `npm start` by hand is a pain. 
-  You can run `npm install` by first changing to the root user with `sudo su` and then running this command: `/opt/elasticbeanstalk/containerfiles/ebnode.py --action npm-install`
- While deploying, you can find your application code in `/tmp/deploy/...`
- After deploy, you can find your application code in `/var/app`
- If you’re having a hard time connecting to some other box and port from your instance, you can run `nc -vf <host> <port>` from your EB box to see if it can reach that port or not. This helped a lot when figuring out the connection between EB and RDS.

![](https://thepracticaldev.s3.amazonaws.com/i/ygoyrhjlpz3nru1nqoi5.jpg)