How do I manipulate subdomains with Pyramid's url dispatch? [duplicate] - python

I'm looking to have multiple domains and subdomains on a single Pyramid instance. However, I can't seem to find any documentation on it. The last question referred to a glossary with very little information and no examples. Do any of you have any examples or can direct me to better documentation?

Pyramid is just a WSGI application. This means it's dependent on the HTTP_HOST environ key (set by the Host header) to determine the host of the application. It's all relative. Point-being that Pyramid has no restrictions on what it can accept, thus the world is your oyster and you can set it up to limit content to various domains however you'd like. This of course starts with what hosts your webserver is configured to feed to your application.
Assuming you're using URL dispatch, you might want to design some custom route predicates that check the request.host value for whatever you'd like. Returning False from that predicate will prevent that route from ever matching a request to that host.
This is a large topic, so it might help if you give some more specifics. For example, since Pyramid is relative, any URL you may want to generate from 'example.com' to redirect someone to 'sub.example.com' will need to be done via a pregenerator.
def pregen(request, elements, kw):
kw['_app_url'] = 'http://sub.example.com'
return elements, kw
def req_sub(info, request):
return request.host.startswith('sub')
config.add_route('sub_only', '/',
custom_predicates=(req_sub,),
pregenerator=pregen)
config.add_route('foo', '/foo')
config.add_view(view, route_name-'foo')
def view(request):
# redirect the user to "http://sub.example.com", regardless of whether
# request.host is "example.com" or "sub.example.com"
return HTTPFound(request.route_url('sub_only'))

If you have control over your hosting environment, I would strongly suggest keeping the domain stuff out of pyramid and handling it with a proxy server such as apache mod proxy, routing to subdomains in pyramid. Then you can easily switch any of the domain name to view routing without having anything fragile (like domain names) in your pyramid code. Your app code will be much cleaner this way, and far easier to change later.
Here's an Apache example of two domains going to one pyramid app, assuming we are serving the pyramid app somehow or another on port 5001 (gunicorn or whatever you want).
<VirtualHost *:80>
ServerName domain_2.com
ProxyPreserveHost On
# send all request to our app at /app1/*
ProxyPass / http://127.0.0.1:5001/app_1/
ProxyPassReverse / http://127.0.0.1:5001/app_1/
</VirtualHost>
<VirtualHost *:80>
ServerName domain_2.com
ProxyPreserveHost On
# send all request to our app at /app2/*
ProxyPass / http://127.0.0.1:5001/app_2/
ProxyPassReverse / http://127.0.0.1:5001/app_2/
</VirtualHost>
And here's an example of one domain going to several pyramid instances:
<VirtualHost *:80>
ServerName mydomain.com
ProxyPreserveHost On
# admin go to manager app on 5001
ProxyPass /media/manager/ http://127.0.0.1:5001/ retry=5
ProxyPassReverse /media/manager/ http://127.0.0.1:5001/
# downloads from server app on 5002
ProxyPass /media/server/ http://127.0.0.1:5002/ retry=5
ProxyPassReverse /media/server/ http://127.0.0.1:5002/
</VirtualHost>

Related

Multiple Python Flask apps on single apache server losing sessions when session.clear is called on one of the apps

