Running Zope2 as a WSGI Application

This document assumes you have installed Zope into a virtualenv (see Installing Zope with virtualenv).

Install the Supporting Software

To run as a WSGI application, you need to install some additional software.

$ bin/pip install \
 --trusted-host download.zope.org \
 --index http://download.zope.org/Zope2/index/2.13.26/ \
 repoze.who repoze.tm2 repoze.retry Paste PasteDeploy PasteScript
Collecting repoze.who
...
Successfully installed Paste-1.7.5.1 PasteDeploy-1.3.4 PasteScript-1.7.5 repoze.retry-1.2 repoze.tm2-1.0 repoze.who-2.0

Update the Zope Application Configuration

The generated etc/zope.conf file assumes that Zope will be running using the built-in ZServer.

$ vim etc/zope.conf

Update the contents as follows.

%define INSTANCE /path/to/virtualenv
instancehome $INSTANCE

Note

The %define instance /path/to/virtualenv element must point to the environment: there is no “relative to this file” support built in.

Set up logging for the application.

<eventlog>
  level info
  <logfile>
    path $INSTANCE/log/event.log
    level info
  </logfile>
</eventlog>

<logger access>
  level WARN
  <logfile>
    path $INSTANCE/log/Z2.log
    format %(message)s
  </logfile>
</logger>

Configure the database (note that you could use ZEO or Relstorage rather than a bare FileStorage):

<zodb_db main>
    # Main FileStorage database
    <filestorage>
      # See .../ZODB/component.xml for directives (sectiontype
      # "filestorage").
      path $INSTANCE/var/Data.fs
    </filestorage>
    mount-point /
</zodb_db>

<zodb_db temporary>
    # Temporary storage database (for sessions)
    <temporarystorage>
      name temporary storage for sessioning
    </temporarystorage>
    mount-point /temp_folder
    container-class Products.TemporaryFolder.TemporaryContainer
</zodb_db>

Because we will be running a separately-configured WSGI server, remove any <http-server> configuration from the file.

Create the WSGI Server Configuration

$ vim etc/zope.wsgi

First, configure the “application” endpoint for Zope:

[app:zope]
use = egg:Zope2#main
zope_conf = %(here)s/zope.conf

Next, set up the WSGI middleware pipeline:

[pipeline:main]
pipeline =
    egg:paste#evalerror
    egg:repoze.retry#retry
    egg:repoze.tm2#tm
    zope

The middleware layers are “wrapped” around the application endpoint as follows:

  • paste#evalerror is debugging middleware, which shows tracebacks for errors raised from the application. It should not be configured for production use.
  • repoze.retry#retry is middleware which retries requests when retriable exceptions are raised. By default, it retries 3 times, and only for requests which raise ZODB.ConflictError. See http://repozeretry.rtfd.org/ for details on configuring it otherwise.
  • repoze.tm2#tm is middleware which begins a new transaction for each request, and then either aborts the transaction (if the request raises an exception) or commits it (if not). See http://repozetm2.rtfd.org/ for details on configuring it.

Finally, configure the WSGI server:

[server:main]
use = egg:paste#http
host = localhost
port = 8080

Note

Any server conforming to PEP 333/3333 should work, although the parameters could change.

Set up the Admin User

Before starting the WSGI server, run the addzope2user script to configure the administrative user.

$ bin/addzope2user admin <yourpasswordhere>
No handlers could be found for logger "ZODB.FileStorage"
User admin created.

Start the WSGI Server

$ bin/paster serve etc/zope.wsgi
Starting server in PID 24934.
serving on http://127.0.0.1:8080

Running Other Applications in the same WSGI Server Process

You can use any of the normal Paste WSGI features to combine Zope and other WSGI applications inside the same server process. E.g., the following configuration uses the composite application support offered by PasteDeploy to host Zope at the / prefix, with static files served from disk at /static:

[app:zope-app]
use = egg:Zope2#main
zope_conf = %(here)s/zope.conf

[pipeline:zope-pipeline]
pipeline =
    egg:paste#evalerror
    egg:repoze.retry#retry
    egg:repoze.tm2#tm
    zope-app

[app:static]
use = egg:Paste#static
document_root = %(here)s/static

[composite:main]
use = egg:Paste#urlmap
/ = zope-pipeline
/static = static