Hosting Pyramid webapps under subpaths - python

We have a hosting setup where we have one top level domain, and we host web applications under subpaths. For instance:
/projects -> Plone
/interal -> Tomcat
etc
In this scenario we need a way to tell the web application at the back end what its base path is, so that it can correctly generate links to its views and static content. For the examples above this is fine.
We have just started using Pyramid, served by Waitress, but so far we've not figure out how to do this. Is there a clean way to configure this base path in Waitress, or is there a more flexible application server that we can use that will support Pyramid?

Everything in WSGI is relative to the current request. You just have to have your environ setup properly (usually by your WSGI server).
For example your web application will know it is mounted at subpath /projects if request.environ['SCRIPT_NAME'] == '/projects'. If you want your application to be agnostic to its mount point, you can simply code it up as if it serves a view at /foo/bar. Then you mount your application on /projects via some middleware which can mutate the environ properly (mod_wsgi and some other servers should be able to do this for you automatically). Now when the incoming URL is /projects/foo/bar the environ['SCRIPT_NAME'] == '/projects' and environ['PATH_INFO'] == '/foo/bar', and your app can focus on the relative path.
In Pyramid this would boil down to an extra step in your ini where you add the prefix middleware to your WSGI stack. The middleware handles mutating the PATH_INFO and SCRIPT_NAME keys in the environ for you.
[app:myapp]
use = egg:myapp
# ...
[filter:proxy-prefix]
use = egg:PasteDeploy#prefix
prefix = /projects
[pipeline:main]
pipeline =
proxy-prefix
myapp

In my pyramid app, in the .ini config files (production and development) I'm doing something like this:
filter-with = urlprefix
[filter:urlprefix]
use = egg:PasteDeploy#prefix
prefix = /mysubfolder
I think it probably accomplishes the same as Michael's answer above; I'm still relatively new to Pyramid as well and am going off of recipes like you. But the end result is that it creates a base URL of /mysubfolder from my root and the rest of the app is relative to that. This is running under pserve locally and I think nginix on my web host.

repoze.vhm should work just fine for your use case.
I think it won't work if you want to use the virtual root feature. I.e a subpath of your proxied web app (https://hidden.tld/root/ should appear as https://example.com/ )
For exposing your app at a subpath of an external domain repoze.vhm works just fine. IMO the best thing about it is, that you don't need to put any subpath config or whatsoever into your web app deployment. This allows you to change the url to whatever you want on the proxy, or even expose the same app instance on multiple domain names and/or subpaths.

Related

Flask application alongside Node.JS application

I wrote a Flask web application for a system that our company uses. However, we have another web application, which is running on Node.JS. The "problem" is that my colleague writes everything on node, while I write everything in Python.
We want to implement both applications on one webpage - for example:
My application will run on example.com/assistant
His application will run on example.com/app1 and example.com/app2
How can we do this? Can we somehow implement the templates that I use with his templates and vice-versa?
Thank you in advance!
V
Serving different apps from the same domain
You can use haproxy for directing requests to specific service based on ACL rules.
You could use path_beg rule, to direct any request beginning with specific path to be directed to corresponding server. See example below.
/etc/haproxy/haproxy.cfg
# only relevant part of the config file
# assumes all apps are on one machine
frontend http-in
bind *:80
acl py_app1 path_beg /assistant
acl node_app1 path_beg /app1
acl node_app2 path_beg /app2
default_backend main_servers
backend py_app1
server flask_app 127.0.0.1:5000
backend node_app1
server nodejs1 127.0.0.1:4001
backend node_app2
server nodejs2 127.0.0.1:4002
backend main_servers
server other1 127.0.0.1:3000 # nginx, apache, or whatever
Sharing template code between apps
This would be harder, as you would need to both agree on some kind of format, which needs to be language and framework-agnostic, and probably logic-less.
Mustache claims to be "framework-agnostic way to render logic-free views". I used it sparringly a few years ago so this one is first that came to mind, however you should do more research on this, maybe there is some better fit.
Python implementation
JS implementation
The problem would be to actually keep the templates always in sync with apps, and not break functionality of the views. If a template changes then you would need to test all apps that use this template file. Also, you probably will block one another from updating your apps at different times, because if one of you change the template files, then you must come to a consensus, update all relevant apps, and deploy them at one time.

What does UPLOADS_DEFAULT_URL configuration value in flask uploads mean?

From this page:
UPLOADS_DEFAULT_URL
If you have a server set up to serve from
UPLOADS_DEFAULT_DEST, then set the server’s base URL here. Continuing
the example above, if /var/uploads is accessible from
http://localhost:5001, then you would set this to
http://localhost:5001/ and URLs for the photos set would start with
http://localhost:5001/photos. Include the trailing slash.
However, you
don’t have to set any of the _URL settings - if you don’t, then they
will be served internally by Flask. They are just there so if you have
heavy upload traffic, you can have a faster production server like
Nginx or Lighttpd serve the uploads.
I do not understand how Flask uses UPLOADS_DEFAULT_URL. The text says that if you don't specify it the uploads will be served internally by flask. Questions:
On what url are they going to be served by flask if I don't specify the url?
If I do specify URL what flask is going to do with it? How is it going to use it?
So it's easier to answer my question: I don't know how exactly python interacts with a web server such as apache or nginx. I do understand that in principle you want these web servers to front/proxy you python app for scalability/load but I don't know exact details on how this is done. May be if I knew that, the information above would be more obvious to me.
From practical perspective: I have someone else's python/flask app, and not a lot of experience with python. The parameter above needs to be specified in the config files. I got the app up and running, I did not specify this particular parameter, the uploads are working fine. I'm wondering what else could I have possibly broken by not specifying the URL.
On what url are they going to be served by flask if I don't specify the url?
From the doc i understand that if you set like this
UPLOADS_DEFAULT_DEST = '/var/uploads/'
UPLOADS_DEFAULT_URL = 'http://localhost:5000/'
Then when you upload a set named photos will store its uploads in /var/uploads/photos.Lets assume it as /var/uploads/photos/test.jpg.Then flask will serve the image as
http://localhost:5000/photos/test.jpg.
If I do specify URL what flask is going to do with it? How is it going to use it?
Let if
UPLOADED_PHOTOS_DEST = '/var/mypics/'
UPLOADED_PHOTOS_URL = 'http://localhost:5000/'
Then when you upload a set named photos will store its uploads in /var/mypics/.Lets assume it as /var/mypics/test.jpg.Then flask will serve the image as
http://localhost:5000/test.jpg.
But we do not use this in production.In production images, statics should be served by nginx or apache

