MoinMoin on Nginx - shawfdong/hyades GitHub Wiki

As an experiment for layered security, I maintain a personal wiki, using the MoinMoin Wiki Engine, on the server maia.ucsc.edu. The following are the building blocks:

Table of Contents

MoinMoin

MoinMoin is written in Python. On a fully patched CentOS 6 system, such as maia.ucsc.edu, the stock Python is ancient:

# python --version
Python 2.6.6
but it is sufficient to run MoinMoin, as the latest MoinMoin (version 1.9.7) only requires Python 2.4.

1. Download the latest release of MoinMoin (moin-1.9.7.tar.gz) from http://moinmo.in/MoinMoinDownload.

2. The web root for static contents is /var/www/maia. Unpack the tarball at /var/www, outside of the web root:

# tar xvzf moin-1.9.7.tar.gz -C /var/www/

3. Copy the static contents of MoinMoin to the web root:

# mkdir -p /var/www/maia/static
# cp -r /var/www/moin-1.9.7/MoinMoin/web/static/htdocs/* /var/www/maia/static/

4. Fix the permission – the wiki data must be writable by the uWSGI server, which runs as uid = nginx & gid = nginx (see below):

# chown -R dong:dong /var/www/maia
# chown -R dong:dong /var/www/moin-1.9.7
# chown -R nginx:nginx /var/www/moin-1.9.7/wiki

5. Adapt /var/www/moin-1.9.7/wikiconfig.py:

import os

from MoinMoin.config import multiconfig, url_prefix_static

class LocalConfig(multiconfig.DefaultConfig):
    wikiconfig_dir = os.path.abspath(os.path.dirname(__file__))

    instance_dir = os.path.join(wikiconfig_dir, 'wiki')

    # Where your own wiki pages are (make regular backups of this directory):
    data_dir = os.path.join(instance_dir, 'data', '') # path with trailing /

    # Where system and help pages are (you may exclude this from backup):
    data_underlay_dir = os.path.join(instance_dir, 'underlay', '') # path with trailing /

    DesktopEdition = False
    acl_rights_before = u"FrankDong:read,write,delete,revert,admin"
    acl_rights_default = u"All:none"
    surge_action_limits = None # no surge protection

    sitename = u"Frank Dong's Wiki"
    
    url_prefix_static = '/static'
    logo_string = u'<img src="%s/common/kailash-logo.png" alt="Kailash">' % url_prefix_static

    page_front_page = u'FrontPage'

    secrets = 'xxxxxxxxxx'
    superuser = [u"FrankDong", ]
    language_default = 'en'
    language_ignore_browser = True

try:
    from wikiconfig_local import Config
except ImportError, err:
    if not str(err).endswith('wikiconfig_local'):
        raise
    Config = LocalConfig

uWSGI

MoinMoin is a WSGI application. Here is how to install and set up a uWSGI server on CentOS 6.

1. Install pip, e.g., install the python-pip package from the EPEL repository:

# yum install python-pip

2. Install uWSGI:

# pip install uWSGI

or upgrade to the latest version of uWSGI:

# pip install -U uWSGI

3. Create a configuration file for uWSGI (/etc/uwsgi/moin.xml)[3][4]:

<uwsgi>
  <socket>/var/lib/uwsgi/moin.sock</socket>
  <uid>nginx</uid>
  <wsgi-file>/var/www/moin-1.9.7/wiki/server/moin.wsgi</wsgi-file>
  <master />
  <workers>4</workers>
  
  <daemonize>/dev/null</daemonize>
</uwsgi>

4. Create an init script for uWSGI (/etc/init.d/uwsgi)[5]:

#! /bin/sh
#
# chkconfig: - 83 17
# description: uWSGI
# processname: uwsgi
# config: /etc/uwsgi.conf
# config: /etc/sysconfig/uwsgi
# pidfile: /var/run/uwsgi/uwsgi.pid
#
### BEGIN INIT INFO
# Provides: uwsgi
# Required-Start: $local_fs $remote_fs $network $named
# Required-Stop: $local_fs $remote_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: start and stop uWSGI
# Description: uWSGI
### END INIT INFO

# Standard LSB functions
#. /lib/lsb/init-functions

