Ubuntu 9.10 Server 配置Apache + WebDav 实现文档协同管理

Filed under: Ubuntu | 4 Comments »
Posted on

先来了解一下百度百科关于WebDav(Web-based Distributed Authoring and Versioning)的解释

一种基于 HTTP 1.1协议的通信协议.它扩展了HTTP 1.1,在GET、POST、HEAD等几个HTTP标准方法以外添加了一些新的方法,使应用程序可直接对Web Server直接读写,并支持写文件锁定(Locking)及解锁(Unlock),还可以支持文件的版本控制。

下面来看如何实现文档的协同管理

1安装软件及模块一览

  (1)Apache2.2.14  自己下载编译。未用ubuntu 9.10 server 下apt-get安装的apache2 是因为这个版本的apache2在启用ssl的时候总是报undefined symbol apr_ldap_ssl_init错误,此处我怀疑可能是ubuntu9.10 server的问题,我在虚拟机ubuntu 8.04 desktop下配置成功。

2 加载Dav Module

     在对Apache进行编译时已经开启了dav的设置(具体参见Ubuntu 9.10 Server 配置基于SSL的Subversion,svn需要webdav协议支持)

#sudo ./configure   –enable-dav –enable-dav-fs –enable-so
                    –enable-ssl –enable-maintainer-mode -prefix=/usr/local/apache2
                    –enable-mods-shared=all   

      注意enable-dav和enable-dav-fs是我们文档协同所需要的。我们可以通过    

cd /usr/local/apache2/bin
sudo ./httpd -l

      来查看已加载的Module。另外自主编译的方式无法通过修改httpd.conf,加入

LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so

      来完成,modules文件夹下也没有这两个so文件,启动apache后会报文件已加载,我搞了很长时间才明白这点。

3 配置WebDav

   在httpd.conf文件下 将#Include conf/extra/httpd-dav.conf的注释去掉,我们来看一下httpd-dav.conf的配置

DavLockDB “/usr/local/apache2/var/DavLock”

Alias /uploads “/usr/local/apache2/uploads”

<Directory “/usr/local/apache2/uploads”>
    Dav On
    Options Indexes FollowSymLinks
    Order Allow,Deny
    Allow from all

    AuthType Basic
    AuthName DAV-upload
    Require valid-user
    # You can use the htpasswd program to create the password database:
    #   htpasswd -c “/usr/local/apache2/user.passwd” DAV-upload admin
    AuthUserFile “/svn/authfile”
    <Limit GET OPTIONS PUT POST DELETE PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK>
    </Limit>
</Directory>

注意一定是Allow from all 另外我使用了Basic的验证方法,要求用户验证;这里Subversion和WebDav使用的是同样的用户文件;Options Indexes FollowSymLinks允许我们在浏览器访问时遍历文件。

4 权限

   #cd /usr/local/apache2
   #sudo mkdir uploads
   #sudo chown www-data:www-data uploads
   #sudo chmod 777 uploads
   以上创建上传目录并设置权限为可读可写  www-data为ubuntu的用户和组

   另外可能需要手动创建 DavLockDB
   #cd /usr/local/apache2
   #sudo mkdir var
   #cd var
   #sudo vim DavLock
   #cd ..
   #cd ..
   #sudo chown www-data:www-data uploads
   #sudo chmod -R 777 var/

5 WebDav客户端

  分别使用了XP和Vista自带的web folder

   使用方法,在XP的资源管理器下选择增加网上邻居(Vista为添加一个网络位置)输入http://your ip or sitename/uploads  并输入用户名和密码。然后再word里就可以直接对文件进行增加修改了,而且当一个用户在更改的时候,其他用户只能只读访问。

   webfolder

当一个用户打开某文件,会加一个只读锁,其他的用户打开该文件时提示

conflict

最后附上fiddler抓到的http包,(webdav协议是http协议的扩展,所以可以观察到)

