The Flask Mega-Tutorial Part XVIII: Deployment on Heroku

This is the eighteenth installment of the Flask Mega-Tutorial series, in which I'm going to deploy Microblog to the Heroku cloud platform.

For your reference, below is a list of the articles in this series.

In the previous article I showed you the "traditional" way to host a Python application, and I gave you two actual examples of deployment to Linux based servers. If you are not used to manage a Linux system, you probably thought that the amount of effort that needs to be put into the task was big, and that surely there must be an easier way.

In this chapter I'm going to show you a completely different approach, in which you rely on a third-party cloud hosting provider to perform most of the administration tasks, freeing you to spend more time working on your application.

Many cloud hosting providers offer a managed platform on which applications can run. All you need to provide to have your application deployed on these platforms is the actual application, because the hardware, operating system, scripting language interpreters, database, etc. are all managed by the service. This type of service is called Platform as a Service, or PaaS.

Sounds too good to be true, right?

I will look at deploying Microblog to Heroku, a popular cloud hosting service that is very friendly for Python applications. I picked Heroku not only because it is popular, but also because it has a free service tier that will allow you to follow me and do a complete deployment without spending any money.

The GitHub links for this chapter are: Browse, Zip, Diff.

Hosting on Heroku

Heroku was one of the first platform as a service providers. It started as a hosting option for Ruby based applications, but then grew to support many other languages like Java, Node.js and of course Python.

Deploying a web application to Heroku is done through the git version control tool, so you must have your application in a git repository. Heroku looks for a file called Procfile in the application's root directory for instructions on how to start the application. For Python projects, Heroku also expects a requirements.txt file that lists all the module dependencies that need to be installed. After the application is uploaded to Heroku's servers through a git push operation, you are essentially done and just need to wait a few seconds until the application is online. It's really that simple.

The different service tiers Heroku offers allow you to choose how much computing power and time you get for your application, so as your user base grows you may outgrow the free allowance and will need to buy more units of computing, which Heroku calls "dynos".

Ready to try Heroku? Let's get started!

Creating a Heroku account

Before you can deploy to Heroku you need to have an account with them. So visit heroku.com and create a free account. Once you have an account and log in to Heroku, you will have access to a dashboard, where all your applications are listed.

Installing the Heroku CLI

Heroku provides a command-line tool for interacting with their service called Heroku CLI, available for Windows, Mac OS X and Linux. The documentation includes installation instructions for all the supported platforms. Go ahead and install it on your system if you plan on deploying the application to test the service.

The first thing you should do once the CLI is installed is login to your Heroku account:

$ heroku login

Heroku CLI will ask you to enter your email address and your account password. Your authenticated status will be remembered in subsequent commands.

Setting Up Git

The git tool is core to the deployment of applications to Heroku, so you must install it on your system if you don't have it yet. If you don't have a package available for your operating system, you can visit the git website to download an installer.

There are a lot of reasons why using git for your projects makes sense. If you plan to deploy to Heroku, you have one more, because to deploy to Heroku, your application must be in a git repository. If you are going to do a test deployment for Microblog, you can clone my version of this application from GitHub:

$ git clone https://github.com/miguelgrinberg/microblog
$ cd microblog
$ git checkout v0.18

The git checkout command selects the specific commit that has the application at the point in its history that corresponds to this chapter.

If you prefer to work with your own code instead of mine, you can transform your own project into a git repository by running git init . on the top-level directory (note the period after init, which tells git that you want to create the repository in the current directory). Once the git repository is created, use the git add command to add all your source files, and git commit to commit them to the repository.

Creating a Heroku Application

To register a new application with Heroku, you use the apps:create command from the root directory of the application, passing the application name as the only argument:

$ heroku apps:create flask-microblog
Creating flask-microblog... done
http://flask-microblog.herokuapp.com/ | https://git.heroku.com/flask-microblog.git

Heroku requires that applications have a unique name. The name flask-microblog that I used above is not going to be available to you because I'm using it, so you will need to pick a different name for your deployment.

The output of this command will include the URL that Heroku assigned to the application, and also its git repository on Heroku's servers. Your local git repository will be configured with an extra remote, called heroku set to this repository. You can verify that it exists with the git remote command:

$ git remote -v
heroku  https://git.heroku.com/flask-microblog.git (fetch)
heroku  https://git.heroku.com/flask-microblog.git (push)

Depending on how you created your git repository, the output of the above command could also include another remote called origin which is not used by Heroku.

