Remote Deployment
Warning
This guide is outdated now that one-click deployment is available!
Warning
This guide is missing the Redis caching setup, and may miss other things as we build out.
The following tools are required to deploy the website:
Additionally, you will have to have set up the website locally to deploy to Heroku, notably including setting up the Postgres database.
Tip
Read the setup guide to learn how to run the website locally.
First Time Deployment
Note
In this section, the project name is assumed to be crwa-flagging
. If you are deploying to another URL, such as crwa-flagging-staging
or a personal domain, then replace each reference to crwa-flagging
with that.
If you've never deployed the app from your computer, follow these instructions.
- If you have not already done so, follow the setup guide. The following should now be true:
- Your terminal is pointed to the root directory of the project
/flagging
. - You should have the HOBOlink credentials ready in a
.env
file. - The Postgres database should be set up and up-to-date locally.
- Your Heroku account needs to be "verified," which means it needs to have a valid credit card registered to it. Registering a credit card does not incur any charges on its own. See here for Heroku's billing page for more information.
Tip
If you are especially weary of cloud costs, you can plug a prepaid credit card in with a small nominal amount for the balance. See here for more.
- Via the command line: login to Heroku, and add Heroku as a remote repo using Heroku's CLI:
heroku login
heroku git:remote -a crwa-flagging
- Add the vault password as an environment variable to Heroku.
heroku config:set VAULT_PASSWORD=vault_password_goes_here -a crwa-flagging
- You need to setup the
FLASK_ENV
andFLASK_APP
environment variables. These are mainly used for the scheduler and other potential add-ons.
heroku config:set FLASK_ENV=production -a crwa-flagging
heroku config:set FLASK_APP="app.main:create_app" -a crwa-flagging
- Add a
BASIC_AUTH_USERNAME
andBASIC_AUTH_PASSWORD
for the admin panel. The username can be whatever you want; e.g.admin
does the trick. The password should be hard to guess.
heroku config:set BASIC_AUTH_USERNAME=admin -a crwa-flagging
heroku config:set BASIC_AUTH_PASSWORD=admin_password_goes_here -a crwa-flagging
Danger
The password should be unique to this platform, not a universal password you use for everything. The password is not encrypted when stoerd, and it is visible to anyone who has access to the Heroku dashboard.
- Add some Heroku add-ons.
heroku addons:create scheduler -a crwa-flagging
heroku addons:create heroku-postgresql -a crwa-flagging
Success
Pay attention to the last line of output:
Creating heroku-postgresql on ⬢ crwa-flagging... free
Database has been created and is available
! This database is empty. If upgrading, you can transfer
! data from another database with pg:copy
Created postgresql-ukulele-12345 as DATABASE_URL
In the above case, postgresql-ukulele-12345
is the "name" of the PostgreSQL add-on's dyno. We will be using this name in the next step.
- Push your local copy of the flagging database to the cloud. In the following command, replace
postgresql-ukulele-12345
with whatever the name of your PostgreSQL dyno is, which should have output from the previous step.
heroku pg:push flagging postgresql-ukulele-12345 -a crwa-flagging
Note
The above command assumes that your local Postgres database is up-to-date.
- Deploy the app.
git push heroku master
- Now try the following:
heroku logs --tail -a crwa-flagging
- If everything worked out, you should see the following at or near the bottom of the log:
2020-06-13T23:17:54.000000+00:00 app[api]: Build succeeded
Note
If you see instead see something like [...] State changed from starting to crashed
, then read the rest of the output to see what happened. The most common error when deploying to production will be a RuntimeError: Unable to load the vault; bad password provided
which is self-explanatory. Update the password, and the website will automatically attempt to redeploy. If you don't see that error, then try to self-diagnose.
-
Go see the website for yourself!
-
You are still not done; you need to do one more step, which is to set up the task scheduler. Run the following command:
heroku addons:open scheduler -a crwa-flagging
- The above command should open up a new window in your browser that lets you add a command that runs on a schedule. That command you set should be
python3 -m flask update-website
, and you should run it once a day at 11:00 AM UTC:
Tip
If you want to have the website update more than once a day, it's probably better to run multiple scheduled jobs that run the same command on 24 hour intervals than it is to run a single scheduled job on hourly intervals.
Note
The update-website
command sends out a Tweet as well as re-running the predictive model. You can make the scheduled task only update the website without sending a tweet by replacing update-website
with update-db
.
Subsequent Deployments
- Heroku doesn't allow you to redeploy the website unless you create a new commit. Add some updates if you need to with
git add .
thengit commit -m "describe your changes here"
.
Note
In the very rare case you simply need to redeploy without making any changes to the site, in lieu of the above, simply do git commit --allow-empty -m "redeploy"
.
- Once you have done that, Heroku will redeploy the site when you merge your working branch:
git push heroku master
Tip
If you are having any issues here related to merge conflicts, instead of deleting everything and starting over, try to pull the data from the heroku
branch in and merge it into your local branch.
git fetch heroku
git pull heroku master
- If you make any changes that affect the database, you should create the database locally, and then push it to the cloud, similar to the step above where we push the database for the first time. Note that updating the database this way requires that you reset it first.
heroku pg:reset -a crwa-flagging
heroku pg:push flagging postgresql-ukulele-12345 -a crwa-flagging
Staging and Production Split
It is recommended, though not required, that you have both "staging" and "production" environments for the website (see here for an explanation), and furthermore it is recommended you deploy to staging and play around with the website to see if it looks right before you ever deploy to production.
Managing effectively two separate Heroku apps from a single repository requires a bit of knowledge about how git works. Basically what you're doing is connecting to two separate remote git repositories. The default remote repo is called heroku
and it was created by Heroku's CLI. But since you now have two Heroku remote repositories, the Heroku CLI doesn't know what it's supposed to name the 2nd one. So you have to manually name it using git.
- Run the following command to create a staging environment if it does not already exist.
heroku create crwa-flagging-staging
- Once it exists, add the staging environment as a remote; check to make sure all the remotes look right. The
heroku
remote should correspond with the production environment, and thestaging
remote should correspond with the staging environment you just created.
git remote add staging https://git.heroku.com/crwa-flagging-staging.git
git remote -v
Success
The above command should output something like this:
heroku https://git.heroku.com/crwa-flagging.git (fetch)
heroku https://git.heroku.com/crwa-flagging.git (push)
origin https://github.com/YOUR_USERNAME_HERE/flagging.git (fetch)
origin https://github.com/YOUR_USERNAME_HERE/flagging.git (push)
staging https://git.heroku.com/crwa-flagging-staging.git (fetch)
staging https://git.heroku.com/crwa-flagging-staging.git (push)
upstream https://github.com/codeforboston/flagging.git (fetch)
upstream https://github.com/codeforboston/flagging.git (push)
-
Now all of your
heroku
commands are going to require specifying this new app instance, but the steps to deploy in staging are otherwise similar to the production deployment, with the exception ofgit push heroku master
. -
Deployment via git requires pushing to the new remote like so:
git push staging master
Updating the database schema
We do not use Alembic or any other tools to handle database migrations. Our database is relatively simple and does not store information that cannot be trivially rewritten, so we can migrate to a new database schema by simply creating the new database locally and completely overwriting the database in production.
Here are the steps to do that:
- Make your changes to the database schema, then initialize the database again.
flask create-db --overwrite
flask init-db
- Reset the database. You'll be asked if you're sure you want to reset, and go through that prompt.
heroku pg:reset -a crwa-flagging
- Now push the new database:
heroku pg:push flagging DATABASE -a crwa-flagging
Note
Unless there's an emergency, it's recommended you do something like this either late at night, or even better when it's no longer boating season.