oTree Production Server Setup¶
This documentation contains all the information neccessary to setup oTree on a fresh Debian 9 install. The rough process is as follows:
- install required software
- setup an otree user and set privileges
- install Python 3.6.x from sources
- initialize the PostgreSQL database
- setup Git with post-receive hooks
- setup nginx as a reverse proxy
The individual chapters cover the steps in more detail.
Contents¶
Preparations¶
It is assumed that root
can login to a standard shell.
Furthermore, it is assumed that the server is reachable via SSH.
If it is not, install openssh-server as root
:
apt-get update
apt-get install openssh-server
The following steps will reference installation scripts. These need to be downloaded, extracted and made executable.
As root
run:
wget https://github.com/chkgk/otree_setup_scripts/archive/master.zip
unzip master.zip
cd otree_setup_scripts-master
chmod +x setup_otree_server.sh
You are now ready for the first step of the installation.
Quick Setup¶
Read Preparations first!
Basic setup as root¶
Run as root
:
./setup_otree_server.sh
Enter passwords along the way. After the script finishes, you have two options: You can continue the installation with or without setting up SSL certificates.
Userspace setup without SSL¶
Run as otree
:
./1_continue_setup.sh
This will automatically execute the following scripts one after the other:
./2_install_python.sh
./3_setup_database.sh
./4_setup_git.sh
./5_setup_nginx.sh
Finally it will remove otree
from the sudo group.
Userspace setup with SSL¶
Run as otree
:
./1_continue_setup_ssl.sh
This will automatically execute the following scripts one after the other:
./2_install_python.sh
./3_setup_database.sh
./4_setup_git.sh
./5_setup_nginx_ssl.sh
Finally it will remove otree
from the sudo group.
Step 1: Software, Users and Privileges¶
This step requires the installation scripts to be downloaded and currently being logged in as root
.
Read Preparations if this is not the case.
Software¶
First we install the neccessary software using Debian’s package manager:
apt-get update
apt-get install -y libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm zlib1g-dev libssl-dev libncurses5-dev libncursesw5-dev xz-utils tk-dev postgresql postgresql-contrib redis-server git supervisor nginx sudo
This includes:
User and privileges¶
Typically, you do not want to work as root
. Accordingly, we will setup a user otree
and allow this user to run specific commands as root
through sudo
:
adduser otree
adduser otree sudo
This creates the user otree
and adds him to the sudo group which allows him to run arbitrary commands as root
. This is just for the setup. We will remove otree
from the sudo group at the end of the installation. In the end, we want otree
to only be able to run specific commands which are needed to control the supervisor daemon. We will now prepare the sudoers file accordingly:
nano /etc/sudoers.d/otree_supervisor
Copy in the following lines:
# allow otree user to start, stop and restart supervisor
otree ALL=NOPASSWD:/usr/sbin/service supervisor start
otree ALL=NOPASSWD:/usr/sbin/service supervisor stop
otree ALL=NOPASSWD:/usr/sbin/service supervisor restart
Save and exit nano with [ctrl] + [s] and [ctrl] + [x].
The three lines grant otree
the right to start, stop, and restart supervisor. There will be more information on supervisor in a later installation step.
Prepare userspace installation¶
Now it is time to continue the installation from the userspace. Before we can do so, however, we need to copy over the installation scripts to otree
’s home directory:
mv *.sh /home/otree/
chmod +x /home/otree/*.sh
chown otree:otree /home/otree/*.sh
Continue with step 2.
Step 2: Python 3.6¶
The Debian 9 stable branch includes Python up to version 3.5. While oTree runs on this version, there are some bugs related to the presentation of the monitoring table. Columns appear to be scrambled. To avoid this, we install Python 3.6 from sources.
Get Python 3.6¶
Log in as otree
and navigate to your home directory. Download and unpack Python 3.6 (any point release is fine, change the following commands accordingly):
cd ~
wget https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tgz
tar zxvf Python-3.6.5.tgz
rm Python-3.6.5.tgz
Configuration and building¶
Change working directory, then configure and make Python 3.6:
cd Python-3.6.5
./configure --with-ensurepip=install --enable-optimizations
make -j8
This might take a while. Time to get some coffee.
Installation¶
By default python
points to python2.7
. We will add python 3.6 as an alternative, but give the old association highest priority. We will have to use python3.6
explicitly (rather than just python
or python3
), but at least we are not breaking anything.
sudo make altinstall
sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 50
sudo update-alternatives --install /usr/bin/python python /usr/local/bin/python3.6 40
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.5 30
Leave and remove working directory:
cd ..
sudo rm -rf Python3.6.5
Virtual environment¶
OTree will run in its own virtual environment. This allows us to keep it separate from the system Python installation and avoids dependency clutter. We will create an initial virtual environment:
python3.6 -m venv venv_otree
source venv_otree/bin/activate
Finally, we make sure that the oTree virtual environment is automatically activated whenever otree
logs in:
echo "source /home/otree/venv_otree/bin/activate" >>/home/otree/.otree_env
echo "source /home/otree/.otree_env" >> /home/otree/.bashrc
This complete the second step.
Step 3: Database and Supervisor¶
We now setup the PostgreSQL database and prepare a supervisor script which makes sure that the oTree web server is automatically started and restarted if if fails for any reason.
PostgreSQL¶
We start by setting up the database and a database user for oTree:
sudo -i -u postgres psql postgres -c "CREATE DATABASE django_db;"
sudo -i -u postgres psql postgres -c "CREATE USER otree_user WITH PASSWORD 'CHANGE_THIS_PASSWORD_TO_YOUR_LIKING';"
sudo -i -u postgres psql postgres -c "GRANT ALL PRIVILEGES ON DATABASE django_db TO $db_user;"
Note: You can use tr -cd '[:alnum:]' < /dev/urandom | fold -w30 | head -n1
to quickly generate a random 30 character password from the command line.
Supervisor¶
We need to make sure that the oTree web server is started on system boot. It should also automatically restart, if it fails for any reason. To do so, we setup a supervisor script:
sudo nano /etc/supervisor/condf.d/otree.conf
Include the following lines:
[program:otree]
command=/home/otree/venv_otree/bin/otree runprodserver 8000
directory=/home/otree/oTree
stdout_logfile=/home/otree/otree-supervisor.log
stderr_logfile=/home/otree/otree-supervisor-errors.log
autostart=true
autorestart=true
environment=
PATH="/home/otree/venv_otree/bin/:%(ENV_PATH)s",
DATABASE_URL="postgres://otree_user:YOUR_DATABASE_PASSWORD@localhost/django_db",
OTREE_ADMIN_PASSWORD="YOUR_WEBINTERFACE_ADMIN_PASSWORD",
OTREE_PRODUCTION=1,
OTREE_AUTH_LEVEL=STUDY,
Make sure to replace YOUR_DATABASE_PASSWORD
with the one you set above. Also come up with a password for the oTree web interface and replace YOUR_WEBINTERFACE_ADMIN_PASSWORD
accordingly. Finally, save the file and exit nano with [ctrl] + [s] and [ctrl] + [x].
Environment Variables¶
Finally, we want otree
to be able to manually reset the database and invoke other oTree commands. We need to make sure that the credentials are available as environment variables whenever otree
logs in.
Edit /home/otree/.otree_env
with nano:
nano /home/otree/.otree_env
Add the following lines to the end:
export DATABASE_URL="postgres://otree_user:YOUR_DATABASE_PASSWORD@localhost/django_db"
export OTREE_ADMIN_PASSWORD="YOUR_WEBINTERFACE_ADMIN_PASSWORD"
export OTREE_PRODUCTION=1
export OTREE_AUTH_LEVEL=STUDY
Again, make sure to replace YOUR_DATABASE_PASSWORD
with the one you set above. Also come up with a password for the oTree web interface and replace YOUR_WEBINTERFACE_ADMIN_PASSWORD
accordingly. Finally, save the file and exit nano with [ctrl] + [s] and [ctrl] + [x].
Continue with step 4.
Step 4: Git Repository¶
We now set up the Git repository and a specific post-receive script that makes it easy for experimenters to deploy experiments on the server.
Directories¶
First we will create two directories: oTree
will contain the live oTree project. oTree.git
will be the repository that experimenters can push their experiments to. After creating the directories, we initialize an empty Git repository in the latter.
mkdir /home/otree/oTree
mkdir /home/otree/oTree.git
cd /home/otree/oTree.git
git init --bare
cd ~
Post-Receive Script¶
Experimenters can push their oTree experiments to the Git repository we have just created. Now we set up a script that is executed after every push to the repository. It will take care of the following steps:
- wipe the current virtual environment
- re-create the virtual environment
- install current versions of all required packages
- attempt to migrate the existing database if migrations are specified by the experimenter
- reset the database in all other cases
- restart the web server
Edit oTree.git/hooks/post-receive
with nano:
nano /home/otree/oTree.git/hooks/post-receive
Add the following script:
#!/bin/bash
GIT_WORK_TREE="/home/otree/oTree"
VENV_DIR="/home/otree/venv_otree"
export GIT_WORK_TREE
git checkout -f
if [[ -d "$VENV_DIR" ]]; then
echo "[log] - Cleaning virtualenv"
rm -rf $VENV_DIR
echo "[log] - Finished creating virtualenv"
fi
# recreate venv
echo "[log] - create venv"
python3.6 -m venv $VENV_DIR
# activate
echo "[log] - activate venv"
echo $VENV_DIR
source $VENV_DIR/bin/activate
source /home/otree/.otree_env
# install requirements
echo "[log] - install requirements"
pip install -U pip
pip install -r $GIT_WORK_TREE/requirements.txt
echo "[log] - Staring DB migration"
cd $GIT_WORK_TREE
if [[ -d "$GIT_WORK_TREE/otree_core_migrations" ]]
then
echo "[log] - detected migrations in otree project dir"
echo "[log] - attempting migrations"
otree migrate
echo "[log] - migrations done"
else
echo "[log] - no migrations defined"
echo "[log] - resetting db"
otree resetdb --noinput
echo "[log] - database reset"
fi
cd ..
echo "[log] - Finished DB migration "
echo "[log] - restart services"
sudo /usr/sbin/service supervisor restart
Finally, we make the script executable:
chmod +x /home/otree/oTree.git/hooks/post-receive
Continue with step 5.
Step 5: Nginx¶
We now set up nginx to serve as a reverse proxy. This allows us to easily set up SSL certificates.
Setup Without SSL¶
We need to remove the default nginx config and add a new one for oTree. Let’s remove the old one first:
sudo rm /etc/nginx/sites-enabled/default
Then we create a new one using nano:
sudo nano /etc/nginx/sites-enabled/otree
Copy in the following script:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name _;
location / {
proxy_pass http://localhost:8000;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
Save the file and exit nano with [ctrl] + [s] and [ctrl] + [x].
Setup with SSL¶
We need to remove the default nginx config and add a new one for oTree. Let’s remove the old one first:
sudo rm /etc/nginx/sites-enabled/default
Then we create a new one using nano:
sudo nano /etc/nginx/sites-enabled/otree
Copy in the following script:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name _;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name _;
ssl_certificate PATH_TO_SSL_CERTIFICATE_PEM;
ssl_certificate_key PATH_TO_SSL_KEY;
location / {
proxy_pass http://localhost:8000;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
Make sure to replace PATH_TO_SSL_CERTIFICATE_PEM
and PATH_TO_SSL_KEY
with the appropriate paths to your SSL certificates. Finally, save the file and exit nano with [ctrl] + [s] and [ctrl] + [x].
This concludes Step 5.
Final Steps¶
The final step is to lock down the otree
user account. Throughout the installation, it had full sudo privileges. To remove them invoke:
sudo deluser otree sudo
This removes otree
from the sudo group.
The group change only takes effect after logging out and in again.
Experimenter Usage¶
The server should now be set up completely. To get an experiment running, experimenters can add the server as a remote to their local git repository and then push their version to the remote repository.
Git Setup on experimenter’s computer¶
If the experimenter is already using Git as their version control system, you can skip this step.
First, install Git from https://git-scm.com/downloads.
Then, navigate to your oTree project folder and initialize the git repository. You only need to do this once for each oTree project folder:
git init
They will also have to configure their username and e-mail address:
git config --global user.name "your name"
git config --global user.email "test@exam"
Setting up the remote repository¶
To add the oTree server as a remote invoke the following command from your oTree project / local git repository directory:
git remote add production ssh://otree@SERVER_URL/home/otree/oTree.git
Make sure to replace SERVER_URL
with the URL the server is accessible from.
Pushing to production¶
When the experiment is ready to go live, experimenters can use the typical workflow of first staging and then commiting their changes before finally pushing them to production:
git add .
git commit -am "your commit message here"
git push production master
Users will have to know and enter the password for the otree
user account.
A few moments later oTree’s web interface should be available from any browser pointed to the server’s URL.
A note of caution¶
If the experimenter does not setup their oTree project to include database migrations the database will be reset after each push. This means that data currently stored in the database will be erased.