From cd9edd674a4e9fe03e69e12fedb03a95d7ed3373 Mon Sep 17 00:00:00 2001 From: Sam McAlilly <38969506+smcalilly@users.noreply.github.com> Date: Thu, 11 Feb 2021 15:59:33 -0600 Subject: [PATCH] edited the heroku section (#167) * edited the heroku CLI steps + reorganized Heroku config info + added a troubleshooting section * removed newline * newline, dunno where from * included the CLI output in the heroku setup steps * removed phrase * rearranged the order of some sections * added subheadings --- heroku/deploy-a-django-app.md | 582 ++++++++++++++++++---------------- 1 file changed, 316 insertions(+), 266 deletions(-) diff --git a/heroku/deploy-a-django-app.md b/heroku/deploy-a-django-app.md index dc0ab5a..630cc44 100644 --- a/heroku/deploy-a-django-app.md +++ b/heroku/deploy-a-django-app.md @@ -3,22 +3,24 @@ This guide provides instructions on deploying a Django app to Heroku, DataMade's preferred platform for hosting dynamic applications. +The easiest way to properly set up your application code for Heroku is +to use our [Django template](/docker/templates/) to create a fresh +Heroku-enabled Django app. The template includes additional nice features like ES6 +support and GitHub Actions configuration, but it is only appropriate for brand new apps. +Once you've created your app, you can skip to learning how to [Provision Heroku +resources](#provision-heroku-resources). + +If you'd like to convert an existing app to Heroku, or if the template is unfeasible +for some other reason, see [Set up application code for Heroku](#set-up-application-code-for-heroku). + ## Contents -- [Set up application code for Heroku](#set-up-application-code-for-heroku) - - [Containerize your app](#containerize-your-app) - - [Clean up old configurations](#clean-up-old-configurations) - - [Serve static files with WhiteNoise](#serve-static-files-with-whitenoise) - - [Read settings and secret variables from the environment](#read-settings-and-secret-variables-from-the-environment) - - [Configure Django logging](#configure-django-logging) -- [Set up GitHub Actions for CI](#set-up-github-actions-for-ci) + - [Provision Heroku resources](#provision-heroku-resources) - - [Ensure that the Heroku CLI is installed](#ensure-that-the-heroku-cli-is-installed) - - [Create Heroku config files](#create-heroku-config-files) - - [`heroku.yml`](#herokuyml) - - [`release.sh`](#releasesh) - - [`app.json`](#appjson) + - [Install the Heroku CLI with the manifest plugin](#install-the-heroku-cli-with-the-manifest-plugin) - [Create apps and pipelines for your project](#create-apps-and-pipelines-for-your-project) + - [Set configuration variables for review apps and deployments](#set-configuration-variables-for-review-apps-and-deployments) + - [Configure deployments from Git branches](#configure-deployments-from-git-branches) - [Set up Slack notifications](#set-up-slack-notifications) - [Enable additional services](#enable-additional-services) - [Solr](#solr) @@ -28,24 +30,284 @@ preferred platform for hosting dynamic applications. - [Step 2: Configure a custom domain on a DNS provider](#step-2-configure-a-custom-domain-on-a-dns-provider) - [Step 3: Enable SSL](#step-3-enable-ssl) - [General guidelines for custom domains](#general-guidelines-for-custom-domains) +- [Set up application code for Heroku](#set-up-application-code-for-heroku) + - [Containerize your app](#containerize-your-app) + - [Clean up old configurations](#clean-up-old-configurations) + - [Serve static files with WhiteNoise](#serve-static-files-with-whitenoise) + - [Read settings and secret variables from the environment](#read-settings-and-secret-variables-from-the-environment) + - [Configure Django logging](#configure-django-logging) + - [Create Heroku config files](#create-heroku-config-files) + - [`heroku.yml`](#herokuyml) + - [`release.sh`](#releasesh) + - [`app.json`](#appjson) + - [Set up GitHub Actions for CI](#set-up-github-actions-for-ci) - [Troubleshooting](#troubleshooting) +## Provision Heroku resources + +**If you initialized your application with DataMade's [`new-django-app` Cookiecutter template](https://github.com/datamade/how-to/tree/master/docker/templates)**, your app is already configured to run on Heroku. +**If you are migrating an existing app**, or if you want to learn more about the configuration that comes with the template, see [Set up application code for Heroku](#set-up-application-code-for-heroku), below, before proceeding with this step. + +The following instructions will help you deploy your properly configured application to the platform. + +### Install the Heroku CLI with the manifest plugin + +The fastest way to get a project up and running on Heroku is to use the [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli). Before you start, make sure you have the CLI installed locally. Once you install the CLI, you'll need to [switch over to the CLI's beta version](https://devcenter.heroku.com/articles/build-docker-images-heroku-yml#creating-your-app-from-setup). This allows you to use the `manifest` CLI plugin, which you must install: + +``` +heroku update beta +heroku plugins:install @heroku-cli/plugin-manifest +``` + +Confirm that you have the manifest plugin installed: + +``` +heroku plugins | grep manifest +``` + +If you don't see any output, [follow the official instructions for installing the +plugin](https://devcenter.heroku.com/changelog-items/1441). + +### Create apps and pipelines for your project + +In order to deploy your project, you need to create Heroku apps for staging +and production, and tie them together in a [pipeline](https://devcenter.heroku.com/articles/pipelines). +To create these resources, start by defining the name of your app: + +```bash +# This should be the same slug as your project's GitHub repo. +export APP_NAME= +``` + +Then, run the following Heroku CLI commands to create a staging app and a pipeline: + +```bash +heroku create ${APP_NAME}-staging -t datamade --manifest +heroku pipelines:create -t datamade ${APP_NAME} -a ${APP_NAME}-staging -s staging +heroku pipelines:connect ${APP_NAME} -r datamade/${APP_NAME} +``` + +Your CLI output should look like this: +```bash +heroku create ${APP_NAME}-staging -t datamade --manifest +Reading heroku.yml manifest... done +Creating ⬢ demo-app-staging... done, stack is container +Adding heroku-postgresql... done +https://demo-app-staging.herokuapp.com/ | https://git.heroku.com/demo-app-staging.git + +heroku pipelines:add ${APP_NAME}-staging -a ${APP_NAME}-staging -s staging +Adding ⬢ demo-app-staging to datamade-app pipeline as staging... done +``` + +If you would like to set up a production app as well, run the following commands +to create one and add it to your pipeline: + +```bash +heroku create ${APP_NAME} -t datamade --manifest +heroku pipelines:add ${APP_NAME} -a ${APP_NAME} -s production +``` + +Once you have the environments you need, enable [review +apps](https://devcenter.heroku.com/articles/github-integration-review-apps) +for your pipeline: + +```bash +# Note that these need to be two separate commands due to an open Heroku bug, +# since --autodeploy and --autodestroy require a PATCH request +heroku reviewapps:enable -p ${APP_NAME} +heroku reviewapps:enable -p ${APP_NAME} --autodeploy --autodestroy +``` + +### Set configuration variables for review apps and deployments +Next, configure environment variables for staging and production apps. `DJANGO_SECRET_KEY` +should be a string generated using the [XKCD password generator](https://preshing.com/20110811/xkcd-password-generator/), +and `DJANGO_ALLOWED_HOSTS` should be a comma-separated string of valid hosts +for your app. + +```bash +heroku config:set -a ${APP_NAME}-staging DJANGO_SECRET_KEY= +heroku config:set -a ${APP_NAME}-staging DJANGO_ALLOWED_HOSTS=.herokuapp.com + +# Run these commands if you have a production application +heroku config:set -a ${APP_NAME} DJANGO_SECRET_KEY= +heroku config:set -a ${APP_NAME} DJANGO_ALLOWED_HOSTS= +``` + +Note that review app config vars cannot yet be set using the CLI, but you can set them in +the Heroku dashboard by navigating to the pipeline home page and visiting +`Settings > Review Apps > Review app config vars` in the nav. + +Also note that while `DATABASE_URL` is probably required by your application, you don't actually +need to set it yourself. The Heroku Postgres add-on will [automatically define this +variable](https://devcenter.heroku.com/articles/heroku-postgresql#designating-a-primary-database) +when it provisions a database for your application. + +### Configure deployments from Git branches +Heroku needs to deploy from specific branches in order to deploy to different environments +(e.g. staging vs. production). In order to properly enable automatic deployments, then, +you'll need to deploy to production from a branch instead of tagged commits (a practice +which we've used in the past for deploying to production). We recommend creating a long-lived +`deploy` branch off of `master` immediately after setting up your repo so that you can +use `master` to deploy to staging and `deploy` to deploy to production. + +## Set up Slack notifications + +Heroku can send build notifications to Slack via the Heroku ChatOps integration. +This integration should already be set up in our Slack channel, but if you need +to install it again, see the [official documentation](https://devcenter.heroku.com/articles/chatops). + +To enable notifications for an app, run the following Slack command in the +corresponding channel: + +```bash +/h route ${PIPELINE_NAME} to ${CHANNEL_NAME} +``` + +For example, to enable notifications for the `parserator` pipeline in the `#parserator` +channel, we would run `/h route parserator to #parserator`. + +## Enable additional services + +If your app requires additional services, like Solr or PostGIS, you'll need +to perform some extra steps to set them up for your pipeline. + +### Solr + +Solr can be configured as a separate service using the [Websolr +add-on for Heroku](https://devcenter.heroku.com/articles/websolr). We recommend +following the instructions for configuring [Websolr with +Haystack](https://devcenter.heroku.com/articles/websolr#haystack-for-django). +In addition to following these instructions, complete the following two steps: + +1. Update your `heroku.yml` and `app.json` config files to add `websolr` to your + add-ons configuration attributes, so Websolr will be enabled for review apps +2. Define `WEBSOLR_URL` as an environment variable for your `app` + service in your `docker-compose.yml` file in order to point your app to your + Solr service in local development + +For help setting up Haystack for local development, see [our guide to +Haystack](https://github.com/datamade/how-to/blob/master/search/03-heavyweight.md#getting-started). +For an example of a working Solr installation in a Heroku app, see the [`2.5_deploy` +branch of LA Metro Councilmatic](https://github.com/datamade/la-metro-councilmatic/tree/2.5_deploy). + +Note that the Websolr add-on [can be expensive](https://elements.heroku.com/addons/websolr#pricing), +with staging instances costing a minimum of $20/mo and the smallest production +instance costing $60/mo. Refer to our [guide to searching +data](https://github.com/datamade/how-to/blob/master/search/03-heavyweight.md#heavyweight) +to make sure you really need Solr before going forward with installing it on your project. + +### PostGIS + +If your app requires PostGIS, you'll need to [manually enable it in your +database](https://devcenter.heroku.com/articles/postgis). Once your database +has been provisioned, run the following command to connect to your database and +enable PostGIS: + +``` +heroku psql -a -c "CREATE EXTENSION postgis" +``` + +To automate this process, you can include a step like this in `scripts/release.sh` +to make sure PostGIS is always enabled in your databases: + +```bash +psql ${DATABASE_URL} -c "CREATE EXTENSION IF NOT EXISTS postgis" +``` + +## Set up a custom domain + +All Heroku apps are automatically delegated a subdomain under the `heroku.com` +root domain, like `example.heroku.com`. This automatic Heroku subdomain +is usually fine for review apps and staging apps, but production apps almost +always require a dedicated custom domain like `example.com`. + +When you're ready to deploy to production and publish your app publicly, you'll +need to set up a custom domain. In order to do this, you need to register the custom +domain in two places: in the Heroku dashboard, and in your (or your client's) DNS provider. +Then, you'll need to instruct Heroku to enable SSL for your domain. + +For detailed documentation on setting up custom domains, see the [Heroku +docs](https://devcenter.heroku.com/articles/custom-domains). + +### Step 1: Configure a custom domain on Heroku + +The first step to setting up a custom domain is to instruct Heroku to use the +domain for your app. Navigate to `Settings > Domains` in your app dashboard, choose +`Add domain`, and enter the name of the custom domain you would like to use. + +When you save the domain, Heroku should display the DNS target for your domain. +Copy this string and use it in the next step to delegate the domain with your +DNS provider. + +### Step 2: Configure a custom domain on a DNS provider + +_Note: If you're not comfortable with basic DNS terminology and you're finding this +section to be confusing, refer to the CloudFlare docs on [how DNS +works](https://www.cloudflare.com/learning/dns/what-is-dns/)._ + +Once you have a DNS target for Heroku, you need to instruct your DNS provider to +direct traffic for your custom domain to Heroku. + +If you're setting up a custom **subdomain**, like `www.example.com` or `app.example.com`, +you'll need to create a `CNAME` record pointing to your DNS target with your DNS +provider. For more details, see the Heroku docs on [configuring DNS for +subdomains](https://devcenter.heroku.com/articles/custom-domains#configuring-dns-for-subdomains). + +If you're setting up a custom **root domain**, like `example.com`, you'll need +to create the equivalent of an `ALIAS` record with your DNS provider. Not all +DNS providers offer the same type of `ALIAS` record, so to provision this record +you should visit the Heroku docs on [configuring DNS for root +domains](https://devcenter.heroku.com/articles/custom-domains#configuring-dns-for-root-domains) +and follow the instruction for your provider. At DataMade we typically use Namecheap, +which allows you to [create `ALIAS` +records](https://www.namecheap.com/support/knowledgebase/article.aspx/10128/2237/how-to-create-an-alias-record). + +After creating the appropriate DNS record with your DNS provider, wait a few +minutes for DNS to propagate and confirm that you can load your app by visiting +your custom domain. Remember that Django will only serve domains that are listed +in its `ALLOWED_HOSTS` settings variable, so you may have to update your `DJANGO_ALLOWED_HOSTS` +config var on Heroku to accomodate your custom domain. + +### Step 3: Enable SSL + +Once your custom domain is properly resolving to your app, navigate to +`Settings > SSL Certificates` in your app dashboard, select `Configure SSL`, +and Choose `Automatic Certificate Management (ACM)`. Your app should now load +properly when you visit it with the `https://` protocol. + +As a final step, we want to make sure that the app always redirects HTTP traffic +to HTTPS. Heroku [can't do this for us](https://help.heroku.com/J2R1S4T8/can-heroku-force-an-application-to-use-ssl-tls), +so we need to configure the app code to do it. If you didn't use the Django template +to create your app, add the following settings to your `settings.py` file: + +```python +if DEBUG is False: + SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') + SECURE_SSL_REDIRECT = True +``` + +When you deploy this change and try to load your app with the `http://` protocol, +it should now automatically redirect you to `https://` and display a valid certificate. + +### General guidelines for custom domains + +When setting up custom domains, follow these general guidelines: + +- Where possible, let the client register the domain name so we don't have to manage it. +- Shorter domains are always better, but we usually defer to our clients' preferences + when choosing a custom domain name. +- If the client has a pre-existing root domain, always advise deploying on a subdomain + like `app.example.com` instead of a path like `example.com/app`. Clients often + ask for paths off of root domains, but they are typically quite hard to deploy. +- If using a root domain, make sure to set up a `www` subdomain to redirect to the root. +- Don't allow `.herokuapp.com` in `DJANGO_ALLOWED_HOSTS` in production, since we want + the custom domain to be canonical for search engine optimization. + ## Set up application code for Heroku -In order to deploy a Django application to Heroku, a few specific configurations +In order to deploy a legacy Django application to Heroku, a few specific configurations need to be enabled in your application code. -The easiest way to properly set up your application code for Heroku is -to use our [Django template](/docker/templates/) to create a fresh -Heroku-enabled Django app. The template includes additional nice features like ES6 -support and GitHub Actions configuration, but it is only appropriate for brand new apps. -Once you've created your app, you can skip to learning how to [Provision Heroku -resources](#provision-heroku-resources). - -If you'd like to convert an existing app to Heroku, or if the template is unfeasible -for some other reason, read on for details on how to configure your Django app -to work on Heroku. - ### Containerize your app We use Heroku as a platform for deploying containerized apps, which means that @@ -172,29 +434,6 @@ LOGGING = { For more detail on Django's logging framework, [see the documentation](https://docs.djangoproject.com/en/2.2/topics/logging/). -## Set up GitHub Actions for CI - -For Heroku deployments, we use GitHub Actions instead of Travis for CI (continuous integration). Read the [how-to to set up GitHub Actions](https://github.com/datamade/how-to/blob/master/ci/github-actions.md). - -## Provision Heroku resources - -Once your application is properly configured for Heroku, the following instructions -will help you deploy your application to the platform. - -### Ensure that the Heroku CLI is installed - -The fastest way to get a project up and running on Heroku is to use the -[Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli). Before you start, -make sure you have the CLI installed locally. In addition, confirm that you have the -manifest plugin) installed: - -``` -heroku plugins | grep manifest -``` - -If you don't see any output, [follow the official instructions for installing the -plugin](https://devcenter.heroku.com/changelog-items/1441). - ### Create Heroku config files If you're converting an existing app to use Heroku, create the following config files @@ -296,226 +535,9 @@ Use the following baseline to get started: } ``` -### Create apps and pipelines for your project - -In order to deploy your project, you need to create Heroku apps for staging -and production, and tie them together in a [pipeline](https://devcenter.heroku.com/articles/pipelines). -To create these resources, start by defining the name of your app: - -```bash -# This should be the same slug as your project's GitHub repo. -export APP_NAME= -``` - -Then, run the following Heroku CLI commands to create a staging app and a pipeline: - -```bash -heroku create ${APP_NAME}-staging -t datamade --manifest -heroku pipelines:create -t datamade ${APP_NAME} -a ${APP_NAME}-staging -s staging -heroku pipelines:connect ${APP_NAME} -r datamade/${APP_NAME} -``` - -If you would like to set up a production app as well, run the following commands -to create one and add it to your pipeline: - -```bash -heroku create ${APP_NAME} -t datamade --manifest -heroku pipelines:add ${APP_NAME} -a ${APP_NAME} -s production -``` - -Once you have the environments you need, enable [review -apps](https://devcenter.heroku.com/articles/github-integration-review-apps) -for your pipeline: - -```bash -# Note that these need to be two separate commands due to an open Heroku bug, -# since --autodeploy and --autodestroy require a PATCH request -heroku reviewapps:enable -p ${APP_NAME} -heroku reviewapps:enable -p ${APP_NAME} --autodeploy --autodestroy -``` - -Next, configure environment variables for staging and production apps. `DJANGO_SECRET_KEY` -should be a string generated using the [XKCD password generator](https://preshing.com/20110811/xkcd-password-generator/), -and `DJANGO_ALLOWED_HOSTS` should be a comma-separated string of valid hosts -for your app. - -```bash -heroku config:set -a ${APP_NAME}-staging DJANGO_SECRET_KEY= -heroku config:set -a ${APP_NAME}-staging DJANGO_ALLOWED_HOSTS=.herokuapp.com - -# Run these commands if you have a production application -heroku config:set -a ${APP_NAME} DJANGO_SECRET_KEY= -heroku config:set -a ${APP_NAME} DJANGO_ALLOWED_HOSTS= -``` - -Note that review app config vars cannot yet be set using the CLI, but you can set them in -the Heroku dashboard by navigating to the pipeline home page and visiting -`Settings > Review Apps > Review app config vars` in the nav. - -Also note that while `DATABASE_URL` is probably required by your application, you don't actually -need to set it yourself. The Heroku Postgres add-on will [automatically define this -variable](https://devcenter.heroku.com/articles/heroku-postgresql#designating-a-primary-database) -when it provisions a database for your application. - -Heroku needs to deploy from specific branches in order to deploy to different environments -(e.g. staging vs. production). In order to properly enable automatic deployments, then, -you'll need to deploy to production from a branch instead of tagged commits (a practice -which we've used in the past for deploying to production). We recommend creating a long-lived -`deploy` branch off of `master` immediately after setting up your repo so that you can -use `master` to deploy to staging and `deploy` to deploy to production. - -## Set up Slack notifications - -Heroku can send build notifications to Slack via the Heroku ChatOps integration. -This integration should already be set up in our Slack channel, but if you need -to install it again, see the [official documentation](https://devcenter.heroku.com/articles/chatops). - -To enable notifications for an app, run the following Slack command in the -corresponding channel: - -```bash -/h route ${PIPELINE_NAME} to ${CHANNEL_NAME} -``` - -For example, to enable notifications for the `parserator` pipeline in the `#parserator` -channel, we would run `/h route parserator to #parserator`. - -## Enable additional services - -If your app requires additional services, like Solr or PostGIS, you'll need -to perform some extra steps to set them up for your pipeline. - -### Solr - -Solr can be configured as a separate service using the [Websolr -add-on for Heroku](https://devcenter.heroku.com/articles/websolr). We recommend -following the instructions for configuring [Websolr with -Haystack](https://devcenter.heroku.com/articles/websolr#haystack-for-django). -In addition to following these instructions, complete the following two steps: - -1. Update your `heroku.yml` and `app.json` config files to add `websolr` to your - add-ons configuration attributes, so Websolr will be enabled for review apps -2. Define `WEBSOLR_URL` as an environment variable for your `app` - service in your `docker-compose.yml` file in order to point your app to your - Solr service in local development - -For help setting up Haystack for local development, see [our guide to -Haystack](https://github.com/datamade/how-to/blob/master/search/03-heavyweight.md#getting-started). -For an example of a working Solr installation in a Heroku app, see the [`2.5_deploy` -branch of LA Metro Councilmatic](https://github.com/datamade/la-metro-councilmatic/tree/2.5_deploy). - -Note that the Websolr add-on [can be expensive](https://elements.heroku.com/addons/websolr#pricing), -with staging instances costing a minimum of $20/mo and the smallest production -instance costing $60/mo. Refer to our [guide to searching -data](https://github.com/datamade/how-to/blob/master/search/03-heavyweight.md#heavyweight) -to make sure you really need Solr before going forward with installing it on your project. - -### PostGIS - -If your app requires PostGIS, you'll need to [manually enable it in your -database](https://devcenter.heroku.com/articles/postgis). Once your database -has been provisioned, run the following command to connect to your database and -enable PostGIS: - -``` -heroku psql -a -c "CREATE EXTENSION postgis" -``` - -To automate this process, you can include a step like this in `scripts/release.sh` -to make sure PostGIS is always enabled in your databases: - -```bash -psql ${DATABASE_URL} -c "CREATE EXTENSION IF NOT EXISTS postgis" -``` - -## Set up a custom domain - -All Heroku apps are automatically delegated a subdomain under the `heroku.com` -root domain, like `example.heroku.com`. This automatic Heroku subdomain -is usually fine for review apps and staging apps, but production apps almost -always require a dedicated custom domain like `example.com`. - -When you're ready to deploy to production and publish your app publicly, you'll -need to set up a custom domain. In order to do this, you need to register the custom -domain in two places: in the Heroku dashboard, and in your (or your client's) DNS provider. -Then, you'll need to instruct Heroku to enable SSL for your domain. - -For detailed documentation on setting up custom domains, see the [Heroku -docs](https://devcenter.heroku.com/articles/custom-domains). - -### Step 1: Configure a custom domain on Heroku - -The first step to setting up a custom domain is to instruct Heroku to use the -domain for your app. Navigate to `Settings > Domains` in your app dashboard, choose -`Add domain`, and enter the name of the custom domain you would like to use. - -When you save the domain, Heroku should display the DNS target for your domain. -Copy this string and use it in the next step to delegate the domain with your -DNS provider. - -### Step 2: Configure a custom domain on a DNS provider - -_Note: If you're not comfortable with basic DNS terminology and you're finding this -section to be confusing, refer to the CloudFlare docs on [how DNS -works](https://www.cloudflare.com/learning/dns/what-is-dns/)._ - -Once you have a DNS target for Heroku, you need to instruct your DNS provider to -direct traffic for your custom domain to Heroku. - -If you're setting up a custom **subdomain**, like `www.example.com` or `app.example.com`, -you'll need to create a `CNAME` record pointing to your DNS target with your DNS -provider. For more details, see the Heroku docs on [configuring DNS for -subdomains](https://devcenter.heroku.com/articles/custom-domains#configuring-dns-for-subdomains). - -If you're setting up a custom **root domain**, like `example.com`, you'll need -to create the equivalent of an `ALIAS` record with your DNS provider. Not all -DNS providers offer the same type of `ALIAS` record, so to provision this record -you should visit the Heroku docs on [configuring DNS for root -domains](https://devcenter.heroku.com/articles/custom-domains#configuring-dns-for-root-domains) -and follow the instruction for your provider. At DataMade we typically use Namecheap, -which allows you to [create `ALIAS` -records](https://www.namecheap.com/support/knowledgebase/article.aspx/10128/2237/how-to-create-an-alias-record). - -After creating the appropriate DNS record with your DNS provider, wait a few -minutes for DNS to propagate and confirm that you can load your app by visiting -your custom domain. Remember that Django will only serve domains that are listed -in its `ALLOWED_HOSTS` settings variable, so you may have to update your `DJANGO_ALLOWED_HOSTS` -config var on Heroku to accomodate your custom domain. - -### Step 3: Enable SSL - -Once your custom domain is properly resolving to your app, navigate to -`Settings > SSL Certificates` in your app dashboard, select `Configure SSL`, -and Choose `Automatic Certificate Management (ACM)`. Your app should now load -properly when you visit it with the `https://` protocol. - -As a final step, we want to make sure that the app always redirects HTTP traffic -to HTTPS. Heroku [can't do this for us](https://help.heroku.com/J2R1S4T8/can-heroku-force-an-application-to-use-ssl-tls), -so we need to configure the app code to do it. If you didn't use the Django template -to create your app, add the following settings to your `settings.py` file: - -```python -if DEBUG is False: - SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') - SECURE_SSL_REDIRECT = True -``` - -When you deploy this change and try to load your app with the `http://` protocol, -it should now automatically redirect you to `https://` and display a valid certificate. - -### General guidelines for custom domains - -When setting up custom domains, follow these general guidelines: +### Set up GitHub Actions for CI -- Where possible, let the client register the domain name so we don't have to manage it. -- Shorter domains are always better, but we usually defer to our clients' preferences - when choosing a custom domain name. -- If the client has a pre-existing root domain, always advise deploying on a subdomain - like `app.example.com` instead of a path like `example.com/app`. Clients often - ask for paths off of root domains, but they are typically quite hard to deploy. -- If using a root domain, make sure to set up a `www` subdomain to redirect to the root. -- Don't allow `.herokuapp.com` in `DJANGO_ALLOWED_HOSTS` in production, since we want - the custom domain to be canonical for search engine optimization. +For Heroku deployments, we use GitHub Actions for CI (continuous integration). Read the [how-to to set up GitHub Actions](https://github.com/datamade/how-to/blob/master/ci/github-actions.md). ## Troubleshooting @@ -575,3 +597,31 @@ of data to use a larger Heroku Postgres plan for review apps. Unfortunately, the is not currently a way to set this type of configuration (and hence prevent these kinds of emails being sent for review apps) because [Heroku defaults to the cheapest plan for review app addons](https://help.heroku.com/SY28FR6H/why-aren-t-i-seeing-the-add-on-plan-specified-in-my-app-json-in-my-review-or-ci-app). + +### Help! My staging pipeline doesn't have a database! +You might deploy a review app and everything works. Then you merge your code to master, which builds a new version to the staging pipeline. But for some reason, there is no database provisioned for staging. + +Did you have the `manifest` CLI plugin installed when you first created the Heroku pipeline? If not, then it won't provision the Postgres add-on. [See this step](#install-the-heroku-cli-with-the-manifest-plugin). + +Here's an example where the `manifest` plugin **was not installed** when creating an app: +``` +heroku create ${APP_NAME}-staging -t datamade --manifest +Creating ⬢ demo-app-staging... done +https://demo-app-staging.herokuapp.com/ | https://git.heroku.com/demo-app-staging.git +``` + +Here is an example where everything worked because the `manifest` plugin was installed: +``` +heroku create ${APP_NAME}-staging -t datamade --manifest +Reading heroku.yml manifest... done +Creating ⬢ demo-app-staging... done, stack is container +Adding heroku-postgresql... done +https://demo-app-staging.herokuapp.com/ | https://git.heroku.com/demo-app-staging.git + +heroku pipelines:add ${APP_NAME}-staging -a ${APP_NAME}-staging -s staging +Adding ⬢ demo-app-staging to datamade-app pipeline as staging... done +``` + +The difference is in the CLI's output. In the working example, note the output `Reading heroku.yml manifest... done` and `Adding heroku-postgresql... done`. + +If that is not the problem, then make sure your app's `heroku.yml` is configured correctly. When Heroku builds your app to a pipeline, it uses the `heroku.yml` file to provision the resources (like Postgres or Solr).