I am trying to use WSGI with a URL that I need to be able to POST to under Apache 2 (using flask
). I am able to run my .wsgi
independently of Apache (python cfg.wsgi
) and it handles GET and POST requests correctly (tested with curl
) but it does not operate when run under Apache: a curl
GET request to the relevant URL (/watchdog.cfg
) returns "404 Not Found" (and if I remove the WSGI mapping the GET works absolutely fine, fully within Apache, but then of course I don't get the POST facility I'm after)
Apache is loading the .wsgi
file (its error log says so and a debug print at the top of the .wsgi
file appears in a debug log), so Python paths and interpreters are likely correct; the issue, it seems, is that the .wsgi
routing function is not being called by Apache (i.e. a debug print just inside the application
function does not appear in the debug log when the URL in question (/watchdog.cfg
) is requested).
My Apache .conf
file is:
<VirtualHost *:80>
DocumentRoot /home/http/
WSGIScriptAlias /watchdog.cfg /home/http/cfg.wsgi
<Directory /home/http>
AllowOverride none
Require all granted
</Directory>
</VirtualHost>
apache2ctl -M | grep wsgi
returns "wsgi_module (shared)", so I believe that Apache has the WSGI module installed. The file watchdog.cfg
has permissions 0644, the file cfg.wsgi
has permissions 0755.
My cfg.wsgi
file is:
from flask import Flask, request, send_file
from os import path
FILE_NAME = 'watchdog.cfg'
application = Flask(__name__)
@application.route('/' + FILE_NAME, methods=['GET', 'POST'])
def cfg():
file_path = '/home/http/' + FILE_NAME;
if request.method == 'POST':
jsonString = request.json
with open(file_path, 'w') as f:
f.write(jsonString)
return "File updated successfully.", 200
elif request.method == 'GET':
if path.exists(file_path):
return send_file(file_path, mimetype='application/json')
else:
return "File not found.", 404
if __name__ == '__main__':
application.run(host='0.0.0.0', port=80)
This is on Raspbian Linux. Any suggestions as to why my routing function is not being called by Apache?
For the record, here is the Flask-less version of my cfg.wsgi
which did work (same Apache .conf
file contents):
from os import path
import logging
FILE_NAME = 'watchdog.cfg'
def application(environ, start_response):
file_path = path.join(path.dirname(path.realpath(__file__)), FILE_NAME)
try:
if environ['REQUEST_METHOD'] == 'GET':
if path.exists(file_path):
start_response('200 OK', [('Content-Type', 'application/json')])
with open(file_path, 'r') as f:
json_data = f.read()
return [str.encode(json_data)]
else:
start_response('404 File Not Found', [('Content-Type', 'text/plain')])
return [b'File Not Found.']
elif environ['REQUEST_METHOD'] == 'POST':
try:
content_length = int(environ.get('CONTENT_LENGTH', 0))
except ValueError:
start_response('400 Bad Request', [('Content-Type', 'text/plain')])
return [b'Invalid Content-Length']
post_data = environ['wsgi.input'].read(content_length)
try:
with open(file_path, 'w') as f:
f.write(post_data.decode('utf-8'))
start_response('200 OK', [('Content-Type', 'text/plain')])
return [b'File uploaded successfully!']
except IOError as e:
start_response('500 Internal Server Error', [('Content-Type', 'text/plain')])
return [b'Failed to write file.']
else:
start_response('405 Method Not Allowed', [('Content-Type', 'text/plain')])
return [b'Method Not Allowed.']
except Exception as e:
start_response('500 Internal Server Error', [('Content-Type', 'text/plain')])
return [b'Internal Server Error.']