How to run Python scripts on a web server (e.g localhost) - python

In my development of Android and Java applications I have been using PHP scripts to interact with an online MySQL database, but now I want to migrate to Python.
How does one run Python scripts on a web server? In my experience with PHP, I have been saving my files under /var/www folder in a Linux environment. Then I just call the file later with a URL of the path. Where do I save my Python scripts?

You can use Flask to run webapps.
The simple Flask app below will help you get started.
from flask import Flask, jsonify
app = Flask(__name__)
#app.route('/sampleurl' methods = ['GET'])
def samplefunction():
#access your DB get your results here
data = {"data":"Processed Data"}
return jsonify(data)
if __name__ == '__main__':
port = 8000 #the custom port you want
app.run(host='0.0.0.0', port=port)
Now when you hit http://your.systems.ip:8000/sampleurl you will get a json response for you mobile app to use.
From within the function you can either do DB reads or file reads, etc.
You can also add parameters like this:
#app.route('/sampleurl' methods = ['GET'])
def samplefunction():
required_params = ['name', 'age']
missing_params = [key for key in required_params if key not in request.args.keys()]
if len(missing_params)==0:
data = {
"name": request.argv['name'],
"age": request.argv['age']
}
return jsonify(data)
else:
resp = {
"status":"failure",
"error" : "missing parameters",
"message" : "Provide %s in request" %(missing_params)
}
return jsonify(resp)
To run this save the flask app in a file e.g. myapp.py
Then from terminal run python myapp.py
It will start the server on port 8000 (or as specified by you.)
Flask's inbuilt server is not recommended for production level use. After you are happy with the app, you might want to look into Nginx + Gunicorn + Flask system.
For detailed instruction on flask you can look at this answer. It is about setting up a webserver on Raspberry pi, but it should work on any linux distro.
Hope that helps.

Use a web application framework like CherryPy, Django, Webapp2 or one of the many others. For a production setup, you will need to configure the web server to make them work.
Or write CGI programs with Python.

On Apache the simplest way would be to write the python as CGI here is an example:
First create an .htaccess for the web folder that is serving your python:
AddHandler cgi-script .py
Options +ExecCGI
Then write python that includes some some cgi libraries and outputs headers as well as the content:
#!/usr/bin/python
import cgi
import cgitb
cgitb.enable()
# HEADERS
print "Content-Type:text/html; charset=UTF-8"
print # blank line required at end of headers
# CONTENT
print "<html><body>"
print "Content"
print "</body></html>"
Make sure the file is owned by Apache chown apache. filename and has the execute bit set chmod +x filename.
There are many significant benefits to actually using a web framework (mentioned in other answers) over this method, but in a localhost web server environment set up for other purposes where you just want to run one or two python scripts, this works well.
Notice I didn't actually utilize the imported cgi library in this script, but hopefully that will direct you to the proper resources.

Most web development in python happens using a web framework. This is different than simply having scripts on the server, because the framework has a lot more functionality, such as handling URL routing, HTML templating, ORM, user session management, CSRF protection, and a lot of other features. This makes it easier to develop web sites, especially since it promotes component reuse, in a OOP fashion.
The most popular python web framework is Django. It's a fully-featured, tighly-coupled framework, with lots of documentation available. If you prefer something more modular and easier to customize, I personally recommend Flask. There's also lots of other choices available.
With that being said, if all you really want is to run a single, simple python script on a server, you can check this question for a simple example using apache+cgi.

Related

Is it possible to change code of flask without rerunning the flask server after deployment?

