Running under a Web Server

Running Pootle with a front end web server will improve performance, give you more flexibility, and might be better for security. It is strongly recommended to run Pootle under Apache, Nginx, or a similar web server.

Running Pootle and RQ workers as a Service

If you plan to run Pootle and/or RQ workers as system services, you can use whatever software you are familiar with for that purpose. For example Supervisor, Circus or daemontools might fit your needs.

Running under Apache

You can use Apache either as a reverse proxy or straight with mod_wsgi.

Proxying with Apache

If you want to reverse proxy through Apache, you will need to have mod_proxy installed for forwarding requests and configure it accordingly.

ProxyPass / http://localhost:8000/
ProxyPassReverse / http://localhost:8000/
ProxyPreserveHost On

Apache with mod_wsgi

Make sure to review your global Apache settings (something like /etc/apache2/httpd.conf or /etc/httpd/conf/httpd.conf) for the server-pool settings. The default settings provided by Apache are too high for running a web application like Pootle. The ideal settings depend heavily on your hardware and the number of users you expect to have. A moderate server with 1GB memory might set MaxClients to something like 20, for example.

Make sure Apache has read access to all of Pootle’s files and write access to the POOTLE_TRANSLATION_DIRECTORY directory.

Note

Most of the paths present in the examples in this section are the result of deploying Pootle using a Python virtualenv as told in the Setting up the Environment section from the Quickstart installation instructions.

If for any reason you have different paths, you will have to adjust the examples before using them.

For example the path /var/www/pootle/env/lib/python2.7/site-packages/ will be different if you have another Python version, or if the Python virtualenv is located in any other place.

First it is necessary to create a WSGI loader script:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import site
import sys


# You probably will need to change these paths to match your deployment,
# most likely because of the Python version you are using.
ALLDIRS = [
    '/var/www/pootle/env/lib/python2.7/site-packages',
    '/var/www/pootle/env/lib/python2.7/site-packages/pootle/apps',
]

# Remember original sys.path.
prev_sys_path = list(sys.path)

# Add each new site-packages directory.
for directory in ALLDIRS:
    site.addsitedir(directory)

# Reorder sys.path so new directories at the front.
new_sys_path = []

for item in list(sys.path):
    if item not in prev_sys_path:
        new_sys_path.append(item)
        sys.path.remove(item)

sys.path[:0] = new_sys_path

# Set the Pootle settings module as DJANGO_SETTINGS_MODULE.
os.environ['DJANGO_SETTINGS_MODULE'] = 'pootle.settings'


# Set the WSGI application.
def application(environ, start_response):
    """Wrapper for Django's WSGIHandler().

    This allows to get values specified by SetEnv in the Apache
    configuration or interpose other changes to that environment, like
    installing middleware.
    """
    try:
        os.environ['POOTLE_SETTINGS'] = environ['POOTLE_SETTINGS']
    except KeyError:
        pass

    from django.core.wsgi import get_wsgi_application
    _wsgi_application = get_wsgi_application()
    return _wsgi_application(environ, start_response)

Place it in /var/www/pootle/wsgi.py. If you use a different location remember to update the Apache configuration accordingly.

A sample Apache configuration with mod_wsgi might look like this:

WSGIRestrictEmbedded On
WSGIPythonOptimize 1

<VirtualHost *:80>
    # Domain for the Pootle server. Use 'localhost' for local deployments.
    #
    # If you want to deploy on example.com/your-pootle/ rather than in
    # my-pootle.example.com/ you will have to do the following changes to
    # this sample Apache configuration:
    #
    # - Change the ServerName directive to:
    #   ServerName example.com
    # - Change the WSGIScriptAlias directive to (note that /your-pootle must
    #   not end with a slash):
    #   WSGIScriptAlias /your-pootle /var/www/pootle/wsgi.py
    # - Change the Alias directive for 'assets' to include the '/your-pootle'.
    # - Include the following settings in your custom Pootle settings:
    #   STATIC_URL = '/your-pootle/assets/'
    #   FORCE_SCRIPT_NAME = '/your-pootle'
    # - If you have previously calculated the stats:
    #   - Restart the RQ workers.
    #   - Run refresh_stats to recalculate the stats data.
    ServerName my-pootle.example.com

    # Set the 'POOTLE_SETTINGS' environment variable pointing at your custom
    # Pootle settings file.  An initial settings file can be created using
    # 'pootle init'
    #
    # This might require enabling the 'env' module.
    SetEnv POOTLE_SETTINGS /var/www/pootle/your_custom_settings.conf


    # The following two optional lines enable the "daemon mode" which
    # limits the number of processes and therefore also keeps memory use
    # more predictable.
    WSGIDaemonProcess pootle processes=2 threads=3 stack-size=1048576 maximum-requests=500 inactivity-timeout=300 display-name=%{GROUP} python-path=/var/www/pootle/env/lib/python2.7/site-packages
    WSGIProcessGroup pootle

    # Point to the WSGI loader script.
    WSGIScriptAlias / /var/www/pootle/wsgi.py

    # Turn off directory listing by default.
    Options -Indexes

    # Compress before being sent to the client over the network.
    # This might require enabling the 'deflate' module.
    SetOutputFilter DEFLATE
    AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml application/x-javascript

    # Set expiration for some types of files.
    # This might require enabling the 'expires' module.
    ExpiresActive On

    ExpiresByType image/jpg "access plus 10 years"
    ExpiresByType image/png "access plus 10 years"
    ExpiresByType text/css "access plus 10 years"
    ExpiresByType application/x-javascript "access plus 10 years"

    # Optimal caching by proxies.
    # This might require enabling the 'headers' module.
    Header set Cache-Control "public"

    # Directly serve static files like css and images, no need to go
    # through mod_wsgi and Django. For high performance consider having a
    # separate server.
    Alias /assets /var/www/pootle/env/lib/python2.7/site-packages/pootle/assets
    <Directory /var/www/pootle/env/lib/python2.7/site-packages/pootle/assets>
        Require all granted
        # For apache 2.2, comment the line directly above, and uncommend the two lines directly below
        #Order deny,allow
        #Allow from all
    </Directory>

</VirtualHost>

You can find more information in the Django docs about Apache and mod_wsgi.

.htaccess

If you do not have access to the main Apache configuration, you should still be able to configure things correctly using the .htaccess file.

More information on configuring mod_wsgi (including .htaccess)

Running under Nginx

Running Pootle under a web server such as Nginx will improve performance. For more information about Nginx and WSGI, visit Nginx’s WSGI module page

A Pootle server is made up of static and dynamic content. By default Pootle serves all content, and for low-latency purposes it is better to get other webserver to serve the content that does not change, the static content. It is just the issue of low latency and making the translation experience more interactive that calls you to proxy through Nginx. The following steps show you how to setup Pootle to proxy through Nginx.

Proxying with Nginx

The default Pootle server runs at port 8000 and for convenience and simplicity does ugly things such as serving static files — you should definitely avoid that in production environments.

By proxying Pootle through nginx, the web server will serve all the static media and the dynamic content will be produced by the app server.

server {
   listen  80;
   server_name  pootle.example.com;

   access_log /path/to/pootle/logs/nginx-access.log;
   gzip on; # Enable gzip compression

   charset utf-8;

   location /assets {
       alias /path/to/pootle/env/lib/python2.6/site-packages/pootle/assets/;
       expires 14d;
       access_log off;
   }

   location / {
     proxy_pass         http://localhost:8000;
     proxy_redirect     off;

     proxy_set_header   Host             $host;
     proxy_set_header   X-Real-IP        $remote_addr;
     proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
   }
 }