Ploneのインストール [Plone4.0]

インストール

poppler-utilsのインストール

poppler-utils を事前にシステムにインストールしておくことで、PDF の本文を検索対象に含めることができる。yum 等でインストールする。

yum install poppler-utils

Unified Installerでのインストール

http://plone.org/ よりダウンロードしインストールする。ここではバージョン 4.0.7 を Standalone で利用する。

# tar zxvf Plone-4.0.7-UnifiedInstaller.tgz
# cd Plone-4.0.7-UnifiedInstaller
# ./install.sh standalone

デフォルトでは /usr/local/Plone にインストールされ、/usr/local/Plone/zinstance に Plone のインスタンスが作成される。後でインスタンスのみ追加できるよう、上で生成されたファイルは残しておく。インスタンスを追加する場合は、次のようにする。

# ./install.sh --target=/usr/local/Plone4 --instance=zinstance2 standalone

Pythonのデフォルトエンコーディングの設定

Zope は文字コードを UTF-8 で扱うため、Python のデフォルトエンコーディングを UTF-8 とする。/usr/local/Plone/Python-2.4/lib/python2.4/site-packages /sitecustomize.py ファイルを作成し以下のように記述すればよい。

import sys
sys.setdefaultencoding("utf-8")

WvWareのインストール

poppler-utils を事前にシステムにインストールしておくことで、WORD の本文を検索対象に含めることができる。必要なパッケージを事前にインストールしておく。

# yum install glib2-devel libgsf-devel

Wv を http://sourceforge.net/projects/wvware/files/ よりダウンロードしてソースからインストールする。

# tar zxvf wv-1.2.4.tar.gz
# cd wv-1.2.4
# ./confiture
# make
# make install

/usr/local/bin にインストールされるため base.cfg を編集して環境変数も設定しておく。

  environment-vars =
      PYTHON_EGG_CACHE ${buildout:directory}/var/.python-eggs
+     PATH /sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin

次に設定を反映する。

# bin/buildout

c2.patch.filenamenormalizerのインストール

デフォルトではファイルダウンロード時にファイル名がid表示になってしまう点を修正する。デフォルトでは画像表示時に、ダウンロードダイアログが出てしまうため、ソースからインストールして一部修正を行う。ダウンロードは http://pypi.python.org/pypi/c2.patch.filenamenormalizer より行える。

# tar zxvf c2.patch.filenamenormalizer-1.0a5.tar.gz
# mv c2.patch.filenamenormalizer-1.0a5 $PLONE_INSTANCE/src/c2.patch.filenamenormalizer

次に c2.patch.filenamenormalizer/c2/patch/filenamenormalizer/monkey.py の下記のように修正する。

#!/usr/bin/env python
# encoding: utf-8
"""
monkey.py

Created by Manabu Terada on 2010-01-08.
Copyright (c) 2010 CMScom. All rights reserved.
"""

import urllib
from email.Message import Message as emailMessage
from Acquisition import aq_get
from webdav.common import rfc1123_date
from Products.Archetypes.Field import FileField
#from Products.Archetypes.utils import contentDispositionHeader
from config import *

from logging import getLogger
logger = getLogger(__name__)
info = logger.info

try:
from plone.app.blob import field
from plone.app.blob.download import handleIfModifiedSince, handleRequestRange
IS_BLOB = True
except ImportError:
IS_BLOB = False

def get_header_value(ua, filename, instance):

cdisposition = (filename[-4:]=='.swf') and 'inline' or 'attachment'

if ('MSIE' in ua or 'Edge' in ua) and not JA_DEPENDENCE:
filename = urllib.quote(
unicode(filename, instance.getCharset()).encode('utf-8', 'replace'))
else:
filename = unicode(filename, instance.getCharset()).encode(charset, 'replace')
m = emailMessage()
disposition=cdisposition
kw = {'filename' : filename}
m.add_header('content-disposition', disposition, **kw)
header_value = m['content-disposition']

return header_value

def ng_download(self, instance, REQUEST=None, RESPONSE=None, no_output=False):
"""Kicks download.

Writes data including file name and content type to RESPONSE
"""
file = self.get(instance, raw=True)
if not REQUEST:
REQUEST = aq_get(instance, 'REQUEST')
ua = REQUEST.get('HTTP_USER_AGENT')