The Ephemeral File System

The Heroku platform is different to other deployment platforms in that it features an ephemeral file system that runs on a virtualized platform. What does that mean? It means that at any time, Heroku can reset the virtual server on which your server runs back to a clean state. You cannot assume that any data that you save to the file system will persist, and in fact, Heroku recycles servers very often.

Working under these conditions introduces some problems for my application, which uses a few files:

  • The default SQLite database engine writes data in a disk file
  • Logs for the application are also written to the file system
  • The compiled language translation repositories are also written to local files

The following sections will address these three areas.

Working with a Heroku Postgres Database

To address the first problem, I'm going to switch to a different database engine. In Chapter 17 you saw me use a MySQL database to add robustness to the Ubuntu deployment. Heroku has a database offering of its own, based on the Postgres database, so I'm going to switch to that to avoid the file-based SQLite.

Databases for Heroku applications are provisioned with the same Heroku CLI. In this case I'm going to create a database on the free tier:

$ heroku addons:add heroku-postgresql:hobby-dev
Creating heroku-postgresql:hobby-dev on flask-microblog... 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-parallel-56076 as DATABASE_URL
Use heroku addons:docs heroku-postgresql to view documentation

The URL for the newly created database is stored in a DATABASE_URL environment variable that will be available when the application runs on Heroku's platform. This is very convenient, because the application already looks for the database URL in that variable.

To make sure that the DATABASE_URL variable is configured in your Heroku application, you can use the following command:

$ heroku config
DATABASE_URL:  postgres://...

An unfortunate problem with recent versions of SQLAlchemy is that they expect Postgres database URLs to begin with postgresql://, instead of the postgres:// that Heroku uses. To ensure that the application can connect to the database, it is necessary to update the URL to the format required by SQLAlchemy. This can be done with a string replacement operation in the Config class:

config.py: Fix Postgres database URLs to be compatible with SQLAlchemy.

class Config(object):
    # ...
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL', '').replace(
        'postgres://', 'postgresql://') or \
        'sqlite:///' + os.path.join(basedir, 'app.db')
    # ...

This string replacement operation is safe to use even when the DATABASE_URL variable is set to a different database, in which case it will not affect it.

Logging to stdout

Heroku expects applications to log directly to stdout. Anything the application prints to the standard output is saved and returned when you use the heroku logs command. So I'm going to add a configuration variable that indicates if I need to log to stdout or to a file like I've been doing. Here is the change in the configuration:

config.py: Option to log to stdout.

class Config(object):
    # ...
    LOG_TO_STDOUT = os.environ.get('LOG_TO_STDOUT')

Then in the application factory function I can check this configuration to know how to configure the application's logger:

app/__init__.py: Log to stdout or file.

def create_app(config_class=Config):
    # ...
    if not app.debug and not app.testing:
        # ...

        if app.config['LOG_TO_STDOUT']:
            stream_handler = logging.StreamHandler()
            if not os.path.exists('logs'):
            file_handler = RotatingFileHandler('logs/microblog.log',
                                               maxBytes=10240, backupCount=10)
                '%(asctime)s %(levelname)s: %(message)s '
                '[in %(pathname)s:%(lineno)d]'))

        app.logger.info('Microblog startup')

    return app

So now I need to set the LOG_TO_STDOUT environment variable when the application runs in Heroku, but not in other configurations. The Heroku CLI makes this easy, as it provides an option to set environment variables to be used at runtime:

$ heroku config:set LOG_TO_STDOUT=1
Setting LOG_TO_STDOUT and restarting flask-microblog... done, v4

Compiled Translations

The third aspect of Microblog that relies on local files is the compiled language translation files. The more direct option to ensure those files never disappear from the ephemeral file system is to add the compiled language files to the git repository, so that they become part of the initial state of the application once it is deployed to Heroku.

A more elegant option, in my opinion, is to include the flask translate compile command in the start up command given to Heroku, so that any time the server is restarted those files are compiled again. I'm going to go with this option, since I know that my start up procedure is going to require more than one command anyway, asI also need to run the database migrations. So for now, I will set this problem aside, and will revisit it later when I write the Procfile.

Elasticsearch Hosting

Elasticsearch is one of the many services that can be added to a Heroku project, but unlike Postgres, this is not a service provided by Heroku, but by third parties that partner with Heroku to provide add-ons. At the time I'm writing this, there are three different providers of an integrated Elasticsearch service.

