1. Introduction

This documentation explains how to deploy a full Taiga service (each module is part of the Taiga platform).

The Taiga platform consists of three main components and each one has its own dependencies both at compile time and runtime:

  • taiga-back (backend/api)

  • taiga-front-dist (frontend)

  • taiga-events (websockets gateway) (optional)

Each component can be run on one unique machine or all of them can be installed to a different machine aswell. In this tutorial we will setup everything on one single machine, installing all three Taiga components. This type of setup should suffice for small/medium production environments.

2. Overview

This tutorial assumes that you are using a clean, recently updated Ubuntu 16.04 image.

Due to the nature of the frontend, Taiga is used through a domain/public-ip, because the frontend application runs in your browser. The frontend must be able to communicate with the backend/API, therefore both the frontend and the backend must be accessible through a domain/public-ip too.

The installation of Taiga must be done with a "regular" user, never with root.

During the tutorial, We assume the following details:

  • ip: 80.88.23.45

  • hostname: example.com (which points to 80.88.23.45)

  • username: taiga

  • system ram >=1GB (needed for compilation of lxml)

  • working dir /home/taiga/ (default for user taiga)

2.1. System Architecture Description

This is a short system architecture description to help you understand the way Taiga is built and works. Before you go any further in the installation, make sure you read this description to get a high-level overview.

Taiga consists of 2 core (mandatory) modules:

  • taiga-back

  • taiga-front

taiga-back is written in django, python3 and serves API endpoints for the frontend.

taiga-front is written mostly in angularjs and coffeescript and depends on the backend.

The python backend is exposed by gunicorn (port 9001), which is a Python WSGI HTTP server. The process manager is Circus, which runs gunicorn and taiga-back together. Technically the backend communicates with the database(postgresql) and through the frontend, it allows the user to use the features of Taiga. The communication between the front- and backend is done using APIs.

The backend is then publicly exposed by nginx which acts as a reverse-proxy for this case. The frontend is located in the dist folder and is exposed publicly by nginx which acts as a static webserver for this case.

3. Prerequisites

Taiga consists of three modules and each of them require different packages and third-party packages. This sections collects the required packages for a successful Taiga installation and configuration. In this section we will install all dependencies for all modules, including the optional modules and services.

Essential packages:
sudo apt-get update
sudo apt-get install -y build-essential binutils-doc autoconf flex bison libjpeg-dev
sudo apt-get install -y libfreetype6-dev zlib1g-dev libzmq3-dev libgdbm-dev libncurses5-dev
sudo apt-get install -y automake libtool libffi-dev curl git tmux gettext
sudo apt-get install -y nginx
sudo apt-get install -y rabbitmq-server redis-server
sudo apt-get install -y circus
The component taiga-back uses postgresql (>= 9.4) as database:
sudo apt-get install -y postgresql-9.5 postgresql-contrib-9.5
sudo apt-get install -y postgresql-doc-9.5 postgresql-server-dev-9.5
Python (3.5) and virtualenvwrapper must be installed along with a few third-party libraries:
sudo apt-get install -y python3 python3-pip python-dev python3-dev python-pip virtualenvwrapper
sudo apt-get install -y libxml2-dev libxslt-dev
sudo apt-get install -y libssl-dev libffi-dev
virtualenvwrapper helps keeping the system clean of third party libraries, installed with the language package manager by installing these packages in an isolated virtual environment.

Restart the shell or run bash to reload the bash environment with the new virtualenvwrapper variables and functions.

This step is mandatory before continuing the installation!

Create a user named taiga, and give it root permissions
sudo adduser taiga
sudo adduser taiga sudo
sudo su taiga
cd ~
Do not change to root user. The installation must be done with the taiga user.

3.1. Configuring Dependencies