HTTP/1.1 207 Multi-Status
Date: Tue, 01 Jun 2010 08:30:34 GMT
Server: Apache/2.2.14 (Unix) mod_ssl/2.2.14 OpenSSL/0.9.8g DAV/2 SVN/1.6.2
Content-Length: 966
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/xml; charset=”utf-8″

<?xml version=”1.0″ encoding=”utf-8″?>
<D:multistatus xmlns:D=”DAV:”>
<D:response xmlns:lp1=”DAV:” xmlns:lp3=”http://subversion.tigris.org/xmlns/dav/” xmlns:lp2=”http://apache.org/dav/props/”>
<D:href>/uploads/blackjack/Post.doc</D:href>
<D:propstat>
<D:prop>
<lp1:resourcetype/>
<lp1:creationdate>2010-06-01T06:11:10Z</lp1:creationdate>
<lp1:getcontentlength>46080</lp1:getcontentlength>
<lp1:getlastmodified>Tue, 01 Jun 2010 06:11:10 GMT</lp1:getlastmodified>
<lp1:getetag>”23a06-b400-487f1d6fea216″</lp1:getetag>
<lp2:executable>F</lp2:executable>
<D:supportedlock>
<D:lockentry>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope><D:shared/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
</D:supportedlock>
<D:lockdiscovery/>
<D:getcontenttype>application/msword</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>

javascript事件机制与jQuery.bind的补充说明

Filed under: javascript+css | 5 Comments »
Posted on

在之前的文章javascript 事件机制 与 jQuery.Bind中,为了说明冒泡阶段中Event Handler Function的表现,我使用了event.data来记录触发function的次数。并且提出了一个问题,就是在jQuery.bind方式中,event.data无法正确记录触发的次数。后来经过测试和查阅网上的相关的资料,得出了一个结论,就是我之前关于event.data的使用方式是错误的,或者说对于跨浏览器的支持是困难的。同时我也意识到,由于event.data在w3c dom level 2文档中,并不是作为event的标准属性出现的,所以jQuery对event进行了fix,使其能够兼容各个浏览器。

在我纠正误用event.data的方式之前,再描述一下我对event的理解。在我查看jQuery(1.3.2)源代码的时候,jQuery.event的add方法中有如下代码

// Init the element's event structure
var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
    handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function() {
         // Handle the second event of a trigger and when
         // an event is called after a page has unloaded
         return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
                jQuery.event.handle.apply(arguments.callee.elem, arguments) :
                undefined;
        });

其中的jQuery.event.handle中进行event的fix

event = arguments[0] = jQuery.event.fix(event || window.event);

这里按照网上的资料大多是说ie下使用window.event,而firefox下使用arguments[0]也就是传递过来的函数参数event。可我在测试中发现ie6,ie7(未测试),ie8在fix之前event并不为空,也就是说在fix的时候并没有使用window.event。

看一下这段代码

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"    />
<title></title>
<style>
     #panelGrandPa,#panelPaPa,#panelSon  { border:1px  solid #320213;}
 </style>
</head>
 <body>
<div id="panelGrandPa" style="width:300px;height:200px;" >
       <div id="panelPaPa" style="width:200px;height:100px;" >
            <div id="panelSon" style="width:100px;height:50px;" >

            </div>
       </div>
</div>
<script>
    function click() {
        alert(event.srcElement.id);
        event.data = event.data || 1;
        alert("click function has fired  " + event.data + " times");
        event.data = parseInt(event.data) + 1;
    }
    function clickSon() {
        alert("I am son");
        click();
    }
    function clickGrandPa() {
        alert("I am GrandPa");
        click();
    }
    document.getElementById("panelGrandPa").onclick = clickGrandPa;
    document.getElementById("panelSon").onclick = clickSon;
</script>
</body>
</html>

只能在ie8下正常工作,在ie6和ie7下都报event.data undefined错误。当然我们这里使用的是window.event也就是页面维护的event相当于全局变量,那我们再试一下事件方法的event参数(之前阅读jQuery源代码提到的ie中除却window.event另外的event)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"    />
<title></title>
<style>
     #panelGrandPa,#panelPaPa,#panelSon  { border:1px  solid #320213;}
 </style>