if not RESPONSE:
RESPONSE = REQUEST.RESPONSE
filename = self.getFilename(instance)
if filename is not None:
header_value = get_header_value(ua, filename, instance)
RESPONSE.setHeader("Content-disposition", header_value)
if no_output:
return file
return file.index_html(REQUEST, RESPONSE)


def blob_index_html(self, instance, REQUEST=None, RESPONSE=None, disposition='inline'):
""" make it directly viewable when entering the objects URL
Original plone.app.blob.field.py
"""
if REQUEST is None:
REQUEST = instance.REQUEST
ua = REQUEST.get('HTTP_USER_AGENT')
if RESPONSE is None:
RESPONSE = REQUEST.RESPONSE
blob = self.getUnwrapped(instance, raw=True)    # TODO: why 'raw'?
RESPONSE.setHeader('Last-Modified', rfc1123_date(instance._p_mtime))
RESPONSE.setHeader('Content-Type', self.getContentType(instance))
RESPONSE.setHeader('Accept-Ranges', 'bytes')
if handleIfModifiedSince(instance, REQUEST, RESPONSE):
return ''
length = blob.get_size()
RESPONSE.setHeader('Content-Length', length)
filename = self.getFilename(instance)
if filename is not None:
# filename = IUserPreferredFileNameNormalizer(REQUEST).normalize(
#     unicode(filename, instance.getCharset()))
# header_value = contentDispositionHeader(
#     disposition=disposition,
#     filename=filename)
# RESPONSE.setHeader("Content-disposition", header_value)
header_value = get_header_value(ua, filename, instance)
RESPONSE.setHeader("Content-disposition", header_value)
range = handleRequestRange(instance, length, REQUEST, RESPONSE)
return blob.getIterator(**range)


FileField.download = ng_download
info('patched %s', 'FileField.download')

if IS_BLOB:
field.BlobField.index_html = blob_index_html
info('patched %s', 'field.BlobField.index_html')

最後に設定を反映する。

# bin/buildout

python-ldapのインストール

Python で LDAP を利用するには python-ldap2.3.13 モジュールをインストールする必要がある。まずインスタンス内の buildout.cfg を設定する。

  eggs =
      Plone
       :
+     python-ldap==2.3.13

次に設定を反映する。

# bin/buildout

インストールには openldap-devel と openssl-devel を組み込んでおく必要がある。インストールされていない場合は先に yum 等でインストールすればよい。

# yum install openldap-devel openssl-devel

起動確認

Plone が起動することを確認する。

# cd /usr/local/Plone/instance
# bin/plonectl start

http://ホスト名:8080/ にアクセスして Plone のページが表示されればインストール成功である。Plone の停止は次のコマンドを実行する。

# bin/plonectl stop

全体の管理者の設定