Before you configure Elasticsearch, be aware that Heroku requires your account to have a credit card on file before any third party add-on is installed, even if you stay within the free tier. If you prefer not to provide your credit card to Heroku, then skip this section. You will still be able to deploy the application, but the search functionality is not going to be enabled.

Out of the Elasticsearch options that are available as add-ons, I decided to try SearchBox, which comes with a free starter plan. To add SearchBox to your account, you have to run the following command while being logged in to Heroku:

$ heroku addons:create searchbox:starter

This command will deploy an Elasticsearch service and leave the connection URL for the service in a SEARCHBOX_URL environment variable associated with your application. Once more keep in mind that this command will fail unless you add your credit card to your Heroku account.

If you recall from Chapter 16, my application looks for the Elasticsearch connection URL in the ELASTICSEARCH_URL variable, so I need to add this variable and set it to the connection URL assigned by SearchBox:

$ heroku config:get SEARCHBOX_URL
$ heroku config:set ELASTICSEARCH_URL=<your-elasticsearch-url>

Here I first asked Heroku to print the value of SEARCHBOX_URL, and then I added a new environment variable with the name ELASTICSEARCH_URL set to that same value.

Many other features of the application are also configured through environment variables, for example SECRET_KEY, MS_TRANSLATOR_KEY, MAIL_SERVER and a few more. These variables need to also be copied over to the Heroku deployment, so that they are accessible to the application. The heroku config:set can be used to transfer these variables from your .env file to Heroku.

The exampe below configures a secret key:

heroku config:set SECRET_KEY=7853fbd853a249c586f7d810a7938b43

Updates to Requirements

Heroku expects the dependencies to be in the requirements.txt file, exactly like I defined it in Chapter 15. But for the application to run on Heroku I need to add two new dependencies to this file.

Heroku does not provide a web server of its own. Instead, it expects the application to start its own web server on the port number given in the environment variable $PORT. Since the Flask development web server is not robust enough to use for production, I'm going to use gunicorn again, the server recommended by Heroku for Python applications.

The application will also be connecting to a Postgres database, and for that SQLAlchemy requires the psycopg2 or psycopg2-binary packages to be installed. The binary version is, in general, preferred as it installs an already built version of this package, as opposite to psycopg2 which requires a C compiler to be installed to build the package during installation.

Both gunicorn and psycopg2-binary need to be added to the requirements.txt file.

The Procfile

Heroku needs to know how to execute the application, and for that it uses a file named Procfile in the root directory of the application. The format of this file is simple, each line includes a process name, a colon, and then the command that starts the process. The most common type of application that runs on Heroku is a web application, and for this type of application the process name should be web. Below you can see a Procfile for Microblog:

Procfile: Heroku Procfile.

web: flask db upgrade; flask translate compile; gunicorn microblog:app

Here I defined the command to start the web application as three commands in sequence. First I run a database migration upgrade, then I compile the language translations, and finally I start the server.

Because the first two sub-commands are based on the flask command, I need to add the FLASK_APP environment variable:

$ heroku config:set FLASK_APP=microblog.py
Setting FLASK_APP and restarting flask-microblog... done, v6
FLASK_APP: microblog.py

The application also relies on other environment variables, such as those that configure the email server or the token for the live translations. Those need to be added with more heroku config:set commands.

The gunicorn command is simpler than what I used for the Ubuntu deployment, because this server has a very good integration with the Heroku environment. For example, the $PORT environment variable is honored by default, and instead of using the -w option to set the number of workers, heroku recommends adding a variable called WEB_CONCURRENCY, which gunicorn uses when -w is not provided, giving you the flexibility to control the number of workers without having to modify the Procfile.

Deploying the Application

All the preparatory steps are complete, so now it is time to run the deployment. To upload the application to Heroku's servers for deployment, the git push command is used. This is similar to how you push changes in your local git repository to GitHub or other remote git server.

There are a couple of variations on how to do this, depending on how you created your git repository. If you are using my v0.18 code, then you need to create a branch based on this tag, and push it as the remote main branch, as follows:

$ git checkout -b deploy
$ git push heroku deploy:main

If instead, you are working with your own repository, then your code is already in a main or master branch, so you first need to make sure that your changes are committed:

$ git commit -a -m "heroku deployment changes"

And then you can run the following to start the deployment:

$ git push heroku main  # you may need to use "master" instead of "main"