</head>
 <body>
<div id="panelGrandPa" style="width:300px;height:200px;" >
       <div id="panelPaPa" style="width:200px;height:100px;" >
            <div id="panelSon" style="width:100px;height:50px;" >

            </div>
       </div>
</div>
<script>
    function click(e) {
        alert(event.srcElement.id);
        e.data = e.data || 1;
        alert("click function has fired  " + e.data + " times");
        e.data = parseInt(e.data) + 1;
    }
    function clickSon() {
        alert("I am son");
        click(arguments[0]);
    }
    function clickGrandPa() {
        alert("I am GrandPa");
        click(arguments[0]);
    }
    document.getElementById("panelGrandPa").attachEvent("onclick", clickGrandPa);
    document.getElementById("panelSon").attachEvent("onclick", clickSon);
</script>
</body>
</html>

注意必须用attachEvent我们才能得到区别于window.event的“另一个”event。以上代码在ie8下正常工作,在ie6和ie7下event.data始终为1

对于window.event,在ie6和ie7下,通过调试工具发现其中并没有event.data的属性。而attachEvent的得到的event.data 在ie6和ie7下不能正确计数,始终为1,但ie8下正确。

鉴于event在各浏览器下的差异以及我们对书写跨浏览器脚本的良好愿望,我个人认为不应该在多个事件方法中传递event.data。

当然jQuery在这方面做得更好经过fix后的event 使得event.data在各种浏览器下表现一致

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"    />
 <script type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.js"></script>
<title></title>
<style>
     #panelGrandPa,#panelPaPa,#panelSon  { border:1px  solid #320213;}
 </style>
<head>
<body>
<div id="panelGrandPa" style="width:300px;height:200px;" >
       <div id="panelPaPa" style="width:200px;height:100px;" >
            <div id="panelSon" style="width:100px;height:50px;" >

            </div>
       </div>
</div>
<script>
    function click(e) {
        alert(e.target.id);
        e.data = e.data || 1;
        alert("click function has fired  " + e.data + " times");
        e.data = parseInt(e.data) + 1;
    }
    function clickSon(e) {
        alert("I am son");
        click(e);
    }
    function clickGrandPa(e) {
        alert("I am GrandPa");
        click(e);
    }
    $("#panelGrandPa").bind("click", clickGrandPa);
    $("#panelSon").bind("click", clickSon);
</script>
</body>
</html>

上述代码在任何浏览器下都不能正常计数,显示event.data为1(这下ie8也不行了)。

我们分析一下原因,这也是我对上一篇提出问题的一个回答

jQuery.event.add方法封装了attachEvent/addEventListener并且给每一个handler方法附加了data

add:function(elem, types, handler, data) {
    //省略部分代码
    // if data is passed, bind to handler
    if (data !== undefined) {
        // Create temporary function pointer to original handler
        var fn = handler;

        // Create unique handler function, wrapped around original handler
        handler = this.proxy(fn);

        // Store data in unique handler
        handler.data = data;
    }
    //省略部分代码
}

在jQuery.event的fix方法中,我们看到其将传入的event复制了一份(包括data),注意不是引用(这意味着每次方法的event都是不同的)

fix: function(event) {
    if (event[expando])
        return event;

    // store a copy of the original event object
    // and "clone" to set read-only properties
    var originalEvent = event;
    event = jQuery.Event(originalEvent);

    for (var i = this.props.length, prop; i; ) {
        prop = this.props[--i];
        event[prop] = originalEvent[prop];
    }
    //以下省略
}

那么这样一来,我们肯定不能在多个事件方法中用上述方法传递data了。

javascript 事件机制 与 jQuery.Bind

Filed under: javascript+css | 3 Comments »
Posted on

image_1