I have a couple of python 3.6 Flask apps running on my apache server using WSGI.
There are 2 different apps running on the same apache server:
www.example.com/lodge
www.example.com/dashboard
Both apps have a unique app.secret_key
The /dashboard app is a flask app with its own set of routes:
/dashboard/login
/dashboard/orders
/dashboard/staff
The login route calls session.clear() and lets the user enter their login information. A logged in token then gets stored in a session variable.
Both the /dashboard/orders and dashboard/staff routes have a decorator which checks for the existence of the logged in token in session and redirects to the login route if it does not exists.
The /lodge app is another simple Flask app with its own routes:
/lodge/welcome
/lodge/personal
/lodge/review
/lodge/confirmation
The welcome route also calls session.clear() and then displays a webform. When the user submits the webform, the personal route is called which stores those webform input values into session.
The issue that I am having is if I navigate to www.example.com/dashboard/login and login, I can then flick between the staff and orders routes no problems at all, however when I then open a new tab and go to www.example.com/lodge/welcome (which then calls session.clear) and then reopen the dashboard tab and try to go to the staff or orders route, I get redirected back to the login route as the session has been cleared.
httpd.conf:
<VirtualHost *:80>
WSGIScriptAlias /newapp "c:/lodge/lodge.wsgi"
<Directory "c:/lodge">
Require all granted
</Directory>
WSGIScriptAlias /dashboard "c:/dashboard/dashboard.wsgi"
<Directory "c:/dashboard">
Require all granted
</Directory>
</VirtualHost>
Side note, this does not happen if I access the dashboard app on http://example.com/dashboard and the lodge app on http://www.example.com/lodge
Answering my own question here.
I achieved multiple applications on the same apache server quite easily by changing the app configs for both apps. No virtual enviroments or tinkering with wsgi scripts needed!
Lodge app:
app = Flask(__name__)
app.config.from_object(__name__)
app.config.update(
SESSION_COOKIE_NAME = 'session_lodge',
SESSION_COOKIE_PATH = '/lodge/'
)
Dashboard app:
app = Flask(__name__)
app.config.from_object(__name__)
app.config.update(
SESSION_COOKIE_NAME = 'session_db',
SESSION_COOKIE_PATH = '/dashboard/'
)
The answeres by #m-dennis and #burhan-khalid porivded some insight to the problem so thanks for that!
Having multiple sub domains was not an option for me and I encountered the same issue when having both apps run in their own virtual enviroments.
Side note, this does not happen if I access the dashboard app on http://example.com/dashboard and the lodge app on http://www.example.com/lodge
This is actually the reason why you are seeing this behavior. Cookies are bound to domains and not paths.
Once you set a cookie at example.com, it is valid for all links, paths and URLs for that domain. It is not valid for www.example.com - this explains why it works if you run one of your apps on a different subdomain.
So what you are seeing is the proper behavior.
Try to use virtual environments. It seems that your flask apps running in one python execution thread. Here you can find, how to run your app(s) in a virtual environment.

Apache config for static site on root, and Django on sub-locations