Twisted redirect subdirectory to another domain

I'm hosting a couple domains static files with Twisted. However, for a subdirectory of the domain, I want to redirect to another domain.
For example: Serve foo.com static files, but foo.com/bar goes to foobar.com/bar
I can't seem to find anything in the Twisted docs for this scenario.
Update
I replied to Glyph that it wasn't working, but I had placed it in the wrong spot. His suggestion was, of course, absolutely correct. I should have provided more initial info. Here it is implemented:
from twisted.application import internet, service
from twisted.web import static, server, vhost, script
from twisted.web.util import Redirect
root = vhost.NameVirtualHost()
# Add a default -- htdocs
root.default=static.File("/home/foo")
root.putChild("myredirect", Redirect("http://othersite.com/myredirect"))
# Add a simple virtual host -- bar.com
root.addHost("bar", static.File("bar"))
# Add a simple virtual host -- foo.com
root.addHost("foo", static.File("/home/foo"))
application = service.Application('web')
sc = service.IServiceCollection(application)
site = server.Site(root)
i = internet.TCPServer(80, site)
i.setServiceParent(sc)
This is pretty straightforward, although it depends on how your site is set up.
Basically though,
from twisted.web.util import Redirect
fooDotComResource.putChild("bar", Redirect("http://foobar.com/bar"))

Django Admin Page broken links

I am deploying a Django app using uwsgi.
The app is deployed under SERVER_URL:PORT.
Using a proxy server, the app can be accessed also via EXTERNAL_WEB_SITE/MY_APP_NAME.
When using the admin page, under: EXTERNAL_WEB_SITE/MY_APP_NAME/ADMIN/, I can see the correct models. But, the links in the admin page that direct to the models themselves direct to: EXTERNAL_WEB_SITE/ADMIN/MAIN_PACKAGE/SELECTED_MODEL/. That is - the MY_APP_NAME won't pass in the link provided.
I suppose this is because in the server itself the app is deployed with no app name, just under a specific port.
In order to solve it, I tried defining FORCE_SCRIPT_NAME=MY_APP_NAME in settings.py. This gives me good links. BUT - when trying to modify an object and save it - under EXTERNAL_WEB_SITE/MY_APP_NAME/ADMIN/MAIN_PACKAGE/SELECTED_MODEL/ITEM/ - after hitting Save I am linked to EXTERNAL_WEB_SITE/MY_APP_NAME/MY_APP_NAME/ADMIN/MAIN_PACKAGE/SELECTED_MODEL/ITEM/ - that is - I get MY_APP_NAME twice.
Does anyone know how to solve this issue?
you need to pass SCRIPT_NAME env variable with your request from proxy server
alternatively you could have two instances running one with FORCE_SCRIPT_NAME set and second without
uwsgi have a nice option, that you can deploy your app on two ports or (even better) set env variable depending on headers or paths
[uwsgi]
route = ^(/MY_APP_NAME)/ addvar:SCRIPT_NAME=$1

cherrypy and relative path in WSGI app

running cherrypy with mod_wsgi on apache along with another php app. The cherrypy app is NOT mounted on root, but rather on something like 'localhost/apps/myapp' via WSGIScriptAlias in the apache config file.
In testapp.py, I have tried the following, and when I try to access localhost/apps/myapp in a browser:
app = cherrypy.tree.mount(MyApp(), '', 'settings.config') #FAILS WITH 404
and
app = cherrypy.tree.mount(MyApp(), '/apps/myapp', 'settings.config') # WORKS
The first case fails because cherrypy expects to be at the server root, instead of relative to where it is mounted via WSGI in apache.
Is there a preferred way to make cherrypy apps work relative to the path they are mounted in apache under WSGIScriptAlias?
Basically, I'll be running several cherrypy apps under several different paths, and would prefer if apache handled the dispatching (i.e. cherrypy just runs the app and doesn't worry about the relative path). This way i can avoid updating several different python files/config files everytime some of the relative paths on the server change.
Any suggestions?
btw, the cherrypy app is currently passed to the wsgi application as follows:
app = cherrypy.tree.mount(HelloWorld(), '', 'settings.config')
return app(environ, start_response)
I am doing this, although this would require cherrypy to know the relative path:
class Dir: pass
root = Dir()
root.apps = Dir()
root.apps.myapp = MyApp()
cherrypy.tree.mount(root)
This allows me to structure the application in any way I need. I'm using nginx and not Apache, but I don't think it'll make any difference. Although it gets a bit wordy if you're using long paths with not much else in between.
cherrypy can support other dispatchers which might be better suited to what you're trying to do, or perhaps you need to write a custom one.
how should this
app = cherrypy.tree.mount(MyApp(), '', 'settings.config')
resolve http://localhost/apps/myapp ?
have u tried http://localhost/ or http://localhost/MyApp.
it is also important where u have defined your WSGIScriptAlias in Apache.
vhost, location?

Categories