NameVirtualHost
ถึงว่าทำไม่ได้สักที
NameVirtualHost
ถึงว่าทำไม่ได้สักที
เวลาเอา web app ที่เขียนด้วย cakephp ไปใส่ใน userdir เช่น /home/veer/public_html/myapp (ซึ่งมักจะไปตรงกับ url http://hostname/~veer/myapp) มักจะมีปัญหากับ mod_rewrite ขึ้นมา แต่ก็แก้ไม่ยาก เพียงแต่แก้ .htaccess ใน myapp กับ myapp/app/webroot
เดิมทีจะเขียนไว้ประมาณนี้ (ใน myapp กับ myapp/app/webroot ไม่เหมือนกัน แต่ก็แก้เหมือนกัน)
RewriteEngine on RewriteRule ^$ app/webroot/ [L] RewriteRule (.*) app/webroot/$1 [L]
ก็แก้โดยใส่ RewriteBase เข้าไปเป็นแบบนี้
RewriteEngine on RewriteBase /~veer/myapp RewriteRule ^$ app/webroot/ [L] RewriteRule (.*) app/webroot/$1 [L]
เสร็จแล้ว
I try to install my application created on Pylons on the Debian server that has already Apache2 + mod_wsgi + virtualenv + userdir.
What I did:
import os
import site
os.environ['PYTHON_EGG_CACHE'] = "/home/myhome/egg"
site.addsitedir("/home/myhome/wsgiapp/basa2")
site.addsitedir("/home/myhome/pyenv/PYLONS-1/lib/python2.5/site-packages")
from paste.deploy import loadapp
APP_CONFIG = "/home/myhome/wsgiapp/basa2/prod.ini"
application = loadapp("config:" + APP_CONFIG)
del environ['pylons.pylons']
following this changeset. (I use Pylons 0.9.7rc3)
The procedures above are just conclusion. I did a lot of trial and error. I also restart Apache web server (I must not have to do). By the ways, it works now.
xmlrpc ด้วย python บน apache ผ่าน mod_wsgi. ใช้ xmlrpc บน python เขียนง่ายมากเลย ทั้ง client และ server ดูตัวอย่างจาก http://docs.python.org/library/simplexmlrpcserver.html ได้
แต่ว่า simple server นี้เป็น standalone server แล้วผมก็เจอปัญหาอีกว่า พอเรียกใช้จากเครื่องอื่น ที่ไม่ใช่เครื่องเดียวกันแล้วมั้นช้าๆ ชอบกล เลยเปลี่ยนไปใช้ wsgi-xmlrpc แทน มีคนเขียนไว้ให้แล้วด้วยดีจัง ^_^.
ทีแรกผมก็ลงโปรแกรมจาก easy_install เลย ใช้ easy_install wsgi_xmlrpc อะไรทำนองนี้ก็ลงได้ แต่เล่นไปเล่นมาเจอปัญหาภาษาไทย ก็เลยเอา source code จาก svn trunk ที่ google code มาใช้แทน ถึงตอนนี้ก็ยังใช้ได้ดีอยู่. (วิธีใช้ mod_wsgi กับ userdir เข้าไปดูที่ http://blog.vee-u.com/2008/06/18/mod_wsgi_userdir_ubuntu/ ได้
และ http://blog.vee-u.com/tag/wsgi/ ได้)
เพื่อที่ผมจะได้เอาไว้ดูเองในภายหลังด้วยจึงต้อง post ตัวอย่างสักหน่อย สมมุติ เขียน client แบบนี้
# -*- coding: UTF-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
from xmlrpclib import ServerProxy
server = ServerProxy("http://localhost/test_service.wsgi", encoding="UTF-8")
print server.test_func("ดีจ๊ะ")
พอโปรแกรมทำงานแล้วได้ผลแบบนี้
ดีจ๊ะ ^_^
เวลาเขียน server ก็เขียนประมาณนี้ใน test_service.wsgi
import site
import os
os.environ['PYTHON_EGG_CACHE'] = "/somewhere/egg"
site.addsitedir("/home/vee/pyenv/WSGI-1/lib/python2.5/site-packages")
from wsgiref import simple_server
import wsgi_xmlrpc
def test_func(txt):
return txt + " ^_^"
application = wsgi_xmlrpc.WSGIXMLRPCApplication(methods=[test_func])
^_^
ในเครื่องแม่ข่ายเครื่องหนึ่งอาจจะเป็นไปได้ว่ามีคนใช้ Pylons, Django, Turbogears แถมยังอาจจะใช้ package ของ Python ที่แตกต่างๆ กัน. ถ้าลงทุก package ที่ทุกคนต้องการไว้ในส่วนกลางหมดก็เป็นไปได้ว่าอาจจะมีบาง package ขัดแย้งกัน โดยเฉพาะโปรแกรมเดียวกันที่ต่าง version กัน. มากไปกว่านั้นก็อาจจะต้องกวนให้ sys admin ช่วย install ให้บ่อยๆ ด้วย หรือจะให้ทุกคนลง package ในส่วนกลางได้เองหมด ก็อาจจะกระทบกับเสถียรภาพโดยรวมของระบบ. อย่ากระนั้นเลยใช้ virtualenv มาแยก Python environment ของแต่ละคนเลยดีกว่า.
ผมก็เลยลองลง virtualenv ใช้กับ Apache + mod_wsgi + mod_userdir บน Ubuntu 8.04 บนเครื่องส่วนตัวของผมเองดู. ใน entry นี้ผมสมมุติว่าใช้ Apache + mod_wsgi + mod_userdir ได้อยู่แล้วนะครับ (และ มี setuptools ไว้แล้ว) แต่ถ้าสนใจเรื่องการติดตั้งระบบที่ใช้ mod_wsgi ผมก็เขียนเก็บไว้บ้างเหมือนกันที http://blog.vee-u.com/tag/mod_wsgi/
ลง virtualenv ง่ายมากเพียงสั่ง
$ sudo easy_install virtualenv
ก็เสร็จแล้ว
จากนั้นก็สร้าง directory ไว้ลง package ส่วนตัว โดยสั่ง
$ mkdir $HOME/pyenv
จากนั้นก็เข้าไปจัดการสร้าง enviroment โดย
$ cd $HOME/pyenv
$ virtualenv –no-site-packages BASELINE
แล้วก็สร้าง environment สำหรับลง Pylons
$ virtualenv –no-site-packages PYLONS-1
ก่อนลง Pylons ก็ activate environment นั้นก่อน
$ source PYLONS-1/bin/activate
พอ activate แล้ว prompt จะเปลี่นนเป็น (PYLONS-1)$
จากนั้นก็ลง Pylons 0.9.7 (รุ่นทดลอง), SQLAlchemy 0.4.8 และ PasteDeploy (ไม่ต้อง sudo ด้วย)
(PYLONS-1)$ easy install pylons==0.9.7rc2
(PYLONS-1)$ easy install sqlalchemy==0.4.8
(PYLONS-1)$ easy install PasteDeploy
แล้วก็ไฟล์สำหรับเรียก Pylons จาก wsgi ประมาณนี้
APP_CONFIG = "/home/veer/Develop/pylons/ex1/production.ini" import os os.environ['PYTHON_EGG_CACHE'] = "/home/veer/egg" import sys # บอกให้ python ไปหา package ที่ที่เราเตรียมไว้ sys.path = [] sys.path.append("/home/veer/pyenv/BASELINE/lib/python2.5/site-packages") sys.path.append("/home/veer/pyenv/PYLONS-1/lib/python2.5/site-packages") sys.path.append("/home/veer/Develop/pylons/ex1") from paste.deploy import loadapp application = loadapp("config:" + APP_CONFIG)
อะไรที่เขียน /home/veer ต่างๆ นี้คือสิ่งที่ใช้ในเครื่องผม เครื่องอื่นๆ ก็คงใช้ต่างๆ กันไป
เท่านี้เว็บของแต่ละคนก็มี environment ของตัวเองแล้ว อย่างในกรณีนี้ package ต่างๆ ก็มาอยู่ใน $HOME ของแต่ละ user แทนที่จะไปอยู่รวมๆ กันใน /usr/lib ผู้ใช้แต่ละคนก็แก้ได้ สะดวกสบาย
อ้างอิง http://code.google.com/p/modwsgi/wiki/VirtualEnvironments
ต่อจาก ติดตั้ง Django ก็ต่อด้วย Pylons. ก่อนหน้าจะพยายามลง Pylons ผมก็ลองพวก WSGIDaemonProcess ไปแล้ว แต่ว่าไม่สำเร็จก็เลยข้ามๆ ไป. ใช้ user เป็น www-data ก็ได้
.
Pylons ก็มา pattern เดิมๆ ที่อ่านมาจาก http://code.google.com/p/modwsgi/wiki/IntegrationWithPylons เริ่มด้วยสร้าง pylons.wsgi ใน /home/veer/public_html/wsgi-scripts ตามนี้
APP_CONFIG = "/home/veer/Develop/pylons/mydb4/production.ini"
import os
os.environ['PYTHON_EGG_CACHE'] = "/home/veer/egg"
import sys
sys.path.append("/home/veer/Develop/pylons/mydb4")
from paste.deploy import loadapp
application = loadapp("config:" + APP_CONFIG)
แล้วก็สร้าง /home/veer/egg เปลี่ยน permission ( mkdir /home/veer/egg; chmod 777 /home/veer/egg )
แล้วก็แก้สร้าง production.ini โดยการ copy มาจาก development.ini แล้วก็แก้ให้
full_stack = false
และ
debug = false
เท่านี้ก็น่าจะพอใช้ได้แล้ว
ลืมไปผมสร้าง app ไว้ใน /home/veer/Develop/mydb4 นะครับ พวก development.ini ก็อยู่ในนี้ล่ะ
อาจจะดูคลั่งๆ หน่อยแต่ mod_wsgi + userdir + Turbogears ก็ใช้ได้แล้ว. ด้วยพื้นฐานจากการใช้ mod_wsgi+userdir , การใช้ mod_wsgi กับ Turbogears และ การใช้ mod_wsgi กับ Turbogears แบบ non-root-mount. ก็แทบจะไม่ต้องทำอะไรแล้ว
.
แค่ copy ไฟล์ tg.wsgi ที่เคยอยู่ใน /home/veer/tg/tgapp/apache ไปไว้ใน /home/veer/public_html/wsgi-scripts/ แล้วก็แก้ prod.cfg ใน /home/veer/tg/tgapp นิดหน่อยที่ server.webpath ให้เปลี่ยนเป็น server.webpath=”/~veer/wsgi-scripts/tg.wsgi” เท่านี้ก็ใช้ซะงั้น.
สำหรับ Turbogears แล้วสำคัญมาที่ต้องใช้ tg.url เวลาเขียน URL ไม่ใส่ URL เอาเองตรงๆ (แบบที่ผมเคยทำ) … ไม่งั้นเวลามา deploy แบบนี้ก็แก้กันอ้วก
.
วิธีทำจริงๆ ก็อ่านจาก http://www.lucasmanual.com/mywiki/TurboGears#head-57ee578707aa057229eb1171a8e4aeb553bd6d3a มาเกือบหมด. แต่ว่าเขียนเสียหน่อยเพื่อความต่อเนื่องจากที่เขียนไว้เดิม. เริ่มจากแก้ /home/veer/tg/tgapp/apache/tg.wsgi:
import sys
sys.path.append('/home/veer/tg/tgapp')
sys.stdout = sys.stderr
import os
os.environ['PYTHON_EGG_CACHE'] = '/home/veer/tg/python-eggs'
import atexit
import cherrypy
import cherrypy._cpwsgi
import turbogears
# ข้างล่างเปลี่ยนไปใช้ fullpath แทนที่จะเขียน prod.cfg หรือ dev.cfg เฉยๆ
turbogears.update_config(configfile="/home/veer/tg/tgapp/prod.cfg", modulename="tgapp.config")
turbogears.config.update({'global': {'server.environment': 'production'}})
turbogears.config.update({'global': {'autoreload.on': False}})
turbogears.config.update({'global': {'server.log_to_screen': False}})
import tgapp.controllers
cherrypy.root = tgapp.controllers.Root()
if cherrypy.server.state == 0:
atexit.register(cherrypy.server.stop)
cherrypy.server.start(init_only=True, server_class=None)
application = cherrypy._cpwsgi.wsgiApp
จริงๆ แล้วก็แก้บรรทัดเดียว
… แต่ตอนลองทำงงเหมือนกัน
แล้วก็ไปสร้าง server.log ใน /home/veer/tg/tgapp/server.log อันนี้มีก็ทำแบบชั่วคราวๆ
(อีกแล้ว)
(อยู่ใน /home/veer/tg/tgapp) touch server.log chmod 777 server.log
ตามด้วยแก้ /home/veer/tg/tgapp/prod.cfg ทีแรกมันไม่มีให้แก้ก็เลยต้อง copy sample-prod.cfg มา
เพิ่ม server.webpath=”/first” เข้าไป (จริงมี # server.webpath=”" อยู่แล้ว ก็แค่เอา shape ออกแล้วใส่ /first ลงไป) แก้ path ของ server.log แบบนี้ args=”(‘/home/veer/tg/tgapp/server.log’,)” จากที่เดิมเขียนไว้ว่า args=”(‘server.log’,)”
ตามด้วยแก้ /etc/apache2/mod-enabled/mod-wsgi.conf เดิมเขียนไว้ว่า
WSGIScriptAlias / /home/veer/tg/tgapp/apache/tg.wsgi
ก็แก้เป็น
WSGIScriptAlias /first /home/veer/tg/tgapp/apache/tg.wsgi
เพื่อเปลี่ยนที่ mount
แล้วก็ restart apache ( /etc/init.d/apache restart ) จากนั้นพอเข้าไปดูใน localhost/first ก็ได้ผลตามต้องการ
… ต่อไปก็เป็น userdir T_T (เหมือนหา doc ไม่ค่อยเจอด้วย
)
ผมอ่านเรื่องเปิดเทียบ web app tech ต่างๆ มา. เห้น mod_wsgi น่าสนใจดีก็เลยจะลองเล่นบ้าง (เอาแบบให้ใช้ได้หลายๆ user ด้วย น่าจะเหมาะกับ lab ดี) ก็เริ่มจากไปอ่าน http://code.google.com/p/modwsgi/wiki/ConfigurationGuidelines
แต่ก่อนจะทำตามตำรา ผมก็ลง mod_wsgi ก่อนเลย
sudo aptitude install libapache2-mod-wsgi
ตามด้วย enable มันซะ
sudo a2enmod mod-wsgi
แปลกนะมีคำว่า mod ติดมาด้วย หาตั้งนาน
ปกติเวลาจะใช้ mod_userdir ก็แค่
sudo a2enmod userdir
(ไม่ใช่เหรอ? …. รวมถึง mod_rewrite และอื่นๆ ด้วย)
ด้วยความพิเศษของ Ubuntu/Debian นิดหน่อยๆ ไฟล์ที่ผมเข้าไปแก้คือ /etc/apache2/mods-enabled/userdir.conf ก็ดัดแปลงตามตัวอย่างอะนะแก้แล้วเป็นแบบนี้
<IfModule mod_userdir.c>
UserDir public_html
UserDir disabled root
<Directory /home/*/public_html/>
AllowOverride FileInfo AuthConfig Limit
Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
</Directory>
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/~([^/]+)
RewriteRule . - [E=APPLICATION_GROUP:~%1]
<Directory /home/*/public_html/wsgi-scripts/>
Options ExecCGI
SetHandler wsgi-script
WSGIApplicationGroup %{ENV:APPLICATION_GROUP}
</Directory>
</IfModule>
เสร็จแล้วผมก็เข้าไปสร้าง folder ที่ /home/veer/public_html/wsgi-scripts พร้องเปลี่ยน permission เป็น 755 ตามด้วยเอา myapp.wsgi ตามตัวอย่างไปวางในนั้น
def application(environ, start_response):
status = '200 OK'
output = 'Hello World!'
response_headers = [('Content-type', 'text/plain'),
('Content-Length', str(len(output)))]
start_response(status, response_headers)
return [output]
จากนั้นก็ไปที่ web browser เรียก http://127.0.0.1/~vee/wsgi-scripts/myapp.wsgi (ตามรูป)
ขั้นตอนถัดไปก็จะลองลง Pylons และ Django ดู