Configure postgresql with the initial user and database:
sudo -u postgres createuser taiga
sudo -u postgres createdb taiga -O taiga --encoding='utf-8' --locale=en_US.utf8 --template=template0
Create a user named taiga, and a virtualhost for RabbitMQ (taiga-events)
sudo rabbitmqctl add_user taiga PASSWORD_FOR_EVENTS
sudo rabbitmqctl add_vhost taiga
sudo rabbitmqctl set_permissions -p taiga taiga ".*" ".*" ".*"
Create the logs folder (mandatory)
mkdir -p ~/logs

4. Backend configuration

This section helps configuring the backend (api) Taiga service and its dependencies.

Download the code
cd ~
git clone https://github.com/taigaio/taiga-back.git taiga-back
cd taiga-back
git checkout stable
Create new virtualenv named taiga
mkvirtualenv -p /usr/bin/python3.5 taiga
Install dependencies
pip install -r requirements.txt
Populate the database with initial basic data
python manage.py migrate --noinput
python manage.py loaddata initial_user
python manage.py loaddata initial_project_templates
python manage.py compilemessages
python manage.py collectstatic --noinput

This creates the administrator account. The login credentials are admin with password 123123.

OPTIONAL: If you would like to have some example data loaded into Taiga, execute the following command, which populates the database with sample projects and random data (useful for demos):

python manage.py sample_data

To finish the setup of taiga-back, create the intial configuration file for proper static/media file resolution, optionally with email sending support:

Copy-paste the following config into ~/taiga-back/settings/local.py and update it with your own details:
from .common import *

MEDIA_URL = "http://example.com/media/"
STATIC_URL = "http://example.com/static/"
SITES["front"]["scheme"] = "http"
SITES["front"]["domain"] = "example.com"

SECRET_KEY = "theveryultratopsecretkey"

DEBUG = False
PUBLIC_REGISTER_ENABLED = True

DEFAULT_FROM_EMAIL = "no-reply@example.com"
SERVER_EMAIL = DEFAULT_FROM_EMAIL

#CELERY_ENABLED = True

EVENTS_PUSH_BACKEND = "taiga.events.backends.rabbitmq.EventsPushBackend"
EVENTS_PUSH_BACKEND_OPTIONS = {"url": "amqp://taiga:PASSWORD_FOR_EVENTS@localhost:5672/taiga"}

# Uncomment and populate with proper connection parameters
# for enable email sending. EMAIL_HOST_USER should end by @domain.tld
#EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
#EMAIL_USE_TLS = False
#EMAIL_HOST = "localhost"
#EMAIL_HOST_USER = ""
#EMAIL_HOST_PASSWORD = ""
#EMAIL_PORT = 25

# Uncomment and populate with proper connection parameters
# for enable github login/singin.
#GITHUB_API_CLIENT_ID = "yourgithubclientid"
#GITHUB_API_CLIENT_SECRET = "yourgithubclientsecret"

4.1. Verification

(Optional) To make sure that everything works, issue the following command to run the backend in development mode for a test:

workon taiga
python manage.py runserver

Then you must be able to see a json representing the list of endpoints at the url: http://localhost:8000/api/v1/ .

At this stage the backend has been installed successfully, but to run the python backend in production, an application server must be configured first. The details for this are explained later in this doc.

5. Frontend installation

Download the code from Github:

Download the code
cd ~
git clone https://github.com/taigaio/taiga-front-dist.git taiga-front-dist
cd taiga-front-dist
git checkout stable
Copy the example config file:
cp ~/taiga-front-dist/dist/conf.example.json ~/taiga-front-dist/dist/conf.json
Edit the example configuration following the pattern below (replace with your own details):
{
	"api": "http://example.com/api/v1/",
	"eventsUrl": "ws://example.com/events",
	"debug": "true",
	"publicRegisterEnabled": true,
	"feedbackEnabled": true,
	"privacyPolicyUrl": null,
	"termsOfServiceUrl": null,
	"maxUploadFileSize": null,
	"contribPlugins": []
}
Be careful using copy-paste from browser to avoid http:// duplication.

Having taiga-front-dist downloaded and configured is insufficient. The next step is to expose the code (in dist directory) under a static file web server. In this tutorial We use nginx as a static file web server and reverse-proxy. The configuration of nginx is explained later.