インストールすると admin ユーザが生成される。パスワード等は /usr/local/Plone/instance/adminPassword.txt に書かれている。ZMI(http://ホスト名:8080/manage)にアクセスしこのユーザでログインし、/acl_users/users で新しいユーザを追加する。

User ID: admtest
Login name: admtest
Password: ****
Confirm password: ****

次に /acl_users/roles で追加したユーザに Manager ロールを与える。最後にデフォルトで作成されていた admin ユーザもパスワードを変更しておく。パスワードが分からなくなった場合は、次のコマンドで臨時ユーザを追加できる。

# bin/instance adduser <username> <password>

Ploneサイトの追加

ZMI(http://ホスト名:8080/manage)にアクセスし全体の管理者でログインする。複数のPloneを追加する場合は、右上のドロップダウンリストより Plone Site を追加する。

Id : web1
Title : WEB1
アドオン : WorkflowPolicySupport

設定ファイルの編集

設定ファイルを変更後は、設定反映後再起動すれば利用できる。

# bin/buildout
# bin/plonectl stop; bin/plonectl start

HTTP起動ポートの設定

Zope インスタンス内の buildout.cfg で設定する。

http-address = 9081

その他

$PLONE_INSTANCE : /usr/local/Plone/zinstance (Plone のインスタンス)

自動起動

起動スクリプトを /etc/init.d/plone として次のように作成し、パーミッションを適宜設定する。

#!/bin/sh
# Startup script for Plone
#
# chkconfig: - 80 20
# description: Zope, a web application server
#
# config: $instance/buildout.cfg
# config: $instance/parts/instance/etc/zope.conf

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

RETVAL=0
plonectl="/usr/local/Plone/zinstance/bin/plonectl"
prog="plone"

start() {
        output=`$plonectl start`
        # the return status of plonectl is not reliable, we need to parse
        # its output via substring match
        if echo $output | grep -q "started"; then
            # success
            action $"Starting $prog:  " /bin/true
            touch /var/lock/subsys/$prog
            RETVAL=0
        else
            # failed
            action $"Starting $prog:  " /bin/false
            RETVAL=1
        fi
        return $RETVAL
}

stop() {
        output=`$plonectl stop`
        # the return status of plonectl is not reliable, we need to parse
        # its output via substring match
        if echo $output | grep -q "stopped"; then
            # success
            action $"Stopping $prog:  " /bin/true
            rm -f /var/lock/subsys/$prog
            RETVAL=0
        else
            # failed
            action $"Stopping $prog:  " /bin/false
            RETVAL=1
        fi
        return $RETVAL
}

restart() {
	stop
	start
}

case "$1" in
  start)
	start
	;;
  stop)
	stop
	;;
  status)
	$plonectl status
	;;
  restart)
	restart
	;;
  condrestart)
	[ -e /var/lock/subsys/$prog ] && restart
	;;
  *)
	echo $"Usage: $0 {start|stop|status|restart|condrestart}"
	RETVAL=1
esac

exit $REVAL

作成後は

/sbin/chkconfig --add plone

でzopeを起動スクリプトとして追加し、

/usr/sbin/ntsysv

で起動時に自動起動されるようにする。以降の起動・停止等は

/sbin/service plone [start | stop | restart | status | condrestart]

で行える。

ログのローテーション

Zope のログは $PLONE_INSTANCE/var/log/ 内に、instance-Z2.log(アクセスログ)、instance.log(エラー情報等)が出力されるがローテーションはされない。そこで logrotate を用いてログのローテーションを行う。/etc/logrotate.d/plone に以下を記述すればよい。

$PLONE_INSTANCE/var/log/instance-Z2.log $PLONE_INSTANCE/var/log/instance.log {
    weekly                 <- 毎週ログローテーション
    rotate 20              <- ローテーション回数
    create 600 plone plone <- パーミッション、ユーザ名、グループ名
    missingok              <- ログファイルが存在しなくてもエラーを出さない
    notifempty             <- ログファイルが空ならローテーションしない
    compress               <- ローテーションされたログをgzipで圧縮
    sharedscripts          <- 複数指定したログファイルに対してpostrotateを実行
    postrotate             <- ログローテーション後に実行するコマンド
        /bin/kill -USR2 $(cat $PLONE_INSTANCE/var/instance.pid)
    endscript
}

ZODB の自動 Pack

ZODB の Pack は Control_Panel/Database/main より行うことができるが、手動で行う必要があるため、これを cron で自動実行するように設定する。これは、wget 等で管理者パスワードを BASIC 認証に渡すこともできるが、管理者パスワードを記述するのにはセキュリティ上好ましくない。そのため、以下のように設定する。

スクリプトの作成

Zope のルートの zope_management_scripts フォルダ内(独自に作成)に、zope_pack という名前のスクリプトを作成する。days パラメータにより、何日前までの undo データを残すかを設定すればよい。

try:
    context.aq_parent.Control_Panel.Database.manage_pack(days=7)
    return 'OK'
except:
    return 'NG'

ZODB の Pack には Manager 権限が必要なので、Proxy タブより Proxy Roles として Manager を選択する。

Proxy Roles : Manager

これにより、このスクリプトにアクセスするユーザが Manager でなくても、スクリプトに書かれた Pack を実行できる。

セキュリティの設定

この状態では、ログインしなくても実行できるため、スクリプトの Security タブよりセキュリティ設定を次のように設定し、Manager 権限でのみ実行できるようにする。

