Quick context:
I have a Ubuntu 14.04 LAMP Server that's been hosting my ExtJS Website for a pretty long time.
Recently, I've had the opportunity of tinkering with DialogFlow, and I've also made a Python Flask app to serve as the Webhook for when the DialogFlow reaches fulfilment.
Now, I was able to test my Python App. I run it, and then I used ngrok to get a public IP for my webhook. My custom DialogFlow is able to send a POST request to my Python App, and my Python app is able to parse the request and give the output I want.
Now, I want to upload this Python Flask app to my Web Server. I have issues with most of the guides I have seen:
- They listen on Port 80 -- This would block the existing Website I have
- They don't work on SSL -- Most of them use the default http-conf file.
Since my DialogFlow is integrated with Google Assistant, my Python Flask app should be hosted on an HTTPS server. I used Lets Encrypt to get my SSL.
Before I proceed, I want to give an overview of my servers file structure:
|----->/var/www/html/
|----->index.html
|----->FlaskAppFolder
|----->flask_test.py (my flask app)
|----->flaskapp.wsgi
This is my default-ssl.conf
file:
<IfModule mod_ssl.c>
<VirtualHost _default_:443>
ServerAdmin my.email@my.domain.com
ServerName mysite.com
ServerAlias www.mysite.com
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/apache.crt
SSLCertificateKeyFile /etc/apache2/ssl/apache.key
<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory /usr/lib/cgi-bin>
SSLOptions +StdEnvVars
</Directory>
BrowserMatch "MSIE [2-6]" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
</VirtualHost>
<VirtualHost _default_:5000>
ServerAdmin my.email@my.domain.com
ServerName mysite.com
ServerAlias www.mysite.com
WSGIScriptAlias / /var/www/html/FlaskAppFolder/flaskapp.wsgi
DocumentRoot /var/www/html/DocumentSearcher
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/apache.crt
SSLCertificateKeyFile /etc/apache2/ssl/apache.key
<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory /usr/lib/cgi-bin>
SSLOptions +StdEnvVars
</Directory>
BrowserMatch "MSIE [2-6]" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
</VirtualHost>
</IfModule>
The first VirtualHost
is for the default port 80, so that my website would still show up. The second VirtualHost
is for port 5000, the port that my flask app uses when I run it.
The following is my port.conf
file:
Listen 80
<IfModule ssl_module>
Listen 443
</IfModule>
<IfModule mod_gnutls.c>
Listen 443
</IfModule>
I found that I can't add Listen 5000
to it. I tried adding Listen 5000
anywhere in the file, may it be under Listen 50
or Listen 443
, my Python Flask app tells me that the port is already under use.
And then this is my flask app names flask_test.py:
import subprocess
import sys
import time
from flask import Flask
from flask import render_template
from flask import make_response
from flask import jsonify
from flask import request
import ssl
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.load_cert_chain('/path/to/my/apache.crt', '/path/to/my/apache.key')
# app = Flask(__name__)
app = Flask('flaskshell')
# function for responses
def results():
# build a request object
req = request.get_json(force=True)
# fetch action from json
action = req.get('queryResult').get('action')
parameters = req.get('queryResult').get('parameters')
keyword = parameters.get('any');
result = #some process here
output = #some process here
output = output.replace('\n', '\n \n')
return {'fulfillmentText': 'Result: \n\n' + str(output)}
# create a route for webhook
@app.route('/', methods=['GET', 'POST'])
def webhook():
# return response
return make_response(jsonify(results()))
# run the app
if __name__ == '__main__':
app.run(host='0.0.0.0', ssl_context=context)
Finally, my flaskapp.wsgi
file:
import sys
import logging
logging.basicConfig(stream=sys.stderr)
sys.path.insert(0, "/var/www/html/DocumentSearcher/")
from flask_test import app as application
Basically, I make sure it runs on https
instead of http
, and it uses port 5000. My Python Flask app will take the POST request from DialogFlow and then use that as input in an internal process, and then return the result out to DialogFlow for a response.
Now, in my DialogFlow's Fulfilment Webhook, I added in my URL and port as such:
https:www.mysite.com:5000
I try a query that I know works, but it doesn't. When I inspect the Diagnostic Info, it tells me that the request timed out. I know that it works because when I hook up the local version to ngrok, and hookup that up to DialogFlow, it works just fine.
Now I'm not sure what to do next. It seems that I can't add port 5000 to my port.conf
file since it will block my Python Flask App from running on port 5000. However, it also seems that it's not just enough to add a VirtualHost for port 5000 on my default-ssl.conf
file.
Any ideas how I can make my Python Flask app visible to the outside world?