6. Events installation

This step is optional and can be skipped

Taiga-events is the Taiga websocket server, it allows taiga-front to show realtime changes in the backlog, taskboard, kanban and issues listing. Taiga-events use rabbitmq (the message broker).

Download taiga-events from Github and install its dependencies:

Download the code
cd ~
git clone https://github.com/taigaio/taiga-events.git taiga-events
cd taiga-events
Install nodejs
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install -y nodejs
Install the javascript dependencies needed
npm install
sudo npm install -g coffee-script
Copy and edit the config.json file. Update with your rabbitmq uri and the secret key.
cp config.example.json config.json
Your config.json should be like:
{
    "url": "amqp://taiga:PASSWORD_FOR_EVENTS@localhost:5672/taiga",
    "secret": "theveryultratopsecretkey",
    "webSocketServer": {
        "port": 8888
    }
}

The 'secret' in config.json must be the same as the "SECRET_KEY" in ~/taiga-back/settings/local.py

Add taiga-events to circus configuration.

Copy-paste the code below into /etc/circus/conf.d/taiga-events.ini
[watcher:taiga-events]
working_dir = /home/taiga/taiga-events
cmd = /usr/bin/coffee
args = index.coffee
uid = taiga
numprocesses = 1
autostart = true
send_hup = true
stdout_stream.class = FileStream
stdout_stream.filename = /home/taiga/logs/taigaevents.stdout.log
stdout_stream.max_bytes = 10485760
stdout_stream.backup_count = 12
stderr_stream.class = FileStream
stderr_stream.filename = /home/taiga/logs/taigaevents.stderr.log
stderr_stream.max_bytes = 10485760
stderr_stream.backup_count = 12
Reload the circusd configurations:
sudo service circusd restart
sudo service circusd status

7. Start and Expose Taiga

Before moving further, make sure you installed taiga-back and taiga-front-dist, however, having installed them is insufficient to run Taiga.

taiga-back should run under an application server, which in turn, should be executed and monitored by a process manager. For this task we will use gunicorn and circus respectively.

Both taiga-front-dist and taiga-back must be exposed to the outside using a proxy/static-file web server. For this purpose, Taiga uses nginx.

7.1. Circus and gunicorn

Circus is a process manager written by Mozilla and Taiga uses it to execute gunicorn. Circus is not only for executing processes, but it also has utils for monitoring them, collecting logs, and restarting processes if something goes wrong, and also for starting processes on system boot.

Initial Taiga configuration for circus in /etc/circus/conf.d/taiga.ini
[watcher:taiga]
working_dir = /home/taiga/taiga-back
cmd = gunicorn
args = -w 3 -t 60 --pythonpath=. -b 127.0.0.1:8001 taiga.wsgi
uid = taiga
numprocesses = 1
autostart = true
send_hup = true
stdout_stream.class = FileStream
stdout_stream.filename = /home/taiga/logs/gunicorn.stdout.log
stdout_stream.max_bytes = 10485760
stdout_stream.backup_count = 4
stderr_stream.class = FileStream
stderr_stream.filename = /home/taiga/logs/gunicorn.stderr.log
stderr_stream.max_bytes = 10485760
stderr_stream.backup_count = 4

[env:taiga]
PATH = /home/taiga/.virtualenvs/taiga/bin:$PATH
TERM=rxvt-256color
SHELL=/bin/bash
USER=taiga
LANG=en_US.UTF-8
HOME=/home/taiga
PYTHONPATH=/home/taiga/.virtualenvs/taiga/lib/python3.5/site-packages

Circus stats can generate a high cpu usage without any load you can set statsd in /etc/circus/circusd.conf to false if you don’t need them.

Taiga stores logs on the user home, making them available and immediately accessible when you enter a machine. To make everything work, make sure you have the logs directory created.

Final step is restarting circus:

sudo service circusd restart
To verify that the services are running, issue:
circusctl status

7.2. Nginx