Regardless of how you push the branch, you should see the following output from Heroku:

$ git push heoroku deploy:main
Enumerating objects: 264, done.
Counting objects: 100% (264/264), done.
Delta compression using up to 12 threads
Compressing objects: 100% (183/183), done.
Writing objects: 100% (264/264), 59.44 KiB | 5.94 MiB/s, done.
Total 264 (delta 132), reused 143 (delta 62)
remote: Compressing source files... done.
remote: Building source:
remote: -----> Building on the Heroku-20 stack
remote: -----> Determining which buildpack to use for this app
remote: -----> Python app detected
remote: -----> No Python version was specified. Using the buildpack default: python-3.9.6
remote:        To use a different version, see: https://devcenter.heroku.com/articles/...
remote: -----> Installing python-3.9.6
remote: -----> Installing pip 20.2.4, setuptools 47.1.1 and wheel 0.36.2
remote: -----> Installing SQLite3
remote: -----> Installing requirements with pip
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote: -----> Compressing...
remote:        Done: 69.2M
remote: -----> Launching...
remote:        Released v7
remote:        https://flask-microblog.herokuapp.com/ deployed to Heroku
remote: Verifying deploy... done.
To https://git.heroku.com/flask-microblog.git
 * [new branch]      deploy -> main

The label heroku that we used in the git push command is the remote that was automatically added by the Heroku CLI when the application was created. The deploy:main argument means that I'm pushing the code from the local repository referenced by the deploy branch to the main branch on the Heroku repository. When you work with your own projects, you will likely be pushing with the command git push heroku main, which pushes your local main branch. Because of the way this project is structured, I'm pushing a branch that is not main, but the destination branch on the Heroku side always needs to be main or master as those are the only branch names that Heroku accepts for deployment.

And that is it, the application should now be deployed at the URL that you were given in the output of the command that created the application. In my case, the URL was https://flask-microblog.herokuapp.com, so that is what I need to type to access the application.

If you want to see the log entries for the running application, use the heroku logs command. This can be useful if for any reason the application fails to start. If there were any errors, those will be in the logs.

Deploying Application Updates