W3C DOM Level2的事件模型规范中,事件在DOM树中的传播过程(从根节点到目标节点)被分为了两个阶段:捕捉(Capture)和冒泡(Bubbling),而事件在传递的过程中需要先经历Capture Phrase后经历Bubble Phrase 。在firefox下,我们可以用target.addEventListener(type, listener, useCapture),第三个参数指定是否为Capture;但IE不支持捕获,而且jQuery也不支持Capture(不过我觉得Bubbling足够了)。因此后面的讨论主要在Bubbling阶段。首先看一下IE下实现事件模型的代码。

请在IE8下运行以下代码(只能在ie8下运行)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"    />
<title></title>
<style>
     #panelGrandPa,#panelPaPa,#panelSon  { border:1px  solid #320213;}
 </style>
</head>
 <body>
<div id="panelGrandPa" style="width:300px;height:200px;" >
       <div id="panelPaPa" style="width:200px;height:100px;" >
            <div id="panelSon" style="width:100px;height:50px;" >

            </div>
       </div>
</div>
<script>
    function click() {
        alert(event.srcElement.id);
        event.data = event.data || 1;
        alert("click function has fired  " + event.data + " times");
        event.data = parseInt(event.data) + 1;
    }
    function clickSon() {
        alert("I am son");
        click();
    }
    function clickGrandPa() {
        alert("I am GrandPa");
        click();
    }
    document.getElementById("panelGrandPa").onclick = clickGrandPa;
    document.getElementById("panelSon").onclick = clickSon;
</script>
</body>
</html>

注意传统element.onclick或者element['on'+eventName],这个是所有浏览器都支持的事件绑定的Event Listener,但由于上述代码使用了event.srcElement.id,因此只能在IE8下运行。下面看一下在firefox下的使用,这里我们采用了符合W3C DOM的target.addEventListener(type, listener, useCapture),另外使用了event.target.id。
请在firefox,chrome下运行以下代码

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"    />
<title></title>
<style>
     #panelGrandPa,#panelPaPa,#panelSon  { border:1px  solid #320213;}
 </style>
<head>
<body>
<div id="panelGrandPa" style="width:300px;height:200px;" >
       <div id="panelPaPa" style="width:200px;height:100px;" >
            <div id="panelSon" style="width:100px;height:50px;" >

            </div>
       </div>
</div>
<script>
    function click(e) {
        alert(e.target.id);
        e.data = e.data || 1;
        alert("click function has fired  " + e.data + " times");
        e.data = parseInt(e.data) + 1;
    }
    function clickSon(e) {
        alert("I am son");
        click(e);
    }
    function clickGrandPa(e) {
        alert("I am GrandPa");
        click(e);
    }
    document.getElementById("panelGrandPa").addEventListener("click", clickGrandPa, false);
    document.getElementById("panelSon").addEventListener("click", clickSon, false);
</script>
</body>
</html>

那么在jQuery中我们是怎么处理的呢

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"    />
 <script type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.js"></script>
<title></title>
<style>
     #panelGrandPa,#panelPaPa,#panelSon  { border:1px  solid #320213;}
 </style>
<head>
<body>
<div id="panelGrandPa" style="width:300px;height:200px;" >
       <div id="panelPaPa" style="width:200px;height:100px;" >
            <div id="panelSon" style="width:100px;height:50px;" >

            </div>
       </div>
</div>
<script>
    function click(e) {
        alert(e.target.id);
        e.data = e.data || 1;
        alert("click function has fired  " + e.data + " times");
        e.data = parseInt(e.data) + 1;
    }
    function clickSon(e) {
        alert("I am son");
        click(e);
    }
    function clickGrandPa(e) {
        alert("I am GrandPa");
        click(e);
    }
    $("#panelGrandPa").bind("click", clickGrandPa);
    $("#panelSon").bind("click", clickSon);
</script>
</body>
</html>

