How do I use Flask routes with Apache and mod_wsgi?

12,700

In your wsgi file you are doing from service import application, which is importing only your application method.

Change that to from service import app as application and everything will work as expected.

After your comment, I thought I'd expand the answer a bit:

Your wsgi file is python code - you can have any valid python code inside this file. The wsgi "handler" that is installed in Apache is looking for the application name in this file, which it will hand off requests to. A Flask class instance - app = Flask(__name__) - provides such an interface, but since its called app and not application, you have to alias it when you import it - that's what the from line does.

You could - and this is perfectly fine - simply do this application = Flask(__name__) and then point the wsgi handler in Apache to your service.py file. If service.py was importable (that means, somewhere in PYTHONPATH), you wouldn't need an intermediary wsgi script.

Although the above works, its bad practice. The wsgi file needs permissions from the Apache process to work; and you generally separate that from the actual source code which should be somewhere else on your filesystem, with appropriate permissions.

Share:
12,700

Related videos on Youtube

Sir Eisenhower
Author by

Sir Eisenhower

Updated on June 29, 2022

Comments

  • Sir Eisenhower
    Sir Eisenhower almost 2 years

    I've got my Apache server setup and it is handling Flask responses via mod_wsgi. I've registered the WSGI script via the alias:

    [httpd.conf]

    WSGIScriptAlias /service "/mnt/www/wsgi-scripts/service.wsgi"
    

    I've added the corresponding WSGI file at the above path:

    [/mnt/www/wsgi-scripts/service.wsgi]

    import sys
    sys.path.insert(0, "/mnt/www/wsgi-scripts")
    
    from service import application
    

    And I have a simple test Flask Python script that provides the service module:

    [/mnt/www/wsgi-scripts/service.py]

    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/')
    def application(environ, start_response):
            status = '200 OK'
            output = "Hello World!"
            response_headers = [('Content-type', 'text/plain'),
                                ('Content-Length', str(len(output)))]
            start_response(status, response_headers)
            return [output]
    
    @app.route('/upload')
    def upload(environ, start_response):
            output = "Uploading"
            status = '200 OK'
            response_headers = [('Content-type', 'text/plain'),
                                ('Content-Length', str(len(output)))]
            start_response(status, response_headers)
            return [output]
    
    if __name__ == '__main__':
            app.run()
    

    When I go to my website URL [hostname]/service it works as expected and I get "Hello World!" back. The problem is that I don't know how to get other routes to work like, like 'upload' in the example above. This works fine in standalone Flask but under mod_wsgi I'm stumped. The only thing I can imagine is registering a separate WSGI script alias in the httpd.conf for each endpoint I want, but that takes away Flask's fancy routing support. Is there a way to make this work?

    • Burhan Khalid
      Burhan Khalid about 12 years
      Have you tried browsing to /service/upload? You might be pleasantly surprised.
  • Sir Eisenhower
    Sir Eisenhower about 12 years
    that did the trick. Thank you! In addition to changing service.wsgi to match what you indicated, I also needed to revert my service.py to be pure flask. In the original problem statement I think I'd gotten off the rails mixing pure mod_wsgi code with Flask. I think the genesis of this confusion was naming my root route handler 'application'.
  • Sir Eisenhower
    Sir Eisenhower about 12 years
    I think I was unclear about mod_wsgi vs. Flask code. I understand that it's all Python. What I was getting stuck on is that in the example above my @app.route('/') is decorating the function application. In my original setup I was importing just application so only that function was getting called. When I changed the service.wsgi to use from service import app as application that did correctly reference the Flask object, but it also seems to have created a naming conflict with the application function. I renamed this function to @def root(): and now it works fine. Thanks again!
  • horcle_buzz
    horcle_buzz about 9 years
    Sweet! This was the answer to my woes.