# Source function library.
. /etc/init.d/functions

# Check that networking is up.
. /etc/sysconfig/network

# Additional environment file
if [ -f /etc/sysconfig/uwsgi ]; then
      . /etc/sysconfig/uwsgi
fi

if [ "$NETWORKING" = "no" ]
then
	exit 0
fi

RETVAL=0
prog="uwsgi"
pidfile=${PIDFILE-/var/run/uwsgi.pid}
lockfile=${LOCKFILE-/var/lock/subsys/uwsgi}
xmlfile=${XMLFILE-/etc/uwsgi/moin.xml}

start () {
	echo -n $"Starting $prog: "
	dir=$(dirname ${pidfile})
	[ -d $dir ] || mkdir $dir
	/usr/bin/uwsgi -x ${xmlfile} --pidfile ${pidfile}
	RETVAL=$?
	[ $RETVAL -eq 0 ] && touch ${lockfile}
}
stop () {
	echo -n $"Stopping $prog: "
	killproc -p ${pidfile} uwsgi
        # or equivalently
        # /usr/bin/uwsgi --stop ${pidfile}
	RETVAL=$?
	echo
	if [ $RETVAL -eq 0 ] ; then
		rm -f ${lockfile} ${pidfile}
	fi
}

restart () {
        stop
        start
}

reload () {
	echo -n $"Reloading $prog: "
	killproc -p ${pidfile} uwsgi -HUP
        # or equivalently
        # /usr/bin/uwsgi --reload ${pidfile}
	RETVAL=$?
	echo
}


# See how we were called.
case "$1" in
  start)
	start
	;;
  stop)
	stop
	;;
  status)
	status -p ${pidfile} uwsgi
	RETVAL=$?
	;;
  restart)
	restart
	;;
  reload)
	reload
	;;
  *)
	echo $"Usage: $0 {start|stop|status|restart|reload}"
	RETVAL=2
        ;;
esac

exit $RETVAL

5. Start uWSGI:

# chkconfig --add uwsgi
# service start uwsgi

nginx

Here is the configuration for nginx (/etc/nginx/conf.d/maia.conf):

server {
    listen       80;
    server_name  maia.ucsc.edu;

    location ^~ / {
        return 301 https://$server_name$request_uri;
    }
}

server {
    listen       443 ssl;
    server_name  maia.ucsc.edu;

    ssl_certificate      /etc/ssl/maia.crt;
    ssl_certificate_key  /etc/ssl/maia.key;
    ssl_client_certificate /etc/ssl/dong-root-ca.crt;
    ssl_crl /etc/ssl/crl.pem;
    ssl_verify_client on;

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout  10m;

    ssl_ciphers  HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers   on;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    root         /var/www/maia;
    index        index.html;
    autoindex    on;

    auth_basic   "Basic Authentication Required";
    auth_basic_user_file   htpasswd;

    # Prevent access to any file starting with a dot
    location ~ /\. { access_log off; log_not_found off; deny all; }

    # Prevent access to any files ending with a ~
    location ~ ~$ { access_log off; log_not_found off; deny all; }

    # Do not log access to robots.txt, to keep the logs cleaner
    location = /robots.txt { access_log off; log_not_found off; }

    # Do not log access to the favicon, to keep the logs cleaner
    location = /favicon.ico { access_log off; log_not_found off; }

    location = /_.gif {
        expires max;
        empty_gif;
    }
 
    # Keep images and CSS around in browser cache for as long as possible
    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        expires max;
        log_not_found off;
    }

    location /wiki {
        include uwsgi_params;
        uwsgi_param SCRIPT_NAME /wiki;
        uwsgi_modifier1 30;
        uwsgi_pass unix:/var/lib/uwsgi/moin.sock;
    }

    error_page  403 404          /_.gif;
    error_page  500 502 503 504  /_.gif;
}

References

  1. ^ MoinMoin InstallDocs
  2. ^ How to Deploy Python WSGI Applications Using uWSGI Web Server with Nginx
  3. ^ uWSGI Options
  4. ^ Configuring uWSGI
  5. ^ Managing the uWSGI server
⚠️ **GitHub.com Fallback** ⚠️