这里使用了e.target,不过和之前的非jQuery版本不同,此处的e(event)是调用了jQuery.event.fix(event),也就是说jQuery的处理让event更加透明。不过这段代码的运行还是有问题的,就是click function的fire time 始终为1,也就是说e.data的值无法在多个事件函数里传递,这个我暂时还没有找到原因;不过希望通过进一步探究jQuery源代码找到问题原因及解决思路,本文旨在说明javascript 事件机制 与 jQuery.Bind的简单用法,就此搁笔了,关于前面抛出的问题,也请各位不吝赐教。

Ubuntu 9.10 Server 配置基于SSL的Subversion

Filed under: Ubuntu | 5 Comments »
Posted on

1 配置准备

  Ubuntu 9.10 Server 英文版。服务器版还是以稳定高效为主,也没有安装图形界面,另外主要是通过putty.exe远程访问。没有采用中文版的原因是,在shell下,中文字体可能没有安装总显示乱码,拜过谷哥大神,未解决。

2 安装软件及模块一览

  (1)Apache2.2.14  自己下载编译。未用ubuntu 9.10 server 下apt-get安装的apache2 是因为这个版本的apache2在启用ssl的时候总是报undefined symbol apr_ldap_ssl_init错误,此处我怀疑可能是ubuntu9.10 server的问题,我在虚拟机ubuntu 8.04 desktop下配置成功。

  (2)OpenSSL 通过apt-get install openssl 安装即可

  (3)Subversion 自己编译下载。很不幸,我无法使用ubuntu的subversion来成功配置SSL。

3 Ubuntu & Linux  

鉴于大家可能对不同发行版的linux不太了解,我简单介绍一下,并比较apache2的Ubuntu版本和自主安装的安装及配置文件路径

   以下摘自Wiki

     One can distinguish between commercially backed distributions, such as Fedora (Red Hat), openSUSE (Novell), Ubuntu (Canonical Ltd.), and Mandriva Linux (Mandriva) and entirely community-driven distributions such as Debian and Gentoo, though there are other distributions that are driven neither by a corporation nor a community, perhaps most famously Slackware.

简单翻译一下,就是说linux有商业支持的发行版如Fedora,openSUSE,Ubuntu和社区推动的版本如Debian和Gentoo。另外Ubuntu本身又是基于Debian的,这点大家应该清楚。

   

  Ubuntu Apache2 自主安装Apache2
安装目录 /etc/apache2 指定路径
例如:
/usr/local/apache2
应用程序 /etc/sbin/apache2
/etc/lib/apache2
/usr/local/apache2/bin/httpd
服务 /etc/init.d/apache2  restart /usr/local/apache2/bin/httpd –k restart 
(不知还有没有别的方式?)
配置文件 /etc/apache2/apache2.conf
/etc/apache2/httpd.conf (通常为空)
/etc/apache2/ports.conf
/etc/apache2/mods_available/
/etc/apache2/sites_available/
apache2.conf负责调用其他的配置文件
/usr/local/apache2/conf/httpd.conf
/usr/local/apache2/conf/extra/
httpd.conf负责调用extra文件夹下的配置文件

4 自主安装Apache2

#sudo wget http://apache.etoak.com/httpd/httpd-2.2.14.tar.gz
#sudo tar -zxvf httpd-2.2.14.tar.gz    
#cd httpd-2.2.14               
#sudo ./configure   –enable-dav –enable-dav-fs –enable-so   –enable-ssl –enable-maintainer-mode -prefix=/usr/local/apache2   –enable-mods-shared=all   
#sudo make                         
#sudo make install

   注意./configure 时确保enable-dav和enable-ssl,其中dav模块是通过apache2存储文件的基础。
5 安装OpenSSL

#sudo apt-get install openssl

6 安装Subversion

