Skip to content

Setup Heroku Deployment

vivekweb2013 edited this page Jun 5, 2022 · 43 revisions

Host BatNoter API Docker Application on Heroku

Create github environments for staging and production deployment

  • Go to github repository and open Settings > Environments
  • Create environments Staging and Production

Setup heroku api key secret in github

  • Go to https://dashboard.heroku.com/account
  • Scroll down to API Key secret
  • Click on Reveal button and copy the api key
  • Now go to github repository and open Settings > Secrets > Action
  • Add a secret HEROKU_API_KEY with the copied value

Login to heroku

heroku login

Create batnoter app & set the stack to container

# create staging instance
heroku create batnoter-staging
heroku stack:set container -a batnoter-staging

# create production instance
heroku create batnoter
heroku stack:set container -a batnoter

Point api subdomain to heroku app

Using heroku's custom domain feature

heroku domains:add api.batnoter.com -a batnoter

Then go to your domain registrar and configure the the CNAME DNS record to point to heroku app

Type:CNAME Host:api Value:batnoter.herokuapp.com

NOTE: To add a custom domain using heroku, you will need to have your heroku account verified by adding credit card (heroku does not charge you for custom subdomain). If you don't have a credit card or you do not wish to use it with heroku you can use the below alternate method that makes use of Cloudflare workers and creates a reverse proxy to heroku app.

Using Cloudflare reverse proxy worker

  • Login to your cloudflare account
  • Add the site, setup the cloudflare name servers as instructed in the process
  • Click on Workers > Create a Service
  • Add the following
    addEventListener('fetch', event => {
      event.respondWith(handleRequest(event.request))
    })
    
    async function handleRequest(request) {
      // new URL object to play with,
      // based on the one being requested.
      // e.g. https://domain.com/blog/page
      var url = new URL(request.url)
      // set hostname to the place we're proxying requests from
      url.hostname = "batnoter.herokuapp.com"
    
      // pass the modified url back to the request,
      let response = await fetch(url, request)
      return response;
    }
    
    Name the service as batnoter-api
  • Now go to Websites > batnoter.com > Workers > HTTP Routes > Add Route and add the following route
  • Add route as api.batnoter.com/* and choose batnoter-api from dropdown and save the route

This will now reverse proxy all the requests to the api.batnoter.com to batnoter.herokuapp.com

Create postgres inside inside heroku app using addons

# create staging instance
heroku addons:create heroku-postgresql:hobby-dev -a batnoter-staging

# create production instance
heroku addons:create heroku-postgresql:hobby-dev -a batnoter

This will create a postgres instances inside respective heroku apps and it also sets the DATABASE_URL environment variable (heroku app config).

Setup environment variables using heroku config

# setup staging app configs
heroku config:set APP_SECRETKEY='<secret>' -a batnoter-staging
heroku config:set APP_CLIENTURL='http://localhost:3000' -a batnoter-staging
heroku config:set DATABASE_SSLMODE='require' -a batnoter-staging
heroku config:set DATABASE_DEBUG='true' -a batnoter-staging
heroku config:set HTTPSERVER_PORT='$PORT' -a batnoter-staging
heroku config:set HTTPSERVER_DEBUG='true' -a batnoter-staging
heroku config:set OAUTH2_GITHUB_CLIENTID='<github_client_id>' -a batnoter-staging
heroku config:set OAUTH2_GITHUB_CLIENTSECRET='<github_client_secret>' -a batnoter-staging
heroku config:set OAUTH2_GITHUB_REDIRECTURL='https://batnoter-staging.herokuapp.com/api/v1/oauth2/github/callback' -a batnoter-staging

# setup production app configs
heroku config:set APP_SECRETKEY='<secret>' -a batnoter
heroku config:set APP_CLIENTURL='https://batnoter.com' -a batnoter
heroku config:set DATABASE_SSLMODE='require' -a batnoter
heroku config:set DATABASE_DEBUG='true' -a batnoter
heroku config:set HTTPSERVER_PORT='$PORT' -a batnoter
heroku config:set HTTPSERVER_DEBUG='true' -a batnoter
heroku config:set OAUTH2_GITHUB_CLIENTID='<github_client_id>' -a batnoter
heroku config:set OAUTH2_GITHUB_CLIENTSECRET='<github_client_secret>' -a batnoter
heroku config:set OAUTH2_GITHUB_REDIRECTURL='https://batnoter.herokuapp.com/api/v1/oauth2/github/callback' -a batnoter

Prepare database

Install postgres client psql if not installed already

brew install libpq

Create batnoter schema

# create schema in staging instance
heroku pg:psql -a batnoter-staging
CREATE SCHEMA IF NOT EXISTS batnoter;
exit

# create schema in production instance
heroku pg:psql -a batnoter
CREATE SCHEMA IF NOT EXISTS batnoter;
exit

Run database migration locally

Unfortunately heroku does not have an option to update the docker command (CMD) and run the image. So we can not use batnoter docker image on heroku to run migrations. We can do it locally simply be running

migrate -path migrations -database "postgresql://user:password@host:5432/database?search_path=batnoter&sslmode=require" -verbose up

Just replace the postgres url with the heroku config DATABASE_URL value.

NOTE: Make sure to provide ?search_path=batnoter&sslmode=require in the connection url

After successful migration restart the respective heroku app

heroku restart -a batnoter-staging
heroku restart -a batnoter

Check application logs using below heroku cli

heroku logs -a batnoter-staging --tail
heroku logs -a batnoter --tail

Download & apply postgres database dump

# take the db dump
pg_dump -Fc -c --no-acl --no-owner -h <DB_HOST> -U <DB_USER> <DB_NAME> > db.dump

# restore the db dump by overriding any existing database if exist
pg_restore --verbose --clean --no-acl --no-owner -h <DB_HOST> -U <DB_USER> -d <DB_NAME> db.dump

Convert postgres database dump to sql file

pg_restore db.dump > db.sql

References & useful links