add an isso.dispatch module to support multiple sites, #34
This commit is contained in:
parent
b21e216b06
commit
6f66960df8
63
dispatch.py
Normal file
63
dispatch.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
try:
|
||||||
|
from urlparse import urlparse
|
||||||
|
except ImportError:
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
from werkzeug.exceptions import ImATeapot
|
||||||
|
|
||||||
|
from isso import make_app, wsgi
|
||||||
|
from isso.core import Config
|
||||||
|
|
||||||
|
logger = logging.getLogger("isso")
|
||||||
|
|
||||||
|
|
||||||
|
class Dispatcher(object):
|
||||||
|
"""
|
||||||
|
A dispatcher to support different websites. Dispatches based on
|
||||||
|
HTTP-Host. If HTTP-Host is not provided, display an error message.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *confs):
|
||||||
|
|
||||||
|
self.isso = {}
|
||||||
|
|
||||||
|
for conf in map(Config.load, confs):
|
||||||
|
|
||||||
|
app = make_app(conf)
|
||||||
|
|
||||||
|
for origin in conf.getiter("general", "host"):
|
||||||
|
self.isso[origin.rstrip("/")] = app
|
||||||
|
|
||||||
|
def __call__(self, environ, start_response):
|
||||||
|
|
||||||
|
if "HTTP_ORIGIN" in environ:
|
||||||
|
origin = environ["HTTP_ORIGIN"]
|
||||||
|
elif "HTTP_REFERER" in environ:
|
||||||
|
rv = urlparse(environ["HTTP_REFERER"])
|
||||||
|
origin = rv.scheme + "://" + rv.hostname + (":" + str(rv.port) if rv.port else "")
|
||||||
|
else:
|
||||||
|
origin = wsgi.host(environ)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# logger.info("dispatch %s", origin)
|
||||||
|
return self.isso[origin](environ, start_response)
|
||||||
|
except KeyError:
|
||||||
|
# logger.info("unable to dispatch %s", origin)
|
||||||
|
resp = ImATeapot("unable to dispatch %s" % origin)
|
||||||
|
return resp(environ, start_response)
|
||||||
|
|
||||||
|
|
||||||
|
if "ISSO_SETTINGS" not in os.environ:
|
||||||
|
logger.fatal('no such environment variable: ISSO_SETTINGS')
|
||||||
|
else:
|
||||||
|
confs = os.environ["ISSO_SETTINGS"].split(";")
|
||||||
|
for path in confs:
|
||||||
|
if not os.path.isfile(path):
|
||||||
|
logger.fatal("%s: no such file", path)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
application = Dispatcher(*confs)
|
@ -208,6 +208,89 @@ reply-to-self
|
|||||||
Do not forget to configure the client.
|
Do not forget to configure the client.
|
||||||
|
|
||||||
|
|
||||||
|
Multiple Sites
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Isso is designed to serve comments for a single website and therefore stores
|
||||||
|
comments for a relative URL to support HTTP, HTTPS and even domain transfers
|
||||||
|
without manual intervention. But you can chain Isso to support multiple
|
||||||
|
websites on different domains.
|
||||||
|
|
||||||
|
The following example uses [gunicorn](http://gunicorn.org/) as WSGI server (you
|
||||||
|
can use uWSGI as well). It is *not* possible to run the isso executable for
|
||||||
|
multiple sites.
|
||||||
|
|
||||||
|
Let's say you maintain two websites, like foo.example and other.foo:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ cat /etc/isso.d/foo.example.cfg
|
||||||
|
[general]
|
||||||
|
host = http://foo.example/
|
||||||
|
dbpath = /var/lib/isso/foo.example.db
|
||||||
|
$ cat /etc/isso.d/other.foo.cfg
|
||||||
|
[general]
|
||||||
|
host = http://other.foo/
|
||||||
|
dbpath = /var/lib/isso/other.foo.db
|
||||||
|
$ export ISSO_SETTINGS="/etc/isso.d/foo.example.cfg;/etc/isso.d/other.foo.cfg"
|
||||||
|
$ gunicorn isso.dispatch -b localhost:8080
|
||||||
|
|
||||||
|
Now, there are two options to configure the webserver:
|
||||||
|
|
||||||
|
1. using a single host to serve comments for both websites
|
||||||
|
2. different hosts for both websites
|
||||||
|
|
||||||
|
In the former case, Isso dispatches based on the HTTP Referer and (if provided)
|
||||||
|
HTTP Origin. If you expect users to supress their referer completely, you
|
||||||
|
should use the second option.
|
||||||
|
|
||||||
|
1. Using a single host to serve comments.
|
||||||
|
|
||||||
|
.. code-block:: nginx
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen [::]:80;
|
||||||
|
server_name comments.example;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://localhost:8080;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
To verify the setup, run:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ curl -vH "Origin: http://foo.example" http://comments.example/
|
||||||
|
...
|
||||||
|
$ curl -vH "Origin: http://other.foo" http://comments.example/
|
||||||
|
...
|
||||||
|
|
||||||
|
In case of a 418 (I'm a teapot), the setup is *not* correctly configured.
|
||||||
|
|
||||||
|
2. Using different hosts for both websites (no need for a dedicated domain,
|
||||||
|
you can also proxy Isso on a sub-uri like /isso).
|
||||||
|
|
||||||
|
.. code-block:: nginx
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen [::]:80;
|
||||||
|
server_name comments.foo.example comments.other.foo;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://localhost:8080;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
No need to verify this setup, here the webserver automatically sets the
|
||||||
|
proper host.
|
||||||
|
|
||||||
|
|
||||||
Appendum
|
Appendum
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user