# sudo apt-get install build-essential openssl ssh expat libxyssl-dev libssl-dev   
# sudo apt-get remove subversion   
# sudo dpkg –purge subversion   
# wget http://subversion.tigris.org/downloads/subversion-1.6.2.tar.gz
# wget http://subversion.tigris.org/downloads/subversion-deps-1.6.2.tar.gz
# tar xvfz subversion-1.6.2.tar.gz   
# tar xvfz subversion-deps-1.6.2.tar.gz   
# cd subversion-1.6.2/neon/   
# ./configure –prefix=/usr/local –with-ssl –with-pic  
# make   
# sudo make install      
# ./configure –prefix=/usr/local –with-ssl –with-neon=/usr/local   
# make   
# sudo make install  

  注意:首先移除ubuntu自带的subversion,随后进行编译安装。其中subversion-deps-1.6.2.tar.gz是Subversion客户端使用的Neon库,它不仅仅可以用来验证服务器证书,也可以必要时提供客户端证书,因此也要安装上

7 配置http访问subversion

  参考了主题:ubuntu下安装svn提供HTTP版本管理服务Install Subversion with Web Access on Ubuntu

(1)#sudo svnadmin create /svn  

   可以看一下/svn下是不是增加了些文件 
(2)#sudo vim /usr/local/apache2/conf/httpd.conf

   增加 
   <Location /svn>
     DAV svn
     SVNPath /svn
     AuthzSVNAccessFile /svn/conf/authz
     AuthType Basic
     AuthName "Subversion.Tracker"
     AuthUserFile /svn/conf/passwd     Require valid-user
   </Location>

    这部分应该也可以放置到 conf/extra/httpd_dav.conf文件中,然后将httpd.conf中的 include conf/extra/httpd_dav.conf 注释去掉,不过奇怪的是httpd_dav.conf文件中的示例使用<Directory>而不是<Location>,我未作尝试。

