0

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:

  1. They listen on Port 80 -- This would block the existing Website I have
  2. 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?

  • Flask is normally deployed with mod_wsgi (Apache) or uWSGI (nginx). See the linked documentation. – Michael Hampton May 18 at 16:06
  • @MichaelHampton yeah but Flask's own documentation doesn't show how to config your ssl Virtual Host, it just uses the default one..? – Razgriz May 19 at 0:16
  • That's not really particular to Flask, so there's no reason to expect to find it there. – Michael Hampton May 19 at 0:20
  • So how do I achieve my goal, then? – Razgriz May 20 at 2:44
  • I would suggest dropping an idea to run flask application over SSL. Your Apache server should cover SSL connections and proxy the necessary requests to your Flask application over http to whatever port it runs on. You could still keep Flask configured on Apache too. So Apache will proxy from one virtual host to another. Just ensure you don't allow connections to Flask from anywhere but localhost. – Sergey Nudnov May 20 at 4:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.