Difference between revisions of "Flask"

From wiki
Jump to navigation Jump to search
 
(7 intermediate revisions by the same user not shown)
Line 37: Line 37:
 
Mayor part is from this site [https://vladikk.com/2013/09/12/serving-flask-with-nginx-on-ubuntu/].
 
Mayor part is from this site [https://vladikk.com/2013/09/12/serving-flask-with-nginx-on-ubuntu/].
  
* Install uwgi-emperor and it's python plugin
+
* Install [[uwsgi]].
Configuration files I used.
 
 
 
:* Generic configuration file (/etc/uwsgi-emperor/emperor.ini):
 
[uwsgi]
 
# try to autoload appropriate plugin if "unknown" option has been specified
 
autoload = true
 
# enable master process manager
 
master = true
 
# spawn 2 uWSGI emperor worker processes
 
workers = 2
 
# automatically kill workers on master's death
 
no-orphans = true
 
# place timestamps into log
 
log-date = true
 
# user identifier of uWSGI processes (same as who runs the web-server)
 
uid = www-data
 
# group identifier of uWSGI processes (same as who runs the web-server)
 
gid = www-data
 
# vassals directory
 
emperor = /etc/uwsgi-emperor/vassals
 
plugins = python3
 
 
 
:* Application configuration file (/etc/uwsgi-emperor/vassals/welcome.ini)
 
 
 
[uwsgi]
 
#application's base folder
 
base = /var/www/flask
 
#python module to import
 
app = welcome
 
module = %(app)
 
pythonpath = %(base)
 
#socket file's location
 
socket = /var/local/uwsgi/%n.sock
 
#permissions for the socket file
 
chmod-socket    = 664
 
#the variable that holds a flask application inside the module imported at line #6
 
callable = app
 
#location of log files
 
logto = /var/log/uwsgi/%n.log
 
plugins = python3
 
  
 
* Create a virtual webserver (port 80 is save enough if you have a secure front-end server)
 
* Create a virtual webserver (port 80 is save enough if you have a secure front-end server)
Line 83: Line 43:
 
<syntaxhighlight lang="nginx">
 
<syntaxhighlight lang="nginx">
 
server {
 
server {
listen 80 ;
+
    listen 80 ;
listen [::]:80 ;
+
    listen [::]:80;
  
root /var/www/flask;
+
    root /var/www/flask;
 +
    server_name <fqdn>;
  
server_name <fqdn>;
+
    location /app1 {
 
+
        include uwsgi_params;
location / {
+
        uwsgi_param SCRIPT_NAME /app1;
include uwsgi_params;
+
        uwsgi_modifier1 30;
        uwsgi_pass unix:/var/local/uwsgi/welcome.sock;
+
        uwsgi_pass unix://tmp/app1.sock;
}
+
    }
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=Generate web pages=
+
===Super simple app===
https://flask.palletsprojects.com/en/1.1.x/patterns/templateinheritance/#template-inheritance
+
In /var/www/flask/app1/app1.py
 
 
 
 
[https://www.idkrtm.com/creating-a-webpage-using-python-and-flask/ Source for this basic app]
 
 
 
Put a index.html in <app-base>/templates/
 
 
 
<syntaxhighlight lang=python>
 
#!/usr/bin/env python3
 
 
 
from flask import Flask, render_template
 
 
 
print(__name__)
 
app = Flask(__name__)
 
 
 
@app.route('/html')
 
def static_page():
 
  return render_template('index.html')
 
 
 
if __name__ == '__main__':
 
    app.run(host='0.0.0.0',port=5000,debug=True)
 
 
 
</syntaxhighlight>
 
 
 
=Microservices and/or more applications on 1 web-server=
 
 
 
Starting with [https://jawher.me/multiple-python-apps-with-nginx-uwsgi-emperor-upstart/ this page] and additional a lot more we got it working on [https://www.raspberrypi.org/software/ raspberry pi debian].
 
 
 
# Make python3 the default<br><code>cd /usr/bin;rm python;ln -s python3 python</code>
 
# Install uwsgi and python plugin<br><code>apt install uwsgi uwsgi-plugin-python3</code>
 
# install nginx<br><code>apt install nginx-full</code>
 
I had to make a small change in the nginx configuration;<br>
 
<code>vi /etc/nginx/conf.d/my.conf<br>
 
server_names_hash_bucket_size 64;
 
</code>
 
 
 
===Super simple apps===
 
In /var/www/flask/app1/app1/py
 
 
<syntaxhighlight lang=python>
 
<syntaxhighlight lang=python>
 
#!/usr/bin/env python3
 
#!/usr/bin/env python3
Line 152: Line 76:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
/var/www/flask/app2/app2.py
+
That's it. Point your webbrowser to http://<your webserver fdqn>/app1</code> and it will show you: "App 1 live and kicking"
 +
 
 +
=Running applications=
 +
You can make any number of applications by adding more apps to [[uwsgi]] and a location in [[nginx]]. You can also run any number of programs by adding routes to an app or with just a few routes like this:
 +
 
 
<syntaxhighlight lang=python>
 
<syntaxhighlight lang=python>
 
#!/usr/bin/env python3
 
#!/usr/bin/env python3
  
from flask import Flask
+
from flask import Flask, render_template
 
import os
 
import os
 +
import subprocess
  
 +
### Application whitelist
 +
whitelist = {
 +
    'script as in URL' :'<scriptlocation>',
 +
    'script as in URL' :'<another scriptlocation>',
 +
    }
 +
   
 
application = Flask(__name__)
 
application = Flask(__name__)
  
@application.route('/app2')
+
@application.route('/app1/<script>/<path:arguments>')
def app2():
+
def func1(script,arguments):
     return "App 2 live and kicking"
+
    if script in whitelist:
 +
        arglist = arguments.split('/')
 +
        result = subprocess.run([whitelist[script]]+arglist, stdout=subprocess.PIPE)
 +
        output = result.stdout
 +
    else:
 +
        output = '{} does not exist in whitelist'.format(script)
 +
    return output
 +
   
 +
@application.route('/app1/<script>')
 +
def func2(script):
 +
    if script in whitelist:
 +
        result = subprocess.run([whitelist[script]], stdout=subprocess.PIPE)
 +
        output = result.stdout
 +
    else:
 +
        output = '{} does not exist in whitelist'.format(script)
 +
     return output
  
 
if __name__ == '__main__':
 
if __name__ == '__main__':
Line 169: Line 119:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
===uwsgi configuration===
+
The route is the request URI as passed by the webserver. In this case 'app1' is the location. The things in <> are converted to python variables. <path:arguments> will put everything, including the '/'-es into 1 variable (arguments). So you can have a variable number of arguments that all will be passed to the pythonscript called by subprocess.
  
/etc/uwsgi/apps-available/emperor.xml
+
The whitelist is there for security to avoid one can run any script is knows the location for.
<syntaxhighlight lang=xml>
 
<uwsgi>
 
  <autoload>true</autoload>
 
  <no-orphan>true</no-orphan>
 
  <emperor>/etc/uwsgi/vassals-enabled</emperor>
 
  <master>true</master>
 
  <emperor-nofollow>true</emperor-nofollow>
 
  <processes>1</processes>
 
  <uid>www-data</uid>
 
  <gid>www-data</gid>
 
</uwsgi>
 
</syntaxhighlight>
 
  
/etc/uwsgi/apps-available/apps.xml
+
=Generate web pages=
<syntaxhighlight lang=xml>
 
<uwsgi>
 
  <plugins>python3</plugins>
 
  <master>false</master>
 
  <processes>1</processes>
 
  <vaccum>true</vaccum>
 
  <chmod-socket>666</chmod-socket>
 
  <socket>/tmp/%n.sock</socket>
 
  <uid>www-data</uid>
 
  <gid>www-data</gid>
 
  <pythonpath>/var/www/flask/%n</pythonpath>
 
  <module>%n</module>
 
</uwsgi>
 
</syntaxhighlight>
 
  
Make them available
+
Flask is by default using the [https://jinja.palletsprojects.com jinja] template engine. They have a nice tutorial for this too[https://flask.palletsprojects.com/en/2.0.x/tutorial/].
<syntaxhighlight lang=bash>
 
cd /etc/uwsgi/apps-enabled
 
ln -s ../apps-available/emperror.xml
 
cd /etc/uwsgi/vassals-enabled
 
ln -s ../apps-available/apps.xml app1.xml
 
ln -s ../apps-available/apps.xml app2.xml
 
</syntaxhighlight>
 
  
===Create a nginx virtual host===
+
Very simple example is to put a index.html in <code><app-base>/templates/</code>
  
/etc/nginx/sites-enabled/apps.conf
+
<syntaxhighlight lang=python>
 +
#!/usr/bin/env python3
  
<syntaxhighlight lang=nginx>
+
from flask import Flask, render_template
server {
+
 
  listen 80;
+
print(__name__)
  server_name <your webserver fdqn>;
+
app = Flask(__name__)
  index index.html;
 
  
  root /var/www/flask;
+
@app.route('/app1/html')
 +
def static_page():
 +
  return render_template('index.html')
  
  location /app1 {
+
if __name__ == '__main__':
     include uwsgi_params;
+
     app.run(host='0.0.0.0',port=5000,debug=True)
    uwsgi_param SCRIPT_NAME /app1;
 
    uwsgi_modifier1 30;
 
    uwsgi_pass unix://tmp/app1.sock;
 
  }
 
  
  location /app2 {
 
    include uwsgi_params;
 
    uwsgi_param SCRIPT_NAME /app2;
 
    uwsgi_modifier1 30;
 
    uwsgi_pass unix://tmp/app2.sock;
 
  }
 
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
 
===Start things===
 
service uwsgi start
 
service nginx start
 
 
That's it. Point your webbrowser to http://<your webserver fdqn>/app1
 
 
Optimization still to be done. I think I start on [https://www.techatbloomberg.com/blog/configuring-uwsgi-production-deployment/ this place]
 

Latest revision as of 08:56, 21 July 2021

Basics

Check this[1]

Hello world app:

#!/usr/bin/env python3

from flask import Flask
print(__name__)
app = Flask(__name__)

@app.route('/')

def welcome():
    return 'Welcome'

if __name__ == '__main__':         # When executed on the commandline (build in webserver)
    app.run(host='0.0.0.0',port=5000) # Listen to localhost port 5000, you can also use flask run for options
    #app.run(host='0.0.0.0',port=8080,Debug=True)  # Run in debug mode, listen to all hosts on port 8080

Run the build-in server listening to all

export FLASK_APP=welcome_app.py 
flask run --host=0.0.0.0
welcome_app
 * Serving Flask app "welcome_app"
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

Now you can browse to <serverIP>:5000

https://code.tutsplus.com/tutorials/creating-a-web-app-from-scratch-using-python-flask-and-mysql--cms-22972

Integrate with nginx

Mayor part is from this site [2].

  • Create a virtual webserver (port 80 is save enough if you have a secure front-end server)
server {
    listen 80 ;
    listen [::]:80;

    root /var/www/flask;
    server_name <fqdn>;

    location /app1 {
        include uwsgi_params;
        uwsgi_param SCRIPT_NAME /app1;
        uwsgi_modifier1 30;
        uwsgi_pass unix://tmp/app1.sock;
    }
}

Super simple app

In /var/www/flask/app1/app1.py

#!/usr/bin/env python3

from flask import Flask
import os

application = Flask(__name__)

@application.route('/app1')
def app1():
    return "App 1 live and kicking"

if __name__ == '__main__':
    application.run(host='0.0.0.0', port=8080,debug=True)

That's it. Point your webbrowser to http://<your webserver fdqn>/app1 and it will show you: "App 1 live and kicking"

Running applications

You can make any number of applications by adding more apps to uwsgi and a location in nginx. You can also run any number of programs by adding routes to an app or with just a few routes like this:

#!/usr/bin/env python3

from flask import Flask, render_template
import os
import subprocess 

### Application whitelist
whitelist = {
    'script as in URL' :'<scriptlocation>',
    'script as in URL' :'<another scriptlocation>',
    }
    
application = Flask(__name__)

@application.route('/app1/<script>/<path:arguments>')
def func1(script,arguments):
    if script in whitelist:
        arglist = arguments.split('/')
        result = subprocess.run([whitelist[script]]+arglist, stdout=subprocess.PIPE)
        output = result.stdout
    else:
        output = '{} does not exist in whitelist'.format(script)
    return output
    
@application.route('/app1/<script>')
def func2(script):
    if script in whitelist:
        result = subprocess.run([whitelist[script]], stdout=subprocess.PIPE)
        output = result.stdout
    else:
        output = '{} does not exist in whitelist'.format(script)
    return output

if __name__ == '__main__':
    application.run(host='0.0.0.0', port=8080,debug=True)

The route is the request URI as passed by the webserver. In this case 'app1' is the location. The things in <> are converted to python variables. <path:arguments> will put everything, including the '/'-es into 1 variable (arguments). So you can have a variable number of arguments that all will be passed to the pythonscript called by subprocess.

The whitelist is there for security to avoid one can run any script is knows the location for.

Generate web pages

Flask is by default using the jinja template engine. They have a nice tutorial for this too[3].

Very simple example is to put a index.html in <app-base>/templates/

#!/usr/bin/env python3

from flask import Flask, render_template

print(__name__)
app = Flask(__name__)

@app.route('/app1/html')
def static_page():
  return render_template('index.html')

if __name__ == '__main__':
    app.run(host='0.0.0.0',port=5000,debug=True)