Consider, I have a flask server deployed which routes to multiple webpages. If I want to change content of one route, by changing its code, is it possible to reflect those changes in webpages without rerunning the flask server? It is possible to host and rerun other scripts on the linux server or entriely another flask server as long as the website url(port number and route) doesn't change.
Please suggest any way you can come up with!
setting flask environment will do the thing for you in the shell.
export FLASK_ENV=development
Assuming you are using flask development server,
Yes, its possible using use_reloader=True,
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello_world():
# You business logic code
return some_data
if __name__ == '__main__':
app.run(debug=False, host='0.0.0.0', port=8000,
use_reloader=True, threaded=True)
However it is not good idea to use it in production, related Is the server bundled with Flask safe to use in production?
My assumption is that you want your deployment service to recognize that a change has occurred in a file, which prompts it to automatically restart to reflect the changes, rather than you manually restarting the service.
Assuming that you are deploying on a production uWSGI server, starting the service with touch-reload=/path/to/folder would allow uWSGI to reload when the specified file/folder is modified or touched. https://uwsgi-docs.readthedocs.io/en/latest/Options.html#touch-reload
--touch-reload=/path/to/file.txt
I think you can only do this with the Apache Webserver. Refer to the Flask documentation.
I haven't tried it (yet), but when you have deployed your new code any small change in the wsgi-file should automatically reload the code.
You mentioned two requirements
I have a flask server deployed
I would assume you mean it is deployed in a production environment. This automatically rules out debug-mode from the development server, because it is not stable, efficient or secure for production use.
Without rerunning the flask server
This rules out autoreload, because this will completely restart your server. Any requests that come in until the server is ready again will fail.
One way of going about is by running your application with debug mode ON through app.run(debug=True)
The problem with this approach is that your application would be exposed over the internet with the application's internal debugger on which shouldn't be done.
A better way I can think of is to call the functions you need to change frequently from a different file other than where your core flask code exists and change in that file whenever needed. This way you don't need to change your Flask code and you won't need to restart the application
Edit:
A sample Flask route would be
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello_world():
# Route's business logic usually goes here
return data
Now, instead of writing your application's business logic in the same file as your route, you could simply write it in a different file as follows and import it in the file with the route:
File with the business logic
def process_hello_world(params):
# Write your business logic here which you want to change without reloading the application
return data
And in the application file with the route call the business logic as follows:
from flask import Flask
from
app = Flask(__name__)
#app.route('/')
def hello_world():
data = process_hello_world()
return data

How to contact server and run program on it

Background:
I need to run a program on a remote server without logging into the server. The server would only allow people to contact it, not to see what files are on it or login.
The server has in it a .py and an installation of Python. That file has the hardcoded login credentials to a database that I do not want users of the local machine program to see.
I would like to contact the server, pass it arguments and request it to run the program with them.
The reason is I don't want my program on the local machine to store the login credentials for the server, so I dont want to ssh because that would again require some form of localized credentialing which leaves the credentials exposed to the users at some point (and I never want them to see them).
Traditionally when I am making remote machine calls, its to an exposed API through the requests or http.client libraries; from what I can find, this may require the socket library, and that is a library I am not very familiar with and couldn't seem to find examples of what I am trying to do.
Server code:
import sys
from pymongo import MongoClient
usr = 'user_login'
pwd = 'user_pass'
client = MongoClient('mongodb://' + usr + ':' + pwd +'#host:port')
db = client['some_db']
db.add_user(sys.argv[1], sys.argv[2])
Question(s):
How can I do a one way request to a server containing a script file and pass it arguments?
Is this the appropriate way to handle ensuring users cannot see admin credentials?
Question 2 is somewhat out of scope here, because the underlying problem is that the program needs to create a new user account on a database, but you must be logged in with an authorized account to do so. If I hardcoded or stored credentials in a file that the local machine could see, then a savvy user could debug the program and see what they are.
I figured putting them on a server where nobody can see the files, just ask the server to run them, would be a safe bet and ensure security.
What you need seems to be a typical HTTP endpoint. Things to read and consider:
A simplest web framework, like web.py. Or you can run your program as a CGI script, no matter the language.
A config file that would keep the credentials of the mongodb admin user. Read it every time your program runs.
The hardest part: a proper authorization layer on top of your script. Else anyone will be able to run it. At the very least, basic http auth, or token bearer auth.
Unless it's inside your tiny private trusted VPN with built-in encryption, serve your endpoint over HTTPS. Since it will be fronted by a web server anyway (either as a pass-through, or via uwsgi), just use the fact that your web server already does HTTPS (and it does, right?).
a simple example
from flask import Flask, request
app = Flask(__name__)
#app.route("/adduser")
def hello():
user = request.args.get("user")
pwd = request.args.get("pwd")
client = MongoClient('mongodb://' + usr + ':' + pwd +'#host:port')
db = client['some_db']
db.add_user(user, pwd)
return "user inserted"
if __name__ == '__main__':
app.run()
and making the following request http://localhost:5000/adduser?user=root&pwd=1234
on top of that you can use POST over SSL (HTTPS) so the data will be encrypted and transmitted in the request body instead the url (like GET) this suppose to be sufficient, security wise

