So far, Unit doesn’t support handling the REMOTE_USER headers directly, so authentication should be implemented via external means. For example, consider using trac-oidc or OAuth2Plugin.

To run the Trac issue tracking system using Unit:

  1. Install Unit with a Python 2 language module.


    As of now, Trac doesn’t fully support Python 3. Mind that Python 2 is officially deprecated.

  2. Prepare and activate a virtual environment to contain your installation (assuming virtualenv is installed):

    $ mkdir -p /path/to/app/
    $ cd /path/to/app/
    $ virtualenv venv
    $ source venv/bin/activate
  3. Next, install Trac and its optional dependencies, then initialize a Trac environment and deploy static files:

    $ pip install Trac
    $ pip install babel docutils genshi \
                  pygments pytz textile             # optional dependencies
    $ mkdir static/                                 # will store Trac's /chrome/ tree
    $ mkdir trac_env/
    $ trac-admin trac_env/ initenv                  # initialize Trac environment
    $ trac-admin trac_env/ deploy static/           # extract Trac's static files
    $ mv static/htdocs static/chrome                # align static file paths
    $ rm -rf static/cgi-bin/                        # remove unneeded files
    $ deactivate
  4. Unit uses WSGI to run Python apps, so a wrapper script is required to run Trac as a Unit app; let’s save it as /path/to/app/ Here, the application callable serves as the entry point for the app:

    import trac.web.main
    def application(environ, start_response):
        environ["trac.locale"] = "en_US.UTF8"
        return trac.web.main.dispatch_request(environ, start_response)
  5. Run the following command so Unit can access the application directory:

    # chown -R unit:unit /path/to/app/


    The unit:unit user-group pair is available only with official packages, Docker images, and some third-party repos. Otherwise, account names may differ; run the ps aux | grep unitd command to be sure.

    For further details, including permissions, see the security checklist.

  6. Next, prepare the Trac configuration for Unit (use real values for share, path, home, module, TRAC_ENV, and PYTHON_EGG_CACHE):

        "listeners": {
            "*:80": {
                "pass": "routes"
        "routes": [
                "match": {
                    "uri": "/chrome/*"
                "action": {
                    "share": "/path/to/app/static$uri"
                "action": {
                    "pass": "applications/trac"
        "applications": {
            "trac": {
                "type": "python 2",
                "path": "/path/to/app/",
                "home": "/path/to/app/venv/",
                "module": "trac_wsgi",
                "environment": {
                    "TRAC_ENV": "/path/to/app/trac_env/",
                    "PYTHON_EGG_CACHE": "/path/to/app/trac_env/eggs/"

    The route serves requests for static files in Trac’s /chrome/ hierarchy from the static/ directory.

  7. Upload the updated configuration. Assuming the JSON above was added to config.json:

    # curl -X PUT --data-binary @config.json --unix-socket \
           /path/to/control.unit.sock http://localhost/config/


    The control socket path may vary; run unitd -h or see Startup and Shutdown for details.

    After a successful update, Trac should be available on the listener’s IP address and port:

    Trac on Unit - New Ticket Screen