I have a single Django app that handles two (or more) parts of site, for example an "admin" and an "api" sections of the site. I also have normal html pages for the rest of the site, where no Django is needed.
I want to have the static html site on the root of my site, and the Django app on some sub-locations, for example
www.example.com -> Apache static html site
www.example.com/admin/ -> Django app, serving the pages for the admin
www.example.com/api/ -> Django app, serving the pages for the api
At first I try to do so all form Django, using the urls like so:
# my_app/urls.py
...
url(r'^admin/', include('admin.urls')),
url(r'^api/', include('api.urls')),
url(r'^(?P<path>.*)$', ??????????),
...
But I couldn't figure out a good way to delegate the serving of those static pages to Apache. (It did work if I use url(r'^(?P<path>.*)$, 'django.views.static.serve', {'document_root': '/path/to/static/site'}), but the Django documentation forbids to use that on a production server.)
Then I tried with the apache configuration:
# httpd.conf
...
DocumentRoot /path/to/static/site
WSGIScriptAlias /admin /path/to/django/my_app/wsgi.py
WSGIScriptAlias /api /path/to/django/my_app/wsgi.py
...
This worked as far as requests to root returned the static site and requests to both "admin" and "api" would return the Django site, but within Django I found no way to distinguish if the request came from '/admin' or from '/api'. (Plus I'm not sure if having two WSGIScriptAlias pointing at the same wsgi might cause some problems.)
If someone knows of a way to achieve this without having to split my Django app into two (or more) parts it would be greatly appreciated.
I had the almost exact same problem. In Apaches virtual host config for the site use
WSGIScriptAliasMatch ^(/(admin|api)) /path/to/django/my_app/wsgi.py$1
instead of
WSGIScriptAlias /admin /path/to/django/my_app/wsgi.py
WSGIScriptAlias /api /path/to/django/my_app/wsgi.py
Check these Q&A for further information:
Django (wsgi) and Wordpress coexisting in Apache virtualhost
Reconfiguring Apache to serve website root from new php source and specific sub-urls from old django site

How do I handle www subdomain in a production instance of Flask

I use an Apache server for production with Flask as a WSGI app.
My Apache VirtualHost conf looks like this
<VirtualHost *:80>
ServerName mysite.com
ServerAlias www.mysite.com
...
</VirtualHost>
And my /etc/hosts file looks like this
200.110.100.11 mysite.com
200.110.100.11 www.mysite.com
I realized yesterday that my site was storing 2 different sessions for the naked domain and the www subdomain. So the user was logged out of www.mysite.com even if he was logged into mysite.com
After reading Flask docs, I figured that I had to set the SERVER_NAME config value and map the hosts file accordingly. So I set the SERVER_NAME config to mysite.com. But now I have a bigger problem. www.mysite.com/ started showing 404 after I set this value. However it is the custom 404 page I have set in my app, which means that the request is reaching my app, but it is not able to find a route. However mysite.com/ continues to work fine.
I chanced upon this thread https://github.com/mitsuhiko/flask/issues/555 and tried adding the line app.url_map.default_subdomain = 'www' to my init module and it only resulted in mysite.com getting a 404 now.
What am I missing here? I am not using Blueprints for my views as yet.

Flask session not persisting

Am running with Python 2.7, Apache + mod_wsgi on CentOS 6.3
Things work fine when I am on localhost. However, when I run the code on a vm in Azure, I do not see the session information being persisted across pages.
Basically in my views, I have something like:
#frontend.route('/')
def index():
session['foo'] = 'bar'
print session['foo']
return redirect(url_for("frontend.page2"))
#frontend.route('page2')
def page2():
print session
The print output is:
bar
<SecureCookieSession {}>
My wsgi configuration for apache is:
WSGISocketPrefix /var/run/wsgi
<VirtualHost *:80>
ServerName example.com
ServerAlias example.com
WSGIDaemonProcess myproj threads=5 processes=5
WSGIScriptAlias / /home/mydir/myproj/apache/myproj.wsgi
<Directory /home/mydir/myproj>
WSGIScriptReloading On
WSGIProcessGroup myproj
WSGIApplicationGroup %{GLOBAL}
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
I have the secret_key set:
app.secret_key = os.urandom(24)
I have tried with both setting SERVER_NAME but it doesn't help:
app.config['SERVER_NAME'] = 'example.com'
Any ideas on how I can debug this more?
Thanks!
Don't use app.secret_key = os.urandom(24)!
You're supposed to enter a static value here, not read from os.urandom each time. You've probably misunderstood the example in the docs, it shows you how you can read random data from os.urandom, but it also clearly states:
Just take that thing and copy/paste it into your code and you’re done
If you read it at runtime, then each of your worker processes will have a different secret key! That means if a request is handled by a different worker, the session will break because the cookie is signed with the wrong secret key.

How can domain aliases be set up using Django?

I am working on creating a website in Django which consists of two parts: the website itself, and the forum. They will both be on separate domains, i.e. example.com and exampleforum.com. How can this be done in Django, when the forum and main site are part of the same instance?
This is done at the web server level. Django doesn't care about the domain on the incoming request.
If you are using Apache just put multiple ServerAlias directives inside your virtual host like this:
<VirtualHost *:80>
ServerName www.mydomain.com
ServerAlias mydomain.com
ServerAlias forum.mydomain.com
... other directives as needed ...
</VirtualHost>
This tells Apache to direct requests for all of those domains into the same instance.
For nginx your config file would look something like:
server {
listen 80;
server_name www.mydomain.com mydomain.com forum.mydomain.com;
... other directives as needed ...
}

Categories