Deploy flask application on 1&1 shared hosting (with CGI)

I’m writing in to provide an answer after nearly a year because the given answer is incomplete and because the suggestion to leave off the /$1 is wrong. Other stackoverflow threads that can be reached by an Internet search using the string “deploy flask on cgi” have also ended without satisfactory solutions.

To begin, my .htaccess file is exactly as in the referenced “flask via CGI” doc, except that the comment in the second line for the RewriteCond has to be removed because in .htaccess any comment must occupy an entire line.

I put the .htaccess file in the public_html document root folder and my cgi script is /home/myusername/public_html/scgi-bin/moc/cgiappserver-prod.cgi.

It’s Python of course and the shebang at the top had better be right. At my ISP they use cpanel which has a wrapper for CGI that they call “scgi”. It’s not the real thing, unfortunately. So treat it as ordinary CGI for purposes of running Flask.

I should add that I only have a shared-hosting account.

Here’s my cgiappserver-prod.cgi file:

#!/home/myusername/local/bin/python
import cgitb; cgitb.enable()  # This line enables CGI error reporting
from wsgiref.handlers import CGIHandler
import traceback
from settings import LGGR

app = None
try:
    import moc
    app = moc.app
except Exception, e:
    LGGR.info( traceback.format_exc([10]) )
    LGGR.info( 'Problem in cgiappserver-prod with moc import: %s' % e )

class ScriptNameStripper(object):
   def __init__(self, app):
       self.app = app
   def __call__(self, environ, start_response):
       environ['SCRIPT_NAME'] = ''
       return self.app(environ, start_response)

app = ScriptNameStripper(app)

try:
    CGIHandler().run(app)
except Exception, e:
    LGGR.info( traceback.format_exc([10]) )
    LGGR.info( 'Problem in cgiappserver-prod with CGIHandler().run(): %s' % e )

So my app is spread over a few files, with setting.py and moc.py in particular showing in the code above.

My hours of foundering around were partly due to all of the unhelpful posts on this subject that I read, but mainly due to my not getting with the business of getting error messages out early enough. (I have access to an error log that is provided by the ISP but it is seldom helpful.)

To start, I have confirmed that the cgitb.enable() function works. I have deliberately misspelled wsgiref and seen a beautiful error page and I have commented out the cgitb (cgi traceback) line to see the error message turn into a useless 500 status code.

Note that I also set up in settings.py a logger, a rotating file logger LGGR. With it I discovered that I had to do something extra— not shown here— to tell the Python interpreter where the sqlite3 library is.

Also, you can simply use print statements, about which the referenced Flask docs on CGI say:

  • With CGI, you will also have to make sure that your code does not
    contain any print statements, or that sys.stdout is overridden by
    something that doesn’t write into the HTTP response.

That’s true, but it’s helpful while debugging to see the print write into the HTTP response.

Finally, when I eventually got it working the location box of the browser sadly had stuff like www.mysite.com/scgi-bin/moc/cgiappserver-prod.cgi/contact in it, whereas I really needed simply www.mysite.com/contact.

The cure was that ScriptNameStripper class in cgiappserver-prod.cgi. I got it from other Flask docs.

Leave a Comment