(3)#sudo htpasswd -cm /svn/conf/passwd <username>
   增加一个用户名,可以打开passwd文件查看是否创建成功
   同时在Ubuntu上创建同名用户和相同密码  (此处待验证,网络上有的文章没有强调这一点
   sudo useradd <username>
   sudo passwd <password>

(4)#sudo chown www-data:www-data  -R /svn 

    将/svn的所有者和所在的组更改为www-data(ubuntu下apache2的账户)

    #sudo chmod –R g+ws /svn

(5)#sudo /usr/local/apache2/bin/httpd –k restart

    看看http://localhost/svn 是否可以访问了

8 配置ssl访问subversion

  参考了Linux SVN+Apache+SSL 安装配置Apache SSL配置

openssl genrsa -des3 -out ca.key 1024
//按提示输入密码:****
chmod 400 ca.key
//生成证书
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt
//按提示分别输入如下内容:
//Country Name: CN
//State or Province Name:
//Locality Name:
//Organization Name:
//Organizational Unit Name:
//Common Name:
//Email Address: your email
chmod 400 ca.crt
openssl genrsa -des3 -out server.key 1024
//按提示输入密码:
chmod 400 server.key
openssl req -new -key server.key -out server.csr
//按提示分别输入如下内容:
//Country Name: CN
//State or Province Name:
//Locality Name:
//Organization Name:
//Organizational Unit Name:
//Common Name:
//Email Address: your email
(ca.crt 和server.csr 的Common Name不能一样)
openssl req -noout -text -in server.csr
openssl x509 -req -days 365 -in server.csr -signkey server.key -out  server.crt
chmod 400 server.crt

vim /usr/local/apache2/conf/httpd.conf
取消Include conf/extra/httpd-ssl.conf前的注释#

打开httpd-ssl.conf文件查看如下两行,确保前面生成的证书放置在该路径下

SSLCertificateFile "/usr/local/apache2/conf/server.crt"

SSLCertificateKeyFile "/usr/local/apache2/conf/server.key"

重启httpd服务

查看https://localhost/svn/  浏览器显示此网站的安全证书有问题,忽略它,输入用户名和密码,至此基于SSL的Subversion配置完成。

9 总结

  配置过程中应该了解ubuntu和其他linux发行版安装软件的不同,掌握make和make install。如碰到apache2不能启动,阅读错误提示以及查看日志(/usr/local/apache2/logs/error.log).

Ubuntu 9.10 Server (Karmic) 迁移Bugzilla

Filed under: wordpress | No Comments »
Posted on

项目组去年年底配置了两台服务器,其中的一台安装了Ubuntu 9.10 Server。由于项目组采用Bugzilla作为bug生命周期的管理,需要把Bugzilla迁移了过来。以下记录迁移过程备忘。

原服务器 Ubuntu 8.04 Desktop ,  Bugzilla 3.2.2

新服务器 Ubuntu 9.10 Server  , –

参考网上部分方案,打算采用比较稳妥的方式,形成如下思路

1 备份mysql数据库

  将数据库bugs备份到文件bugsdata.sql
    $mysqldump bugs > bugsdata.sql
    再修改bugsdata.sql,在文件头加两行
    create database if not exists bugs;
    USE bugs;

2 在已安装mysql的9.10Server上恢复数据库

   此步骤一定在第5步之前,因为Bugzilla的checksetup.pl会自动升级数据库脚本从3.2.2到3.4.4

3 打包Bugzilla 文件夹并恢复到Ubuntu 9.10上  (此步骤浏览时报错,忘了具体错误,比较难处理,转到步骤3)

4 下载最新Bugzilla 3.4.4, 重新编译。 至于为什么不用ubuntu自带的Bugzilla以及如何下载编译配置Bugzilla,请参见这篇博文Ubuntu 8.04 安装 Bugzilla 3.2.2

   为了防止版本文件夹的变化而修改apache虚拟目录文件,可以创建symbolic link,比如解压后的文件夹为 Bugzilla_3.4.4 可以用 ln –s Bugzilla Bugzilla_3.4.4 创建名为Bugzilla的symbolic link,在apache虚拟目录的配置中可以使用该名称,将来出现新版本只更新Bugzilla的指向即可。

5 运行 ./checksetup.pl 的时候,按照提示下载缺少的部分模块,总是有3个模块安装不上

Checking perl modules…
Checking for DateTime (v0.28) not found
Checking for DateTime-TimeZone (v0.71) not found 
Checking for Template-Toolkit (v2.22) not found

解决方法 sudo apt-get install libmysql++-dev  (参考了ubuntuforums.org里一位老兄的帖子Installing bugzilla and DateTime problem)

6 接下来就是按照提示修改Bugzilla的localconfig

$webservergroup = ‘www-data’;

# The DNS name of the host that the database server runs on.
$db_host = ‘localhost’;
# The name of the database
$db_name = ‘bugs’;

# Who we connect to the database as.

# The DNS name of the host that the database server runs on.
$db_host = ‘localhost’;
# The name of the database
$db_name = ‘bugs’;

# Who we connect to the database as.
$db_user = ‘bugs’;
$db_pass = ‘admin’;
注意其中的webservergroup 我设置为了www-data,注意这个是ubuntu的运行apache的用户组(不同于其他linux发行版的apache用户组)

7 别忘了在apache下配置该虚拟目录,ubuntu自带的apache可以直接修改的/etc/apache2/sites-enabled下面的文件加入

Alias /bugzilla “/var/www/bugzilla″
<Directory  “/var/www/bugzilla″>

Options +ExecCGI
AllowOverride Limit
DirectoryIndex index.cgi
AddHandler cgi-script .cgi
</Directory>
不过我们的服务器使用了自己下载编译的apache2,因为该服务器还做为svn的源代码管理服务器。我在ubuntu 9.10 server 下的apache在启用ssl的时候总是报undefined symbol apr_ldap_ssl_init错误,此处我怀疑可能是ubuntu9.10 server的问题,我在虚拟机ubuntu 8.04 desktop下没有出现此问题。

apache2的安装目录更改为/usr/local/apache2,在/usr/local/apache2/conf/httpd.conf中加入上述内容。

关于apache2的下载编译以及使用ssl的SVN请浏览Ubuntu 9.10 Server 配置基于SSL的Subversion

8 sudo /etc/init.d/apache2 restart  (自带的apache2)

   或者
   cd /usr/local/apache2/bin  (编译的apache2)
   sudo ./httpd –k restart