Manager : Change Python Scripts のみOFF, 他全てON
その他Acquire?を含め : 全てOFF

Change Python Scripts を OFF にすることで、Manager でもこのスクリプトの変更を禁止する。変更が必要な場合は、改めてこのパーミッションを ON とすればよい。これは、Proxy Roles の設定で Manager を設定しているため、スクリプトの改ざんにより悪用されることを防ぐためである。

ユーザの作成

Zope のルートの acl_users/users で Anonymous として update 用のユーザを設定する。Anonymous とするには、このユーザに acl_users/roles でどのロールも与えなければよい。このユーザを用いることで、たとえこのパスワードが漏れたとしても Zope の設定変更等は行えない。

ユーザ名 : zope_conf_user

ローカルロールの設定

さらに、スクリプトの Security タブより、上記ユーザに local role として、Manager 権限を与える。

User  : zope_conf_user
Roles : Manager

このようにすることで、このユーザは、Pack の実行を除き何もできない。

自動実行

最後に root の cron で wget 等を動かし、スクリプトにアクセスして Pack を実行させればよい。

15 2 * * 0 wget --no-proxy --http-user="zope_conf_user" --http-passwd="XXX"
   --delete-after http://localhost:9380/zope_management_scripts/zope_pack

 

PloneとApacheの連携

Apache のバーチャルホスト経由で Plone にアクセスする仕組みを構築する。

Web サイトのホスト : www.example.ac.jp
Plone のホスト : 192.168.2.2

モジュールの追加

mod_rewrite と mod_proxy が必要なので、読み込む設定を追加する。
/etc/httpd/conf/httpd.conf (抜粋)

LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

rewriteの設定

http でのアクセスを Apache でプロクシする場合は /etc/httpd/conf/httpd.conf の適当な場所(VirtualHost ディレクティブ内等)に、Zope の VirtualHostMonster が理解できる形で記述する。

RewriteEngine On
RewriteRule ^/XXX[/]?(.*) http://192.168.2.2:8080/VirtualHostBase/http/www.example.ac.jp:80/YYY/VirtualHostRoot/_vh_XXX/$1 [P]

この例は Plone サイトに直接アクセス(http://192.168.2.2:8080/YYY)するかわりに、Apache 経由(http://www.example.ac.jp/XXX)でアクセスできるように書き換えを行った例である。

同様に、https でのアクセスを Apache でプロクシする場合は /etc/httpd/conf.d/ssl.conf の適当な場所(VirtualHost ディレクティブ内等)に、設定を記述する。

RewriteEngine On
RewriteRule ^/XXX[/]?(.*) http://192.168.2.2:8080/VirtualHostBase/https/www.example.ac.jp:443/YYY/VirtualHostRoot/_vh_XXX/$1 [P]

この例では、Plone サイトに直接アクセス(http://192.168.2.2:8080/YYY)するかわりに、Apache 経由(https://www.example.ac.jp/XXX)でアクセスできるように書き換えが行われる。ただし、Web サイトと Plone サイト間の通信は暗号されない。

さらにログイン時のみSSL接続とするには、最終的に次のように設定すれば良い。

  • http.conf
<VirtualHost www.example.ac.jp:80>
ServerName www.example.ac.jp:80
(中略)

RewriteEngine On

# 各種ログインURL
RewriteRule ^/(.*login_form$|.*require_login$) https://%{HTTP_HOST}/$1 [R]

# Ploneの表示
RewriteRule ^/(.*) http://192.168.2.2:8080/VirtualHostBase/http/%{HTTP_HOST}:80/YYY/VirtualHostRoot/_vh_/$1 [P]
</VirtualHost>
  • ssl.conf
<VirtualHost www.example.ac.jp:443>
ServerName www.example.ac.jp:443
(中略)

RewriteEngine On

# ログアウト
RewriteCond %{HTTP_REFERER} https://(www.example.ac.jp.*)
RewriteRule ^/.*logged_out http://%1 [R]

# Ploneの表示
RewriteRule ^/(.*) http://192.168.2.2:8080/VirtualHostBase/https/%{HTTP_HOST}:443/YYY/VirtualHostRoot/_vh_/$1 [P]
</VirtualHost>