Let’s Build |> a Slack Clone with Elixir, Phoenix, and React (part 7 — Deploy to Heroku & AWS S3)
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.
Update this line in user_socket.ex to add a 45 second timeout:
Create a Procfile in the Phoenix root
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)
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.
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.
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