Flask development server with X-Sendfile

I have a Flask application that will run under Apache in production. I have some static files, but they require authenticated access. So using X-Sendfile seemed reasonable to speed up the file delivery after authentication:
flaskapp = flask.Flask()
flaskapp.use_x_sendfile = True
Then where I'm generating the response:
return flask.send_file(filepath)
It seems to work fine under Apache. The problem is when I run the development server:
# Use SharedDataMiddleware to deliver JS, CSS, icons, etc.
flaskapp.wsgi_app = SharedDataMiddleware(flaskapp.wsgi_app, {'/static': '/path/to/static'})
flaskapp.run(host='0.0.0.0', debug=True)
When I run it this way with use_x_sendfile = True, the X-Sendfile header shows up in the actual response and an empty file (0 byte) is delivered to the client. Turning off X-Sendfile (and forcing the browser to discard the cached file) fixes the issue, so it seems the Werkzeug server Flask runs isn't processing the X-Sendfile header. Is there a way to enable the development server to process X-Sendfile, or am I forced to turn this off during development?
The flask documentation mentions that the server must support the X-Sendfile, and werkzeug's dev server doesn't (there's no mention anywhere in the documentation and a grep through werkzeug's source for sendfile returned no matches).
It wouldn't probably be too hard to add this behaviour to the server, but I'm not really sure if supporting such advanced features is a priority for a developement server.
Btw, as additional keyword arguments to run are passed through to werkzeug's run_simple, you don't need to create the middleware yourself, you can just use:
flaskapp.run(host='0.0.0.0', debug=True, static_files={'/static': '/path/to/static'})

Using CherryPy/Cherryd to launch multiple Flask instances

