wiki:Example

Example configurations

This is a list of tips and tricks aimed at showing you how versatile uWSGI is.

Do not use them as copy&paste source, try to understand and adapt them to your setup !!!

Django on Apache

Put a file (named django_wsgi.py) in your project directory:

import os
#substitute mysite with the name of your project !!!
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'

import django.core.handlers.wsgi

application = django.core.handlers.wsgi.WSGIHandler()

Run the uWSGI server on a TCP socket

    uwsgi --socket 127.0.0.1:3031 --chdir <path to your project directory> --pp .. -w django_wsgi

(adding .. to the pythonpath is needed to allows project.app imports styles in your application's files)

or use the xml configuration:

<uwsgi>
  <socket>127.0.0.1:3031</socket>
  <chdir>path to your django project directory</chdir>
  <pythonpath>..</pythonpath>
  <module>django_wsgi</module>
</uwsgi>
uwsgi -x django.xml

Finally, add <Location> directive to apache configuration

<Location />
    SetHandler uwsgi-handler
    uWSGISocket 127.0.0.1:3031
</Location>

Do not forget to load the uwsgi apache2 module in your apache configuration (normally it will be installed in /usr/lib/apache2)

Django again but with fun

Run without configuration files or wsgi module (beware of pythonpath, djtest in this test must be importable):

./uwsgi -s 127.0.0.1:3031 -M -p 4 --env DJANGO_SETTINGS_MODULE=djtest.settings -w "django.core.handlers.wsgi:WSGIHandler()"

Run with only xml

<uwsgi>
  <socket>127.0.0.1:3031</socket>
  <master/>
  <processes>4</processes>
  <env>DJANGO_SETTINGS_MODULE=djtest.settings</env>
  <module>django.core.handlers.wsgi:WSGIHandler()</module>
</uwsgi>
./uwsgi -x mydjango.xml

...or with a .ini file

[uwsgi]
socket = 127.0.0.1:3031
master = true
processes = 4
env = DJANGO_SETTINGS_MODULE=djtest.settings
module = django.core.handlers.wsgi:WSGIHandler()
./uwsgi --ini mydjango.ini

Pylons and nginx the happy way

add uWSGI configuration directly in your development.ini/production.ini or whatever config file you are using for Pylons

[uwsgi]
socket = /tmp/i_am_a_unix_socket.sock
master = true
processes = 1
./uwsgi --ini-paste <path_to_your_pylons-configuration_file>

finally add a location to nginx.conf

location / {
  include uwsgi_params;
  uwsgi_pass unix:///tmp/i_am_a_unix_socket.sock;
}

Pyramid and nginx

The same as Pylons and nginx

Trac on apache in a sub-uri

Put this wsgi script (call it mytrac.py) in a dir in the pythonpath (or add the dir with the <pythonpath> directive)

import os
import trac.web.main

os.environ['TRAC_ENV'] = '<absolute_path_to_trac_project>'
applications = {'/trac':trac.web.main.dispatch_request}

Run the server

    uwsgi -s /tmp/uwsgi.sock -C -w mytrac

Modify apache

<Location /trac>
    SetHandler uwsgi-handler
    uWSGISocket /tmp/uwsgi.sock
</Location>

Better trac (on /)

uwsgi -s /tmp/uwsgi.sock -C -w trac.web.main:dispatch_request --env TRAC_ENV=<absolute_path_to_trac_project>

Django and Mercurial just married

import uwsgi

from mercurial import demandimport; demandimport.enable()
from mercurial.hgweb.hgwebdir_mod import hgwebdir

hgapp = hgwebdir('hgweb.config')

import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'app.settings'

import django.core.handlers.wsgi
djangoapp = django.core.handlers.wsgi.WSGIHandler()

uwsgi.applications = {'':djangoapp, '/hg':hgapp}

Web2Py (2uWSGI)

This is the "one-man-band" of all python frameworks.

Unzip it in your directory of choice and...

./uwsgi --pythonpath <path_to_your_web2py_dir> --module wsgihandler -s /tmp/we2py.sock

or

<uwsgi>
  <pythonpath>path_to_your_web2py_dir</pythonpath>
  <module>wsgihandler</module>
  <socket>/tmp/web2py.sock</socket>
  <master/>
  <processes>8</processes>
  <memory-report/>
</uwsgi>
./uwsgi -x myweb2py.xml

Web2Py behind Mongrel2

Some environ vars were not set or set incorrectly in older versions of uWSGI.

Add the following to gluon/main.py in the wsgibase function, directly below the comment block ( # handle fcgi ....), at the top of the triple nested try statement (align with the comment and other code there!):

                uwsgi = environ.get('uwsgi.version')
                if uwsgi:
                    uwsgi_version = []
                    for x in uwsgi.split('.'):
                        for y in x.split('-'):
                            if y == 'dev':
                                y = -1
                            uwsgi_version.append(int(y))
                if uwsgi and uwsgi_version < [1, 1, -1, 1996]:
                    # handles uWSGI broken path_info AND missing QUERY_STRING
                    environ['PATH_INFO'] = ''
                if uwsgi and not environ.get('REMOTE_ADDR'):
                    # REMOTE_ADDR is used for logging, which silently fails
                    environ['REMOTE_ADDR'] = environ.get('HTTP_X_FORWARDED_FOR',
                                                         'address.unknown')

3 Web2Py instances, one XML configuration

(please do not get too excited about the next lines)

<foo>

<uwsgi id="app1">
  <pythonpath>app1/web2py</pythonpath>
  <module>wsgihandler</module>
  <master/>
  <processes>4</processes>
  <socket>/tmp/web2py_app1.sock</socket>
</uwsgi>

<uwsgi id="app2">
  <pythonpath>app2/web2py</pythonpath>
  <module>wsgihandler</module>
  <master/>
  <processes>4</processes>
  <socket>/tmp/web2py_app2.sock</socket>
</uwsgi>

<uwsgi id="app3">
  <pythonpath>app3/web2py</pythonpath>
  <module>wsgihandler</module>
  <master/>
  <processes>4</processes>
  <socket>/tmp/web2py_app3.sock</socket>
</uwsgi>

</foo>

Now run 3 instances of uwsgi

./uwsgi -x megaconf.xml:app1
./uwsgi -x megaconf.xml:app2
./uwsgi -x megaconf.xml:app3

Ok, i have heard you... "Why the fu*k i cannot use 3 different xml files ?"

You can, but then you cannot do this magic:

<uwsgi>

  <pythonpath id="app1">app1/web2py</pythonpath>
  <pythonpath id="app2">app2/web2py</pythonpath>
  <pythonpath id="app3">app3/web2py</pythonpath>

  <module>wsgihandler</module>
  <master/>
  <processes>4</processes>

  <socket id="app1">/tmp/web2py_app1.sock</socket>
  <socket id="app2">/tmp/web2py_app2.sock</socket>
  <socket id="app3">/tmp/web2py_app3.sock</socket>
</uwsgi>

A little note:

We have used the <foo> root tag for multiple <uwsgi> blocks. This can be every name you want. This will allows you to put <uwsgi> configurations on other xml files.

Flask deploy

Flask is an amazing microframework. Deploying it on uWSGI is super-fast/super-easy

(call it myapp.py)

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return "Hello World!"

if __name__ == '__main__':
    app.run()
./uwsgi -s /tmp/mysock.sock --module myapp --callable app

or

./uwsgi -s /tmp/mysock.sock -w myapp:app

UNIX gurus, please sit down

No description, only code for you

#!/bin/sh

export UWSGI_SOCKET=/tmp/uwsgi.sock
export UWSGI_MODULE=trac.web.main
export UWSGI_CALLABLE=dispatch_request
export UWSGI_MASTER=1
export UWSGI_PROCESSES=8
export UWSGI_MEMORY_REPORT=1
export UWSGI_HARAKIRI=30
export TRAC_ENV=/tmp/mytrac

exec /usr/bin/uwsgi

The shebang mess

On systems like FreeBSD or OSX you can do funny things like this:

#!/usr/bin/uwsgi --socket :3031 --callable app

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return "Hello World!"

if __name__ == '__main__':
    app.run()

but on (for example) Linux systems you will get:

uwsgi: unrecognized option '--socket :3031 --callable app'

sadly there is no easy fix :(

Use the embedded HTTP server/router

Oh yes, you do not need to have a real webserver:

./uwsgi --http 127.0.0.1:8080 --module myapp --callable app

this will run myapp:app on http port 8080

Force uWSGI to natively speaks HTTP (or fastcgi)

listen on http port 8090

./uwsgi --socket :8090 --protocol=http --module myapp --callable app

listen on fastcgi port 5000

./uwsgi --socket :5000 --protocol=fastcgi --module myapp --callable app

MoinMoin online now

Untar the moinmoin tarball and simply run uWSGI from moin-x.xx directory:

/usr/bin/uwsgi -s /tmp/moin.sock --wsgi-file wiki/server/moin.wsgi -M -p 4

you can mount it on a subdir (example: /wiki) with:

/usr/bin/uwsgi -s /tmp/moin.sock --mount /wiki=wiki/server/moin.wsgi -M -p 4

then change your apache config

<Location /wiki>
    SetHandler uwsgi-handler
    uWSGISocket /tmp/moin.sock
</Location>

or nginx

location /wiki {
    include uwsgi_params;
    uwsgi_param SCRIPT_NAME /wiki;
    uwsgi_modifier1 30;
    uwsgi_pass unix:/tmp/uwsgi.sock;
}

Bazaar smart server in virtualenv with <eval> config

virtualenv mybzr
./mybzr/bin/easy_install bzr

Now create an xml configuration file with embedded wsgi module

<uwsgi>

        <processes>4</processes>
        <master/>
        <home>bzu</home>

        <socket>:8001</socket>
        <memory-report/>

        <eval>

from bzrlib.transport.http import wsgi

application = wsgi.make_app("/Users/serena/bzr", "/", readonly=False)

        </eval>
</uwsgi>

Yes, it is fun but what if my python code contains (xml)invalid symbols (like <,>,&) ?

use the xml CDATA feature:

<uwsgi>

        <processes>4</processes>
        <master/>
        <home>bzu</home>

        <socket>:8001</socket>
        <memory-report/>

<![CDATA[

from bzrlib.transport.http import wsgi

application = wsgi.make_app("/Users/serena/bzr", "/", readonly=False)


]]>

</uwsgi>

...and run

./uwsgi -x bazaar.xml

(Django + PEP-370 + shell scripting) unleashed

(only for python >= 2.6)

install Django in a user directory (with pip):

export PYTHONUSERBASE=/home/damjan/django-app/env
pip install --user Django

create a shell script in your Django project directory (/home/damjan/django-app/django370.sh):

#!/bin/sh
DIRNAME=`dirname $0`
cd $DIRNAME

export PYTHONUSERBASE=$DIRNAME/env
export UWSGI_MODULE="django.core.handlers.wsgi"
export UWSGI_CALLABLE="WSGIHandler()"
export DJANGO_SETTINGS_MODULE="myapp.settings"
exec /usr/local/bin/uwsgi "$@"

chmod +x it

run it !!!:

/home/damjan/django-app/django370.sh -M -p 4 --socket 127.0.0.1:1717

Werkzeug test_app with embedded http server port 9090

./uwsgi -w werkzeug.testapp:test_app --http :9090

Two Pinax site in two virtualenv in two virtualhost with only one uWSGI instance

We have two virtualenv, DJANGOVENVS/pinax1 and DJANGOVENVS/pinax2.

Each virtualenv contains a pinax site in the directory 'pinaxsite' and a script (called pinax.py) in every pinaxsite/deploy directory (that is a copy of deploy/pinax.wsgi)

Now configure nginx

   server {
        listen       8080;
        server_name  sirius.local;

        location / {
                include uwsgi_params;
                uwsgi_pass 127.0.0.1:3031;
                uwsgi_param UWSGI_PYHOME /Users/roberto/DJANGOVENVS/pinax1;
                uwsgi_param UWSGI_SCRIPT deploy.pinax;
                uwsgi_param UWSGI_CHDIR /Users/roberto/DJANGOVENVS/pinax1/pinaxsite;
        }
    }

    server {
        listen       8080;
        server_name  localhost;

        location / {
                include uwsgi_params;
                uwsgi_pass 127.0.0.1:3031;
                uwsgi_param UWSGI_PYHOME /Users/roberto/DJANGOVENVS/pinax2;
                uwsgi_param UWSGI_SCRIPT deploy.pinax;
                uwsgi_param UWSGI_CHDIR /Users/roberto/DJANGOVENVS/pinax2/pinaxsite;
        }

    }



and run uWSGI in VirtualHosting mode

./uwsgi -s :3031 -M -p 10 --vhost --no-site

web.py the raw way

Add a WSGI callable to your app:

application = app.wsgifunc()

example: (call it testapp.py)

import web

urls = (
    '/(.*)', 'hello'
)
app = web.application(urls, globals())

class hello:
    def GET(self, name):
        if not name:
            name = 'World'
        return 'Hello, ' + name + '!'

application = app.wsgifunc()

run it:

./uwsgi -s /tmp/web.py.socket -w testapp

Step by step guide for repoze.plone

Oh yes, you can run Plone with uWSGI...

You need python2 .4

wget http://www.python.org/ftp/python/2.4.6/Python-2.4.6.tar.bz2 
tar jxvf Python-2.4.6.tar.bz2
cd Python-2.4.6
./configure --prefix=/opt/uPlone
make
make install
wget http://peak.telecommunity.com/dist/ez_setup.py
/opt/uPlone/bin/python ez_setup.py
/opt/uPlone/bin/easy_install -i http://dist.repoze.org/plone/latest/simple repoze.plone
wget http://projects.unbit.it/downloads/uwsgi-latest.tar.gz
tar zxvf uwsgi-latest.tar.gz
cd uwsgi-X.X.X
/opt/uPlone/bin/python uwsgiconfig.py --build
cp uwsgi /opt/uPlone/bin
cd /opt/uPlone
./bin/mkzope2instance .
./bin/addzope2user admin admin
./bin/uwsgi --http :9090 -M --memory-report -T --ini-paste etc/zope2.ini

Beware of cd uwsgi-X.X.X line, it must be substituted with the right uwsgi source directory

Remember that Zope startup can be slow, so wait until all the workers are spawned before connecting

Some Zope module use threads, so remeber to add -T

ZODB does not coop well with multiprocess environments so starts only 1 worker, or use ZEO and spawn all the workers you want.

If you are using a version >= 0.9.7 you can start more threads per worker using the --threads <n> option. Single-worker+threads works flawlessly with zope/plone

./bin/uwsgi --socket /tmp/uwsgi.sock --chmod -M --memory-report --ini-paste etc/zope2.ini --threads 10

Save your resources when your apps are idle

Use the --idle flag

uwsgi --master --idle 30 --processes 4 --socket /tmp/uwsgi.sock --wsgi-file myapp.wsgi

After 30 seconds of inactivity the workers will be taken off. At the first request they will be respawned.

Massive Django hosting with automagic config and lower resource impact (nginx+Emperor+fastrouter+subscriptions+idle, requires uWSGI 0.9.8.1)

There are various options to host massive applications, this example will show one that require pratically no work to add new apps after the initial setup.

First, configure nginx

location / {
    include uwsgi_params;
    # force the fastrouter to use the Host header as key for domain:app mappings
    uwsgi_param UWSGI_FASTROUTER_KEY $host;
    uwsgi_pass /tmp/fastrouter.socket
}

On every request, nginx will contact the FastRouter asking for a specific hostname.

Now we will create a magic config template for a Django app (supposing all of the projects are in /var/apps and will run as django uid/gid).

Each project wil be available at <projectname>.example.com and all of the domains (one-per-line) specified in the file domains.txt in each project dir.

[uwsgi]
djangoproject = /var/apps/%n/
env = DJANGO_SETTINGS_MODULE=%n.settings
pymodule-alias = %n=%(djangoproject)
chdir = %(djangoproject)
module = django.core.handlers.wsgi:WSGIHandler()
socket = 127.0.0.1:0
master = true
processes = 4
idle = 3600
uid = django
gid = django
subscribe-to = 127.0.0.1:3032:%n.example.com
subscribe-to = 127.0.0.1:3032:@%(djangoproject)/domains.txt

the first directive create a config placeholder (the absolute path of the project dir) that will be used in the rest of the config file

the socket option use '0' as the port number. This will bind to a random port. This is not a problem as the Subscription subsystem will communicate it to the fastrouter.

With idle we inform the master of the instance to shut down worker inactive for more than 1 hour.

The last subscribe-to directive use the @ to inform the master to take the key from a file

Move this file in /etc/djangoapps (this is the directory that will be scanned by the emperor for new django apps) and call it 'django_base' (or something similar without extension, so the emperor will not consider it as a valid config file)

Now let's spawn the emperor and the fastrouter

uwsgi --master --emperor /etc/djangoapps --fastrouter /tmp/fastrouter.socket --fastrouter-subscription-server 127.0.0.1:3032

We are ready, copy your project to /var/apps and spawn it simply symlinking /etc/djangoapps/django_base to /etc/djangoapps/<projectname>.ini

Example (for a project in /var/apps/pinax000)

ln -s /etc/djangoapps/django_base /etc/djangoapps/pinax000.ini

When you want to remove the app simply remove the symlink (or touch it for a reload)

... and massive RubyOnRails hosting with aggressive memory control and zerg mode

This is the same setup of the previous example but using yaml files (directly linked in rails root of each app) and a second template used for ZergMode.

WARNING in this example we use the libyaml-based parser (selected at uWSGI compile time if available). If you are using the embedded one (simpler, dumber but more tolerant) simply remove the ticks surrounding the strings in the config files

We suppose a Rails3 style application (refinerycms is a good candidate) with config.ru file.

Let's define our base template (we will put it in /etc/uwsgi/rails_base_template)

uwsgi:
  plugins: rack
  master: 1
  processes: 4
  memory-report: 1
  railsroot: "/var/railsapps/%c"
  chdir: "%(railsroot)"
  rack: "%(railsroot)/config.ru"
  idle: 300
  ruby-gc-freq: 10
  subscribe-to: "127.0.0.1:3032:%c.example.com,7"
  subscribe-to: 127.0.0.1:3032:@domains.txt
  socket: 127.0.0.1:0
  show-config: 1
  post-buffering: 4096
  zerg-server: "/var/run/zergs/%n.sock"
  reload-on-rss: 256

Instead of %n, this time we will use %c. It resolve to the name of the dir containing the config file. In this way we can put a uwsgi_base.yml in each rails root and add various links to zerg instances in the same directory.

the subscription system is the same. The only difference is on specifying the modifier (Rack uses the 7) with an additional (comma separated) section.

post-buffering is required for rack apps

ruby-gc-freq will set after how many requests the ruby GC must be called.

idle mode is set to 5 minutes (do not be afraid of slow-rails-startup as copy-on-write is used all over the place)

show-config is used to print a ini style image of the current configuration. This is a good form of first-aid debugging.

reload-on-rss will reload workers using more that 256 megs of physical memory.

then we define a template for zergs (we will put it in /etc/uwsgi/rails_zerg_template):

uwsgi:
  plugins: rack
  master: 1
  processes: 2
  memory-report: 1
  railsroot: "/var/railsapps/%c"
  chdir: "%(railsroot)"
  rack: "%(railsroot)/config.ru"
  idle: 300
  ruby-gc-freq: 10
  post-buffering: 4096
  zerg: "/var/run/zergs/%c.sock"
  reload-on-rss: 256

we set only 2 process for each zerg instance. There is no need for subscription as the original instance will continue to send data to the fastrouter.

If you want your zergs to be able to survive on main instance death, add subscriptions even in the zerg template

Now run the emperor with glob style search path

uwsgi --master --emperor /var/railsapps/*/uwsgi_*.yml --fastrouter /tmp/fastrouter.socket --fastrouter-subscription-server 127.0.0.1:3032

To add a rails instance make a link from base template to uwsgi.yml in your rails root

ln -s /etc/uwsgi/rails_base_template /var/railsapps/app000/uwsgi_base.yml
ln -s /etc/uwsgi/rails_base_template /var/railsapps/a_second_app/uwsgi_base.yml
ln -s /etc/uwsgi/rails_base_template /var/railsapps/a_third_app/uwsgi_base.yml
... and so on ...

Then app000 start being slashdotted and we need to add power to it

(remember to check if you have enough resources to add more workers)

ln -s /etc/uwsgi/rails_zerg_template /var/railsapps/app000/uwsgi_zerg1.yml

hmm not enough power, let's add another zerg

ln -s /etc/uwsgi/rails_zerg_template /var/railsapps/app000/uwsgi_zerg2.yml

When local resources are finished you will need to add another server.

Simply follow the same setup but without enabling fastrouter and without running nginx.

The second server will subscribe to the fastrouter on the first one (remember to bind the subscription server to a routable address) and load balancing will happen automagically.

Example on node1:

uwsgi --master --emperor /var/railsapps/*/uwsgi_*.yml --fastrouter /tmp/fastrouter.socket --fastrouter-subscription-server 192.168.0.1:3032

On node2 simply:

uwsgi --master --emperor /var/railsapps/*/uwsgi_*.yml

And change subscriptions to point to address 192.168.0.1:3032

uwsgi:
  plugins: rack
  master: 1
  processes: 4
  memory-report: 1
  railsroot: "/var/railsapps/%c"
  chdir: "%(railsroot)"
  rack: "%(railsroot)/config.ru"
  idle: 300
  ruby-gc-freq: 10
  subscribe-to: "192.168.0.1:3032:%c.example.com,7"
  subscribe-to: 192.168.0.1:3032:@domains.txt
  socket: 127.0.0.1:0
  show-config: 1
  post-buffering: 4096
  zerg-server: "/var/run/zergs/%n.sock"
  reload-on-rss: 256

You can add all of the nodes you want and subscribe them to the main.

Using python Queue module for implementing async management of long running task

Remember to add --enable-threads and --master

import Queue
from threading import Thread
import uwsgi

CONSUMERS = 4

def consumer(q):
    while True:
        item = q.get()
        print(item)
        #... DO A HEAVY TASK HERE ...
        q.task_done()

def spawn_consumers():
    global q
    q = Queue.Queue()
    for i in range(CONSUMERS):
        t = Thread(target=consumer,args=(q,))
        t.daemon = True
        t.start()
        print("consumer %d on worker %d started" % (i, uwsgi.worker_id()))

# set the function to call after each fork()
uwsgi.post_fork_hook = spawn_consumers


def application(env, start_response):
    global q

    # we pass a copy of the env dictionary as it gets cleared after yield/return
    q.put(env.copy())

    start_response('200 OK', [('Content-Type', 'text/html')])

    #end the request
    yield "Task enqueued"

Execute a function every 30 seconds in the spooler

Abuse uWSGI Decorators, they kick ass !!!

from uwsgidecorators import *

@timer(30, target='spooler')
def hello_world(signum):
    print("30 seconds elapsed")

The interesting part is the target attribute. It points to the process (the spooler in this case) that has to execute the handler

Config via pipe

print """
[uwsgi]
socket = :3031
module = welcome
"""
python generate.py | uwsgi --ini -

A bottle app+uWSGI embedded in the same binary

uWSGI 0.9.8.2 (many thanks to Cal Leeming of Simplicity Media Ltd for the idea) has the possibility to embed binary files (config files included) in its executable.

To add files simply list them in your build profile:

[uwsgi]
inherit = default
embed_files = uwsgidecorators.py,bottle.py,foobar.jpg
embed_config = myapp.ini

running

python uwsgiconfig.py --build <buildprofile>

will create a uWSGI binary with 3 files and 1 configuration linked in

You can now reference those files with sym://symbol

where symbol is the name of the embedded files with . and / substituted with _ (bottle.py will be bottle_py and so on)

uwsgi --pymodule-alias bottle=sym://bottle_py

will map the bottle module to the file embedded as bottle_py

Let's see a full example

  • step 1, the WSGI bottle app (myapp.py)
from bottle import route, run, default_app

@route('/:name')
def index(name='World'):
    return '<b>Hello %s!</b>' % name


application = default_app()
  • step 2, the uWSGI config file (myapp.ini)
[uwsgi]
pymodule-alias = bottle=sym://bottle_py
file = sym://myapp_py
socket = :3031
  • step 3, the build profile (buildconf/allinone.ini)
[uwsgi]
inherit = default
embed_files = bottle.py,myapp.py
embed_config = myapp.ini
  • step 4, build them all
python uwsgiconfig --build allinone
  • step 5, simply run uwsgi ;)
./uwsgi

Varnish and nginx, the best way (0.9.8.4)

Starting from 0.9.8.4 the http parser of uWSGI has been extremely improved. Normally you would put nginx+uwsgi behind varnish. This is a completely WASTE OF RESOURCES.

If you have written your app to map static assets to an external domain, you can simply put uWSGI directly behind varnish and leave nginx alone to serve static files.

To start uWSGI in high-performance http mode (beware, this is completely different from the --http option given by the http plugin)

uwsgi --http-socket 127.0.0.1:3031 --master --processes 4 --module myapp

(as you can see it is a normal uwsgi startup command line, with the addition of --http-socket instead of --socket)

Now point your varnish to the uwsgi http socket

backend uwsgi {
   .host = "127.0.0.1";
   .port = "3031";
}

sub vcl_recv {
       
    set req.backend = uwsgi;

}

pretty boring...

What about load balancing between multiple uwsgi instances ?

backend uwsgi0 {
   .host = "127.0.0.1";
   .port = "3031";
}

backend uwsgi1 {
   .host = "192.168.0.17";
   .port = "3031";
}

director uwsgi round-robin {

        {
                .backend = uwsgi0;
        }
        {
                .backend = uwsgi1;
        }

}

sub vcl_recv {
       
    set req.backend = uwsgi;

}

obviously you can add probe objects if you want to have a more reliable healthcheck system.

What about putting nginx behind varnish ?

Pretty easy, simply add nginx as a new backend and route specific requests to it:

backend uwsgi {
   .host = "127.0.0.1";
   .port = "8080";
}

backend nginx {
   .host = "127.0.0.1";
   .port = "80";
}

sub vcl_recv {
       if (req.url ~ "^/images") {
               set req.backend = nginx;
       }
       else {
               set req.backend = uwsgi;
       }
}

Cheroke wizard for single-process 2 + flask+trac

Recent Cherokee uWSGI wizard can load all of the uWSGI config files.

The following config file (.ini format) will load 2 flask apps and a trac one in the same process. Use it as the default handler for your site/virtualhost

[uwsgi]

; this will search for app callable (as normally used by flask apps)
callable = app

; the first flask app mounted under /app1
mount = /app1:/home/spock/apps/myapp1.py

; the second one
mount = /app2:/home/spock/apps/myapp2.py

; the third one (trac)
env = TRAC_ENV=path_to_trac_project
mount = /trac=trac.web.main:dispatch_request

; this will instruct uWSGI to automatically rebuild requests without the help of cherokee
manage-script-name = true

Binding the http router on privileged (80) ports

Binding on port 80 requires root privileges. Obviously it is bad to run the uWSGI stack as root, you will always want to drop its privileges.

Use shared sockets:

 ./uwsgi --shared-socket :80 --http =0 --uid 1000 --gid 1000

That means: create a socket on port 80 that can be used by various components. The "http" component will use it thanks to the '=n' form (n is the number of socket to use)