Installation Read The Docs

First, obtain Python 2.7 and virtualenv if you do not already have them. Using a virtualenv environment will make the installation easier, and will help to avoid clutter in your system-wide libraries.

Python 2.7

To install Python 2.7 from source, please see How to install Python 2.7 from source on CentOS.

Linux users may find they need to install a few additional packages in order to sucessfully execute pip install -r requirements.txt. For example, a clean install of CentOS 5.11 (Final) will require the following packages:

yum -y groupinstall "Development Tools"
yum -y install python-devel python-setuptools
yum -y install libxml2-devel libxslt-devel zlib-devel
cd /tmp
wget https://bootstrap.pypa.io/get-pip.py --no-check-certificate
python get-pip.py

Git 2.8

You will also need Git in order to clone the repository.

yum -y install curl-devel
yum -y install perl-devel
wget https://www.kernel.org/pub/software/scm/git/git-2.8.2.tar.gz
tar xf git-2.8.2.tar.gz
cd git-2.8.2
./configure --prefix=/usr/local
make install

Read The Docs

Once you have these, create a virtual environment somewhere on your disk, then active it:

virtualenv rtd
cd rtd
source bin/active

Create a folder in here, and clone the repository:

mkdir checkouts
cd checkouts
git clone https://github.com/rtfd/readthedocs.org.git

Next, install the depedencies using pip (included inside of virtualenv):

cd readthedocs.org
pip install -r requirements.txt
  • Could not find a version that satisfies the requirement backports.ssl_match_hostname (from tornado>=4.1->mkdocs==0.14.0->-r requirements/pip.txt (line 7)) (from versions: )

    No matching distribution found for backports.ssl_match_hostname (from tornado>=4.1->mkdocs==0.14.0->-r requirements/pip.txt (line 7))

     source rtd/bin/active
     cd /tmp 
     wget https://pypi.python.org/packages/76/21/2dc61178a2038a5cb35d14b61467c6ac632791ed05131dda72c20e7b9e23/backports.ssl_match_hostname-3.5.0.1.tar.gz
     tar xf backports.ssl_match_hostname-3.5.0.1.tar.gz
     cd backports.ssl_match_hostname-3.5.0.1
     python setup.py install
    

This may take a while, so go grab a beverage. When it’s done, build your database:

./manage.py migrate

Then please create a super account for Django

./manage.py createsuperuser

Next, create an account for API use and set SLUMBER_USERNAME and SLUMBER_PASSWORD in order for everything to work properly.

./manage.py shell
>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('test','','test')
>>> user.is_staff = True
>>> user.save()

Now let’s properly generate the static assets:

./manage.py collectstatic

Finally, your’re ready to start the webserver:

./manage.py runserver

For builds to properly kick off as expected, it is necessary the port you’re serving on (i.e. runserver 0.0.0.0:8000) match the port defined in PRODUCTION_DOMAIN. You can utilize local_settings.py to modify this. (By default, it’s localhost:8000)

If you put a file named local_settings.py in the readthedocs/settings directory, it will override settings available in the base install.

Example local_settings.py:

PRODUCTION_DOMAIN = '192.168.241.130:8000'
SLUMBER_API_HOST = 'http://192.168.241.130:8000'
PUBLIC_API_URL = 'http://192.168.241.130:8000'
MEDIA_URL = 'http://192.168.241.130:80/media/'

TIME_ZONE = 'Asia/Chongqing'

ALLOW_ADMIN = False
DEBUG = False

Configuration of the production servers

uWSGI

To install uWSGI with Python support, please refer to Python & WSGI applications

cd rtd
source bin/active
pip install uwsgi

Configuration file readthedocs_wsgi.ini

[uwsgi]
ini = :pro

[pro]
env = DJANGO_SETTINGS_MODULE=readthedocs.settings.pro
ini = :readthedocs

[dev]
env = DJANGO_SETTINGS_MODULE=readthedocs.settings.dev
ini = :readthedocs

[readthedocs]
virtualenv = /home/x/rtd/
chdir = /home/x/rtd/checkouts/readthedocs.org/
wsgi-file = readthedocs/wsgi.py
# module = django.core.handlers.wsgi:WSGIHandler()
# module = readthedocs.wsgi:applicaiton

# http = 0.0.0.0:8000
socket = 127.0.0.1:3031
# socket = /tmp/%n.sock
# chmod-socket = 777

uid = x
gid = x

stats = 127.0.0.1:9191
pidfile = logs/%n.pid
# daemonize = logs/%n.log

master = true
workers = 4
enable-threads = true

vaccum = true

Nginx

Building nginx from Sources, refer to Building nginx from Sources

wget http://nginx.org/download/nginx-1.10.0.tar.gz
tar xf nginx-1.10.0.tar.gz
wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.38.tar.gz
tar xf pcre-8.38.tar.gz
wget http://zlib.net/zlib-1.2.8.tar.gz
tar xf zlib-1.2.8.tar.gz
cd nginx-1.10.0
./configure
--prefix=/usr/local
--conf-path=/etc/nginx/nginx.conf
--pid-path=/var/run/nginx.pid
--error-log-path=/var/log/nginx/error.log
--http-log-path=/var/log/nginx/access.log
--with-http_ssl_module
--with-pcre=../pcre-8.38
--with-zlib=../zlib-1.2.8
make && make install

Configuration File’s Structure

nginx.conf

location / {
        include uwsgi_params;
        uwsgi_pass 127.0.0.1:3031;
        uwsgi_read_timeout 60;
}

location /static/ {
        alias /home/x/rtd/checkouts/readthedocs.org/media/static/;
}

location /media/ {
        alias /home/x/rtd/checkouts/readthedocs.org/media/;
}

location /docs/ {
        alias /home/x/rtd/checkouts/readthedocs.org/public_web_root/;
        index  index.html index.htm;
}

XSendfile: Nginx & Django

nginx.conf

location /protected/docs/ {
        alias /home/x/rtd/checkouts/readthedocs.org/public_web_root/;
        index  index.html index.htm;
}

middleware.py

from django.http import HttpResponse


class AuthenticationMiddleware(object):
    def __init__(self):
        self.mime_map = {
            '.css': 'text/css',
            '.htm': 'text/html',
            '.html': 'text/html',
            '.jpeg': 'image/jpeg',
            '.jpg': 'image/jpeg',
            '.js': 'application/javascript',
            '.json': 'application/json',
            '.zip': 'application/x-zip-compressed',
        }
        self.protected_url = '/protected'

    def is_authenticated(self, request):
        return True

    def x_accel_redirect(self, request_path):
        resp = HttpResponse()
        ext = path.splitext(request_path)[1]
        if ext:
            resp['Content-Type'] = self.mime_map[ext]
        resp['X-Accel-Redirect'] = self. protected_url + request_path
        return resp

    def process_request(self, request):
        if request.path.startswith('/docs') and self.is_authenticated(request):
            return self.x_accel_redirect(request.path)

References