Deploying Python Apps on Heroku

A Word About Heroku

As you may already know, Webfaction shut down recently and applications were migrated to another host automatically for most customers provided they were fairly standard and/or popular. That said, I had some things like an R Shiny server and several Python apps that simply would not be easy to migrate. While my Php apps were easy to move to another webhosting environment (Hostgator for the time being), I was forced to move my Python apps elsewhere. After some searching I decided to give Heroku a try. If you don't already know, Heroku is a cloud PaaS (Platform as a Service) that makes deploying web applications a breeze. There are many other PaaS options to choose from, and still many offering free tiers of service for developers who perhaps don't want to spend hosting money on their applications for whatever reason (small scale applications, hobby development, etc.). If this sounds like a match for your current needs, you can sign up at Heroku. Of course, if you ever decide to scale up or you need some other features like databases beyond what the free tier provides, you can always do that.

Deploying on Heroku

Like any platform, there is a learning curve. The documentation and tutorials for getting started are quite good. Once you're up and running with one of the examples, you may run into problems deploying apps that worked on other platforms and now seem broken. Personally, I ran into issues along those lines. Following the documentation and tutorial code got me pretty far, but I was having issues with Python finding modules and getting my CherryPy server up and running. Specifically, this is what the command line was telling me:

crash

Resolving Python Module Import Issues

Keeping in mind that I created a "requirements.txt" and the build was successful, I was left scratching my head as to why the imports were failing. The only thing I could conclude from the command line was that there was something wrong with the path(s) in which Python was looking for modules. Fortunately, as is often the case, I could print out the locations Python was pulling modules from and also look where Python modules were actually installed. This took a bit of looking, but overall it was pretty straight forward. The first task was to look at sys.path(), which was returning ['/app', '/app/.heroku/python/lib/python37.zip', '/app/.heroku/python/lib/python3.7', '/app/.heroku/python/lib/python3.7/lib-dynload', '/app/dokkaebi']. Okay, nothing looks terrible here, but it didn't give me the information I needed to fix the path issues. Poking around a bit, I found the location of "site-packages", which ended up being in the "/app/.heroku/python/lib/python3.7/site-packages" location on Heroku. It's unclear to me as to why this path was not included when Python searched for modules, but adding it to the list inside my app fixed the problem: sys.path.append("/app/.heroku/python/lib/python3.7/site-packages").

Resolving CherryPy Server Issues

Okay, now the server starts, but immediately crashes due to a timeout when trying to bind to a port:

cherrypy crash

This was a simple fix, and was a more general "moving to a new platform" issue. Specifically, some hosting environments require you to use 127.0.0.1 as your hostname, while Heroku requires you to use 0.0.0.0 as your hostname. In addition, you cannot specify the port that CherryPy runs on before Heroku runs your application, so it must be obtained from the "PORT" environment variable Heroku sets for web applications and given to CherryPy at runtime rather than from a configuration file. To do this, just use os.environ.get('PORT') to get the port from Heroku.

Thoughts on Moving Python Apps from Webfaction to Heroku

Overall, the process was simple and the only hiccups in migrating them were what you might expect - differences in configurations and some Heroku-specific quirks like getting a handle on the right port and figuring out where Python modules are pulled from. Making the appropriate updates to my applications based on some simple detective work was relatively painless, and now I have all of the benefits of using the free tier Heroku platform for my Python needs as well as the option to scale up if I decide it's necessary.