To deploy a new version of the application, you just need to run a new git push command with the new code. This will repeat the deployment process, take the old deployment offline, and then replace it with the new code. The commands in the Procfile will run again as part of the new deployment, so any new database migrations or translations will be updated during the process.


  • #176 Riyad said 2021-04-14T23:21:49Z

    I tried your suggestion, but it still gave an error, the error was the same error that I would get if removed the "sslmode=require" which is fixing the problem with the beginning of the "DATABASE_URL" "postgres://". I kept trying different solutions to this issue from this github thread https://bit.ly/3tjt3kt, all of them didn't work, but after trying a dozen of times I got this when I git push heroku master: "Your account has reached its concurrent builds limit". Does this mean I can't use the current Heroku account for free anymore?

    I also noticed when I deploy the app to Heroku, it says something about sqlite3 although I haven't imported it or added it to the requirements.txt: remote: -----> Installing pip 20.2.4, setuptools 47.1.1 and wheel 0.36.2 remote: -----> Installing SQLite3 <<<<<< remote: -----> Installing requirements with pip

    Does this mean that the postgresql addon isn't used by heroku? I'm really sorry for asking a lot of questions, but I have been working on this app for more than two months and I really don't want to quit at the end. maybe if you could just take a look at the files on github you may be able to notice what I'm doing wrong. github link: https://github.com/Rio363/Flask-Riozaki-App Thank you so much for replying to my messages.

  • #177 Riyad said 2021-04-14T23:33:28Z

    and this is the error from the logs: psycopg2.errors.UndefinedTable: relation "user" does not exist.

  • #178 Miguel Grinberg said 2021-04-15T11:50:17Z

    @Ryad: I'm sorry but I'm completely lost. Did my suggestion helped make your app use the Postgres database or is it still going to SQLite? That's the important thing. If the app is on Postgres, near the end of the deployment when the flask db upgrade command runs the tables should be created. Look for any errors or messages when that command executes.

  • #179 Riyad said 2021-04-15T13:24:28Z

    this is the error that I get now sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedTable) relation "user" does not exist "user" is the only table in the database, and I don't understand why it does not exist

  • #180 Miguel Grinberg said 2021-04-15T18:28:16Z

    @Ryad: you ignored my suggestion. Look for the output of the flask db upgrade command to continue debugging this problem.

  • #181 Riyad said 2021-04-15T23:48:23Z

    I'm sorry, the app is now working without giving a 500 error and without pushing the "app.db" to git. But the problem wasn't fixed, each time I do a git push command the database is replaced again. I don't want to replace the database when I git push updates to Heroku My understanding of this is that the web app is still somehow using sqlite3, whenever I do a git push command I get the following: remote: -----> Building on the Heroku-20 stack remote: -----> Using buildpack: heroku/python remote: -----> Python app detected remote: -----> No change in requirements detected, installing from cache remote: -----> Installing pip 20.2.4, setuptools 47.1.1 and wheel 0.36.2 remote: -----> Installing SQLite3 <<<<<<<<< remote: -----> Installing requirements with pip

    it's installing SQLite3 for some reason, though I have the postgres addon,

    and when I see the logs regarding the "flask db upgrade" command, it's using the file from my local "migrations/versions/" folder which is called "df7484c....." the logs: Starting process with command flask db upgrade; gunicorn myApp:app [alembic.runtime.migration] Context impl SQLiteImpl. <<<<<< INFO [alembic.runtime.migration] Will assume non-transactional DDL. INFO [alembic.runtime.migration] Running upgrade -> df7487cba442, empty message <<<<<<<<

    How to do I make sure the database isn't replaced? and make sure I'm actually using the postgres addon?

  • #182 Miguel Grinberg said 2021-04-16T09:22:57Z

    @Riyad: I really don't know how to help, because from the start you are still having the same very basic issue, which is that your configuration tells the application to use SQLite instead of Postgres. You are getting distracted by minor changes in behavior while you change other unrelated things, but the fact remains that your SQLALCHEMY_DATABASE_URI configuration variable points to sqlite instead of Postgres, and you seem to be looking elsewhere.

    The fact that SQLite3 is installed is not relevant. What matters is that Alembic should be using Postgres, but it is still using sqlite:

    [alembic.runtime.migration] Context impl SQLiteImpl.

    Until this shows Postgres there is nothing else to work on except figuring out why your SQLALCHEMY_DATABASE_URI has the wrong value.

  • #183 Riyad said 2021-04-16T15:45:59Z

    I changed the the SQLALCHEMY_DATABASE_URI slightly to this: SQLALCHEMY_DATABASE_URI = os.environ.get("DATABASE_URL").replace("postgres://", "postgresql://", 1) or \ 'sqlite:///' + os.path.join(basedir, 'app.db') and it's working now as expected thank you so much again for replying to my messages :)

    I would absolutely appreciate it if you can tell me what you think about it: app link: https://riozaki.herokuapp.com/ Thank you for your help again, you saved me from quitting coding for good.

  • #184 Hongyuan Qiu said 2021-04-27T13:22:36Z

    Hi Miguel,

    Thanks for the excellent tutorial! The application worked well locally. After deploying the Microblog to Heroku, the application had a problem with the Elasticsearch. There is something wrong with the index:

    Exception on /index [POST] raise HTTP_EXCEPTIONS.get(status_code, TransportError)( elasticsearch.exceptions.NotFoundError: NotFoundError(404, 'index_not_found_exception', 'no such index [post]', post, index_expression)

  • #185 Hongyuan Qiu said 2021-04-27T14:00:40Z

    Hi Miguel,

    I just solved the problem. I went to the dashboard of Elasticsearch on Heroku. Over there I added an index 'post' to solve the problem.

    I tried deleting the index first and then tried Post.reindex() in flask shell in the local development environment. It worked successfully. But when I tried the Post.reindex() in the Heroku flask shell, it didn't work. Does it mean the index could not be added automatically in Heroku?

    Is there an elegant way to add the index in the code? I found someone mentioned using create_if_not_exists (https://stackoverflow.com/questions/61931193/elasticsearch-notfounderror-notfounderror404-index-not-found-exception), but it was not clearly explained.


  • #186 Miguel Grinberg said 2021-04-27T22:06:43Z

    @Hongyuan: The index is created the first time something is written to it. At least it should be. Which Elasticsearch service are you using on Heroku?

  • #187 Hongyuan Qiu said 2021-04-30T16:56:11Z

    Hi there,

    By following this excellent article, I deployed the application to Heroku successfully. I solved many problems while deploying. I would like to share my solutions to these problems. Of course, you may find the same solutions from others' comments.

    Problem 1: I developed the work using Python 3.7.3 and set it the Python runtime. After that, I had a runtime error when deploying the work to Heroku-20 stack: Requested runtime (python-3.7.3) is not available for this stack (heroku-20). Solution: I changed the Python runtime version to Python 3.9.4. You may check the language runtime over here: https://devcenter.heroku.com/articles/heroku-20-stack


    Problem 2: After setting Python runtime 3.9.4, I got an error indicating the psycopg2 package could not be installed. Solution: I changed this package to psycopg2-binary.


    Problem 3: After deploying the application to Heroku, I got an error when connecting to the Postgres database: sqlalchemy.exc.NoSuchModuleError: Can't load plugin: sqlalchemy.dialects:postgres.

    Solution: I solved the problem by following this article: https://stackoverflow.com/questions/62688256/sqlalchemy-exc-nosuchmoduleerror-cant-load-plugin-sqlalchemy-dialectspostgre A similar solution was mentioned by someone else in the Comment but the problem was not the same as mine...


    Problem 4: Finally, I got an Error indicating something went wrong with Elasticsearch index: Exception on /index [POST] raise HTTP_EXCEPTIONS.get(status_code, TransportError)( elasticsearch.exceptions.NotFoundError: NotFoundError(404, 'index_not_found_exception', 'no such index [post]', post, index_expression)

    Solution: To solve this problem, I went to SearchBox Elasticsearch, and selected the Indices under Dashboard. I added the post index manually.


    Hope it may help.

  • #188 Niel said 2021-05-28T08:57:23Z

    Hi Miguel, I'am getting error on building wheel for psychopg2 the following are the errors: ================================================ remote: Building wheel for psycopg2 (setup.py): started remote: Building wheel for psycopg2 (setup.py): finished with status 'error' remote: ERROR: Command errored out with exit status 1: remote: command: /app/.heroku/python/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-wuxzxei1/psycopg2/setup.py'"'"'; file='"'"'/tmp/pip-install-wuxzxei1/psycopg2/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(file);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, file, '"'"'exec'"'"'))' bdist_wheel -d /tmp/pip-wheel-m3i_8a4j remote: cwd: /tmp/pip-install-wuxzxei1/psycopg2/ ========================================================== remote: psycopg/psycopgmodule.c: In function ‘psyco_is_main_interp’: remote: psycopg/psycopgmodule.c:685:18: error: dereferencing pointer to incomplete type ‘PyInterpreterState’ {aka ‘struct _is’} remote: 685 | while (interp->next) remote: | ^~ remote: error: command '/usr/bin/gcc' failed with exit code 1 remote: ---------------------------------------- remote: ERROR: Failed building wheel for psycopg2 remote: Running setup.py clean for psycopg2 ========================================================== remote: ! Push rejected, failed to compile Python app. remote: remote: ! Push failed remote: ! remote: ! ## Warning - The same version of this code has already been built: 4582b24bc675332e6348471a0565fe5aad9f47a4 remote: ! remote: ! We have detected that you have triggered a build from source code with version 4582b24bc675332e6348471a0565fe5aad9f47a4 remote: ! at least twice. One common cause of this behavior is attempting to deploy code from a different branch. ==========================================================

    please help Miguel Thanks

  • #189 Miguel Grinberg said 2021-05-28T09:40:59Z

    @Niel: try installing the psycopg2-binary package instead.

  • #190 Niel said 2021-06-02T12:46:34Z

    @Miguel: I tried installing the psychopg2-binary package by updating requirements.txt in the local git repository but i was getting the same error, later on if followed this : https://stackoverflow.com/questions/53186027/deploying-flask-application-to-heroku-gives-an-importerror-from-psycopg2/56672267

    and it was deployed successfully from master to master branch but i'am unable to access the application on url: 'https://git.heroku.com/nielsfirstproject.git'

    so, i went on stackoverflow again and tried on: "https://nielsfirstproject.herokuapp.com/" and got this potential security issue saying page unable to access my application

    The heroku logs --tail gives the output: heroku logs --tail 2021-06-02T10:09:08.989527+00:00 app[web.1]: [2021-06-02 10:09:08,989] INFO in init: Microblog startup 2021-06-02T10:09:08.989613+00:00 app[web.1]: Microblog startup 2021-06-02T10:09:09.343781+00:00 app[web.1]: compiling catalog app/translations/es/LC_MESSAGES/messages.po to app/translations/es/LC_MESSAGES/messages.mo 2021-06-02T10:09:09.467877+00:00 app[web.1]: bash: gunicorn: command not found 2021-06-02T10:09:09.519606+00:00 heroku[web.1]: Process exited with status 127 2021-06-02T10:09:09.621561+00:00 heroku[web.1]: State changed from starting to crashed 2021-06-02T11:24:29.053478+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=nielsfirstproject.herokuapp.com request_id=b8940f83-4930-4e02-bd15-765fe4121cfc fwd="" dyno= connect= service= status=503 bytes= protocol=https 2021-06-02T11:24:30.072975+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=nielsfirstproject.herokuapp.com request_id=d8d229f2-bc1e-435d-8782-b5abedb08ef1 fwd="" dyno= connect= service= status=503 bytes= protocol=https 2021-06-02T11:24:43.142516+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=nielsfirstproject.herokuapp.com request_id=12a91b15-d726-4a51-8a96-108f940eabc3 fwd="" dyno= connect= service= status=503 bytes= protocol=https 2021-06-02T11:24:43.587982+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=nielsfirstproject.herokuapp.com request_id=8fdec491-33c3-4e58-a685-3a720940e412 fwd="" dyno= connect= service= status=503 bytes= protocol=https 2021-06-02T11:25:09.865382+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=nielsfirstproject.herokuapp.com request_id=500ffd52-1193-42b8-996a-5a947f65c563 fwd="" dyno= connect= service= status=503 bytes= protocol=https 2021-06-02T11:25:10.256634+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=nielsfirstproject.herokuapp.com request_id=a8306b9a-8fcd-42f7-8d38-6aea3f42c3bf fwd="" dyno= connect= service= status=503 bytes= protocol=https

    Thanks Miguel

  • #191 Miguel Grinberg said 2021-06-03T10:47:59Z

    @Niel: Did you notice the "gunicorn command not found" error in the logs? Seems you did not install this package.

  • #192 Niel said 2021-06-03T12:24:09Z

    @Miguel To install gunicorn and psychopg2-binary, it just has to be in the requirements.txt file in microblog directory in my laptop from where i'am deploying the application right ? These are requirements.txt file contents:

    alembic==0.9.6 Babel==2.5.1 blinker==1.4 certifi==2017.7.27.1 chardet==3.0.4 click==6.7 dnspython==2.1.0 dominate==2.3.1 elasticsearch==7.10.1 email-validator==1.1.2 Flask==1.1.2 Flask-Babel==2.0.0 Flask-Bootstrap== Flask-Login==0.5.0 Flask-Mail==0.9.1 Flask-Migrate==2.5.3 Flask-Moment==0.11.0 Flask-SQLAlchemy==2.4.4 Flask-WTF==0.14.3 guess-language-spirit==0.5.3 idna==2.6 itsdangerous==0.24 Jinja2==2.11.2 Mako==1.0.7 MarkupSafe==1.1.1 PyJWT==1.5.3 python-dateutil==2.6.1 python-dotenv==0.15.0 python-editor==1.0.3 pytz==2017.2 requests==2.25.1 six==1.11.0 SQLAlchemy==1.3.22 urllib3==1.26.2 visitor==0.1.3 Werkzeug==1.0.1 WTForms==2.1 psychopg2-binary==2.8.6 gunicorn==19.7.1

    i don't know what i did wrong, can you please tell me how to wipe everything from heroku and start again ?

    "git push heroku master" command says " Everything up-to-date"

    thanks Miguel

  • #193 Miguel Grinberg said 2021-06-05T15:38:30Z

    @Niel: you have a typo, the package is psycopg2-binary. There is no "h" in the package name.

  • #194 Tommy Herbert said 2021-06-08T09:50:38Z

    Don't know if you're trying to keep this up to date, but Heroku uses 'main' instead of 'master' now. Thanks for everything!

  • #195 Miguel Grinberg said 2021-06-08T10:53:51Z

    @Tommy: Yes, an update to this chapter with this and a couple of other changes is going live soon!

  • #196 Ryan said 2021-09-08T11:41:14Z

    Hello Miguel, its me again. I have a couple questions early into the tutorial.

    Firstly, since I already have an existing directory with the name "microblog on my Mac > /Users/Ryan/microblog

    What I did when i gitclone your code, is to create another directory and perform the clone in that directory > /Users/Ryan/Heroku/microblog

    With git remote -v, I only gotten the following message with the 'origin' instead of 'heroku'

    origin https://github.com/miguelgrinberg/microblog (fetch) origin https://github.com/miguelgrinberg/microblog (push)

    Is that normal since you mentioned that output of the command include another remote 'origin' but i only have 'origin'. Should i expect more than two lines of remote?

    Thereafter, I proceed to the next step of heroku apps:create flask-microblog and i did it in this directory, /Users/Ryan/Heroku/microblog. I am not sure when you mention root directory, it refers to /Heroku/ or /microblog/. If you can help me to understand it.

    Regardless, the creation is successful (when i login to Heroku via browser, i can see the app).

    Moving on to next, i face a problem when trying to execute "heroku addons:add heroku-postgresql:hobby-dev". I tried to execute the command both in /Heroku/ and /microblog/ directory. And it gives me the following error.

    › Error: Missing required flag: › -a, --app APP app to run command against › See more help with --help

    I tried execute "heroku addons:add heroku-postgresql:hobby-dev -all" to check all accessible apps but it returns the following error:

    Creating heroku-postgresql:hobby-dev on ⬢ ll... ! ▸ Couldn't find that app.

    Appreciate if you can explain to me the solution or point me out my mistake. Thanks.

  • #197 Miguel Grinberg said 2021-09-08T13:58:00Z

    @Ryan: I think this part is going to be difficult for you if you are not familiar with how git works. I suggest you follow a basic git tutorial to have a better understanding of what I'm doing here.

    The git remote -v command that you are trying looks correct, but you are following the steps out of order. You are doing it before the Heroku app is created. This is explained in the tutorial, a heroku remote is added to the repository when the Heroku app is created.

    When I say root directory I mean the root directory of the project. This /heroku directory that you created is not part of the project so it never needs to be used. It does not hurt anything, but it is also not useful for any purpose.

    It's hard for me to tell you what's wrong with the database creation. It seems your Heroku app is not correctly assigned to the project directory, and for that reason the Heroku CLI complains that it does not know what app you want to add a database to. You seem to be trying a lot of different things, without fully understanding the effect of the commands that you are running. This must have left your project in an incorrect state. You can delete the Heroku app in the web control panel, remove the source code and start over from scratch, this time following the instructions as defined in the article and in the same order.

  • #198 Ryan said 2021-09-09T07:15:54Z

    Hello Miguel, thanks for the clarification. It is all good.

    The problem i had is i was confusing over the directory.

    Previously i perform the "heroku apps:create flask-microblogryan" in /Users/Ryan/Heroku/ And i start fresh and perform the "heroku apps:create flask-microblogryan" in /Users/Ryan/Heroku/microblog

    Then it works. I now have clearer concept of the directory after your explanation. Thanks.

  • #199 Ryan said 2021-09-09T09:17:40Z

    Hello Miguel, thank you very much. I have completed the tutorial.

    However, i still have a bit questions regarding the heroku config part. As you didn't explicitly state what else is needed to configure.

    I am wondering if i should follow the below for anything related to the email functions (if i decided to use a real email like Gmail). Which is different from my previous .env files which states MAIL_SERVER as localhost and MAIL_PORT as 25 without the TLS, Username, Password

    MAIL_SERVER=smtp.googlemail.com MAIL_PORT=587 MAIL_USE_TLS=1 MAIL_USERNAME=<your-gmail-username> MAIL_PASSWORD=<your-gmail-password>

    That said, I also research and see that there's no addon for Gmail in heroku, instead SendGrid option is available. So I am not sure if the gmail is going to work, I will try testing it later on.

    My most concerning question is to do with the MAIL_PASSWORD variable. Is this mandatory to pass it to Heroku if i did use Gmail? Is it safe to pass it to Heroku as i can actually easily see the configuration in my Heroku settings.

    Thank you very much for the tutorial. I shall move on / move back to solve the ubuntu deployment which is still stucked now.

  • #200 Miguel Grinberg said 2021-09-09T22:21:43Z

    @Ryan: Yes, the email variables need to be set in Heroku if you want emails to work. I'm not sure what kind of email solution you were using the localhost, but that is not going to work from Heroku. Gmail should work with Heroku you do not need an extension, but you will have to add your Gmail password as a variable. You should not use your normal Gmail account for this, create a new one that does not represent any risk to you. In any case, Gmail can only be used for personal use, so you will need a different solution if you plan on sending lots of emails from a Heroku application.

Leave a Comment