Per suggestions on SO/SF and other sites, I am using CherryPy as the WSGI server to launch multiple instances of a Python web server I built with Flask. Each instance runs on its own port and sits behind Nginx. I should note that the below does work for me, but I'm troubled that I have gone about things the wrong way and it works "by accident".
Here is my current cherrypy.conf file:
[global]
server.socket_host = '0.0.0.0'
server.socket_port = 8891
request.dispatch: cherrypy.dispatch.MethodDispatcher()
tree.mount = {'/':my_flask_server.app}
Without diving too far into my Flask server, here's how it starts:
import flask
app = flask.Flask(__name__)
#app.route('/')
def hello_world():
return "hello"
And here is the command I issue on the command line to launch with Cherryd:
cherryd -c cherrypy.conf -i my_flask_server
Questions are:
Is wrapping Flask inside CherryPy still the preferred method of using Flask in production? https://stackoverflow.com/questions/4884541/cherrypy-vs-flask-werkzeug
Is this the proper way to use a .conf file to launch CherryPy and import the Flask app? I have scoured the CherryPy documentation, but I cannot find any use cases that match what I am trying to do here specifically.
Is the proper way to launch multiple CherryPy/Flask instances on a single machine to execute multiple cherryd commands (daemonizing with -d, etc) with unique .conf files for each port to be used (8891, 8892, etc)? Or is there a better "CherryPy" way to accomplish this?
Thanks for any help and insight.
I can't speak for Flask, but I can for CherryPy. That looks like the "proper way"...mostly. That line about a MethodDispatcher is a no-op since it only affects CherryPy Applications, and you don't appear to have mounted any (just a single Flask app instead).
Regarding point 3, you have it right. CherryPy allows you to run multiple Server objects in the same process in order to listen on multiple ports (or protocols), but it doesn't have any sugar for starting up multiple processes. As you say, multiple cherryd commands with varying config files is how to do it (unless you want to use a more integrated cluster/config management tool like eggmonster).
Terminology: Mounting vs Grafting
In principle this is a proper way to serve a flask app through cherrypy, just a quick note on your naming:
It is worth noting here that tree.mount is not a configuration key by itself - tree will lead to cherrypy._cpconfig._tree_config_handler(k, v) being called with the arguments 'mount', {'/': my_flask_server.app}.
The key parameter is not used at all by the _tree_config_handler so in your config "mount" is just an arbitrary label for that specific dict of path mappings. It also does not "mount" the application (it's not a CherryPy app after all). By that I mean, it does not cherrypy.tree.mount(…) it but rather cherrypy.tree.grafts an arbitrary WSGI handler onto your "script-name" (paths, but in CherryPy terminology) namespace.
Cherrypy's log message somewhat misleadingly says "Mounted <app as string> on /"]
This is a somewhat important point since with graft, unlike mount, you cannot specify further options such as static file service for your app or streaming responses on that path.
So I would recommend changing the tree.mount config key to something descriptive that does not invite reading too much semantics about what happens within CherryPy (since there is the cherrypy.tree.mount method) due to that config. E.g., tree.flask_app_name if you're just mapping that one app in that dict (there can be many tree directives, all of them just getting merged into the paths namespace) or tree.wsgi_delegates if you map many apps in that dict.
Using CherryPy to serve additional content without making an app of it
Another side note, if you want cherrypy to e.g. provide static file service for your app, you don't have to create a boilerplate cherrypy app to hold that configuration. You just have to mount None with the appropriate additional config. The following files would suffice to have CherryPy to serve static content from the subdirectory 'static' if they are put into the directory where you launch cherryd to serve static content (invoke cherryd as cherryd -c cherrypy.conf -i my_flask_server -i static:
static.py
import cherrypy
# next line could also have config as an inline dict, but
# file config is often easier to handle
cherrypy.tree.mount(None, '/static-path', 'static.conf')
static.conf
# static.conf
[/]
tools.staticdir.on = True
tools.staticdir.root = os.getcwd()
tools.staticdir.dir = 'static'
tools.staticdir.index = 'index.html'

How to deploy Django application at sub-url?

I need to set up a django development environment that is publicly viewable on the internet (I am doing this for school, and my projects need to be viewable by my professor, this isn't a setup that needs much security). I have a virtual server running Ubuntu 8.04 LTS.
I need to have multiple django applications running in subdirectories of my main site. That is, I need mysite.com to be a static page, mysite.com/wordpress to be my wordpress blog, and mysite.com/django1 mysite.com/django2 etc. to be django projects.
I am using apache, and I will either be using sqlite or mysql.
There seem to be as many different ways to install and configure django as there are websites offering advice, and all of them assume a single project is going to be the root of the website. I'd really appreciate some help, thank you.
You can use
WSGIScriptAlias /django1 /home/keratacon/www/django1/wsgi.py
WSGIScriptAlias /django2 /home/keratacon/www/django2/wsgi.py
in your apache+mod_wsgi config, assuming wsgi.py is the name of your wsgi script.
This blog explains the solution (assuming that mod_wsgi is used, with nginx/uwsgi the solution is similar apparently in nginx/uwsgi this is not necessary).
The first parameter of WSGIScriptAlias - the /sub-url will be stripped from the request url and the rest will go to your django app. If your Django app urls all start with /sub-url (which are stripped by mod_wsgi), then you will not be able to show the views at those urls, unless you "re-insert" the /sub-url to the request path part.
import django.core.handlers.wsgi
_application = django.core.handlers.wsgi.WSGIHandler()
def application(environ, start_response):
#the line below will re-append the sub-url to all urls
environ['PATH_INFO'] = environ['SCRIPT_NAME'] + environ['PATH_INFO']
#this one will make django think that it's the only thing running on the server
environ['SCRIPT_NAME'] = '' # my little addition to make it work
return _application(environ, start_response)
Also in your urls.py all urls must be prefixed with the sub-url of your interest.
Finally, the WSGIScriptAlias must be the same as your sub-url:
#the below line will "take-out" the sub-url and pass the rest
#to your wsgi script
WSGIScriptAlias /sub-url /path/to/wsgi_script
Where file /path/to/wsgi_script must contain the definition of application as shown in the first code snippet.
To make the "sub-url" setup explicit in Django, the equivalent request path patching would have to occur within the Django framework.

Categories

Resources