Nginx is used as a static file web server to serve taiga-front-dist and send proxy requests to taiga-back.

Remove the default nginx config file to avoid collision with Taiga:
sudo rm /etc/nginx/sites-enabled/default
To create a new nginx virtualhost for Taiga, create and edit the /etc/nginx/conf.d/taiga.conf file, as follows:
server {
    listen 80 default_server;
    server_name _;

    large_client_header_buffers 4 32k;
    client_max_body_size 50M;
    charset utf-8;

    access_log /home/taiga/logs/nginx.access.log;
    error_log /home/taiga/logs/nginx.error.log;

    # Frontend
    location / {
        root /home/taiga/taiga-front-dist/dist/;
        try_files $uri $uri/ /index.html;
    }

    # Backend
    location /api {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:8001/api;
        proxy_redirect off;
    }

    # Django admin access (/admin/)
    location /admin {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:8001$request_uri;
        proxy_redirect off;
    }

    # Static files
    location /static {
        alias /home/taiga/taiga-back/static;
    }

    # Media files
    location /media {
        alias /home/taiga/taiga-back/media;
    }

	# Taiga-events
	location /events {
	proxy_pass http://127.0.0.1:8888/events;
	proxy_http_version 1.1;
	proxy_set_header Upgrade $http_upgrade;
	proxy_set_header Connection "upgrade";
	proxy_connect_timeout 7d;
	proxy_send_timeout 7d;
	proxy_read_timeout 7d;
	}
}
Issue the following command to verify the nginx configuration and to track any error in the service:
sudo nginx -t

Finally, restart nginx:

sudo service nginx restart

Now you should have the service up and running on: http://example.com/

8. Optional Components and Settings

The following items are completely optional and are up for you to configure them. Taiga-events module is also an optional feature, but its installation is part of this tutorial.

8.1. Async tasks (Optional)

The default behavior in Taiga is to do all tasks in a synchronous way, but some of them can be completely asynchronous (for example webhooks or import/export). To do this, you have to configure and install the celery service requirements.

There is just an exception related to exported files, if your instance works in asynchronous mode the exported project files will be automatically removed from the storage after 24 hours, if not those media files won’t be automatically removed (taiga-back doesn’t really know anything about the existance of those files).

Install rabbitmq-server and redis-server:

sudo apt-get install -y rabbitmq-server redis-server

To run celery with Taiga, include the following code line in the local.py file:

CELERY_ENABLED = True

You can configure other broker or results backend. If you need more info about it, check the celery documentation web page: http://docs.celeryproject.org/en/latest/index.html

Once you have configured celery on Taiga, you have to add celery to circus configuration. See Circus and gunicorn section.

Taiga celery configuration block for circus on /etc/circus/conf.d/taiga-celery.ini
[watcher:taiga-celery]
working_dir = /home/taiga/taiga-back
cmd = celery
args = -A taiga worker -c 4
uid = taiga
numprocesses = 1
autostart = true
send_hup = true
stdout_stream.class = FileStream
stdout_stream.filename = /home/taiga/logs/celery.stdout.log
stdout_stream.max_bytes = 10485760
stdout_stream.backup_count = 4
stderr_stream.class = FileStream
stderr_stream.filename = /home/taiga/logs/celery.stderr.log
stderr_stream.max_bytes = 10485760
stderr_stream.backup_count = 4

[env:taiga-celery]
PATH = /home/taiga/.virtualenvs/taiga/bin:$PATH
TERM=rxvt-256color
SHELL=/bin/bash
USER=taiga
LANG=en_US.UTF-8
HOME=/home/taiga
PYTHONPATH=/home/taiga/.virtualenvs/taiga/lib/python3.5/site-packages

Reload the circus configuration, restart taiga, then start taiga-celery:

circusctl reloadconfig
circusctl restart taiga
circusctl start taiga-celery

8.2. Taiga Hardening - HTTPS

Follow the instructions in this section to server Taiga under HTTPS.

Place the SSL certificates in /etc/nginx/ssl. It is recommended to replace the original configuration for port 80 so that users are redirected to the HTTPS version automatically.

