How to deploy Django application at sub-url? - python

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.

Related

Python Flask "The configuration file does not exist." accessing sub-path

I am deploying Flask on CPanel, and basic configurations are working correctly,
up to the point that I can access home route, defined as:
#app.route("/home")
#app.route("/")
def home():
return "This is home page, blah blah blah"
The site can be thought of, as being accessed at
https://sub-domain.main-domain.com/base-url,
thus, home page is accessed as https://sub-domain.main-domain.com/base-url/ and that works perfectly.
Problem
So, the issue comes when I access any other route, other than the slash("/"),
in the above example, for instance, accessing
https://sub-domain.main-domain.com/base-url/home,
doesn't seem to work at all, and results in
The configuration file does not exist. error.
Any possible help would be kindly appreciated. my passenger_wsgi.py is configured as:
import sys
# add your project directory to the sys.path
base_dir = u'/home/cpaneusername/base-dir'
if base_dir not in sys.path:
sys.path = [base_dir] + sys.path
# import flask app but need to call it "application" for WSGI to work
from app import website as application
Nevertheless, thanks for the assistance.
What I can suggest resolving the issue is to change the base URL of your Python app and remove any sub-folders from it. For example, just keep it that way:
https://sub-domain.main-domain.com/
And try again.
Otherwise, you might want to change the /home route of your app to this one instead:
#app.route("/base-url/home")
If none of the above works, then make sure that you have the correct .htaccess rules in place to forward the requests properly to your app, but I assume you already have considering the fact that you are able to access the / of the app.
I tried moving the Python app and other supporting modules to /public folder, and in the wsgi file, I imported as
from public.app import website as application
There, it worked.

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

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.

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 hide "cgi-bin", ".py", etc from my URLs?

Brand new to web design, using python. Got Apache up and running, test python script working in cgi-bin directory. Get valid results when I type in the URL explicitly: ".../cgi-bin/showenv.py"
But I don't want the URL to look that way. Here at stackoverflow, for example, the URLs that display in my address bar never have the messy details showing the script that was used to run them. They're clean of cgi-bin, .py, etc. extensions. How do I do that?
EDIT: Thanks for responses, every single one helpful, lots to learn. I'm going with URL Rewriting for now; example in the docs looks extremely close to what I actually want to do. But I'm committed to python, so will have to look at WSGI down the road.
The python way of writing web applications is not cgi-bin. It is by using WSGI.
WSGI is a standard interface between web servers and Python web applications or frameworks. The PEP 0333 defines it.
There are no disadvantages in using it instead of CGI. And you'll gain a lot. Beautiful URLs is just one of the neat things you can do easily.
Also, writing a WSGI application means you can deploy on any web server that supports the WSGI interface. Apache does so by using mod_wsgi.
You can configure it in apache like that:
WSGIScriptAlias /myapp /usr/local/www/wsgi-scripts/myapp.py
Then all requests on http://myserver.domain/myapp will go to myapp.py's application callable, including http://myserver.domain/myapp/something/here.
example myapp.py:
def application(environ, start_response):
start_response('200 OK', [('Content-type', 'text/plain')])
return ['Hello World!']
I think you can do this by rewriting URL through Apache configuration. You can see the Apache documentation for rewriting here.
You have to use URL Rewriting.
It is not a noob question, it can be quite tricky :)
http://httpd.apache.org/docs/2.0/misc/rewriteguide.html
Hope you find it helpful
this is an excerpt from a .htaccess that I use to achieve such a thing, this for example redirects all requests that were not to index.php to that file, of course you then have to check the server-variables within the file you redirect to to see, what was requested.
Or you simply make a rewrite rule, where you use a RegExp like ^.*\/cgi-bin\/.*\.py$ to determine when and what to rewrite. Such a RegExp must be crafted very carefully, so that rewriting only takes place when desired.
<IfModule mod_rewrite.c>
RewriteEngine On #activate rewriting
RewriteBase / #url base for rewriting
RewriteCond %{REQUEST_FILENAME} !index.php #requested file is not index.php
RewriteCond %{REQUEST_FILENAME} !^.*\.gif$ #requested file is no .gif
RewriteCond %{REQUEST_FILENAME} !^.*\.jpg$ #requested file is no .jpg
RewriteCond %{REQUEST_FILENAME} !-d #is not a directory
RewriteRule . /index.php [L] #send it all to index.php
</IfModule>
The above Example uses RewriteConditions to determine when to rewrite ( .gif's, .jpeg's and index.php are excluded ).
Hmm, so thats a long text already. Hope it was a bit helpful, but you won't be able to avoid learning the syntax of the Apache RewriteEngine.
You'll find the ScriptAlias directive helpful. Using
ScriptAlias /urlpath /your/cgi-bin/script.py
you can access your script via http://yourserver/urlpath.
You also might want to look into mod_passenger, though the last time I used it, WSGI was kind of a "second-class citizen" within the library—it could detect WSGI scripts if it were used to serve the whole domain, but otherwise there are no directives to get it to run a WSGI app.
Just use some good web framework e.g. django and you can have such URLs
more than URLs you will have a better infrastructure, templates, db orm etc

Categories

Resources