Let’s Build |> a Slack Clone with Elixir, Phoenix, and React (part 7 — Deploy to Heroku & AWS S3)

Live Demo — GitHub Repo
Part 1 — Part 2 — Part 3 — Part 4 — Part 5 — Part 6 — Part 7

We have a fully functioning Phoenix and React app at this point that lets users register, create a chat room, send and receive messages in real time, and see a list of all active users in a room.

The last step is to deploy our application. Heroku is the easiest way to deploy a Phoenix application, so that is what we’ll be doing . Then I am going to push the React app to an AWS S3 bucket set up for static website hosting.

The Phoenix Framework has great docs for Herkou deployments, so I recommend starting there. Here I’ll be walking through exactly what I did.

Note: Heroku expects your app to be in the root directory of your git repo. In this blog post, I created the Phoenix app in the /api subdirectory, so the deployment command will be a little different. But to run the heroku commands, you will need to be in the root of your git repo.

Create the heroku app

heroku create --buildpack "https://github.com/HashNuke/heroku-buildpack-elixir.git"

The Phoenix docs then say to add a buildpack for static assets. However, we created our app with the no-brunch option, and will not be including any static assets in the api, so I am skipping that step.

Edit the prod.exs endpoint config to use your Heroku app’s url for the endpoint, and get the secret_key_base from an environment variable. Also, add a Repo config block for our production database. Then remove the import_config statement at the bottom.

Note: The original configuration caused 301 & 403 errors in Safari and Firefox for websocket connections, below is my current working code. It is important to include the frontend domain in check_origin, and I did could not use force_ssl option like the Phoenix docs.
sling/api/config/prod.exs

Update this line in user_socket.ex to add a 45 second timeout:

sling/api/web/channels/user_socket.ex

Create a Procfile in the Phoenix root

sling/api/Procfile

Add the Heroku PostgreSQL addon

heroku addons:create heroku-postgresql:hobby-dev

Set the POOL_SIZE env variable

heroku config:set POOL_SIZE=18

Create a new secret to be used as secret_key_base (you will need to be in the Phoenix app root to run the mix task)

mix phoenix.gen.secret

Use that new secret and set it as the secret_key_base variable in heroku

heroku config:set SECRET_KEY_BASE="your generated secret"

We had previously configured Guardian to use a GUARDIAN_SECRET_KEY in prod.exs, so generate another secret, then set that heroku variable

heroku config:set GUARDIAN_SECRET_KEY="your guardian secret"

Now we can deploy to Heroku — remember: we are deploying the Phoenix app from the /api subdirectory

git subtree push --prefix api heroku master

Hopefully that command successfully deployed your application. Next, run our database migrations:

heroku run "POOL_SIZE=2 mix ecto.migrate"

That should be it on the API side. If you run heroku open, it will open your browser to the Phoenix welcome page. Then if you navigate to /api/rooms, you should get a Not Authenticated error in json, so we know our API is working.

Here is our git commit with the Heroku production configuration

Frontend deployment

There are many ways to deploy a React application, at the end of the day its just one html, js, and css file. I’ll be deploying my site to an AWS S3 bucket.

Checkout out the AWS docs for how to configure an S3 bucket for static website hosting.

I use a nifty script for making my deployments easy. First, I’ll need to install the s3 and dotenv npm packages

yarn add s3 dotenv

Then you will need to define a few secret AWS variables in .env based on your AWS account. Checkout the .env.example file for an example.

Afterwards, add two new npm commands to your package.json scripts

"upload": "node scripts/upload.js",
"deploy": "rm -rf build && npm run build && npm run upload"

Then you will have to create the upload.js script. View the file here.

Finally, you can run the deploy command, which will build the React app in a production optimized bundle in the /build directory, and then sync that directory to your S3 bucket.

When you run deploy, you should specify the REACT_APP_API_URL as your Heroku app’s API url, so it overrides our dotenv config. (You may want to make a bash alias command to make this easy).

REACT_APP_API_URL=https://your-app.herokuapp.com/api npm run deploy
Here’s the final git commit with our frontend deployment scripts

That is a wrap for now. View the live online demo, or project on GitHub.