Second we need to generate a stronger GHE parameter:

cd /etc/ssl
sudo openssl dhparam -out dhparam.pem 4096
Update the configuration in /etc/nginx/conf.d/taiga.conf

(Taiga-events not included)

server {
    listen 80 default_server;
    server_name _;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl default_server;
    server_name _;

    large_client_header_buffers 4 32k;
    client_max_body_size 50M;
    charset utf-8;

    index index.html;

    # Frontend
    location / {
        root /home/taiga/taiga-front-dist/dist/;
        try_files $uri $uri/ /index.html;
    }

    # Backend
    location /api {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:8001/api;
        proxy_redirect off;
    }

    location /admin {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:8001$request_uri;
        proxy_redirect off;
    }

    # Static files
    location /static {
        alias /home/taiga/taiga-back/static;
    }

    # Media files
    location /media {
        alias /home/taiga/taiga-back/media;
    }

    add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
    add_header Public-Key-Pins 'pin-sha256="klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY="; pin-sha256="633lt352PKRXbOwf4xSEa1M517scpD3l5f79xMD9r9Q="; max-age=2592000; includeSubDomains';

    ssl on;
    ssl_certificate /etc/nginx/ssl/example.com/ssl-bundle.crt;
    ssl_certificate_key /etc/nginx/ssl/example.com/example_com.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK';
    ssl_session_cache shared:SSL:10m;
    ssl_dhparam /etc/ssl/dhparam.pem;
    ssl_stapling on;
    ssl_stapling_verify on;

}

Before activating the HTTPS site, the configuration for the frontend and the backend must be updated. Change the scheme from http to https throughout the configurations.

Update ~/taiga-back/settings/local.py
from .common import *

MEDIA_URL = "https://example.com/media/"
STATIC_URL = "https://example.com/static/"
SITES["front"]["scheme"] = "https"
SITES["front"]["domain"] = "example.com"

SECRET_KEY = "theveryultratopsecretkey"

DEBUG = False
PUBLIC_REGISTER_ENABLED = True

DEFAULT_FROM_EMAIL = "no-reply@example.com"
SERVER_EMAIL = DEFAULT_FROM_EMAIL

# Uncomment and populate with proper connection parameters
# for enable email sending.
#EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
#EMAIL_USE_TLS = False
#EMAIL_HOST = "localhost"
#EMAIL_HOST_USER = ""
#EMAIL_HOST_PASSWORD = ""
#EMAIL_PORT = 25

# Uncomment and populate with proper connection parameters
# for enable github login/singin.
#GITHUB_API_CLIENT_ID = "yourgithubclientid"
#GITHUB_API_CLIENT_SECRET = "yourgithubclientsecret"
Update ~/taiga-front-dist/dist/conf.json
{
    "api": "https://example.com/api/v1/",
    "eventsUrl": "wss://example.com/events",
    "debug": "true",
    "publicRegisterEnabled": true,
    "feedbackEnabled": true,
    "privacyPolicyUrl": null,
    "termsOfServiceUrl": null,
    "maxUploadFileSize": null
}
Restart circus after updating the configuration:
sudo service circusd restart
Reload the nginx configuration:
sudo service nginx reload

9. Troubleshooting

If you face any issue during or after installing Taiga, please collect the content of the following files:
  • /etc/nginx/conf.d/taiga.conf

  • /etc/circus/conf.d/taiga.ini

  • /etc/circus/conf.d/taiga-celery.ini

  • /etc/circus/conf.d/taiga-events.ini

  • /home/taiga/taiga-back/settings/local.py

  • /home/taiga/taiga-front-dist/dist/conf.json

  • /home/taiga/taiga-events/config.json

  • All files in /home/taiga/logs

Issue the following commands to check the status of services used by Taiga:
sudo service nginx status
sudo service circusd status
sudo service rabbitmq-server status
sudo service postgresql status

Check If you see any error in the service statuses and make sure all service status is Active.