返回列表 发帖
第十九章 数据库系统
现在许多的商业应用、网页程序都必须使用数据库来存放数据。例如,网站上的留言版、讨论区、购物网站等,全部都是使用数据库来存放重要的数据。本章中,我们将介绍二种常见的数据库:MySQL 及 PostgreSQL。
本章包含了数据库的安装、设定、语法、及各种操作方式的介绍,读完本章后,您将可以了解下列主题:
如何安装、设定 MySQL。
如何安装、设定 PostgreSQL。
如何使用 MySQL 的图形化管理工具。
如何使用 PostgreSQL 的图形化管理工具。
基本的数据库语法介绍。
如何备份、回存数据库。
这些信息将有助您建立一个功能强大的网站,并对于日后安装数据库相关应用时更加得心应手。
19.1 概论
电子商务的兴起让数据库的应用更受到大家的瞩目。在信息科学的应用上,数据库可以说是最历久弥坚的领域。近来,数据产生和数据收集方面的技术有非常快速的进展。许多商业产品广泛使用了条形码、许多企业和政府的交易皆已计算机化,这使得计算机成为数据收集的主要工具。同时,数以百万计的数据库正被使用在企业管理、政府管理、科学和工程的数据管理和许多其它的应用上。
我们可以安装一套数据库系统,并经由一个接口自行开发程序来使用它。数据库的好处有很多,相信对数据库稍有涉入的人都知道,例如数据存取快速、不重复、权限控制、数据独立性等等。以写一个简单的留言版程序而言,传统上使用档案做为留言的记录,若要删除一笔数据,必须对整个档案一行一行的比对;但数据库只需指定该留言的编号即可。不过,如果把数据库系统局限于留言版也太大才小用了。
我们将介绍在 FreeBSD 上使用数据库,因为目前网页数据库使用情形十分风行,尤其在网页开发上使用 MySQL 或 PostgreSQL 数据库加 PHP 更是绝配。目前 Open Source 的数据库中,最常用、最有名的就是 PostgreSQL 及 MySQL,因此,本章将先介绍这二个数据库系统的安装及使用。
至于 PostgreSQL 及 MySQL 这二个数据库系统有什么差别?到底应该选哪一个呢?在 MySQL 3.x 以前,如果您问我这个问题,我一定说 PostgreSQL,因为 MySQL 3.x 不支援 transaction。所谓的 transaction 就是将一连串的 SQL 指令做为一个执行单位,当其中一个指令失败,在同一个 transaction 所执行过的命令都取消。Transaction 对于程序开发的应用十分重要,例如,当我们要新增处理一笔订单时,我们会先将订单输入数据库中,再将金额输入应收帐款中。如果我们在新增应收帐款时出现错误,而订单却已输入数据库,是不正确的做法。有了支援 transaction 的数据库,我们可以将订单的输入和应收帐款的输入做为一个执行单位,如果其中一个执行失败,则数据库会自动取消先前先做的动作,如此一来便可以确保数据的正确性。由于 transaction 十分重要,因此在做为商业上的应用时,我会选择 PostgreSQL。
不过 MySQL 4.x 后已经加入 transaction 的支持,只是功能还是没有 PostgreSQL 那么完整。那么除此之外,这二个数据库的差别是什么?PostgreSQL 是一个功能强大的数据库系统,它的威力不下于商业用的数据库。而 MySQL 的特性是对于简单 SQL 指令处理快速,大部份的日常简单操作,MySQL 的速度会比 PostgreSQL 快一点。以下我们列出它们在功能上的主要差异:
功能
MySQL 3.x
MySQL 4.1.x
PostgreSQL
版权宣告
GPL
GPL
BSD
Sub-Selects
No
Yes
Yes
Views
No
No
Yes
Foreign Key relationships
No
Yes
Yes
Foreign Key constraints
No
No
Yes
Triggers
No
No
Yes
Indexing on non trivial types
No
No
Yes
Sequences
Some
Some
Yes
Transactions
No
Yes
Yes
OO (Inheritance of tables)
No
No
Yes
Async Notifications
No
No
Yes
Constraints
No
No
Yes
SELECT INTO
No
Yes
Yes
Stored Procedures
No
No
Yes
Row level locking
Yes
Yes
Yes
Table level locking
Yes
Yes
Yes
Multi version Concurrency Control
No
No
Yes
我们可以看到 PostgreSQL 功能真的强大很多,如果您必须设计功能强大又复杂的系统,PostgreSQL 是不二之选。而 MySQL 4.x 以后的重要功能都很齐全,速度也很快,比较适合简单的网页应用,所以目前大部份网页应用软件使用 MySQL 比较多。不过呢,笔者认为 PostgreSQL 及 MySQL 都使用 Transaction 时,二者的效能表现差不多,就网页应用而言,我的首选还是 PostgreSQL。
19.2 安装 MySQL
MySQL 和 FreeBSD 一样也有多种版本同时开发,例如 3.x、4.0.x、4.1.x、5.x 等,其中 4.1.x 是目前较稳定的版本。
您可以自行到
http://www.mysql.com
取得最新版的 MySQL Source Package 来安装,不过安装上比较麻烦。所以我们使用 ports 来安装 MySQL:# cd /usr/ports/databases/mysql41-server
# make WITH_CHARSET=big5 WITH_XCHARSET=all install clean
我们指定 MySQL 预设的字集为 Big5,并另外支持所有的字集。接下来请修改 /etc/rc.conf 并加入下列这一行,以让开机时启动 MySQL:
mysql_enable="yes"
接着您就可以使用下列指令启动 MySQL 了:# /usr/local/etc/rc.d/mysql-server.sh start
启动 MySQL 后,我们就可以使用下列指令进入 MySQL 交互式命令列了:# /usr/local/bin/mysql mysql
若安装成功,你将看到以下画面:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 14 to server version: 4.1.13
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql>
MySQL 刚安装完成时,并未设定 root 的密码,因此我们接着要设定 root 的密码并实时更新设定:
mysql> UPDATE user SET password=password('你的密码') where user='root';
Query OK, 0 rows affected (0.00 sec)
Rows matched: 2  Changed: 0  Warnings: 0
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.02 sec)
以上指令及 MySQL 更详细的设定说明,我们会在下一小节中加以说明。最后请以 exit; 来离开 MySQL。
如果您有其它使用者要加入也可以加入,最好不要让使有人都有对所有数据库有全部的权限。使用命令列的方式新增使用者有点麻烦,我们等一下再使用其它图形化接口进入新增使用者。
建议您以后使用 MySQL 的图形化接口管理工具「MySQL Administrator」及「MySQL Query Browser」来管理 MySQL,我们会再后续章节中说明如何使用这些管理工具。
19.3 SQL 语法介绍
在使用数据库之前,我们必须先了解一些简单而基本的数据库理论。如果您对于数据库 SQL 语法已经很熟悉了,您可以跳过这一个小节。
基本上数据库的结构有下列几个特点:
一个数据库系统中可以有多个独立数据库。
数据库是由许多数据表 (table) 所组成。
数据表中包含许多记录 (record)。
每一笔记录中的字段数目都一样。
每一个字段储存一种分类过的数据。
例如我们有一个数据库名称是NCU,其中有多个数据表,其中一个资料表名为 student 内容如下:
STUDENT_ID
LAST_NAME
FIRST_NAME
DEPARTMENT
1
Chang
Jack
MIS
2
Wang
Alex
BA
在数据表中有许多字段 (column),每个字段都有一个名称,也就是第一列 (row) 中的 STUDENT_ID、LAST_NAME、FIRST_NAME、DEPARTMENT。接着我们将数据存入,每一笔记录我们都可以看成一列 (row),每一个记录都有一个「唯一的 ID (编号)」。唯一的 ID 十分重要,它是我们在存取数据库时的依据。在新增资料时,以 MySQL 而言,我们可以自行指定 ID 或是由系统自行取得。
另一个观念是关系型数据库。关系型数据库的意义就是每一个资料表间可以存在关系,例如我们在 NCU 的数据库中有另一个数据表名为 score,内容如下:
SCORE_ID
STUDENT_ID
CHINESE
ENGLISH
1
2
99
90
2
1
89
87
score 数据表中存放学生的成绩,我们不需在该数据表中存放学生的信息,只要在该数据表中存放一个字段名为 STUDENT_ID,经由这一个唯一的 ID 我们可以去 student 的数据表中找到学生的数据。
有了这些观念就足以让我们开发出许多数据库的程序了。
SQL (Structured Query Language) 语法十分简单,它是关系型数据库的标准语言,虽然在某些不同数据库系统上有些许的差异,但基本上都遵循一定的标准。
我们可以在命令列下进入 MySQL 来练习 SQL 的语法:# /usr/local/bin/mysql -u root -p
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 202 to server version: 4.1.13
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql>
下完指令后会要求输入密码,请输入您之前设定的密码。登入后你就可以直接在出现的命令列 mysql> 之后输入 SQL 的语法了。
关于 MySQL 详细的语法,你可以参考 MySQL 中文参考手册,该文件可以在
http://www.freebsd.org.hk/html/mysqldoc/
中找到。该文件中对于 MySQL 每个细节都有详细的描述,例如字段的名称限制、规则等,我们不会在这里提及。我们只介绍几个简单而常用的指令。 我们以建立一个学生数据表来说明这些语法。
CREATE
ALTER
DROP
INSERT
SELECT
UPDATE
DELETE
制成 script 档
19.3.1 CREATE
建立数据库:CREATE DATABASE db_name
建立数据表:CREATE TABLE tbl_name [(create_definition,...)] [options]
我们先建立一个名为 NCU 的数据库:
mysql> CREATE DATABASE NCU;
请注意,每一个指令皆以 ";" 为结尾,如果没有 ";" 就算换行也是代表同一条指令的延续。
我们可以使用下列指令 show 来列出系统中已存在的数据库有哪些:
mysql> show databases;
+-----------+
| Database  |
+-----------+
| mysql     |
| test      |
| NCU       |
+-----------+
3 rows in set (0.01 sec)
接着用 USE 这个指令来使用 NCU 数据库:
mysql> USE NCU;
接着建立一个放置学生数据的数据表,名为 STUDENT,内容为编号(STUDENT_ID)、姓名 (NAME)、科系 (DEPARTMENT):
mysql> CREATE TABLE STUDENT (
STUDENT_ID int(10) DEFAULT '0' NOT NULL AUTO_INCREMENT,
NAME varchar(50),
DEPARTMENT varchar(10),
PRIMARY KEY (STUDENT_ID) );
在上面的指令中,我们定义学生编号为十位数的整数(int),内定值是 0,不可以是空的 (NOT NULL),数字自动增加 (AUTO_INCREMENT)。姓名是最长为五十个字节的字符串(VARCHAR),科系为最长十个字节的字符串。最后定义主要的 id 是 STUDENT_ID,也就是该数据表中的唯一 ID。
我们可以看到在建立数据表时,我们会顺便划分各个字段所要储存的数据长度及其格式,常用的字段格式请参考 MySQL 中文参考手册。
如果要看现在使用的数据库中有哪些数据表,一样可以使用指令 show 来查看:
mysql> show tables;
+--------------------+
| Tables_in_NCU      |
+--------------------+
| STUDENT            |
+--------------------+
4 rows in set (0.00 sec)
19.3.2 ALTER
建立了数据表后,如果发现数据表的字段不符需求,我们不必将数据表删除重建,可以使用 ALTER 指令来修改数据表的格式。另如我们要新增一个姓别字段,内容只可以是 "男" 或 "女",我们可以使用下面的指令:
mysql> ALTER TABLE STUDENT
ADD SEX ENUM('男','女') DEFAULT '女';
我们增加了一个字段 SEX,使用 ENUM 的格式,指定内容只能为 "男" 或 "女",且默认值是 "女"。
如果我们要将 SEX 字段改名为 DISTINCTION,并将格式改为 VARCHAR:
mysql> ALTER TABLE STUDENT
CHANGE SEX DISTINCTION VARCHAR(4);
如果我们只是要将 SEX 字段格式改为 VARCHAR,但不更改名称,只要将上面的指令中 DISTINCTION 改成 SEX 即可。
如果我们要删除整个 DISTINCTION 字段及该字段的数据:
mysql> ALTER TABLE STUDENT DROP DISTINCTION;
19.3.3 DROP
删除数据库:DROP DATABASE db_name
删除数据表:DROP TABLE table_bame
我们可以使用 DROP 指令来删除不要的资料。例如我们要删除 STUDENT 这一个资料表的话,可以使用下列指令:
mysql> DROP TABLE STUDENT;
19.3.4 INSERT
使用 INSERT 指令可以让我们一笔一笔增加数据。
STUDENT_ID
NAME
DEPARTMENT
1
Jack
MIS
假设我们的数据表中的字段如上表,我们要新增一笔数据,姓名是 JACK、部门是 MIS:
mysql> INSERT INTO STUDENT (NAME, DEPARTMENT)
VALUES ('JACK', 'MIS');
由于我们在指定 STUDENT_ID 的格式时,加了参数 AUTO_INCREMENT,所以我们不需指定值,mysql 会自动帮我们依序指定。
19.3.5 SELECT
我们可以使用 SELECT 来看数据表中的数据,还可以依自己给定的条件来过滤数据。
假设我们要看 STUDENT 数据表中的所有数据的话,可以使用下列指令:
mysql> SELECT * FROM STUDENT;
假设我们只要看 NAME 及 DEPARTMENT 字段的话,我们可以使用下列指令:
mysql> SELECT NAME, DEPARTMENT FROM STUDENT;
假设我们只要看 NAME 字段,而且所属部门为 MIS 的人:
mysql> SELECT NAME FROM STUDENT
WHERE DEPARTMENT='MIS';
假设我们要看 MIS 部门中的人所有字段,而且输出结果时要依 STUDENT_ID 来排序:
mysql> SELECT * FROM STUDENT
WHERE DEPARTMENT='MIS'
ORDER BY STUDENT_ID DESC;
最后的 DESC 表示递减 (descending),由大到小排序。也可以使用 ASC 来表示递增 (ascending)。
除了这些之外,在 MySQL 中还有一些可以使用的函式,例如我们可以使用 count() 这个函式来计算出有多少笔记录:
mysql> SELECT count(*) FROM STUDENT WHERE DEPARTMENT='MIS';
+----------+
| count(*) |
+----------+
| 5        |
+----------+
1 row in set (0.00 sec)
上述结果表示部门为 MIS 的记录有五笔。
会了这些基本的 INSERT 指定就够我们做一般的应用了。
19.3.6 UPDATE
我们可以使用 UPDATE 指令来更新记录。例如我们要将所有记录的部门数据为 MIS 者都改成 CSIE,可以使用下列指令:
mysql> UPDATE STUDENT SET DEPARTMENT='CSIE'
WHERE DEPARTMENT='MIS';
19.3.7 DELETE
DELETE 指令可以让我们删除一笔或多笔数据。例如我们要删除 STUDENT 数据表中姓名为 JACK 的记录:
mysql> DELETE FROM STUDENT WHRE NAME='JACK';
如果我们要删除姓名为 JACK 且部门为 MIS 的数据:
mysql> DELETE FROM STUDENT
WHERE NAME='JACK' AND DEPARTMENT='MIS';
19.3.8 制成 script 档
我们可以将要执行的指定制成档案,以利管理。例如我们写了一个程序,需要先在数据库中建立一些数据,我们可以将对数据库的规划做成一个档案来管理。这样可以使用们要安装程序时更快速方便。
假设我们要建立一个数据库 NCU,该数据库中有一个数据表 STUDENT,数据表中要先建有以下记录:
STUDENT_ID
NAME
DEPARTMENT
1
Jack
MIS
2
Mary
CSIE
我们先建立一个文件名为 ncu.sql,内容如下:
CREATE DATABASE NCU;
USE NCU;
CREATE TABLE STUDENT (
STUDENT_ID int(10) DEFAULT '0' NOT NULL AUTO_INCREMENT,
NAME varchar(50),
DEPARTMENT varchar(10),
PRIMARY KEY (STUDENT_ID) );
INSERT INTO STUDENT (NAME, DEPARTMENT)
VALUES ('JACK', 'MIS');
INSERT INTO STUDENT (NAME, DEPARTMENT)
VALUES ('MARY', 'CSIE');
接着使用下列指令来快速建立数据库:# /usr/local/bin/mysql -u root -p
输入使用者 root 的密码后就完成建立了。
如果我们在数据库中早就有一个数据库名为 NCU,而我们要新增上述数据表及记录,我们只要将原本 ncu.sql 的内容最前面二行删除,改成下列内容:
CREATE TABLE STUDENT (
STUDENT_ID int(10) DEFAULT '0' NOT NULL AUTO_INCREMENT,
NAME varchar(50),
DEPARTMENT varchar(10),
PRIMARY KEY (STUDENT_ID) );
INSERT INTO STUDENT (NAME, DEPARTMENT)
VALUES ('JACK', 'MIS');
INSERT INTO STUDENT (NAME, DEPARTMENT)
VALUES ('MARY', 'CSIE');
之后再以下列指令来在 NCU 数据库中建立数据表:# /usr/local/bin/mysql -u root -p NCU
在网络上有许多 PHP 程序可以下载,下载后要安装数据库时,大多是以这种方式来使用。
19.4 MySQL 管理
19.4.1 维护密码安全
当我们要使用 MySQL 时,必须输入密码。输入密码的方式有很多种,第一种也是最不安全的一个方式是直接在命令列打指令时就输入:# /usr/local/bin/mysql -u root -pmypwd
上面这种方法会让别的使用者使用 ps 指令就可以看到你在执行的指定及密码。因此绝对不要使用这种方法,请改用下列方式输入:# /usr/local/myqsl/bin/mysql -u root -p
接着会要求你输入密码时再输入即可。
另一个方式是在你的家目录下建立一个存放密码的档案,文件名为 .my.cnf,当 mysql 需要使用密码时会自动去读取。该档的内容如下:
[client]
password=your_passowrd
接着要把 .my.cnf 的权限改成只有档案拥有者才可以读写:# chmod 600 ~/.my.cnf
19.4.2 备份数据库
数据库的数据要定时备份,这样才不会在失手时或系统有问题时产生困扰。在 MySQL 中提供一个备份程序 mysqldump。
假设我们有一个数据库名为 WWW,我们可以使用下列指令来备份整个数据库:# /usr/local/bin/mysqldump -u root -p WWW > www.sql
这样就可以把数据库的数据存在 www.sql 这个档案中了。日后要回复时只要使用下列指定就可以把资料存回:# /usr/local/bin/mysql -u root -p WWW
我们要注意的是备份出来的档案应该要放在不同的计算机中,而且要注意权限的控制。由于该文件是文字文件,任何人都可以读,所以要特别注意。
我们可以利用 crontab 这个指令来定时备份数据库。我们先建立一个 shell script 档,名为 backupsql.sh,内容如下:
/usr/local/bin/mysqldump -uroot WWW>/home/www.sql
chmod 600 /home/www.sql
接着将该档权限改成只有拥有人可以读、写、执行,其它人都不行:# chmod 700 backupsql.sh
为了要让执行 backupsql.sh 时可以不必输入密码,我们必须先将密码存在 ~/.my.cnf ,请先建立 ~/.my.cnf 档案内容如下:
[client]
password=your_passowrd
接着要把 .my.cnf 的权限改成只有档案拥有者才可以读写:# chmod 600 ~/.my.cnf
接着要让它能定时执行,命令列打 crontab -e 来进入文字编辑,加入下列内容:
#每天 3:05 备份网页数据库
5        3        *        *        *        /root/backupsql.sh
19.4.3 使用者管理
如果您要新增可以联机到 MySQL 的使用者,可以在 MySQL 交互式接口串使用 GRANT 指令来新增使用者。GRANT 在设定使用者权限时,如果使用者存在则更新其权限,如果不存在则新增该使用者。
用法:GRANT 权限 ON 数据库(或表) TO user@host IDENTIFIED BY '密码';
范例一:
新增一个本机的使用者 admin,并开放所有权限,密码为 mypwd:
mysql> GRANT ALL PRIVILEGES ON *.* TO admin@localhost IDENTIFIED BY 'mypwd';
Query OK, 0 row affected (0.00 sec)
范例二:
新增一个来自 www.mydomain.com 的使用者 www,并设定只能对 www 数据库中所有数据表执行 SELECT, INSERT, UPDATE, DROP, CREATE, DELETE, INDEX,密码为 mypwd:
mysql> GRANT SELECT, INSERT, UPDATE, DROP, CREATE, DELETE,
INDEX ON www.* TO www@www.mydomain.com IDENTIFIED BY 'mypwd';
Query OK, 0 row affected (0.00 sec)
如果要删除使用者上述新增的使用者 www,可以使用下列指令:
mysql> DELETE FROM user WHERE user='www' and host='www.mydomain.com';
Query OK, 1 rows affected (0.01 sec)
在新增或删除使用者后,离开 MySQL 之前都必须指行下列指令来让它生效:
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.01 sec)
19.4.4 如何更改使用者密码
我们可以使用下列指令来更改自己的密码:# /usr/local/bin/mysqladmin -u root -p password newpwd
上面指令中的使用者是 localhost 的 root ,新的密码是 newpwd。在输入指令后,会先询问你旧的密码。
我们也可以使用具有管理使用者权限的 mysql 使用者登入 MySQL 后,使用 UPDATE 指令来更改密码:# /usr/local/bin/mysql -u root -p mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 202 to server version: 4.1.13
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> UPDATE user set password=password('新密码')
where user='使用者' and host='主机';
19.5 MySQL 图形化管理工具介绍
MySQL 有许多图形化的管理工具,我们在此介绍二个官方的工具「MySQL Administrator」及「MySQL Query Browser」。MySQL Administrator 是用来管理 MySQL Server 用的,您可以查看目前系统状态、新增使用者等。而 MySQL Query Browser 可以用来查看数据库内容。
我们可以在一台 Windows 的机器上使用图形化的管理工具,或者是在本机的 XWindow 中执行也可以。如果要从另一台计算机联机到 MySQL,则在使用这些工具连到 MySQL 之前,您必须先新增具有权限从远方联机到 MySQL 的使用者。假设我们要新增一个使用者 root,它可以从 192.168.0.2 这台机器联机到 MySQL,而密码为 mypasswd,则可以使用下列指令:
mysql> GRANT ALL on *.* to root@192.168.0.2 IDENTIFIED BY 'mypasswd';
Query OK, 1 rows affected (0.01 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.01 sec)
19.5.1 MySQL Administrator
请先到 MySQL 网站下载 MySQL Administrator,并执行安装,安装后请执行 MySQL Administrator。执行后,您会看到下列画面:
图 19-1

请在 Server Host 字段中输入 MySQL Server 的 IP,并输入使用者名称及密码。登入后的第一页,您可以看到目前 MySQL 的状态。如果您的 Server 和 MySQL Administrator 是在同一台机器上,则可以对 MySQL 进行更多的控制,例如停用 MySQL 等。
MySQL Administrator 的管理界面使用上很容易,您可以自已点点看有什么功能,这里我们只介绍如何使用它来新增使用者。首先,请在右边选单中选取「User Administration」,接着在下图标示 2 的地方按鼠标右键,然后选择「Add new User」。
图 19-2

然后您就可以在 MySQL User 字段中输入使用者名称,并输入密码。输入完后请按「Apply changes」以套用设定。
接下来我们可以再进一步设定使用者 john 设定权限。假设我们希望设使用者 john 只可以对数据库 www 进行 SELECT、INSERT、UPDATE、及 DELETE 的指令,则可以点选「Schema Privileges」标签,并选取好权限后,按下图 3 的按钮以新增权限。最后请点选「Apply changes」以套用设定。
图 19-3

最后,我们要设定使用者可以从什么地方联机到 MySQL Server,请对着该使用者按右键,并选择「Add Host From Which The User Can Connect」,接着输入 IP 即可。
图 19-4

如果您要删除使用者,只要对着使用者按右键,并选取「Delete User」即可。
19.5.2 MySQL Query Browser
MySQL Query Browser 一样可以从 MySQL 官方网站下载。下载并安装后,就可以执行 MySQL Query Browser 了。执行 Query Browser 后,会出现一个要求登入的窗口,同样的,您必须输入账号、密码及所要联机的主机。
如果您已经安装了 MySQL Administrator,您可以直接从 MySQL Administrator 中执行 Query Browser,而且不必再输入账号密码:
图 19-5

在 MySQL Query Browser 中,我们可以建立删除数据库、数据表、查询数据库中的数据。如果您要建立一个新的数据库,请对着下图中 1 的位置按鼠标右键,再点选「Create New Schema」,最后输入数据库名称即可。
图 19-6

建立了数据库后,我们可以再建资料表。请对着我们刚建立的数据库按鼠标右键,再点选「Create New Table」即出现下列窗口:
图 19-7

请在「Table Name」中输入表格名称,并在上图 2 的部份输入每一个字段的类别,最后按「Apply Changes」即可。建立数据库后,您就可以在 Query Browser 中输入、检视数据库中的数据。只要对着刚才建立的表格点二下,并点选「Execute」即可查看数据库中的数据。如果您要新增一笔数据,请点选下图中 3 的位置,并选择「Edit」即可进行编辑。
图 19-8

MySQL 图形化接口的使用相当直觉,您只要多试几次就可以明白各种使用方法了。

小提示
如果您想要使用网页接口的 MySQL 管理工具,您可以到
http://www.phpmyadmin.net/
下载 phpMyAdmin。phpMyAdmin 的设定十分简单,您可以在网络上搜寻到很多相关文件。
19.6 PostgreSQL 安装设定
另一个好用的数据库为 PostgreSQL,这是笔者偏好的数据库,比起 MySQL,它的设定更简单、功能更强大。
我们同样使用 port 来安装 PosgreSQL:# cd /usr/ports/databases/postgresql80-server
# make install clean
执行了 make install 之后,会出现一个进阶设定的窗口,我们使用预设的设定即可。接着,您将看到一个提示讯息,要求你先行备份原本的数据库。如果您是第一次安装 PostgreSQL,可以直接略过。
安装完成后,我们就可以开始做数据库的初始化了。我们使用下列指令来初始化数据库:# su -l pgsql -c initdb
这个指令的意思是以使用者 pgsql 的身份执行 initdb。PostgreSQL 安装时会自动建立一个使用者及群组 pgsql,这是 PostgreSQL 预设最高使用者的账号,您可以使用 vipw 来修改该使用者的数据。由于 pgsql 预设使用的 shell 是 sh,笔者习惯使用 tcsh,所以我将该使用者的数据修改如下:
pgsql:*:70:70::0:0ostgreSQL Daemon:/usr/local/pgsql:/bin/tcsh
初始化数据库后还有一些后续的设定。一开始 PostgreSQL 只允许让 pgsql 这个使用者经由本机联机存取数据库,如果您希望其它使用者可以经由其它机器联机,您必须先修改 ~pgsql/data/postgresql.conf 这个档案。找出 listen_addresses  的部份,并修改如下:
listen_addresses = '*'
listen_addresses 是表示您所要允许联机的 IP 地址,我们填入 * 表示允许任何联机。如果您安装的 PostgreSQL 是 7.x 的版本,您要修改的是这下列一行:
tcpip_socket = true
postgresql.conf 这个档案记录着 PostgreSQL 的其本设定,其中使用 "#" 为首的是批注。其内容包括可以设定所要使用的连接埠、最大联机数量等,不过我们通常没有必要修改它。
接着我们要设定从别的机器联机所使用的认证方式,请编辑 ~pgsql/data/pg_hba.conf,在文件最下方加入下列设定:
# "local" is for Unix domain socket connections only
local   all         all                               trust
host    all         all         127.0.0.1/32          trust
host    all         all         ::1/128               trust
host    all         all         192.168.0.1   255.255.255.0     md5
这里的设定除了第一行是批注外,第二、三、四行表示信任来自本机的联机,只要使用者存在于数据库中就不需要密码,这三行预设就存在于 pg_hba.conf 中。最后一行表示网域 192.168.0.1~192.168.0.255 的联机都要使用 md5 验证密码。
如果您希望在开机时就启动 PostgreSQL,请修改 /etc/rc.conf 并加入下列这一行:
postgresql_enable="YES"
在我们新增其它使用者之前,必须先启动 PostgreSQL ,以下为启动数据库服务的指令:# /usr/local/etc/rc.d/010.pgsql.sh start
如果您没有在 rc.conf 中加入启动 PostgreSQL 的设定,则上述指令并不会启动 PostgreSQL。
因为 010.pgsql.sh 这支 script 放在 /usr/local/etc/rc.d ,所以在一开机时,系统就会自动执行它来启动 PostgreSQL,如果您要停止 PostgreSQL,只要执行下列指令:# /usr/local/etc/rc.d/010.pgsql.sh stop
接着我们就可以增加一个可以使用远程联机的使用者:# su -l pgsql
% createuser -P
Enter name of user to add: alex
Enter password for user "alex":
Enter it again:
Shall the new user be allowed to create databases? (y/n) y
Shall the new user be allowed to create more new users? (y/n) y
CREATE USER
如此一来我们就可以使用 alex 这个使用者从远程登入了。
19.7 PostgreSQL 管理指令
PostgreSQL 和 MySQL 在指令的应用上有所不同,它将许多管理数据库的指令独立成一个个的执行文件,其中有些指令是使用 psql 为基础所写成的 scripts。例如新增、删除数据库或使用者等指令,都可以直接在命令列执行。以下为常用的指令列表:
指令
用途
createdb
建立一个新的数据库。
dropdb
删除数据库。
createuser
建立数据库使用者。
dropuser
删除数据库使用者。
pg_dump
备份一个数据库。
pg_dumpall
备份所有数据库。
psql
交互式的 SQL 指令工具。
19.7.1 建立及删除使用者
因为 PostgreSQL 安装完毕时只有一个使用者 pgsql,如果您要使用其它使用者登入,您必须先以 pgsql 这个使用者来新增其它使用者账号。首先,我们先将身份切换成 pgsql:# su -l pgsql
我们使用 su 加上参数 -l 表示模拟使用者真正 login 的情形,也就是会将工作目录切换到 /usr/local/pgsql,并加载该目录中的 .cshrc 等档案。接着我们就可以使用下列指令来建立一个新的使用者了,假设我们要为 root 建立一个账号:% createuser root
Shall the new user be allowed to create databases? (y/n) y
Shall the new user be allowed to create more new users? (y/n) y
CREATE USER
如此一来,root 也具有存取数据库的权限了。但因为 PostgreSQL 内定没有密码的使用者不可以使用远程登入,如果您希望所新增的使用者可以使用远程登入,您必须在 createuser 指令加上参数 -P 以输入密码,请注意 P 是大写喔。如果你要从数据库中删除一个使用者账号,只要使用 dropuser 这个指令即可:% dropuser root
值得注意的是,您无法使用删除你正在使用中的账号,例如以 root 身份来删除 root 是不被允许的。
如果您要修改某个使用者的密码,可以使用下列指令:# su -l pgsql
% psql template1
Welcome to psql 8.0.3, the PostgreSQL interactive terminal.
Type: \copyright for distribution terms
\h for help with SQL commands
\? for help on internal slash commands
\g or terminate with semicolon to execute query
\q to quit
template1=# ALTER USER pgsql WITH PASSWORD 'mypass';
ALTER USER
template1=# quit
我们先切换身份为 psql 以确保具有权限修改使用者密码,接着我们使用 psql 进入预设的数据库,并使用 ALTER USER 来修改使用者 pgsql 的密码,将密码设为 mypass。最后使用 quit 离开数据库。
19.7.2 建立及删除数据库
在使用数据库之前,我们必须先建立一个数据库。假设我们要建立的数据库名称为 MYDB,您可以使用下列指令加以建立:% createdb MYDB
在 UNIX 的世界中,大小写是有分别的,在 PostgreSQL 中也是一样。因此,不论是在建立数据库,数据表或其字段时,都要注意大小写。建议您除了数据库名称外,最好全部使用小写。
同样的,如果你要删除一个数据库,只要使用 dropdb 这个指令:% dropdb MYDB
19.7.3 交互式 SQL 指令
PostgreSQL 的 client 端指令中,功能最强大的莫过于 psql 这个指令了。psql 可以除了让我们进入交互式的 SQL statement 环境外,也可以加上一些参数变成一个直接响应的指令。例如,我们想要查看目前有哪些数据库:% psql -l
List of databases
Name | Owner | Encoding
-----------+-------+-----------
MYDB | root | SQL_ASCII
template0 | pgsql | SQL_ASCII
template1 | pgsql | SQL_ASCII
(3 rows)
加上 -l 这个参数后,就可以列出所有数据库名称了。除了您所建立的数据库外,还有二个 templateX 的数据库,该数据库存放着 PostgreSQL 的设定,不可以删除。接下来让我们选定一个数据库以进入交互式的窗口:% psql MYDB
Welcome to psql, the PostgreSQL interactive terminal.
Type:        \copyright for distribution terms
        \h for help with SQL commands
        \? for help on internal slash commands
        \g or terminate with semicolon to execute query
        \q to quit
MYDB=#
在这里,我们可以使用 19.3 所列出的一些标准的 SQL statement 来存取数据库,例如 create、drop、delete、update、insert、alter 等。建议您进一步至 PostgreSQL 网站参考其使用手册,PostgreSQL 官方网站是
http://www.postgresql.org
。您也可以在下列网址中找到中文的使用手册:
http://www.freebsd.org.hk/html/pgsqldoc-7.0c/postgres.htm

在交互式的接口中,您可以使用 \h 及 \? 来查询可以使用的指令。其中 \h 为查询 SQL statement ,而 \? 则是常询 PostgreSQL 特有的反斜线指令,我们最常用的反斜线指令有 \q 离开交互式接口,及 \d 列出该数据库的所有数据表。
如果您觉得这种命令列的接口不好使用,我们在下一节将会介绍如何在 MS Windows 使用图形化接口的管理工具。
19.7.4 数据库备份及回复
定期备份数据库是十分重要的一件事,我们一定要养成备份的习惯。在 PostgreSQL 中,备份十分容易,假设我们要备份的数据库是 MYDB,您可以使用下列指令:% pg_dump MYDB > MYDB.sql
如此一来,你就可以把 MYDB 这个数据库 dump 出来了。然而,数据库的数据往往十分庞大,动辄数十 MB 至数百 MB,为了节省空间,您可以在备份时顺便压缩数据库。以上述指令而言,我们只要将输出导向到 gzip 即可进行同步压缩:% pg_dump MYDB | gzip > MYDB.sql.gz
我们一般从数据库 dump 出来的数据都是文字文件,所以使用 gzip压缩可以得到很高的压缩比。假设不压缩所备份出来的档案有五十 MB,使用 gzip压缩后大约只剩六百多 KB。因此,我习惯都会加上 gzip压缩。
pg_dump 这个指令只能用来备份单一的数据库,如果您要将所有的数据库中都备份起来,您可以使用 pg_dumpall 来备份:% pg_dumpall |gzip > ALLDB.sql.gz
有了备份,自然也要回存。由于我们使用 pg_dump 所备份出来的数据库实际上是将一堆数据以 SQL statement 的方式存起来,如果您将该备份的档案以文书编辑器打开,您可以看到它其实是先存放数据库中所有数据表的信息,再将存放数据。所以我们只要将这些指令导向到 psql 来执行即可。首先,请先建立要回存的数据库名称,假设我们要将 MYDB 所备份出来的数据存放在 NEWDB 这个数据库中,我们要先建立一个名为 NEWDB 的数据库:% createdb NEWDB
接着再使用下列指令来将数据回存:% cat MYDB.sql | psql NEWDB
如果您备份出来的数据有经过压缩,则需改以下列指令回存:% gunzip -c MYDB.sql.gz | psql NEWDB
或是% cat MYDB.sql.gz | gunzip | psql NEWDB
如果您要回存的档案是经由 pg_dumpall 所备份出来的数据,则必须使用 pgsql 这个使用者来执行下列指令:% gunzip -c ALLDB.sql.gz | psql -e template1
19.8 PostgreSQL 图形化管理工具介绍
许多人可能不太习惯使用命令列来管理数据库,还好 PostgreSQL 提供了许多图形接口的管理工具。您可以在 MS Windows 执行的 pgAdmin。由于这些图形接口操作上比较容易,只要您多试几次,就可以熟悉它们的使用,因此,我们不会深入介绍每个功能的用法。
对于初学者而言,使用 pgAdmin 会比在命令列中输入来得容易。您可以自
http://www.pgadmin.org/
下载最新版本的 pgAdmin。
安装完成后,我们打开 pgAdmin,按了左上角的图示后即出现联机设定的窗体。请输入您数据库服务器的位置及账号密码,如图 19-9 所示:
图 19-9

请注意,您必须先将 PostgreSQL 的 TCP/IP 联机打开,而且在 pg_hba.conf 中必须允许使用 pgAdmin 的这台主机登入。您可以参考 19.6 中的说明来设定 pg_hba.conf。输入联机数据后,即可开始使用。以建立一个新的数据库为例,我们先在左边的窗口中,对着数据库按右键,再选取 [新物件]->[新建数据库] 如图 19-10 所示:
图 19-10

接着我们可以输入数据库名称、编码方式等,如图 19-11:
图 19-11

我们输入了数据库名称为 test,并指定使用 UNICODE 的编码方式。接下来您可以看到在管理窗口中多了一个数据库「test」,我们可以在此数据库中再建立数据表。请先点选数据库「test」,再选择「模式」->「public」->「数据表」,并对着数据表按右键选择「新建数据表」。
图 19-12

接下来,您就可以输入资料表名称,再选取「资料行」以设定本数据表的字段数据。
图 19-13

在 pgAdmin 的主画面中,最上方有几个功能键,可以让我们手动输入 SQL 指令或是查看数据表内容,建议您可以每一个功能都试试看,以熟悉 pgAdmin 的使用接口。基本上 pgAdmin 十分容易上手,而且也功能十分齐全。

小提示
如果您想要使用网页接口的 PostgreSQL 管理工具,您可以到
http://phppgadmin.sourceforge.net/
下载 phpPgAdmin。phpPgAdmin 的设定和 phpMyAdmin 一样十分容易,只要您已经安装好网页服务器,就可以使用 phpPgAdmin。

TOP

第十八章 DHCP服务器
DHCP (Dynamic Host Configuration Protocol) 服务器可以用来让网络中的计算机自动取得 IP 设定。架设 DHCP 服务器可以让网络中的计算机设定更容易,您不必再去一台台为每一台计算机设定 IP,这对于大型网络而言可以大幅减少管理者的负担。
读完本章后,您将了解下列主题:
如何架设 DHCP 服务器。
DHCP 服务器的运作原理。
如何使用 DHCP 服务器来追踪网络问题。
18.1 DHCP 简介
一台计算机要连上网络必须要先设定 IP、子网掩码、路由、DNS 等。一般使用者对这些网络设定并不熟,如果要使用者自己设定这些项目很麻烦。而且,如果网络上有十几台,甚至几百台计算机,如果由 MIS 人员分配 IP、设定计算机实在太累人了。日后如果有新的计算机加入您的网域,系统管理者又要一台台去设定网络数据。这种无趣又乏味的设定工作对管理者而言实在是浪费时间。如果您有使用笔记型计算机,在没有 DHCP 的情形下,在公司要设定一次 IP,回到家又要再设定一次,太麻烦了。
如果有了 DHCP 服务器,网络上的计算机只要设定好自动取得 IP,系统开机后就可以自动取得网络设定。管理者不需要告诉使用者该使用什么 IP,不必再为一台台计算机设定 IP,生活从此更美好了。有了 DHCP 服务器之后,使用笔记型计算机的人只要设定好使用 DHCP,将计算机插上网络线后就可以自动取得 IP,而不必再做任何设定。
在设定 DHCP 服务器时,我们会设定要让使用者自动取得的 IP 地址范围、路由、DNS,在启动 DHCP 服务器之后,这些信息就会放到内存中等客户端来问。当一台使用 DHCP 自动取得 IP 的计算机连上网络后,它会以广播的方式询问网络上有没有 DHCP 服务器,而 DHCP 服务器会响应,并送给客户端网络设定的数据。客户端收到这些信息后,就将它设定为自己的 IP、DNS 等。
如果以 DHCP 的术语来说,DHCP 分配出一个 IP 的情形叫做 DHCP「出租」IP 给客户端。DHCP 的租约是有期限的,时间到了之后,客户端就必须重新取得一次 IP,不过客户端可以要求继续使用同一个 IP。为了避免有机器一直要求使用同一个 IP,我们也可以设定同一个 IP 最长的租期是多久。
除了动态的分配 IP 外,DHCP 也可以同时设定指派固定 IP。每一张网络卡都会有一个固定的网络卡地址 (MAC、Physical Address),例如,我们可以在 FreeBSD 中使用指令 ifconfig 或是在 Windows 中使用 ipconfig/all 来看到 MAC 的信息。以下列为例:# ifconfig
fxp0: flags=88c3 mtu 1500
options=b
inet6 fe80::202:b3ff:fe48:7c74%fxp0 prefixlen 64 scopeid 0x1
inet 10.0.0.1 netmask 0xff000000 broadcast 10.255.255.255
ether 00:02:b3:48:7c:74
media: Ethernet autoselect (100baseTX )
status: active
上列粗体部份「00:02:b3:48:7c:74」就是网络卡地址,我们可以设定某个网络卡地址一定使用固定 IP,如此一来,只要这一台机器使用 DHCP 要求 IP 时,DHCP 服务器都会给它固定的地址。
如果您的机器有多张网络卡,在设定 DHCP 时,我们可以指定只要接受某个网卡进来的要求。DHCP 服务器所需要的系统资源很少,所以通常除了 DHCP 外,我们还会在同一台机器上架设其它服务。例如,NAT、防火墙、网页服务器、或 DNS 等。以一个公司而言,DHCP 是一种内部所使用的服务器,它和网络上要使用 DHCP 服务的计算机一定有所连结,中间不会有防火墙阻挡了 DHCP 的封包。通常我会将 DHCP 和 NAT、或 DNS 服务器放在一起。
18.2 安装 DHCP 服务器
在安装 DHCP 服务器之前,请确定您的核心有支持 bpf 装置。FreeBSD 的 GENERIC 核心预设就有支持 bpf 装置,如果您有修改过核心,请重新加入 bpf 的支持。
DHCP 服务器有很多软件可以使用,我们使用 ISC DHCP,请使用下列指令安装:# cd /usr/ports/net/isc-dhcp3-server
# make install clean
执行上述指令后,将出现下列画面:
图 18-1

我们只要使用预设的设定即可。
安装完后,在 /usr/local/etc/dhcpd.conf.sample 有一份预设的 DHCP 设定档。我们可以将它复制成 /usr/local/etc/dhcpd.conf 并进行修改。以下是笔者的设定文件范例:
option domain-name "twbsd.org";
option domain-name-servers 168.95.1.1;
option subnet-mask 255.255.0.0;
option broadcast-address 192.168.255.255;
# 本地时间与格林威治时间差(快八小时)。
option time-offset 28800;
# 预设租期时间长度: 一天(秒)。
default-lease-time 86400;
# 最大租期长度: 十天(秒)。
max-lease-time 864000;
ddns-update-style none;
# 子网络与网络屏蔽。
subnet 192.168.0.0 netmask 255.255.0.0 {
        # 动态分配 IP 位置范围。
        range dynamic-bootp 192.168.100.1 192.168.100.253;
        range dynamic-bootp 192.168.101.1 192.168.101.253;
        # 子网络路由器。
        option routers 192.168.1.1;
}
# 设定使用固定 IP 的机器
host alexserver {
        hardware ethernet 00:07:e9:03:39:80;
        fixed-address 192.168.1.2;
}
dhcpd.conf 设定文件中,每一个项目的说明如下:
option domain-name:用来设定网域名称。
option domain-name-servers:设定 DNS 服务器 IP。
option subnet-mask:设定要给 client 的预设子网掩码。
option broadcast-address:设定要给 client 的预设广播地址。
option time-offset:设定本地时间和格林威治时间差几秒。
default-lease-time:设定预设的租期。租期以秒计算,租约到期后,服务器会回收该 IP。
max-lease-time:当租约到期后,客户端可以继续要求使用同一个 IP,这个选项控制该 IP 最长可以被使用多久。
ddns-update-style:这是用来设定是否支持 ddns 更新 IP,这个选项一定要存在才不会有错误。
接下来的 subnet 设定中,我们所使用的子网络是 192.168.0.0/255.255.0.0,DHCP 的 IP 分配范围是 192.168.100.1~192.168.100.253 及 192.168.101.1~192.168.100.253。并设定预设的路由器为 192.168.1.1。
另外,我们设定了一个命名为 alexserver 的设定,只要网络卡地址是 00:07:e9:03:39:80 的计算机则指派 192.168.1.2 这个固定 IP 给它。
接下来请在 /etc/rc.conf 中加入下列这一行,以在开机时启动 DHCP 服务器:
dhcpd_enable="YES"
如果您有多张网络卡分属于不同的网域,则在 dhcpd.conf 必须设定这些网域都必须要有设定值。如果您只想要 DHCP 监听某个网络卡,则可以在 /etc/rc.conf 中加入下列设定,让 DHCP 只接收该网卡进来的要求:
dhcpd_ifaces="fxp1"
最后我们就可以使用下列指令启动 DHCP 服务器了:# /usr/local/etc/rc.d/isc-dhcpd.sh start

18.3 客户端 DHCP 设定
在客户端设定方面,如果您使用的是 FreeBSD,请参考「网络设定」一章中关于使用 DHCP 动态取得 IP 的设定说明。
如果您使用的是 Windows 2000/XP,请以鼠标右键点选桌面上的「网络上的芳邻」,选「内容」后出现「网络联机」的画面后,点选「局域网络」后出现下列画面:
图 18-2

接着请选则「Internet Protocol (TCP/IP)」后,点选「内容」出现下列画面:
图 18-3

接下来按确定即可使用 DHCP。
18.4 DHCP 及系统管理
DHCP 服务器会将所有出租过的 IP 信息存放在 /var/db/dhcpd/dhcpd.leases 中。我们来看看该档案的内容:
lease 192.168.101.99 {
   starts 1 2005/10/03 01:47:16;
   ends 2 2005/10/04 01:47:16;
   binding state active;
   next binding state free;
   hardware ethernet 00:02:b3:1d:61:7a;
   uid "\001\000\002\263\035az";
   client-hostname "test-winxp";
}
lease 192.168.101.44 {
   starts 1 2005/10/03 02:09:40;
   ends 2 2005/10/04 02:09:40;
   binding state active;
   next binding state free;
   hardware ethernet 00:02:b3:26:ca:64;
   uid "\001\000\002\263&\312d";
   client-hostname "build";
}
我们可以看到每一个区段都是一次 IP 出租的信息。这些信息中包含了 IP、开始时间、网络卡地址、客户端计算机名称等等。这些信息有的时候对于我们管理网络中的计算机还蛮有用的。
举例而言,假设有人不小心将计算机设定成您的 IP,在 FreeBSD 的 console 下您会看到下列讯息:
arp: 192.168.1.9 moved from 00:c5:b5:5d:9c:94 to 00:aa:00:01:b7:54 on fxp1
arp: 192.168.1.9 moved from 00:aa:00:01:b7:54 to 00:e9:38:54:92:c3 on fxp1
arp: 00:0c:29:07:0e:7d is using my IP address 192.168.0.4!
如果是有人在使用您的 IP,您会看到如上述最后一条讯息「xxx is using my IP address」。如果是另外一台机器的 IP 改变了,您会看到「xxx moved from xxx to xxx」的讯息。从这些讯息中,我们可以知道误用 IP 的人的网络卡地址。以上述范例的第三行为例,其网络卡地址是「00:0c:29:07:0e:7d」。接下来,您就可以去 dhcpd.leases 中检查,该网络卡地址是不是曾经使用过 DHCP 服务器。如果有,则您可以找到它的「client-hostname」,并经由该信息找到该计算机。

TOP

第十七章 邮件服务器进阶应用
基本的邮件服务器已能满足大多数人的需求,但经过一段时间之后,您可能会遇到更多的使用者要求。例如,开始有人报怨垃圾信太多、有人希望可以使用网页收发信件等等。本章将介绍一些邮件服务器的应用,让您的服务器功能更加强大。
读完本章后,您将了解下列主题:
如何架设虚拟邮件主机。
如何阻挡垃圾信及病毒信。
如何架设 Openwebmail 以使用网页收发信件。
17.1 虚拟邮件主机
如果我们想要在同一台机器上收多台主机的信件,或者想要在一台主机上设定可以 "收" "发" 信件的虚拟账号 (如果只要收,可以简单的设定 aliases 即可),我们可以经由虚拟主机的设定来达成。假设有二个 Domain Name,一个是 abc.com,另一个是 old.cde.com。这份文件包含了二种设定方式:一个是让二个 domain name 收到的信对映到一台机器上的使用者,也就是说不能有不存在的虚拟使用者;另一个设定是让你可以设定不同的虚拟使用者对映到不同机器上的任何使用者。不管我们要做哪一种设定,都必需要先设定 DNS。
请注意,这份文件中的设定并不会让你可以拥有一个真正的虚拟账号,因为这里是将虚拟账号对映到一个存在的邮件地址。使用这份文件的设定和设定 /etc/aliases 最大的不同在于设定 aliases 只能让虚拟的账号收信,而无法寄信。
17.1.1 DNS 设定
为了要让寄出去的信知道要往哪一台主机上送,必须要先设定 DNS。假设我们现在已经有一台设定好 DNS 的主机,hostname 是 abc.com。我们要让 abc.com 处理 old.cde.com 的信件的话,最简单的方式就是将 mail.cde.com 指向 abc.com (CNAME records),也就是二个 doamin 有同样的 IP。不过这样一来,old.cde.com 就不能独立存在了,也就是说不会有一台机器的 hostname 名为 old.cde.com,并提供 FTP、www(也可以有虚拟主机)、telnet等服务。
因此,我们要使用的是改变 DNS 的 MX record。设定只有处理该主机的邮件时,才将 old.cde.com 转向 abc.com。请在你的 DNS 中加入下列设定:
old.cde.com        IN  MX  10    abc.com.
完成后要重新读设定档并等一段时间设定才会在网络上生效。接着我们就可以来做 sendmail 的设定了。
17.1.2 对映到同一台机器的真实使用者
第一种设定的使用时机,例如你的公司主机原来是 mail.cde.com,现在换成了 abc.com,你希望让原本的使用者 jack@mail.cde.com 和新的 jack@abc.com 都能由 jack@abc.com 来收信。这种设定很简单,只要编辑 /etc/mail/relay-domains 及 /etc/mail/local-host-names 这二个档案,加入要增加收信的主机名称即可。以本例而言,除了那二个档案原本的内容外,要再增加一行:
mail.cde.com
这样了不管是原本 mail.cde.com 或是真正主机名称 abc.com 的信件,都可以由 abc.com 的相同的使用者收信。
17.1.3 可以拥有虚拟使用者
第二种设定是让我们可以设定一个虚拟的账号,并且可以利用它来送信。这个设定是经由编辑 /etc/mail/virtusertable 来达成。相同的,我们在 abc.com 这台主机中设定它的 virtusertable。我们以下列二个 virtusertable 的例子来说明,请注意,二个字段间的空白是用 tab 键,而非使用空格键:
范例一:
joe@mail.cde.com            jschmoe
jane@mail.cde.com           jdoe@othercompany.com
@mail.cde.com               jschmoe
上面的例子中,凡是寄给 joe@mail.cde.com 的信都会送给本地使用者 jschmoe。而以 joe@mail.cde.com 寄出的信收件人所看到的寄件人一样是 joe@mail.cde.com,如果在寄信时要身份认证的话,必须使用 jschmoe 的账号及其密码。接下来,寄给 jane@mail.cde.com 的信会送给 jdoe@othercompany.com,剩下来所有给 mail.cde.com 的信都会送给本地 jschmoe 这个使用者。
范例二:
joe@mail.cde.com            jschmoe
bogus@mail.cde.com          error:nouser No such user here
list@mail.cde.com           yourdomain-list
@mail.cde.com               %1@othercompany.com
这一个例子中,第一行和范例一一样,凡是寄给 joe@mail.cde.com 的信都会送给本地使用者 jschmoe。而凡是寄给 bogus@mail.cde.com 都会响应没有这个使用者。第三行如果是寄给 list@mail.cde.com 的信,都会转给本地的 yourdomain-list 这个虚拟使用者,你可以在 /etc/aliases 中加入关于 yourdomain-list 这个使用者的信要怎么处理,怎么设定别名。最后一行,凡是其它非上述三行使用者的信,都交由在 othercompany.com 这台机器上相对映的使用者来处理。
你可以依照上面的范例来编辑你的 virtusertable,完成编辑后,必须要使用以下指令来将这些档案做成 sendmail 能接受的 DB 格式:# makemap hash virtusertable.db
# newaliases
都完成后,我们就可以到别台机器使用虚拟账号来试试收发信。假设我们要使用的虚拟账号是上述范例一中的第二行 jane@mail.cde.com,以 outlook 中的设定为例,所设定的 E-mail 仍然是 jane@mail.cde.com,如下图所示:
图 17-1

所设定的 pop3 及 smtp 主机也是 mail.cde.com。但是使用者及密码是 othercompany.com 上的使用者 jdoe 及其密码,如下图所示:
图17-2

在上图中,如果 othercompany.com 在寄信时要身份认证,则上图中 "外寄邮件服务器" 的选项 "我的服务器需要验证"必须打勾。如此一来您就可以使用 jane@mail.cde.com 来收发信,而且在别人收到信时会显示寄件人是 jane@mail.cde.com
17.2 垃圾信及病毒防护
全拜电子邮件所赐,经由因特网,我们可以很快的传送邮件。然而,却有人利用电子邮件从事令人不悦的广告发送行为。垃圾邮件可以说是目前网络上最令人厌恶的行为,相信常使用电子邮件的读者们每天一定都会收到许多垃圾信件。所有服务器上处理的使用者都要处理这些垃圾邮件简直是太浪费资源了。而且,除了垃圾信外,邮件中所夹带的病毒也十分危险,万一有人不小心打开了具有病毒的信件,接下来又是另一场灾难。
面对这些垃圾信及病毒信,我们有更好的解决方式,就是使用 MailScanner 加上病毒防护的功能,让我们的邮件服务器更加安全、好用。MailScanner 是一套免费的软件,很多网站都使用它来过滤垃圾信件。除了垃圾信外,我们还可以外挂其它模块,以支持病毒扫瞄。另外,我们也可以用它来阻挡具有特定的扩展名附件的邮件。您可以到
http://www.sng.ecs.soton.ac.uk/mailscanner/
找到更多关于 MailScanner 的说明。
使用 MailScanner 的好处是我们原本安装的 Sendmail 不需要做任何的修改,只要将 Sendmail 跑在 MTA only 的模式即可。
17.2.1 MailScanner 架构说明
在没有安装任何垃圾信处理软件之前,在寄信、或者由其它服务器收到信件时,我们的服务器会先判断该信件是否为本机的信件,如果是,则呼叫 MDA (mail 这支指令),将信件放到 /var/mail 目录下。如果是要给其它服务器的信件,则放到 /var/spool/mqueue 下,Sendmail 会定时检查该目录,并将信件传送出去。示意图如下所示:
图 17-3

在有了 MailScanner 后,当 Sendmail 收到信后,会先将信件放到 /var/spool/mqueue.in 中。接下来 MailScanner 会定时去检查该目录下的档案,经过 MailScanner 扫瞄检查后,合法的邮件会被放到 /var/spool/mqueue 中。接下来的处理程序就和原本 Sendmail 的处理一样。示意图如下:
图 17-4

MailScanner 在检查邮件时有很多功能,它使用了一些外挂模块来检查垃圾信及病毒信。详细的检查过程如下:
定时检查 /var/spool/mqueue.in 中的邮件。
先使用 RBL 检查寄件者的 IP 是否在黑名单中。
使用 SpamAssassin 来检查信件内容,看看信件格式是否有不合法或是具有垃圾信特征。
呼叫病毒检查的模块来扫瞄邮件。
进行其它的内容检查,包含附件的扩展名、邮件内容是否包含特定的 HTML 格式等等。
全都都合法则将信件放到 /var/spool/mqueue 中。如果不合法,则依我们的设定进行退信、隔离、删除、或加上标记后送出。
图 17-5

当 MailScanner 判断某封信件为垃圾信时,它有几种处理模式,包含附加标记在主旨上后送出、退信、删除、隔离、转寄等等。我们在使用 MailScanner 之后,应该要先在邮件的主旨上附上标记后送出。当有使用者发现不是垃圾信却被设为垃圾信时,我们可以将该信件的寄件者加入白名单中 (就是不检查信件的寄件者清单)。如此运作一段时间都没问题后,再使用比较严格的方式,进行退信或删除。如此一来,我们才不会遗漏正常的信件。
MailScanner 的功能十分强大,但是设定却很容易,我们只要进行一些基本设定,即可以拥有强大的垃圾信及病毒扫瞄功能。
17.2.2 安装 MailScanner
FreeBSD 已经将 MailScanner 放入 ports 中,我们只要使用 ports 来安装即可。除了 MailScanner 外,我们还要安装 SpamAssassin 及防毒软件 ClamAV。
首先请使用下列指令安装 MailScanner:# cd /usr/ports/mail/mailscanner/
# make install
# make initial-config
接着安装 ClamAV:# cd /usr/ports/security/clamav/
# make install clean
执行了 make install 后,会出现一个选单,请记得要选取「MILTER」。
最后安装 SpamAssassin:# cd /usr/ports/mail/p5-Mail-SpamAssassin/
# make install clean
安装完后,我们必须先进行一些基本的设定。首先是防毒软件方面,我们必须设定定时更新病毒码。请先编辑 /etc/rc.conf 并加入下列这一行:
clamav_freshclam_enable="YES"
上述设定将会在开机时启动 freshclam 这支程序,预设每二小时会去检查一次是否有新的病毒码要下载。
由于 MailScanner 会取代原本 Sendmail 的部份功能,而 Sendmail 只要启用 MTA 模式即可,所以我们先编辑 /etc/rc.conf 并停用原本的 Sendmail。
sendmail_enable="NONE"
接着我们使用下列指令来将 MailScanner 及 Sendmail 开机时所必须使用的启动程序更名,这样系统在开机时才会启动 MailScanner 及 Sendmail 的 MTA 模式:# cd /usr/local/etc/rc.d
# mv mta.sh.sample mta.sh
# mv mailscanner.sh.sample mailscanner.sh
由于 MailScanner 会在信件进来时,先将信件放到 /var/spool/mqueue.in 中,我们必须先建立下列 MailScanner 所必须使用的目录:# mkdir -p /var/spool/mqueue.in
# mkdir -p /var/spool/MailScanner/incoming
# mkdir -p /var/spool/MailScanner/quarantine
这样我们就已经完成了大部份的设定,接下来我们必须进行 MailScanner 的细部设定。MailScanner 的设定档位于 /usr/local/etc/MailScanner/MailScanner.conf,如果您希望快速的设定好 MailScanner,以下是几个必须修改的地方:
# MailScanner 会检查档案的扩展名、格式。如果是 zip 档,它也会将它解压缩并检查压缩
# 档中的内容。我们常会遇到因为扩展名问题而副件被 MailScanner 的问题。如果您将下列选
# 选项设为 0,则 MailScanner 就不会去检查压缩档中的档案格式。
Maximum Archive Depth = 0
# 设定使用 clamav 做为病毒扫瞄工具。
Virus Scanners = clamav
# 是否启用 SpamAssassin。我们将它改为 yes,以使用 SpamAssassin 来检查垃圾信。
Use SpamAssassin = yes
# 下列选项控制了当被 MailScanner 判定为垃圾信时要如何处理。预设是在主旨加上标记并
# 送出。我们可以将它改为 delete (删除)、store (隔离)、bounce (退信) 等。建议您
# 先设定为 deliver,等过一阵子确定都没有误判后,再将它改为 bounce。
Spam Actions = deliver
# 下列选项控制了当被 MailScanner 判定为高分数的垃圾信时要如何处理。所谓的高分数垃
# 圾信就是 MailScanner 有很高的把握认为这是垃圾信。预设是在主旨加上标记并送出。我
# 们一样可以将它改为 delete (删除)、store (隔离)、bounce (退信) 等。建议您先设
# 定为 deliver,等过一阵子确定都没有误判后,再将它改为 delete。
High Scoring Spam Actions = deliver
最后,您就可以重开机以使用 MailScanner 的功能了。
17.2.3 设定 MailScanner
除了上述的设定外,MailScanner 及 SpamAssassin 还有很多的设定项目可以修改,相关的设定档全部都放在 /usr/local/etc/MailScanner 中。我们先来说明一下这些设定档的用途:
檔名
用途
MailScanner.conf
这是 MailScanner 的主要设定档。
filename.rules.conf
用来设定拒绝的邮件附件的扩展名格式。
spam.whitelist.rules
用来设定白名单,也就是不会被判断为垃圾信的寄件者清单。
spam.blacklist.rules
用来设定黑名单,也就是一定是垃圾信的来源清单。
MailScanner.conf 是最主要的设定档,我们先来看看几个比较常用的项目:
# 设定您的组织缩写。这个项目会被 MailScanner 用在信件的标头中。必须注意的是这个设
# 定最好只使用英字及数字。
%org-name% = twbsd
# 用来设定您的组织全名。这个名称会出现在 MailScanner 所寄出的回报信件中,它会被当
# 成签名档附在信件的最下方。
%org-long-name% = Taiwan BSD Group
# 用来设定您的组织网址。这个网址会出现在 MailScanner 所寄出的回报信件中,在信件最
# 方会出现这个连结。
%web-site% = http://www.twbsd.org
# 设定 MailScanner 多久要检查一次是否有新的信件进来,以秒为单位。
Queue Scan Interval = 6
# 设定允许的最大附件大小。如果设为 -1 表示不检查,0 表示不允许附件。
Maximum Attachment Size = -1
# MailScanner 会检查档案的扩展名、格式。如果是 zip 档,它也会将它解压缩并检查压缩
# 档中的内容。我们常会遇到因为扩展名问题而副件被 MailScanner 的问题。如果您将下列选
# 选项设为 0,则 MailScanner 就不会去检查压缩档中的档案格式。
Maximum Archive Depth = 0
# 设定使用 clamav 做为病毒扫瞄工具。
Virus Scanners = clamav
# 是否要检查网络钓鱼。网络钓鱼 (Phishing) 的意思是使用伪装的信件,让使用者以为是另
# 一个网站所寄来的数据,让使用者上勾。例如,伪造某银行的信件,要您输入信用卡号等。不
# 过这个项目可能会让您信件中有类似 192.168.1.1 这种 IP 时出现警告讯息。
Find Phishing Fraud = yes
# 是否要在信件中出现 IP 的连结时提出警告。
Also Find Numeric Phishing = yes
# 下列几个项目都是用来检查一些信件中的 HTML 格式,并将比较可能有危险的格式移除。如果
# 将它们设为 yes,表示允许;no 表示不允许;disarm 表示以该格式的功能取消,但信件还
# 是送出。
Allow IFrame Tags = disarm
Allow Form Tags = disarm
Allow Script Tags = disarm
... 略 ...
# 是否启用 SpamAssassin。我们将它改为 yes,以使用 SpamAssassin 来检查垃圾信。
Use SpamAssassin = yes
# SpamAssassin 会检查信件内容,并依内容格式给予信件分数,分数越高表示越有可能是垃
# 圾信。您可以在收到信件后,查看邮件原始档,在原始档中有一行
# 「X-twbsd-MailScanner-SpamScore」,其后接的「s」数目就是分数。这个选项设定
# 了分数多少会被当作垃圾信。
Required SpamAssassin Score = 6
# 这个选项设定了分数多少表示是高分数的垃圾信。
High SpamAssassin Score = 10
# 下列选项控制了当被 MailScanner 判定为垃圾信时要如何处理。预设是在主旨加上标记并
# 送出。我们可以将它改为 delete (删除)、store (隔离)、bounce (退信) 等。建议您
# 先设定为 deliver,等过一阵子确定都没有误判后,再将它改为 bounce。
Spam Actions = deliver
# 下列选项控制了当被 MailScanner 判定为高分数的垃圾信时要如何处理。所谓的高分数垃
# 圾信就是 MailScanner 有很高的把握认为这是垃圾信。预设是在主旨加上标记并送出。我
# 们一样可以将它改为 delete (删除)、store (隔离)、bounce (退信) 等。建议您先设
# 定为 deliver,等过一阵子确定都没有误判后,再将它改为 delete。
High Scoring Spam Actions = deliver
# 是否要在扫瞄发现信件没问题后,在信件最后加下 "Inline HTML Signature" 或
# "Inline Text Signature" 这二个选项所设定的内容。如果设为 yes,则信件最
# 后都会有使用 MailScanner 扫瞄过的讯息。
Sign Clean Messages = no
filename.rules.conf 可以用来设定邮件附件中不允许哪些扩展名。在 filename.rules.conf 中已经有一些预设的扩展名,如果您想要允许某些扩展名,可以修改该档案。例如,我们如果想要允许 .exe 档,则可以在下列这一行前加上「#」:
#deny \.exe$ Windows/DOS Executable
spam.whitelist.rules 及 spam.blacklist.rules 可以用来设定黑白名单。如果您有信件被误判为垃圾信,可以在白名单中加入让寄件来源,如此一来,该信件就不会再被当作垃圾信了。反之,如果有垃圾信没有被判断为垃圾信,则可以自行在黑名单中加入。这二个档案的格式一样,以 spam.whitelist.rules 为例:
From: *@*.friends.net yes
From: *@friends.net ye
From: 220.132.178.149 yes
From: 192.168. yes
它有三个字段,第一个字段是指定要检查的是来源或目的地,第二个是设定来源,第三个字段为 yes 表示是白名单。以上述内容为例,是设定所有从 friends.net 所寄来的信件都不是垃圾信。另外,我们也可以直接使用 IP 或网域。
17.2.4 MailScanner 进阶管理
在 MailScanner 上线后,我们必须先将设定放松一点,例如在判断是垃圾信时,不要退件或删除,还是先寄给使用者。如果使用者发现不该是垃圾信的邮件被误判,则可以将该信件加入白名单中。经过一段时间的测试都没问题了,再设定将高分数的垃圾信删除、并退回低分数的垃圾信。
当有误判时,我们必须要检查邮件源始档,知道误判原因后,才能将该寄信者加入白名单中。我们来看一下一封垃圾信的标头:
图 17-6

我们可以看到这封信的分数是 7 (有 7 个 s),表示这是垃圾信。如果您觉得判断是否为垃圾信的分数太低,很多不是垃圾信也会被当成垃圾信,则可以将 MailScanner.conf 中的「Required SpamAssassin Score」调低。笔者使用的是 5。
当一封信被判断是垃圾信时,如果您选择将它隔离,则隔离的信件会放在 /var/spool/MailScanner/quarantine 中。当邮件附件中包含不合法的档名时,收信者会收到下列信件:
图 17-7

如果您打附件,则会有下列内容:
This is a message from the MailScanner E-Mail Virus Protection Service
----------------------------------------------------------------------
The original e-mail attachment "netuse.bat"
is on the list of unacceptable attachments for this site and has been
replaced by this warning message.
If you wish to receive a copy of the original attachment, please
e-mail helpdesk and include the whole of this message
in your request. Alternatively, you can call them, with
the contents of this message to hand when you call.
At Sat Oct 1 21:37:13 2005 the virus scanner said:
MailScanner: Batch files are often malicious (netuse.bat)
Note to Help Desk: Look on the twbsd MailScanner in
/var/spool/MailScanner/quarantine/20051001
(message j91Db6xx015931).
--
Postmaster
MailScanner thanks transtec Computers for their support
如果有使用者要求要取回该档案,您可以看一下上列附件的内容,并依它所说明的地址 (以上列为例是 /var/spool/MailScanner/quarantine/20051001/j91Db6xx015931 这个目录) 取回档案。
17.3 Open WebMail
Open WebMail 是一套由国人开发的多国语 Web Base 的邮件软件。它不仅可以让我们从网页上收发信件,还包含了一些强大的功能。例如,拼字检查、行事历、网络硬盘等等。安装它之后,使用者可以从任何计算机经由浏览器收发信件,真的很方便。
17.3.1 系统需求
在安装 Open WebMail 前,你必须先安装具有 CGI 功能的 Apache 服务器,如果你是照本书的说明安装,那么你的服务器就具有这项功能了,只要你有编辑 httpd.conf 将 CGI 的功能启动。除此之外,在开始安装 Open Webmail 之前,我们必须先安装下列套件。
Open WebMail 使用具有 SUID 功能的 suidperl,但由于 suidperl 有危险性,所以 FreeBSD 将 suidperl 的功能关闭了。因此,在安装之前,我们必须先安装具 SUID 功能的 Perl。请注意,由于 Perl 有很多相关的模块,如果您之前有更新过 port tree,则现在要安装的 Perl 版本可能和原本系统中的版本不同,将会造成很多程序无法运作。所以,如果您之前有做过 port 的更新,您应该要使用 portupgrade 来安装 Perl。
我们使用 portupgarde 来安装 Perl,如果您还没有安装 portupgrade,请使用下列指令安装:# cd /usr/ports/sysutils/portupgrade
# make install clean
关于 portupgrade 的说明,请先参考「软件安装」一章。接下来,我们就可以使用 portupgrade 来更新 Perl 了。请先使用 perl -v 来查看您目前所使用的 Port 版本,FreeBSD 6.0 预设是使用 Perl 5.8.x,所以我们使用下列指令更新:# portupgrade -rf "perl-5.8.*" -m "ENABLE_SUIDPERL=yes"
# ln -s /usr/local/bin/suidperl /usr/bin/suidperl
接下来,我们就可以来安装一些 Open WebMail 所需的软件了,如果在安装过程中,您发现这些软件已经安装过了,则可以跳过该软件。首先,为了要有检查附加档案的功能,必须安装 MIME-Base64,我们可以使用下列指令安装:# cd /usr/ports/converters/p5-MIME-Base64
# make install clean
为了具有拼字检查功能,必须安装 ispell,请以 ports 安装:# cd /usr/ports/textproc/ispell
# make install clean
为了要支持 MD5 加密,我们必须安装 perl 的 MD5 模块:# cd /usr/ports/security/p5-MD5
# make install clean
为了要让 Open Webmail 可以有语言转换的能力,我们必须安装Text-Iconvv:# cd /usr/ports/converters/p5-Text-Iconv
# make install clean
另外,还要先安装 libnet 这个网络模块:# cd /usr/ports/net/p5-Net
# make install clean
您的 Apache 必须支持 CGI,请编辑 httpd.conf,找到关于你网页根目录设定的地方,并在 Options 选项中加入 ExecCGI,并设定好 cgi-bin 的所在目录:
#
# This may also be "None", "All", or any combination of "Indexes",
# "Includes", "FollowSymLinks", "ExecCGI", or "MultiViews".
#
# Note that "MultiViews" must be named *explicitly* --- "Options All"
# doesn't give it to you.
#
    Options Indexes FollowSymLinks MultiViews ExecCGI
... 略 ...
ScriptAlias /cgi-bin/ "/home/www/cgi-bin/"
... 略 ...
接着请重新启动 Apache 就做好事前的准备了。
17.3.2 安装 Open WebMail
您可以到下列网址取得最新版的 Open Web Mail。
http://turtle.ee.ncku.edu.tw/openwebmail/download/
假设您网页根目录在 /home/www 中,而在 apache 中所设定的 cgi-bin 目录是在 /home/www/cgi-bin 中。请将取得的档案放到你的网页根目录去,并 cd 到你的网页根目录。执行下列指令以将取得的档案解压缩:# tar -zxvBpf openwebmail-2.51.tar.gz
解压缩后会在 cgi-bin 中产生一个目录为 openwebmail,存放 Open WebMail 的主要程序;另外会产生一个 data 的目录,在 data 目录下也有一个 openwebmail 的目录,该目录存放 openwebmail 非 cgi 的数据(如图片、声音等)。我将 /home/www/data/openwebmail 的目录搬到 /home/www/openwebmail。并将 cgi-bin 目录下的 openwebmail 搬移到 /home/www/cgi-bin 目录中。现在 openwebmail 的 cgi 程序位于 /home/www/cgi-bin/openwebmail 中,非 cgi 档案位于 /home/www/openwebmail 中,我们要记住的就是这二个目录的位置以方便下列的设定。
最后要修改 /home/www/cgi-bin/openwebmail/etc/openwebmail.conf,更改你的参数设定,尤其是路径。基本上要修改的地方有:
# ow_cgidir : openwebmail cgi 程序的目录
ow_cgidir /home/www/cgi-bin/openwebmail
# ow_cgiurl : 以 openwebmail 的 cgi 程序目录所在的 url
ow_cgiurl /cgi-bin/openwebmail
# ow_htmldir : openwebmail 非 cgi 的目录
ow_htmldir /home/www/openwebmail
# ow_htmlurl : 非 cgi 程序所在的 url
ow_htmlurl /openwebmail
我们接着要初始化 Open Webmail,请执行下列指令:# /home/www/cgi-bin/openwebmail/openwebmail-tool.pl --init
您会被要求是否要送出系统信息到 Open Webmail 的总部,如果您不想送出任何数据,只需按 N 即可。最后我们就可以使用 http://yourhost/cgi-bin/openwebmail/openwebmail.pl 来连到登入的首页,请使用系统中的使用者账号 (root 不能登入) 及密码登入,登入后画面如下图所示。
图 17-8

Open WebMail 是台湾人写的软件,它的使用手册非常丰富,您可以点选登入首页的「说明」部份来查看使用手册。

TOP

第十六章 邮件服务器
邮件服务器是因特网上常用的服务器,我们平常收发电子邮件都必须经过邮件服务器。通常一般人都是使用 ISP 或免费的电子邮件信箱,由于这种服务的使用者很多,您的电子邮件账号通常很长,而且不是您所喜欢的名称。例如 ,如果您的名字是 Alex,您大概很难申请到 alex@yahoo.com 这么好记的地址,只能申请到类似 alex0706_tw@yahoo.com 这种又臭又长的信箱。如果您想要有比较好的信箱地址,则必须自行架设一台邮件服务器。
本章将介绍如何使用 FreeBSD 架设邮件服务器,读完本章后,您将可以对邮件服务器的运作更加了解。本章将包含下列主题:
电子邮件的运作原理。
如何架设安全的邮件服务器。
如何架设 POP3 及 IMAP 服务器。
如何设定邮件别名及自动转寄。
如何限制信件大小。
邮件结构及限制寄件者来源。
邮件收发问题处理。
16.1 电子邮件概论
一个电子邮件地址可以分为二个部份,第一个部份是使用者名称,第二个部份是主机名称。以 john@yahoo.com 为例,yahoo.com 就是主机名称,而 john 为使用者名称。john@yahoo.com 可以念作「John at yahoo.com」,翻成中文就是在 yahoo.com 上的使用者 John。
假设 Alex 使用的信箱是 alex@gmail.com,则当 Alex 要寄信给 john@yahoo.com 时,会经过下列步骤:
首先 Alex 从个人计算机中写好一封信,送到他所属的 gmail.com 的主机中。
gmail.com 会先将信件存在自己的机器上的暂存区。
gmail.com 会检查信件目的地,并查找 yahoo.com 的 IP 地址。
接着经由因特网将信件送到 yahoo.com 的主机。
yahoo.com 的主机收到信后,发现是给自己机器中的使用者,所以将信件存放到使用者的新件匣中。
当 John 有空时,从家里打开计算机,并主动去 yahoo.com 检查是否有新的信件,当发现有新的信,则下载到自己的计算机中。
图 16-1

如果 alex@gmail.com 要寄信给 john@gmail.com,因为寄信者和收信者使用同一个邮件服务器,所以在上述步骤二中,gmail.com 的主机发现收信者是自己机器的使用者,则会将该信件存放在使用者的新件匣中。
从寄信到收信的流程中,每一个网络上的组件都扮演着不同的角色,我们分别来谈一下每一个角色的功能:
Mail User Agent (MUA):邮件使用者代理人,这是使用者用来写信、收信的程序。例如,我们常用的 Outlook Exporess、Thunderbird 等。它的作用在于提供使用者一个好用的收发信件接口,并将信传到自己的邮件服务器。
Mail Transfer Agent (MTA):邮件转送代理人,是一个负责转送信件的服务器。UNIX 中使用的 Sendmail、Postfix 就是 MTA 软件。它的作用在于收到 MTU 寄来的信后,根据信件地址,将信件转送到目的地。在目的地中,也有另一台 MTA 会负责接收信件。有时候信件并不会一次就从使用者的计算机传送到目的地的主机,而是会经由许多 MTA 转送到目的地的主机。这种 MTA 接收非自己的信件,并转送到别台 MTA 的动作就叫作「Relay」。
Mail Delivery Agent (MDA):邮件递送代理人,负责将要给本地使用者的邮件分配到使用者的信箱中。在 UNIX 中,MDA 通常是 mail 这支程序。
图 16-2

当我们在寄信时,所使用的是 SMTP (Simple Mail Transfer Protocol) 通讯协议,在一台邮件服务器上,必须要先安装邮件服器软件,以接收 SMTP 协议所寄来的信件。MTA 和 MTA 之间传送信件时也是使用 SMTP 协定。而收信时,使用的是 POP3 (Post Office Protocol) 或是 IMAP (Internet Message Access Protocol) 协定。
一般常用的 SMTP 软件为 FreeBSD 内附的 Sendmail、Qmail、或 Postfix。而收信时所使用的 POP3 及 IMAP 软件 FreeBSD 并未内建,因此我们必须自行安装。然而做为一台 Mail Server,我们要设定的是最少要做到可以正常使用 POP3 及 SMTP 来让使用者收发信。另外,我们也将介绍使用 Web 接口的邮件收发软件,Web 接口的邮件收发软件可以让使用者不必使用 Outlook 等软件即可经由任何操作系统的浏览器轻松收发信件。
传统上,SMTP 在接受使用者寄信时,并不须经过身份认证,任何人都可以使用你的主机来制造垃圾信。因此 FreeBSD 内建的 Sendmail 是不接受 SMTP 寄信的。而一般的 ISP 业者大多是以控制联机来源的方式,禁止非允许网域的使用者 RELAY。但如果我们以控制联机来源的方式,便无法在其它非允许的IP地址使用SMTP,这对于想要任何地方都可以发信的人十分不分便。因此,本章里我们将介绍如何让使用者透过 FreeBSD 使用 SMTP 身份认证的功能来寄信,让要使用诸如 Outlook 以 SMTP 寄信的使用者必须先通过本机的身份认证。
在开始架设邮件服务器之前,您必须先设定好 DNS。由于传送信件时,必须查找目的地主机的 IP。如果您的主机没有合法的 DNS 设定,信件将无法正确送达。假设您要架设一台处理 twbsd.org 的邮件服务器,在 DNS 设定方面有二种方式。第一种是直接将您的主机名称设为 twbsd.org,并设定 DNS 将 twbsd.org 对映到您的主机 IP。第一种方法是使用 DNS 的 MX 设定,将 twbsd.org 的邮件交由另一台主机处理。如果您的 DNS 是交由申请单位代管,则只要到申请单位设定好名称对映即可。如果您要自行架设 DNS 服务器,请参考「DNS 服务器」一章的说明。
另外,您的服务器 IP 也必须设好反解,IP 名称必须和您的主机名称对映,如果反解不正常,有的服务器可能会拒收您所送出的信件。
16.2 具身份认证的 sendmail
本文参考自中央研究院计算器中心张毓麟先生所发表的「具身分认证的邮件传送系统」,该文件的网址是 http://beta.wsl.sinica.edu.tw/~ylchang/Email/sendmail-auth。张先生对于在 FreeBSD 系统上建立安全的邮件服务器有多篇文章,您可以自 http://beta.wsl.sinica.edu.tw/~ylchang/Email/index.html 取得更多内容。
由于本章有许多指令,为了避免打字错误造成安装失败,笔者将这些安装过程写成一个快速安装的程序,您可以自本书光盘二中取出安装。安装方式如下:# mount /cdrom
# cp -R /cdrom/mailserver /tmp/
# cd /tmp/mailserver
# sh mailserver.sh
接着依照画面指示即可快速安装本章具身份认证的 sendmail 了。安装完成之后,您可以使用下列指令以启动 sendmail:# /usr/local/etc/rc.d/saslauthd.sh
# /usr/sbin/sendmail -bd -q30m
如果我们希望在一开机便启动 Sendmail,请在 /etc/rc.conf 中加入下面这一行:
sendmail_enable="YES"
如果您希望自行一步步操作,请依下列各小节的说明来安装,但请特别注意一些标点符号的差异,例如 ` (位于键盘左上角) 及 ' (位于键盘右边) 等符号。笔者建议您如果要自行安装,在输入设定档内容时请使用本书光盘片中的范例,以免打字错误。
16.2.1 安装 Cyrus SASL
SASL (Simple Authentication and Security Layer) 可以让一些通讯协议 (例如 SMTP、IMAP 等) 具有身份认证的功能。Sendmail 自从 8.10 就支持 SASL 的功能。目前 cyrus-sasl 版本是 cyrus-sasl-2.1.21.tar.gz,我们可以 ftp 到各大 FTP 站台的 distfiles 目录下去取得最新版的 cyrus-sasl 或从本书光盘中的 mailserver 目录中取得。取回后以下列指令安装。# tar zxf cyrus-sasl-2.1.21.tar.gz
# cd cyrus-sasl-2.1.21
# ./configure --enable-login --enable-plain
# make
# make install
# cd /usr/lib
# ln -s /usr/local/lib/sasl2 .
# ln -s /usr/local/lib/sasl2 sasl
# ln -s /usr/local/lib/libsasl* .
# echo "pwcheck_method: saslauthd " > /usr/lib/sasl2/Sendmail.conf
接着我们要在一开机时就执行 saslauthd 这支认证用的程序,请新增文件名为 /usr/local/etc/rc.d/saslauthd.sh 的执行档,内容如下:
#!/bin/sh
case $1 in
"start")
        echo "Starting saslauthd"
        /usr/local/sbin/saslauthd -a pam
        ;;
"stop")
        echo "Stoping saslauthd"
        killall saslauthd
        ;;
*)
        echo "Usage $0 start|stop"
        ;;
esac
然后将该档案属性变为可执行,并建立一个 saslauthd 所需使用的工作目录:# chmod 755 /usr/local/etc/rc.d/saslauthd.sh
# mkdir -p /var/state/saslauthd
16.2.2 安装 Sendmail
在安装 Sendmail 之前,如果系统中正在执行旧版的 Sendmail,请先使用以下指令将它停掉:# kill -9 `cat /var/run/sendmail.pid|head -1`
接着请到 www.sendmail.org 去下载最新版的 sendmail,您也可以在光盘二的 /ports/mailserver 目录中找到 Sendmail 8.13.5。Sendmail 自 8.12.0 版起,需要先建立一个使用者smmsp及所属群组供 Sendmail 使用。而 FreeBSD 自从 4.5-RELEASE 起己经内建了该使用者,如果你使用的是 4.5-RELEASE 以前的版本,请先编辑 /etc/group 加入下面一行:
smmsp:*:25:
再来增加使用者,执行 vipw 并增加下面一行:
smmsp:*:25:25::0:0:Sendmail user:/var/spool/clientmqueue:/sbin/nologin
将抓回来的 sendmail.8.13.5.tar.gz 放到 /tmp 底下,并以下列指令解压缩:# tar zxvf sendmail.8.13.5.tar.gz
接着 ee /tmp/sendmail-8.13.5/devtools/Site/site.config.m4 建立档案并加入下列内容:
PREPENDDEF(`confENVDEF', `-DMAP_REGEX')
PREPENDDEF(`confOPTIMIZE', `-O2')
APPENDDEF(`confENVDEF', `-DTCPWRAPPERS -DSASL=2')
APPENDDEF(`conf_sendmail_LIBS', `-lwrap -lsasl2')
APPENDDEF(`confLIBDIRS', `-L/usr/local/lib')
APPENDDEF(`confINCDIRS', `-I/usr/local/include')
APPENDDEF(`confENVDEF', `-DMILTER')
由于上述档案内容中,有很多特殊的符号,为了避免打错字,建议您直接使用本书所附第二片光盘中的 /examples/site.config.m4 。完成后就可以开始安装 Sendmail 了:# cd /tmp/sendmail-8.13.5
# sh Build
# sh Build install
为了要让本地的使用者不必经由身份认证使用 SMTP,还须再做下列设定:# cd /tmp/sendmail-8.13.5/obj*
# cd mail.local
# make force-install
# chown root /usr/libexec/mail.local
# chmod u+s /usr/libexec/mail.local
接下来编辑 sendmail 设定模板档案以便产生出具有身分认证功能的 sendmail.cf 设定文件,请以下列指令执行:# cd /tmp/sendmail-8.13.5/cf/cf
# cp generic-bsd4.4.mc MYCF.mc
# cd ../feature
# cat access_db.m4 >> ../cf/MYCF.mc
# cat delay_checks.m4 >> ../cf/MYCF.mc
# cat virtusertable.m4 >> ../cf/MYCF.mc
# cd ../cf
# cat >> MYCF.mc
TRUST_AUTH_MECH(`LOGIN PLAIN')dnl
define(`confAUTH_MECHANISMS', `LOGIN PLAIN')dnl
^D(同时按Ctrl+D)
上述要增加到 MYCF.mc 的二行字符串,您一样可以在本书所附第二片光盘中的 /examples/ 目录中找到 MYCF.mc.append 。为了避免打字错误,您可以使用下列指令来将上述二行附加在 MYCF.mc 中:# mount /cdrom
# cat /cdrom/example/MYCF.mc.append >> MYCF.mc
接着我们要建立 sendmail.cf:# sh Build MYCF.cf
# cp MYCF.mc /etc/mail/sendmail.mc
# cp MYCF.cf /etc/mail/sendmail.cf
接下来请编辑 /etc/mail/access 这个档案,我们可以在 access 指定哪些 IP 或 domain 来源的机器是否可以经由我们的服务器寄信。如果您希望自己内部网域的机器可以不必使用身份认证,你可以在这个档案中加入内部网域的 IP。
127.0.0.1             RELAY
192.168.0.1        RELAY
# 内部网络不需要认证
192.168.0            RELAY
接着请产生二个 sendmail 所需要的档案:# touch /etc/mail/virtusertable
# touch /etc/mail/aliases
然后请新增 /etc/mail/local-host-names 的档案,里面填入 localhost 以及机器的完整名字 (如 mail.abc.com),当收到信的收件者不是给 mail.abc.com 时便会拒绝。接着,再新增一个档名为 /etc/mail/relay-domains 的档案填入本地的 domainname,例如 mydomain.com,这样一来由本地的 domain 发信时便不需再一次做使用者认证。然后将这些档案做成 sendmail 能接受的 DB 格式:# cd /etc/mail
# makemap hash access.db
# makemap hash virtusertable.db
# newaliases
这样就完成了。您可以执行 sendmail -d0.1 -bv root | grep SASL 应该会出现 SASL 的字样,表示己可认证。
最后,我们可以使用下列指令来启动认证所需的程序及 Sendmail:# /usr/local/etc/rc.d/saslauthd.sh start
# /usr/sbin/sendmail -bd -q30m
在启动 Sendmail 之后,如果执行 telnet localhost 25 ,再打ehlo localhost,我们应该看到一堆 250- 开头的讯息,其中有一行 250-AUTH LOGIN PLAIN 就代表 Sendmail 己经具有身份认证的功能,此时请输入 quit 结束。万一没有出现,请阅读 /var/log/maillog 里面的讯息可以知道错在哪里。# telnet localhost 25
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 vmware.alexwang.com ESMTP Sendmail 8.13.5/8.13.5; Sat, 24 Sep 2005 19:16:09 +0800 (CST)
ehlo localhost  
250-vmware.alexwang.com Hello localhost [127.0.0.1], pleased to meet you
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-EXPN
250-VERB
250-8BITMIME
250-SIZE
250-DSN
250-ETRN
250-AUTH LOGIN PLAIN  quit  
221 2.0.0 vmware.alexwang.com closing connection
Connection closed by foreign host.
如果我们希望在一开机便启动 Sendmail,请在 /etc/rc.conf 中加入下面这一行:
sendmail_enable="YES"
16.2.3 Client 端的设定
微软的 outlook 由 4.0 版开始支持发信时身分认证功能,只要在 outlook 的设定里面将『外寄邮件服务器需要查验身分』的选项打勾就可以了。
第一步骤,选取『工具』菜单的『账号』选项:
图 16-3

第二步骤,选取账号选单中的『内容』按钮:
图 16-4

步骤三,将『外寄邮件服务器需要查验身分』功能项打勾:
图 16-5

按确定钮回到 outlook 中,即可使用身分认证功能发信。
16.3 POP3 及 IMAP 设定
传统上使用 Outlook 等收信软件时,我们会使用 POP3 来下载服务器上的信件。使用者有新的信件时,该信件会存放于 /var/mail/username 中,这个档案我们称之为 inbox。当我们使用 POP3 收信软件下载信件时,在下载完毕后,除非我们有设定在服务器上保留原本的信件,否则预设会在下载后自动将该信件自服务器中移除,以节省空间。
然而,如果您平常使用多台计算机,或是想在不同的地方依然可以看到之前的信件,则 POP3 就不太符合需求。除了 POP3 外,还有一个邮件通讯协议名为 IMAP。IMAP 和 POP3 最主要的差异在于 IMAP 一开始只下载信件标题,直到点选该信件后,它才会将信件下载至您所使用的计算机中。而在下载之后,IMAP 并不会将服务器上的邮件删除,所有浏览过的信件依然保存于 /var/mail/username 中。随着信件越来越多,inbox 的资料也会越来越大。此时我们可以使用 IMAP 建立新信夹的功能,在使用者家目录中建立许多新的数据夹,并将 inbox 的信件移至新建立的数据夹中,以减少 inbox 的大小,并加快收信的速度。而且,当我们寄出新信件时,若使用 POP3 协定,则寄件备份只会存放于您寄信时所使用的计算机中,但 IMAP 则会将寄件备份存于于服务器中。因此,如果您常使用多台不同的计算机收信,使用 IMAP 会蛮方便的,但 IMAP 在使用上速度会比 POP3 慢。
本章中,我们将介绍二种不同的 POP3 及 IMAP 收信软件,您可以依自己的需求安装合适的软件。
16.3.1 简单的 POP3 服务器
POP3 的设定很简单,我们只要选一个喜欢的 pop3 软件,以 ports 安装完后再做一些设定就好了。在这里我选用 popa3d:# cd /usr/ports/mail/popa3d
# make install clean
接着编辑 /etc/inetd.conf,找到 pop3 的部份,将开头的 # 拿掉后,并加以修改如下:
#
# example entry for the optional pop3 server
#
pop3    stream  tcp     nowait  root    /usr/local/libexec/popa3d       popa3d
接着重新跑 inetd 即可:# kill -HUP `cat /var/run/inetd.pid`
16.3.2 加密的 POP3 及 IMAP
在 FreeBSD ports 中,收录了许多 IMAP 及 POP3 的软件,我们选择了 IMAP-UW 这套软件来安装。IMAP-UW 不仅支持 IMAP 及 POP3,我们也可以设定要求使用加密过的 POP3 及 IMAP-UW 以加强密码及信件传送的安全性。首先,请使用下列指令安装 IMAP-UW:# cd /usr/ports/mail/imap-uw
# make WITH_SSL_AND_PLAINTEXT=yes install
接下来,我们要产生 IMAP 及 POP3 所需使用的 SSL 凭证:# cd /usr/ports/mail/imap-uw
# make cert
接着屏幕会出现一些问题,请依序回答:
输入国家代码,例如 TW。
Country Name (2 letter code) [NO]:TW
输入所在省份,例如 Taiwan。
State or Province Name (full name) [Some-State]:Taiwan
输入所在城市,例如 Taipei。
Locality Name (eg, city) []:Taipei
输入您的组织名称,你可以输入公司或学校名称,或直接按 Enter 即可。
Organization Name (eg, company) [FooBar Inc.]:My Company
输入单位名称,可以直接按 Enter 跳过。
Organizational Unit Name (eg, section) []:
输入您的机器完整名称,也就是您在 Outlook 等收信软件中所设定的服务器名称。
Common Name (FQDN of your server) []:mydomain.com
接下来我们必须设定一下 /etc/inetd.conf,并加入 POP3 及 IMAP 的相关设定:
pop3        stream        tcp        nowait        root        /usr/local/libexec/ipop3d        ipop3d
imap4        stream        tcp        nowait        root        /usr/local/libexec/imapd        imapd
pop3s        stream        tcp        nowait        root        /usr/local/libexec/ipop3d        ipop3d
imaps        stream        tcp        nowait        root        /usr/local/libexec/imapd        imapd
若您在开机时并未执行 inetd,请在 /etc/rc.conf 中加入下列设定:
inetd_enable="YES"
若您已启动 inetd,则设定完 inetd.conf 之后,我们必须重新启动 inetd:# kill -HUP `cat /var/run/inetd.pid`
现在我们就可以设定使用 Outlook 来收发。如果您想使用加密的 IMAP 或 POP3 联机,您可以在设定完新的邮件账号后,点选内容,并选取 [进阶] 的部份,将 [这个服务器需要安全联机] 打勾,即可设 IMAP 或 POP3 收信时使用加密的联机。
图 16-6

16.4 进阶邮件服务器设定
架设邮件服务器只是服务器管理的第一步,后续的维护更是重要。好的系统管理者不仅仅是把机器架好,而是要管理好系统安全、解决使用者问题、并尽可能满足使用者需求。因此,我们接下来必须说明服务器的进阶管理议题,在使用者有问题时,我们才知道要如何处理。
16.4.1 设定邮件别名及自动转寄
当有同事离职时,我们常会被要求将该同事的信件转给某人。这种自动转寄的功能在 Sendmail 中很容易就可以做到,我们只要设定 /etc/aliases 即可。
/etc/aliases 是用以告知 sendmail 要将信转给哪个使用者或是交由哪个程序处理。aliases 这个档案是用来设定邮件的别名,也就是可以设定要将某人的信件转给其它地方(人员或程序),你也可以同时将某人的信转给很多人。这个档案的位置是由 sendmail.cf 档案中的 AliasFile 这个选项所决定的。当 sendmail 收到信时,会一行一行比对,当第一行符合后,就不会再继续下去,所以应注意优先级。
我们来看下列几个设定的范例:
#本档案的语法开头的 "#" 代表该行是批注,大小写都视为一样。
# 范例一
root: alex
# 范例二
john: alex,john
# 范例三
webmanager: alex,jack,jim@other.hostname.com
# 范例四
nobody: /dev/null
# 范例五
homework: |/usr/local/bin/homework.sh
# 范例六
olduser: :include: /usr/local/olduser_list
范例一是将寄给 root 的信转给本机中的使用者 alex。
范例二是将寄给 john 的信转给本机中的使用者 alex 及 john,也就是除了原本的 john 外,alex 也会收到寄给 john 的信。
范例三是将寄给 webmanager 的信转给本地的使用者 alex,jack及 jim@other.hostname.com
范例四是将寄给 nobody 的信直接丢掉,丢入 /dev/null 这个无底深渊,也就是所有给 nobody 的信都直接删除。
范例五是将寄给 homework 的信交给 /usr/local/bin/homework.sh 这支程序处理。
范例六是将寄给 olduser 的信转给档案 /usr/local/olduser_list中所列出的所有使用者。olduser_list 为使用者清单的文字文件。
当设定了一堆复杂的别名之后,我们要看最后信会寄到哪里时,可以使用下面指令来看寄给 username 的信最后寄给谁:# sendmail -bv username
aliases 档中将很多东西都转向 root,因此你可以去读 root 的信箱或是将 root 的信转给别的地方,下面这一行是将 root 的信都转给 my@my.domain:
root:        me@my.domain
当邮件无法送出被退回时给使用者时,都是以 MAILER-DEAMON 为账号寄出。因为使用者可能会回复那封被退回的信,所以这个别名是必备的。而 postmaster 则负责处理所有关于邮件问题的信件,因此也是必备的,一定要保留下面二行,这是必要的系统基本设定:
MAILER-DAEMON: postmaster
postmaster: root
请注意,修改完 /etc/aliases 后,我们必须使用下列指令来让所做的修改在 Sendmail 中发生作用:# newaliases
16.4.2 一舨使用者设定自动转寄及自动回信
除了管理者可以经由设定 /etc/aliases 来转信使用者的信件外,一般使用者也可以设定将寄给自己的信转寄一份给其它人。
一般使用者只要在自己的家目录中新增一个档名为 .forward 的档案,并设定要转寄的对象即可。以下为 .forward 的设定范例:
\alex
alexwang@yahoo.com
如果我们在使用者 john 的家目录中新的上述的 .forward 档,则所有寄给 john 的信都会转寄给本机的 alex 及 alexwang@yahoo.com。我们必须要注意的是在上述的设定中,使用者 john 并不会收到寄给自己的信。如果自己也要收到信的设,必须在 .forward 檔中加入自己的名字。
另外,如果您要出国旅游,可能有很长的一段时间无法收信,并希望当有人寄信给您时,系统能自动回信告诉寄件者,则可以使用 .forward 的功能加上 vacation 这个指令来达成。
假设您的使用者名称是 alex,首先,我们先在 alex 的家目录下新增档案 .forward,其内容如下:
\alex
"|/usr/bin/vacation alex"
接着,我们要在家目录下新增档案 .vacation.msg 并加入下列内容:
From: "Alex Wang"
Subject: I am on vacation now
Hello,
I will not be reading my mail for a while.
Your mail will be read when I return.
Thanks,
Alex
如果有人寄信给 alex 的话,除了 alex 会收到信外,寄件者也会收到一封标题为「I am on vacation now」的信,内容就是 .vacation.msg 中的内容。
vacation 这个指令名字取的很有趣,作者大概认为无法收信就是渡假去了。我们在 .forward 档中设定了当有信件进来时,就交由 vacation 去处理,而 vacation 会自动将 .vacation.msg 的内容回复给寄件者,这样就达到了自动回信的功能了。

小提示
一般使用者可以经由设定 .forward 及 .vacation.msg 来自动回信,但是这种设定方式对于一般使用者而言可能不太方便。我们可以使用下一章要介绍的 Openwebmail 来提供从网页中设定自动回复的功能。
16.4.3 限制每封邮件大小上限
不论您的系统硬盘多大、网络多快,在复杂的网络世界中,难保没有人会恶意寄送大型邮件来灌瀑您的信箱。不论如何,我们还是应该要做好基本的防护。在 Sendmail 的设定档中,可以让我们限制接收的邮件大小。
如果您要限制接收信件的大小,可以修改 /etc/mail/sendmail.cf,将下列项目开头的批注移除:
# maximum message size
O MaxMessageSize=5000000
我们限制最大的信件大小为 5000000 bytes (即 5MB)。修改完后,您必须重新启动 sendmail 设定才会生效。# killall sendmail
# /usr/sbin/sendmail -bd -q30m
16.5 邮件问题处理
在管理邮件服务器时,我们常会遇到使用者报怨信件无法送出、信件收不到、寄信出现错误等等。在遇到这类问题时,我们必须具备问题追踪的能力,以协助使用者解决寄信的问题。
在处理收发信件问题时,您可能必须查询 DNS 的设定、了解邮件结构。在说明如何处理收发信件问题前,我们先来了解一些基本的邮件管理知识。
16.5.1 邮件结构
Sendmail 会将所有的使用者新收到的信件放在 /var/mail 中,并将使用者刚寄出的信放在 /var/spool/mqueue 中。在 /var/mail 目录中,每个使用者的新件匣都是一个和使用者名称一样的档案。例如,使用者 alex 的新件匣是 /var/mail/alex、使用者 john 的新件匣是 /var/mail/john。当我们使用 Outlook 或 webmail 收信时,随然我们看到的是一封封的邮件,但在系统中,这些邮件是以纯文字模式全部存放在同一个档案中。所以,当使用者的信件很多时,该档案会越来越大,在使用 IMAP 或 webmail 收信时,速度也会变得比较慢。
由于 /var/mail 及 /var/spool/mqueue 中的信件都是以纯文字格式存放信件,管理者可以直接使用任何文书编辑软件打开使用者的信箱。因此,管理者本身的操守很重要,否则所有人的机密都会被看见。
为了了解一封信的结构,我们还是要看一下信件的内容。您可以打开 /var/mail 目录中自己的信件,或是在 Outlook Express 中对着信按右键 -> [内容],再选 [详细资料] -> [邮件原始文件],即下图示:
图 16-7

接下来,我们可以看到一个邮件原始数据如下:
# Return-Path 表示要回信则会回给 edm@ebp.eracom.com.tw
Return-Path:
# 这是由 alexwang.com 的 Sendmail 所产生的标头。表示信件是由 ebp135.eranet.net
# 所寄出,并由 alexwang.com 处理此信件。
Received: from eracom.com.tw (ebp135.eranet.net [203.95.231.171])
        by alexwang.com (8.13.5/8.13.5) with ESMTP id j8QE1IpL059750
        for ; Mon, 26 Sep 2005 22:01:24 +0800 (CST)
# 这是由 eracom 的邮件软件所产生的标头。
Received: from mail pickup service by eracom with Microsoft SMTPSVC;
         Mon, 26 Sep 2005 22:01:25 +0800
# Thread-index 及 Thread-Topic 是用来在回信时让客户端的软件判断信件是和哪几封信
# 同一个主题用的。
thread-index: AcXCg/dY0ifrCKOiTJO8PTlqFlJD/A==
Thread-Topic: =?big5?B?pn6lTrDiVkqvqVPVIp9yp2qq6xV2kT6FJsXqkU6vnr+A=?=
        =?big5?B?v/m5TA==?=
# From 是寄件者的名称及 Email。
From: =?big5?B?pn6lTrDisrw=?=
# 这是收件者的信箱。
To:
# CC 是复本收件者。
Cc:
# Subject 是本封信件的主题。
Subject: =?big5?B?pn6lTrDisrwgLqvmhqVPVIp9yp2qq6xV2kT6FJsXqkU6vnr+A=?=
        =?big5?B?v/m5TA==?=
# Date 是收信的时间。
Date: Mon, 26 Sep 2005 18:20:49 +0800
# Message-ID 是由发信软件所产的邮件编号。
Message-ID:
# 此封邮件所使用的 MIME 版本。
MIME-Version: 1.0
# 邮件内容格式。
Content-Type: multipart/alternative;
        boundary="----=_NextPart_000_9A3D5_01C5C2C7.057BB140"
# 邮件的优先级。
Priority: normal
# 表示这是 multi-part MIME 格式的邮件。
This is a multi-part message in MIME format.
# 以下为邮件本文
... 略 ...
我们可以从邮件的标头中看到信件真正的来源。有的邮件来源可能会假造,我们也可以从邮件的标头中看出来。
16.5.2 限制寄件者来源
邮件信箱用久了,难免会收到垃圾信。如果您常收到垃圾信,或是想要阻挡某一个网域寄来的信件,最简单的做法是使用 Sendmail 内建的阻挡功能。
我们可以经由设定 /etc/mail/access 来阻挡某个网域的信件。以下是几个设定的范例:
192.168                RELAY
free.spammail.com      REJECT
cyperspammer.com       550 We don't accept from spammers
somespammer.com        DISCARD
sendmail.org           OK
/etc/mail/access 的格式是先列出网域、网址、或 Email,再加上 DISCARD、REJECT、RELAY、OK、或是一串有错误代码的讯息。如果是 OK,表示可以寄信到这一台机器中,这是默认值,所以我们很少用到 OK 这个关键词。而 RELAY 表示可以使用这台机器送信到其它的机器。REJECT 表示不可以使用这台机器的邮件服器。DISCARD 表示将信收下,并直接删除,寄件者会以为信件正常被送出。550 加上一个字符串表示响应此字符串给寄件者。
在设定完 /etc/mail/access 后,我们必须执行下列指令,以将该档案做成 Sendmail 所使用的数据文件:# makemap hash /etc/mail/access
我们当我们收到垃圾信时,寄件者往往是假造的,但我们还是可以从邮件标头中看出该信件的真正来源。以下列标头为例:
Received: from hoho88_nserver.cx (10p2.ppp.odn.ad.jp [219.66.191.46])
by alexwang.com (8.13.1/8.13.1) with SMTP id j8P6ke57004728
for ; Sun, 25 Sep 2005 14:46:40 +0800 (CST)
Date: Sun, 25 Sep 2005 14:46:40 +0800 (CST)
Delivered-To:
Message-ID: 20030120467mail@mail.hi9658754215_starweb88_mainserver.cx
From: mikas_mail_0911@yahoo.co.jp
To: alex@alexwang.com
Subject: =?iso-2022-jp?B?gXWCqJCimGKCyYLIgsGCxIKoguiC3IK3gUk=?=
MIME-Version: 1.0
Content-Type: text/plain;
charset="iso-2022-jp"
我们可以看到虽然寄件者是 mikas_0911@yahoo.co.jp、发信的主机是 hoho88_nserver.cx,但实际上是的来源 IP 是 219.66.191.46,这个 IP 就是我们要阻挡的地址。或者,您可以阻挡整个 ppp.odn.ad.jp 的信件。
16.5.3 处理未寄出之信件
系统中所有未寄出的信件都会放在 /var/spool/mqueue 中,在该目录中,一封未寄出的信会有二个档案,这二个档案包含了原始信件及寄件失败的原因。我们可以使用下列指令列出所有未寄出的信件。# mailq
               /var/spool/mqueue (1 request)
-----Q-ID----- --Size-- -----Q-Time----- ------------Sender/Recipient-----------
j8NFunJe071657    15472 Fri Sep 23 23:56
                (Deferred: Connection refused by mail.somewhere.com.)
                                       
               Total requests: 1
我们可以看到有一封信未送出,原因是被 mail.somewhere.com 拒绝了。
一般而言,Sendmail 每隔一段时间 (依启动 Sendmail 所加的 -q 参数而决定) 会自动重新送出队列中的信件,最后都无法送出则会通知寄件者。如果您要立即重新送出队列中的信件,可以使用下列指令:# sendmail -qf
如果您要删除某一封在队列中的信件,请先使用 mailq 查看 Q-ID,再到 /var/spool/mqueue 中删除 qfXXXX 及 dfXXXX 的档案,其中 XXXX 是您要删除的 Q-ID。
16.5.4 收发信件问题处理
电子邮件在现在的企业中使用非常频繁,很多公司几乎所有事务都经由电子邮件处理,收发信不正常往往是 MIS 人员的恶梦。很多时候问题可能不是出现在邮件服务器本身,而是网络设定、DNS 问题、或是对方服务器的问题。当您遇到收发信件问题时,就必须要从系统记录、发信软件中查出蛛丝马迹。在检查问题之前,请先确认您的邮件服务器的 DNS 设定没问题,而且邮件服务器 IP 和主机名称正反解都正确。DNS 设定不正常的服务器往往是不能收发信件的主因。
发信问题处理
在发信问题方面,如果您使用发信软件寄不出信件,请先检查发信软件所秀出的讯息,再找解决之道。通常发信问题可以分为二类,一种是在使用 Outlook Express 送信时就已经送不出去,另一种是信送出了,但对方没收到。第一种问题比较好解决,我们只要看 Outlook Express 的错误讯息即可看出端倪。以下列讯息为例:
图 16-8

我们可以看到错误讯息中有「Relaying denied. Proper authentication required.」,很明显的是因为这一台服务器必须经过身份认证后才可以使用,我们只要在送信设定中使用身份认证即可。在 Outlook Express 的讯息中,也有可能出现类似 DNS 找不到、主机找不到、使用者不存在等问题。我们只要依这些讯息来查看设定、Email 地址,即可找到原因。
第二种问题是信件寄出了,但是对方没收到。这种情形,我们就必须要多花点心力了。首先,我们先到服务器上 /var/spool/mqueue 查看信件是否在队列中。如果在,则查看一下送出去出的原因,并依错误讯息解决问题。如果从错误讯息中看不出问题,则可以查阅 /var/log/maillog,并找出该信件的寄送讯息:
Sep 23 00:22:42 mail sendmail[22426]: j8MGMKkE022408:
to=john@myfriend.com, ctladdr=john@myfriend.com (1029/501),
delay=00:00:22, xdelay=00:00:05, mailer=esmtp, mailer=esmtp,
relay=alexwang.com, dsn=5.1.2, stat=Host unknown (Name server:
myfriend.com: host not found)
以上述范例为例,就是因为找不到 myfriend.com 这台主机。这时候,我们可以手动使用 nslookup 查找该主机,并检查 DNS 的设定是否有问题。如果是 DNS 主机的问题,则可以更换 DNS 服务器设定。
如果收件者的服务器有安装防垃圾信软件,有的时候我们的服务器所使用的 IP 可能会因为某些列为垃圾信。在发信后,您可能会收到下列退信:
----- The following addresses had permanent fatal errors -----
(reason: 554 EMail from mailserver at 10.22.102.129 is refused.
See
http://spamblock.outblaze.com/10.22.102.129)
----- Transcript of session follows -----
... while talking to sultant-com.outblaze.com.:
>>> DATA
这时候我们就必须依该信件指示,到该黑名单网站中要求对方将我们的 IP 从黑名单中移除。
如果从 /var/log/maillog 中确认信已经从本机寄出而对方还是没收到,则接下来就要请对方 MIS 人员查看对方服务器是否有问题了。
总结关于发信问题处理步骤如下:
检查 DNS 设定。
查看发信软件的错误讯息。
检查服务器的队列。
查看 /var/log/maillog。
依联机记录找出问题并解决。
收信问题处理
在收信问题方面,和发信问题一样,最关键的还是 DNS 设定。我们必须先检查客户端所使用的计算机是不是可以正常的找到邮件服务器。如果找不到,则必须修改 DNS 设定。
接下来,必须确认客户端的发信软件有连到服务器,并可以正常使用 POP3 或 IMAP。如果在联机时出现错误,您一样可以从 /var/log/maillog 中看出问题。以下列联机记录为例:
Sep 23 02:16:12 mail sm-mta-in[24776]: j8MV5024776: ruleset=check_rcpt,
arg1=, relay=[219.93.1.218], reject=550 5.7.1
... Relaying denied. IP name lookup failed
从记录中,我们可以看出来是因为反查 mail1.stofane.dk 失败,所以我们的服务器拒收此封信件。这就是为什么邮件服务器最好还是要设定好 IP 反查的原因。
如果有人抱怨一直没有收到客户寄来的信,我们可以从 /var/log/maillog 中找出该寄件者到底有没有将信件寄到我们的服务器。如果没有,则可以请对方检查邮件信箱是否正确、对方服务器中是否有其它讯息。

TOP

第十五章 FTP 服务器
FTP (File Transfer Protocol) 是常用的网络协议,主要的功能是用来传输档案,我们时常从 FTP 站台下载档案。本章将介绍如何使用 FreeBSD 架设 FTP 服务器,并说明各种 FTP 服务器的管理技巧。本章除了 FreeBSD 内附的 FTP 服务器软件外,并将介绍笔者开发的 SmbFTPD。读完本章后,您将进一步了解下列主题:
FTP 协定的运作方法。
如何使用 FreeBSD FTP。
加强权限控制以建立安全的 FTP 服务器。
安装设定 SmbFTPD。
如何使用具 SSL 加密的 FTP。
如何进行流量控制。
15.1 FTP 概论
FTP 是一个历史悠久的网络通讯协议,和大多数的网络协议一样,它采用 Client/Server 架构,各地的使用者可以经由网络连到服务器上传或下载档案。FTP 协议比较特别的地方在于它在使用时必须建立二个联机:一个用来传输指令、一个用来传输档案。
图 15-1

当我们使用 FTP 软件连到 FTP 服务器时,客户端会先连到服务器的连接埠 21,并建立一条「控制联机」(Control Stream)。接下来,您会输入账号、密码等指令,这些指令及 FTP 的响应都是使用都是使用「控制联机」。当您要下载档案时,或者是执行 ls 以列出目录中的档案时,档案或目录列表的下载是经另一个联机「数据联机」(Data Stream)。「数据联机」和「控制联机」不同的是数据联机所传输的数据比较大,而控制联机只是用来传输指令及简单的响应。
基本上,一个完整的 FTP 联机建立过程为:
客户端打开自已机器大于 1024 的连接埠,并连到服务器的连接埠 21,建立「控制联机」。
客户端开始对服务器下指令,告诉服务器客户端用来传输档案的连接埠为何。
服务器从连接埠 20 连到客户端所开放的埠号 (大于 1024),以建立「数据联机」。
上述这种联机建立的方式是由服务器主动建立「数据联机」,我们称之为「主动模式」(Active Mode)。基本上主动模式的运作在没有防火墙或 NAT 的情形下没有什么问题,但若客户端有防火墙,则可能会无法建立联机。
图 15-2

因为「控制联机」是由客户端主动连到服务器,所以在客户端有防火墙或 NAT 时,还是可以连到服务器。接下来在建立「数据联机」时,客户端会从「控制联机」中告诉服务器它的 IP 及埠号,请服务器连过来。但是由于客户端有防火墙,所以服务器要连到客户端时会失败,而无法建立联机。
基本上,如果客户端使用的是 FreeBSD 的 NAT 不会有这种问题,FreeBSD 会自动做转换,但若是使用其它的防火墙就不一定可以支持 FTP 的 Active Mode。
何谓 Passive Mode
要解决 FTP Active Mode 的问题,可以在联机时改用「被动模式」(Passive Mode)。所谓的被动模式就是由服务器打开一个连接埠,被动地等客户端连过来建立「数据联机」。被动模式的联机建立过程为:
客户端打开自已机器大于 1024 的连接埠,并连到服务器的连接埠 21,建立「控制联机」。
客户端开始对服务器下指令,告诉服务器进入「被动模式」。
服务器打开一个大于 1024 的连接埠,等待客户端的联机。
客伺端打开自已机器大于 1024 的连接埠,并连到服务器以建立「数据联机」。
图 15-3

由于控制联机及数据联机都是由客户端主动连过去服务器,如此即可避开防火墙及 NAT 的问题。我们来看看如何判断联机失败是否因为主动模式的原因:# ftp ftp.freebsd.org
Trying 204.152.184.73...
Connected to ftp.freebsd.org (204.152.184.73).
220 Welcome to freebsd.isc.org.
Name (ftp.freebsd.org:alex): anonymous
331 Please specify the password.
Password:
230-
230-You have reached the freebsd.isc.org FTP server, serving the
230-full FreeBSD FTP archive over IPv4 (204.152.184.73) and IPv6
230-(2001:4f8:0:2::e) networks. This server is also known as:
230-
230- ftp.freebsd.org
230- ftp4.freebsd.org
230- ftp4.us.freebsd.org
230-
230-This server is operated by Internet Systems Consortium (ISC),
230-on behalf of the FreeBSD Project, with hardware donations from
230-Apple, Intel and Iron Systems.
230-
230-Questions about this service can be sent to: freebsd@isc.org.
230-
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
^C
ftp> passive
Passive mode on
ftp> ls
227 Entering Passive Mode (204,152,184,73,54,200)
150 Here comes the directory listing.
drwxrwxr-x 3 0 0 512 Apr 17 2003 pub
226 Directory send OK.
ftp>
当您登入一台 FTP 服务器后,如果您输入 ls,却等了很久都没有响应,您可以输入 +C 以中断命令。接着输入 passive 以进入被动模式,再打 ls 就可以看到目录内容,则无法联机的问题一定是主动模式的原故。
15.2 设定 FTP 服务器
FreeBSD 内建有 FTP 服务器的功能,如果您要使用内建的 ftpd,我们不需要特别进行任何安装的动作,只要做好设定即可。本小节中,我们将介绍如何设定启动 FTP 服务器的功能,并进行一些基本的配置。
15.2.1 启动 FTP 服务器
我们有二种方式启动 ftpd,一种是使用 standalone daemon,另一种是使用 inetd。inetd 是 UNIX 系统中一个强大的「超级服务器」,我们可以使用它来管理许多系统服务,例如 telnet、ssh、ftp 等。大部份的系统服务都是使用 inetd 来启动,使用它的好处在于可以统一管理各种服务,并经由它来设定服务规则,例如是否要阻挡某些 IP 来源等。不过,使用 inetd 的方式缺点是每次有联机要求时,inetd 的 daemon 必须依联机的种类去执行相对映的指令,所以速度比较慢。
另一种启动 FTP 的方式是使用 standalone daemon,也就是直接执行 FTP daemon,当它接收到新的联机时,就 fork() 出来处理,这种方式联机建立的速度较快,比较适合专门的 FTP 服务器。
使用 inetd
我们先来介绍如何使用 inetd 的方式启动 FTP 服务器。首先,请编辑 /etc/inetd.conf,将 ftp 设定开头的 # 移除:
ftp     stream  tcp     nowait  root    /usr/libexec/ftpd       ftpd -l
ftp     stream  tcp6    nowait  root    /usr/libexec/ftpd       ftpd -l
接下来,我们必须使用下列指令重跑 inetd:# kill -1 `cat /var/run/inetd.pid`
现在您就可以开始使用 FreeBSD 的 FTP 服务了。
使用独立 Daemon
如果您要以独立的 daemon 方式启动 FTP,请先确定在 inetd.conf 中没有启动 FTP 服务。接下来,请在新增一个档案 /usr/local/etc/rc.d/ftpd.sh 内容如下:
#!/bin/sh
ftpd_program="/usr/libexec/ftpd"
ftpd_flags="-D -l"
case $1 in
start)
        echo "Starting FTPD"
        $ftpd_program $ftpd_flags
;;
stop)
        echo "Stopping FTPD"
        killall ftpd
;;
restart)
        $0 stop
        sleep 1
        $0 start
;;
esac
编辑完后,我们必须将该档案变成可执行:# chmod 755 /usr/local/etc/rc.d/ftpd.sh
接下来,您就可以使用下列指令启动 FTPD 了:# /usr/local/etc/rc.d/ftpd.sh start
如果您要停止 FTPD 服务,则使用下列指令:# /usr/local/etc/rc.d/ftpd.sh start
15.2.2 编辑欢迎讯息
当我们联机到一个 FTP 站台时,我们可以看到二个欢迎讯息,一个是登入前的讯息,另一个是登入后的讯息。以下列讯息为例:# ftp localhost
Trying ::1...
Connected to localhost.alexwang.com.
220- Welcome to My FTP Server.
220-
220- This is a welcome message
220-
220- Nice to see you.
220 vmware.alexwang.com FTP server (Version 6.00LS) ready.
Name (localhost:alex):
331 Password required for alex.
Password:
230- This is the message of the day.
230-
230- It will be shown after user login.
230 User alex logged in.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>
开头为 220- 的就是登入前的讯息,我们称它为欢迎讯息。以 230- 为开头的是登入后的讯息,我们称它为本日讯息 (Message of the day)。这二种讯息我们都可以自行设定。
如果您要设定的是登入前的讯息,请新增一个档案 /etc/ftpwelcome,并将您的讯息写入该文件中。以下为上述范例中的讯息内容:
Welcome to My FTP Server.
This is a welcome message
Nice to see you.
您不需要写 220- 等数据,FTP 服务器会自动帮您加上这种代码。而登入后的讯息是存放在 /etc/ftpmotd,您可以编辑该档以进行设定。
15.2.3 FTP 服务器管理
在启动 FTP 服务器时,我们可以加入一些参数以调整服务器的行为。例如,修改预设的连接端口、记录使用者上传、下载的档案等等。有些参数必须要在使用独立的 daemon 方式启动时才有用,而有的参数在 inetd 模式下也可以使用。
下表为我们常用的参数:
参数
是否只能在 Daemon 模式下使用
意义
-a

当您有二张网络卡或是二个 IP 时,我们可以设定只接受联机到某一个 IP 的联机要求。例如:
ftpd -D -a 192.168.0.1
此范例表示只接受使用者联机到 192.168.0.1 这个 IP。
-d

记录 FTP 的除错讯息。除了加入这个参数外,您必须修改 /etc/syslog.conf,并加入下列内容以记录 FTP 的讯息。
!ftpd
*.*                    /var/log/ftpd.log
-h

不要显示 FTP 服务器的主机名称、软件信息、版本等。
-l

记录 FTP 登入成功及失败的讯息。如果您使用二次 -l,则使用者上传、下载、删除、建立目录时都会留下记录。预设的记录会留在 /var/log/xferlog 中。
-P

我们知道 FTP 预设会监听连接埠 21,以接受客户端的联机要求。不过如果您是以独立的 daemon 方式启动 FTP,则 可以使用 -P 加上连接埠号以改变预设连接埠。
另外,还有很多用来控制使用者权限的参数,我们会在下一小节中说明。您也可以使用 man ftpd 以查看更多关于 ftpd 的参数。
如果您要修改 ftpd 启动的参数,在 inetd 模式下,您可以修改 /etc/inetd.conf,并在 ftp 设定的最后面加入参数,如下列粗体字所示:
ftp  stream  tcp     nowait  root   /usr/libexec/ftpd    ftpd -l -l -d
ftp  stream  tcp6    nowait  root   /usr/libexec/ftpd    ftpd -l -l -d
上面的范例中,我们多加入了参数 -l -d,以记录更多 ftpd 的讯息。
如果您是以独立的 Daemon 方式启动 ftpd,则请修改 /usr/local/etc/rc.d/ftpd.sh:
#!/bin/sh
ftpd_program="/usr/libexec/ftpd"
ftpd_flags="-D -l -l -d"
...
我们只要修改 ftpd_flags 的部份,加入您所要的参数即可。
15.3 FTP 权限控制
预设的 FTP 启动后,使用者可以上传、下载任何他们有权存取的档案。在登入后,使用者可以进到任何系统中的目录 (如果目录权限允许的话)。本小节将告诉您一些 FTP 读写权限的控制,让您可以更进一步控制服务器的系统安全。
15.3.1 限制账号与联机来源
我们可以设定限制某些账号不可以使用 FTP 登入。使用者在登入 FTP 服务器时,有几个规则会拒绝该账号登入:
如果 /var/run/nologin 存在,则所有账号都不可以登入。这个档案可以用来暂时停止 FTP 服务。
使用者一定要有密码才能登入,没有密码的使用者无法登入。
使用者名称不可以出现在 /etc/ftpusers 中。
使用者群组不可以出现在 /etc/ftpusers 中。
使用者所使用的 shell 必须要时合法的 shell。合法的 shell 会被定义在 /etc/shells 中。
除了匿名模式外,使用者名称不可以是 ftp 或 anonymous。关于匿名模式,我们会在下一小节中说明。
/etc/ftpusers 定义了不可以使用 FTP 服务的使用者及群组。我们来看一下该档案的内容:
# $FreeBSD: src/etc/ftpusers,v 1.13 2004/06/30 16:47:08 maxim Exp $
#
# list of users disallowed any ftp access.
# read by ftpd(8).
root
toor
daemon
operator
bin
tty
kmem
games
news
@guest
...
我们可以看到该档案中已经有一些使用者不可以登入 FTP。这些使用者都是系统预设的账号,我们也可以经由修改它来加入其它使用者。
在 /etc/ftpusers 中,如果开头是 "@" 表示群组名称。例如上述档案内容中的 @guest 表示群组 guest 不可以登入系统。
除了控制使用者账号外,在「inetd」模式下,我们还可以控制联机来源。所有 FreeBSD 中由 inetd 所启动的服务都可以经由修改 /etc/hosts.allow 以使用 TCP Wrappd 来限制联机来源。下列为预设的 /etc/hosts.allow 内容:
# Provide a small amount of protection for ftpd
ftpd : localhost : allow
ftpd : .nice.guy.example.com : allow
ftpd : .evil.cracker.example.com : deny
ftpd : ALL : allow
如果我们要限制某几个 IP 或网域不能使用 FTP,可以使用下列范例:
# Provide a small amount of protection for ftpd
ftpd : localhost : allow
ftpd : 210.122.13.5 : deny
ftpd : .evil.cracker : deny
ftpd : ALL : allow
我们在上述范例中拒绝 IP 210.122.13.5 及 evil.cracker 网域的主机使用 FTP,并在最后一行设定其它来源都许可。
如果您要设定只有某些来源可以使用 FTP,而拒绝大多数的主机,则可以设定:
# Provide a small amount of protection for ftpd
ftpd : localhost : allow
ftpd : 192.168.0. : allow
ftpd : my.friend.com : allow
ftpd : ALL : deny
我们设定了只有本机 (localhost)、192.168.0.x、及 my.friend.com 才可以使用 FTP,其它联机都拒绝。
15.3.2 限制上传下载权限
在使用者登入后,只要目录、档案权限许可,它们可以自由的上传、下载档案。如果您希望加以限制读写的权限,可以在启动 FTP 时加上下列几个参数:
参数
意义
-o
限制所有使用者只能上传档案,而无法下载任何档案。
-r
限制所有使用者对于服务器内所有档案只能只读,不可以建立目录、上传、更改档名、或任何会动到档案目录的指令。
上述的参数必须在启动 FTP 服务器时指定,请参考15.2.3 一节,针对 inetd 及独立的 Daemon 有不同的设定方法。
15.3.3 chroot
一般使用者登入后,预设会进入自己的家目录中。使用者可以改变工作路径到系统的任何目录中。如果您希望使用者登入后只能在自己的家目录中活动,而不能进入其它系统目录中,可以使用 chroot 的功能。
所谓的 chroot 就是将某一个目录变成使用者看到的根目录。例如,我们让使用者 alex 登入后,将 /home/alex 变成根目录。则 alex 在使用指令「cd /」时,还是会停留在 /home/alex。如果他使用指令「pwd」查看目前所在路径,则会显示 /。如此一来,我们就可以确保使用者不会到处乱跑,进入一些不该进入的地方。这个功能对于提升 FTP 的安全性有莫大的助益。
设定 chroot 的方法很简单,只要修改 /etc/ftpchroot 即可。chroot 的设定是以使用者、群组的基础,以下是几个设定范例:
alex
@guest
john /var/ftp
@other /var/ftp
上述范例中的第一行是设定使用者 alex 登入后,以自己的家目录为根目录。第二行的 @guest 表示只要是群组为 guest 的使用者,都以自己的家目录为根目录。而第三、四行分别表示使用者 john 及群组 other 都以 /var/ftp 为根目录。
只要我们善用 chroot 的功能,就可以加强保护系统其它目录,让没有权利的使用者不可以进入系统目录中。建议您在开放 FTP 服务时,将所有使用者都加入 /etc/ftpchroot 中。
15.3.4 匿名的 FTP
我们平常在登入 FreeBSD 的 FTP 站台时,可以使用 anonymous 或是 ftp 这二个使用者登入,而且在登入时,任何密码都可以通过。这种可以使用 anonymous 登入的 FTP 就叫作匿名 FTP。anonymous 及 ftp 这二个账号是预设的匿名账号,当使用者以匿名登入时,服务器会将匿名账号对映到系统内的真实使用者 ftp。所以,如果您要提供匿名的 FTP 服务,请使用下列指令新增使用者账号 ftp:# pw adduser ftp
# mkdir /home/ftp
# chown ftp:ftp /home/ftp
我们建立了使用者 ftp 及其家目录 /home/ftp。使用 pw 指令所建立的使用者在 /etc/master.passwd 中的密码字段预设为 *,表示不可以登入。这个使用者除了匿名 FTP 外,将不可以使用 telnet、SSH、或是其它服务。
在新增了使用者 ftp 之后,我们就已经支持匿名 FTP 的功能了。现在您可以使用 anonymous 或 ftp 账号登入,而且不需任何密码。由于开放了匿名 FTP 后,任何人都可以登入系统,所以匿名账号登入后一定会使用 chroot,以将匿名使用者限制在家目录中。
除了强制使用 chroot 外,我们还可以在启动 FTP 时加上一些参数,以针对匿名使用者进行更多的限制。下表为启动 FTP 服务时可以使用的参数:
参数
意义
-M
禁止匿名使用者建立新的目录。
-m
允许匿名使用者覆写一个存在的档案。预设启动 FTP 时,并不允许匿名使用者覆写已经存在的档案。当使用者上传档案时,如果已经有同档名的档案存在,系统会自动为上传的档案改名。
-O
让匿名使用者只能上传档案,下载档案的功能会被取消。
匿名使用者权限除上表中的几个参数外,一样可以使用 -r、-o 等用来控制一般使用者权限的参数来控制匿名使用者。
匿名的 FTP 服务器可以说是危险的开始,如果您没有对匿名的使用者进行权限控制,在开于匿名 FTP 后,将会产生许多安全性的问题。最常见的就是您的 FTP 服务器会被做为档案交流的跳板或是病毒的集散地。例如,当您的匿名 FTP 站台允许使用者上传、下载档案时,一定会有人将自己的档案上传到您的服务器中,并告诉其它人可以到您的服务器中下载档案。此时,您的服务器莫名其妙就会变成别人的服务器,任何人都可以用您的服务器、网络频宽来分享档案。所以,在匿名模式下,最好还是在启动 FTP 时加上参数 -r 以取消上传的功能吧。
15.4 SmbFTPD
SmbFTPD 是笔者从 FreeBSD 5.4 的 FTP daemon 修改而成的软件。FreeBSD 内建的 FTP 服务器比较简单,它不支持流量控制、不支持 SSL 加密、对中文档名的支持也比较差。例如,您无法使用「许」、「功」等中文字。SMbFTPD 除了拥有原本 FreeBSD ftpd 所有功能外,还有更多使用者权限控制、支持特殊中文字、整合设定文件路径及更多功能。另外,它也支持 SSL/TLS 加密的功能,该功能是由 BSDftpd-ssl 移植而来。
SmbFTPD 和一般 FTP daemon 最大的不同在于它使用类似 Samba 的数据夹权限设定,您可以设定让 FTP 使用者登入后所看到的目录跟使用 Windows 登入 Samba 时一模一样。也就是说 FTP 登入的使用者对于数据夹的存取权限和使用 Windows 登入 Samba 一模一样。
而您也可以将 SmbFTPD 做为一般 FTP daemon 使用,或同时支持 Samba 模式。FreeBSD 的 FTP daemon 本来效能就很好,修改过的 SmbFTPD 效能也十分优越,而且程序文件本身体积很小。
效能优越。
档案很小 (约 70KB),占用内存空间小。
支援 SSL/TLS 加密。
可以更改 port。
针对使用者、群组做流量控制。
针对使用者、群组设定 chroot 的路径。
类似 Samba 的数据夹权限,可以针对目录设定使用者的读写权限。
限制 FTP 指令的使用,如上传、下载等。
匿名使用者登入。
诸多匿名使用者的权限控制。
同时支持 Samba 权限控制模式及一般 FTP 模式。
可以拒绝某些使用者 "ls" 出某一个 share 下的档案。
可以拒绝某些使用者下载档案或是修改已存在的档案。
可以让某个数据夹处于只能上传的模式。
15.4.1 安装 SmbFTPD
您可以到
http://www.twbsd.org/cht/smbftpd/index.php
下载最新版的 SmbFTPD,下载 SmbFTPD 后,解压缩后进行该目录。接着您就可以执行下列指令进行编译:# ./configure
# make
configure 指令会侦测您的系统,并依您的环境以决定编译时所要加入的功能。例如,是否支持 IPv6、SSL/TLS、TCP Wrapper、或是 PAM 等。
编译完成后,如果您支持 SSL/TLS,您必须有 SSL 凭证。如果您有安装 Apache+SSL,您也可以和 Apache 共享它的凭证。如果您要产生凭证,您必须再执行下列指令以产生凭证。# make cert
执行上述指令后,我们会先产生一个根凭证,再产生 FTP 所使用的凭证,接着再用我们产生的根凭证为 FTP 用的凭证签章。全部都完成后,我们就可以使用下列指令来安装:# make install
和 FreeBSD 内建的 FTP 服务器一样,SmbFTPD 可以使用 inetd 或是独立的 Daemon 方式启动。如果您要使用 inetd 的方式启动 SmbFTPD,请修改 /etc/inetd.conf 并加入下列内容:
ftp     stream  tcp     nowait  root    /usr/local/sbin/smbftpd smbftpd
接下来请执行下列指令重跑 inetd:# kill -1 `cat /var/run/inetd.pid`
如果您要以独立的 Daemon 方式启动 SmbFTPD,请先在 /etc/rc.conf 加入下列这一行,以在开机时启动 SmbFTPD:
smbftpd_enable="Yes"
接下来就可以使用下列指令看看是否能启动 SmbFTPD:# /usr/local/etc/rc.d/smbftpd.sh start
如果您要停止 SmbFTPD:# /usr/local/etc/rc.d/smbftpd.sh stop
SmbFTPD 是由 FreeBSD 的 FTP Deamon 改写而成,所以有些设定和 FreeBSD 的 FTPD 相同。例如登入前及登入后的讯息可以经由设定 /etc/ftpwelcome 及 /etc/ftpmotd 这二个档来达成。另外,您也可以设定 /etc/hosts.allow  以限制联机来源。不同的是,不管是以独立的 Daemon 或是 inetd 方式启动 SmbFTPD,都可以使用 hosts.allow 的功能。
另外,SmbFTPD 将所有设定项目放在 /usr/local/etc/smbftpd/smbftpd.conf 中,您可以经由修改它来客制化您的服务器。经由修改 smbftpd.conf,您可以设定使用不同的连接埠、更改服务器名称、设定最大联机数目、目录权限、流量控制、SSL 设定等等。
下列几个小节中,我们将介绍一些比较特别的设定,关于更多选项及其详细的设定请参考 smbftpd.conf 一章中的说明。
15.4.2 限制登入账号
我们可以设定限制某些账号不可以使用 FTP 登入。使用者在登入 FTP 服务器时,除了账号密码要符合外,还有几个规则会拒绝该账号登入:
如果 /var/run/nologin 存在,则所有账号都不可以登入。这个档案可以用来暂时停止 FTP 服务。
如果 smbftpd.conf 中 EmptyPasswdLogin 没有设为 Yes,则使用者一定要有密码才能登入,没有密码的使用者无法登入。
使用者名称及群组不可以出现在 smbftpd.conf 中的 NoLoginList 中。
如果 smbftpd.conf 中 RequireValidShell 设为 Yes,则使用者所使用的 shell 必须要时合法的 shell。合法的 shell 会被定义在 /etc/shells 中。
我们可以看到在 smbftpd.conf 中有三个选项控制了使用者可以登入与否:EmptyPasswdLogin、NoLoginList、RequrieValidShell。 其中,NoLoginList 这个项目可以让我们设定不允许登入的使用者清单。
我们在安装了 SmbFTPD 后,即限制了某些系统使用者登入。我们来看一下该选项的内容:
NoLoginList root,toor,daemon,operator,lp,bin,tty,shutdown,kmem,...
这个项目中,每个使用者或群组都是使用逗号分开。如果一个项目的开头是 "@" 表示群组名称。例如 @guest 表示群组 guest 不可以登入系统。
15.4.3 限制上下传频宽
SmbFTPD 支持针对不同的使用者设定不同的上下传频宽限制。smbftpd.conf 中的 MaxDownloadRate 及 MaxUploadRate 控制了使用者上下传的频宽。
这二个选项可以重复设定多次,以支持多个使用者及群组。MaxDownloadRate 及 MaxUploadRate 的格式如下:MaxDownloadRate @group|user rate
其格式就是在选项后面加上群组或使用者名称,最后再加上频宽的限制,频宽是以 KB/s 为单位。如果是群组名称,其开头必须加上 "@"。我们来看看下列的设定范例:
MaxDownloadRate @group100 100
MaxDownloadRate ftp 20
MaxDownloadRate @friends 1000
我们可以看到目前有三个控制下传频宽的项目。第一个项目表示群组为 group100 的使用者,其下载频宽为 100 KB/s。第二个项目表示使用者 ftp 的下载频宽为 20 KB/s。如果您支持匿名的 FTP,匿名 FTP 使用者对于系统而言实质账号是 ftp,您只要针对 ftp 使用者做设定即可套用在匿名使用者 anonymous 及 ftp 上。
15.4.4 匿名的 FTP
我们平常在登入 FreeBSD 的 FTP 站台时,可以使用 anonymous 或是 ftp 这二个使用者登入,而且在登入时,任何密码都可以通过。这种可以使用 anonymous 登入的 FTP 就叫作匿名 FTP。anonymous 及 ftp 这二个账号是预设的匿名账号,当使用者以匿名登入时,服务器会将匿名账号对映到系统内的真实使用者 ftp。所以,如果您要提供匿名的 FTP 服务,必须先增加一个真实的使用者账号 ftp。
在新增了使用者 ftp 之后,我们还必须设定一下 smbftpd.conf 中关于匿名登入的项目。在 smbftpd 中,关于匿名 FTP 的项目有:AnonymousLogin、AnonymousOnly。
AnonymousLogin 控制了是否要启用匿名使用者登入的功能。如果 AnonymousLogin 设为 Yes,表示可以使用匿名使用者登入。另外,AnonymousOnly 控制了在允许匿名使用者登入后,是否还要允许一般使用者登入。如果 AnonymousOnly 设为 Yes,则只有匿名使用者才可以登入,一般使用者都不可以登入哦。
请注意,虽然匿名使用者登入的账号有二个:anonymous 及 ftp。但我们不管是在设定流量、目录权限时,都只要设定真实使用者 "ftp" 账号即可。
15.5 SmbFTPD 的目录权限控制
15.5.1 何谓 SMB Mode
SmbFTPD 和一般的 FTP 服务器最大的不同在于它的目录权限管理方式。SmbFTPD 有二种目录权限管理方式:一般模式及 SMB 模式。一般模式下,SmbFTPD 的行为就和一般的 FTP 服务器一样,使用者登入后可以看到所有的系统目录。
SMB 模式比较特别,它会依照您的设定产生一个虚拟的根目录,在根目录中,只会显示该使用者可以使用的资料夹。如果您使用过 Samba,SmbFTPD 的 SMB 模式就和 Samba 的共享数据夹设定类似。例如,您可以设定一个数据夹名为「音乐」,它的真实目录是在 /home/mp3,并可以设定哪些使用者可以存取此数据夹、只读或可擦写、是否可以下载档案等等。
以下列数据夹设定文件为例:
[音乐]
path = /home/mp3
rw = alex
ro = @guest, john
disable_download = ftp
[upload]
path = /var/ftp
rw = ftp,alex
disable_ls = ftp
disable_download = ftp
上述的范例中,我们有二个共享数据夹:「音乐」及「upload」。其中,path 为该数据夹位于系统中的真实目录。rw 为具有读写权限的使用者 清单,而 ro 为只读的使用者清单。在上述的设定下,使用者 alex 登入后,如果他在根目录中下「ls」指令,他将看到下列内容:
ftp> ls /
200 PORT command successful.
150 Opening ASCII mode data connection for 'file list'.
dr-x------ 1 root users 512  Feb  3 21:40 音乐
dr-x------ 1 root users 2048 Aug 28 03:18 upload
226 Transfer complete.
ftp>
我们可以看到使用者 alex 登入后,他所看到的根目录只有二个数据夹:「音乐」及「upload」。他的活动范围也将只限于这二个数据夹,而无法进入系统中的其它目录。也就是说,如果 alex 输入指令「cd /upload」则会进入「upload」这个数据夹中 (在系统中的真正路径是 /var/ftp)。
SMB 模式的好处在于您可以将不同目录集中设定成位于虚拟的根目录中,并针对这些目录设定不同使用者的权限。使用者权限可以是只读、可擦写、禁止下载档案、禁止看到目录中的档案内容,您甚至可以设定其一个资料夹为隐藏,「ls」时看不到该目录,但却可以「cd」进入目录中。
SMB 模式是一个比较有弹性的目录权限管理方式,您可以经由设定 SMB 模式达到多种不同的目录权限控制。
我们还可以让某些使用者使用一般模式,某些使用者使用 SMB 模式。这些设定十分容易,我们将在下一小节中做说明。
15.5.2 如何设定 SMB Mode
在 smbftpd.conf 中有三个选项和 SMB 模式的目录权限管理有关:DefaultMode、ExceptionList、ShareConfPath。
DefaultMode 设定了预设的目录权限管理模式为何,而 ExecptionList 为例外的清单。如果 DefaultMode 为 Normal,而 ExceptionList 中有使用者 alex,则除了 alex 会使用 SMB 模式外,其它使用者都会使用一般模式。反之,如果 DefaultMode 为 SMB,则 ExceptionList 中的使用者或群组将使用一般模式,其它的使用者会使用 SMB 模式的目录权限管理方式。
ShareConfPath 设定了共享数据夹设定文件的位置,预设为 /usr/local/etc/smbftpd/smbftpd_share.conf。每一个以中括号括起来的区段都是一个数据夹的设定,下列即为数据夹设定的范例:
[音乐]
path = /home/mp3
rw = alex
ro = @guest, john
disable_download = ftp
每一个资料夹的区段都有下列这几个关键词可用:
path:设定数据夹的实际路径。
rw:设定具有读写权限的使用者及群组。
ro:设定只能进行只读的使用者及群组。
disable_download:设定禁止使用下载功能的使用者及群组。
disable_ls:设定在数据夹中 ls 看不到数据夹内容的使用者及群组。
disable_modify:设定不可以修改此资料夹中已经在的档案之使用者及群组。在此项目中的使用者或群组无法更名、删除、修改已存在的档案或目录,只能上传及建立新目录。但前提是使用者必须具有 rw 的权限。
browseable:设定此数据夹在列出根目录的所有数据夹时是否要显示。这个项目只能设定 Yes 或 No,如果设定为 No,则使用者 「ls /」时将看不到此数据夹,但可以使用「cd」指令进入该数据夹内。
除了 path 及 browseable 外,每一个项目可以加上使用者及群组的设定。如果是群组名称,其开头必须加上 "@" 符号。例如,上述范例中,@guest 表示 guest 群组。
您必须要特别注意的是,当您设定了使用者对于数据夹的权限是只读或可擦写后,该使用者或群组在系统中的 UNIX 权限也必须要符合设定才会有作用。例如,如果一个数据夹对使用者 alex 设定为可擦写,您必须确定 alex 对于数据夹在系统中的权限是可擦写,如果不是,您必须使用 chmod 的指令改变该目录的属性。
另外,我们有一个特别的数据夹名称「homes」,如果有 homes 这个数据夹的设定,则使用者登入后会看到一个数据夹名为「home」,该数据夹即为使用者的家目录。家目录预设是该使用者具有读写的权限,所以您无法设定 rw、ro 这二个参数。而且,您也无法设定 path,使用者家目录的所在路径是由系统密码文件中的设定而决定。您只能设定 browseable、disable_ls、disable_modify、及 disable_download。
如果您的 SmbFTPD 支持匿名使用者,匿名使用者 anonymous 及 ftp 会被对映到真实的使用者 ftp,您只要针对 ftp 使用者做设定即会套用在匿名使用者上。
在修改了 smbftpd_share.conf 后,您必须重新启动 SmbFTPD 后设定才会生效。
15.5.3 设定范例
我们列举几个设定的范例让您参考。
范例一:
我们设定一个数据夹名为「public」,其真实路径是 /home/public。只有 wheel 群组的使用者具有读写权限,而匿名使用者及 guest 群组只具有只读的权限。
[public]
path = /home/public
rw = @wheel
ro = @guest, ftp
范例二:
我们设定一个数据夹名为「private」,其真实路径是 /home/movie。只有使用者 alex 具有读写的权限,而 friend 群组只能只读,另外,guest 群组的使用者无法下载该数据夹中的任何档案。
[public]
path = /home/movie
rw = alex
ro = @guest, @friend
disable_download = @guest
范例三:
我们设定一个数据夹名为「upload」,其真实路径是 /var/ftp/pub。只有使用者 alex 具有完整的读写权限,匿名使用者无法下载档案、看不到目录中的档案、无法修改目录中的档案、只能上传档案。
[upload]
path = /var/ftp/pub
rw = alex,ftp
disable_download = ftp
disable_modify = ftp
disable_ls = ftp
15.5.4 chroot
我们除了可以使用 SMB 模式以创造出虚拟的根目录外,SmbFTPD 还支持 chroot 的功能。
所谓的 chroot 就是将某一个目录变成使用者看到的根目录。例如,我们让使用者 alex 登入后,将 /home/alex 变成根目录。则 alex 在使用指令「cd /」时,还是会停留在 /home/alex。如果他使用指令「pwd」查看目前所在路径,则会显示 /。如此一来,我们就可以确保使用者不会到处乱跑,进入一些不该进入的地方。这个功能对于提升 FTP 的安全性有莫大的助益。
当一个使用者同时属于 SMB 模式及 chroot 时,我们会使用 chroot 而非 SMB 模式。
设定 chroot 的方法很简单,只要修改 smbftpd.conf,将使用者加入 ChrootSet 即可。ChrootSet 选项的设定是以使用者、群组的基础,我们可以同时设定多个 ChrootSet。以下是几个设定范例:
ChrootSet ftp /var/spool/ftp
ChrootSet @ftpgroup ~
ChrootSet @webusers ~/public_html
上述范例中的第一行是设定所有匿名的使用者都以 /var/spool/ftp 为根目录。第二行表示只要是群组为 ftpgroup 的使用者都以自己的家目录为根目录。而第三行表示只要是群组为 webusers 的使用者都以自己家目录下的 public_html 为根目录。
在 ChrootSet 的选项中,群组名称开头都会有 "@" 符号。而目录名称 "~" 表示是使用者的家目录。
另外,如果只有一个 "@" 符号,表示所有使用者。下列范例即表示所有的使用者都以自己的家目录为根目录:
ChrootSet @ ~
只要我们善用 chroot 的功能,就可以加强保护系统其它目录,让没有权利的使用者不可以进入系统目录中。
15.6 SSL/TLS 联机加密
15.6.1 设定启用 SSL/TLS
当我们使用网络服务时,经由网络传送的数据都有可能被他人拦截窃听。简单的说,当您从网页上输入账号密码时,如果有人在您所使用的计算机和服务器之间拦截,就可以轻易的从网络封包中窃听到您所输入的数据。
SSL 的加密方式是由服务器端提供了一组加解密用的金钥,在服务器端所使用的是私密金钥 (Private key),而客户端所使用的是公开金钥 (Public key)。在联机建立后,HTTP 服务器会将公开金钥传给客户端使用。公开金钥加密过的资料只能由私密金钥解密,在客户端要送出数据之前,会先使用公开金钥进行加密的动作,而服务器收到数据后,会使用私密金钥进行解密。
如果您的系统有安装 OpenSSL,则 SmbFTPD 安装后即支持 SSL 的功能。在下列 configure 的讯息中,「Check SSL support」为「YES」表示有支持 SSL。# ./configure
opie..................  [YES]
libutil.h.............  [YES]
O_EXLOCK..............  [YES]
FD_COPY...............  [YES]
TCP Wrapper...........  [YES]
Have printflike.......  [YES]
pw_expire.............  [YES]
bsd glob..............  [YES]
MD5File...............  [YES]
user_from_uid.........  [YES]
Shadow passowd........  [NO]
Linux sendfile........  [NO]
FreeBSD sendfile......  [YES]
Use PAM...............  [YES]
Check setproctitle....  [YES]
Check fgetln..........  [YES]
Check sin_len.........  [YES]
Check IPv6 support....  [YES]
Check SSL support.....  [YES]
Finished configure.
在执行完 configure 及 make 之后,即完成编译。在安装前,我们会执行「make cert」以产生 SSL 凭证。最后「make install」会将 SSL 凭证安装在 /usr/local/etc/smbftpd/ 目录中。
在启动 SmbFTPD 之前,您必须先设定 smbftpd.conf 以启用 SSL 功能。smbftpd.conf 中所有 SSL 相关的选项说明请参考下一章的说明,我们这里只说明几个常用的项目。
首先是「SecurityPolicy」,这个项目用来控制是否要启用 SSL 的功能。「secure」 为只允许使用 SSL 联机,「nosecure」 为不使用 SSL 联机,「both」 为二种联机都支持,预设为 「both」。
「NormalUserMustSecure」用来控制是否要强制一般使用者使用 SSL 联机。因为 SSL 主要是用来保护密码、个人数据,如果您强制将「NormalUserMustSecure」设为 Yes,则一般使用者一定要使用 SSL 才能登入。
「AnonymDisableSecure」用以控制匿名使用者是否要使用 SSL。当 AnonymDisableSecure 设为「Yes」时,系统将不允许匿名的使用者使用加密的联机。既然 SSL/TLS 的目的是避免使用者数据在网络上流传,而匿名使用者是任何人都可以使用,保护匿名使用者的数据似乎比较不需要。所以您可以将这个选项设为「No」,以避免匿名使用者也使用加密联机登入,徒然耗费 CPU 的资源。
15.6.2 安装支持 SSL/TLS 的客户端软件
在支持 SSL/TLS 的客户端软件方面,如果您使用 Windows,建议您使用 Filezilla (http://filezilla.sourceforge.net/)。Filezilla 支持 SSL 及 TLS,而且 FTP client 的功能相当完整。它是一套免费、持续更新中的软件。
如果您使用 FreeBSD,可以使用下列指令安装 ftp-tls:# cd /usr/ports/ftp/ftp-tls
# make install
接下来您就可以使用下列指令连到您的 FTP Server 了:# /usr/bin/ftp-tls 192.168.0.1
15.7 smbftpd.conf
15.7.1 系统区段
ServerName 定义服务器名称
这个选项可以用来定义您的服务器名称,当使用者登入后将看到:
Connected to localhost.com.
220
Server Name
FTP server (SmbFTPD Ver 0.9) ready.
Name (localhost:alex):
如果您没有设定 ServerName,则 SmbFTPD 将显示系统的 Hostname。
ServerName "Server Name"
ListenOnAddress 设定要提供服务的 IP
当使用 -D 模式 (standalone) 启动 FTP 时,您可以指定只接受连到这个地址的联机。例如,假设您有二张网络卡,一个 IP 是 172.16.1.1,另一个是 61.62.63.64,您可以设定 ListenOnAddress 172.16.1.1 以表示只接受连到这个 IP 的联机。
如果您要接受所有联机,则请移除这个选项。
ListenOnAddress 192.168.0.1
Port 设定连接埠
当使用 -D 模式 (standalone) 启动 FTP 时,您可以指定 SmbFTPD 所要使用的 Port。一般的 FTP port 为 21,您也可以使用 ftp 这个字符串表示,系统会自动去 /etc/service 中查到相对的 port。
Port 21
Umask 设定新建档案的权限
当使用者建立档案或目录时,所要使用的 umask。例如,您想要让使用者新增档案时的权限为 644,则设 umask 为 022。详细关于 umask 的设定请 man 2 umask。这个选项的值必须为 8 进位的数字,如 022、027 等。
Umask 022
PidFile 设定存放 Process ID 的档案
这是您要存放 smbftpd pid 档的地方,当使用 daemon 模式时,我们会将 smbftpd 的 process id 写到这个档案中。
PidFile /var/run/smbftpd.pid
DebugMode 启用除错模式
是否要用 syslog 记录更多除错用的讯息。这个选项的值可以是 Yes 或 No,默认值为 No。
DebugMode No
LogCommand 记录使用者执行过的指令
是否要使用 syslog 的 LOG_FTP 记录使用者执行过的 FTP 指令。如果您将这个指令设为 Yes, 则使用者所执行的 retrieve(get)、store(put)、append、delete、mkdir、rmdir、rename 等都会被记录下来,并用记录该指令的文件名参数。在 FreeBSD 中,syslogd 会将这些记录在 /var/log/xferlog 中。 这个选项的值可以是 Yes 或 No,默认值为 No。
LogCommand No
DoWtmpLog 记录登入记录
是否要将 ftp 联机记录在 /var/log/wtmp 中。这个选项的值可以是 Yes 或 No,默认值为 No。
DoWtmpLog No
DisableEPSV 停用指令 EPSV
是否要停用 EPSV 这个指令。如果您的服务器位于一些旧的防火墙后面,而一直无法联机,您可以设着停用 EPSV。这个选项的值可以是 Yes 或 No,默认值为 No。
DisableEPSV No
ShowSymlink 是否要显示符号连结文件
当 ShowSymlink 为 No ,我们在使用者 ls 时不会列出 symbolic link 的档案或目录。这个选项的值可以是 Yes 或 No,默认值为 No。
ShowSymlink No
RestrictedPorts 禁止使用小于 1024 的埠号
当这个选项设为 No 时,smbftpd 将不检查限制使用者使用的连结埠。我们预设限制使用者在使用 PORT 命令时,只能使用 unprivileged ports (> 1024),不过这样将违反 FTP protocol。
这个选项的值可以是 Yes 或 No,默认值为 No。
RestrictedPorts Yes
RestrictedDataPorts 限制数据联机所使用的端口号
这个指令设成 NO 时,smbftpd 将只使用 port 定义范围在 IP_PORTRANGE_DEFAULT 的 port,而非 IP_PORTRANGE_HIGH 的 port。这个选项对于某些特殊的防火墙设定蛮有用的。请 man 4 ip 以得到更多信息。
这个选项的值可以是 Yes 或 No,默认值为 No。
RestrictedDataPorts Yes

15.7.2 使用者登入控制
MaxConnection 设定最多联机数目
这个选项可以让您控制最多同时联机的数量。如果 MaxConnection 大于 0,则在联机数目到达您所设定的值时,使用者就无法再登入。如果值为 0,则表示不做任何限制。
MaxConnection 30
RequireValidShell 登入的使用者是否要有合法 Sheel
当 RequireValidShell 为 Yes 时,使用者必须有合法的 shell 才可以登入。合法的 shell 是以 getusershell(3) 这个函数取得,大多数的操作系统中,合法的 shell 都被定义在 /etc/shells 中。这个选项的值可以是 Yes 或 No,默认值为 No。
RequireValidShell No
EmptyPasswdLogin 是否允许空白密码
是否允许空密码的使用者登入。
这个选项的值可以是 Yes 或 No,默认值为 No。
EmptyPasswdLogin No
NoLoginList 设定禁止登入的使用者清单
设定您不想让其登入的使用者,在 NoLoginList 中的使用者或群组不可以登入。
NoLoginList 的参数可以是使用者或是群组,如果是设定群组,请在群组名称前加上 @。当要设定多个使用者或群组时,请使用逗号 , 分开。 匿名使用者「ftp」及「anonumous」会被对映到真实的使用者「ftp」,如果您要设定的是匿名的使用者「ftp」及「anonymous」,请使用「ftp」这个使用者。
例如:
NoLoginList user1,@group1,user2
表示不允许使用者 user1, user2 及群组 group1 登入。
NoLoginList user1,user2,@group1,@group2
TimeOut 设定联机逾时秒数
当使用者超过这个时间没有任何动作时,则中断联机。单位为秒。
TimeOut 900
MaxTimeOut 设定最大联机逾时秒数
使用者可以自行设定 timeout 的时间,但我们可以在这里设定最长 timeout 的时间。预设是 2 小时。
MaxTimeOut 7200

15.7.3 FTP 目录权限控制
DefaultMode 预设的权限控制模式
SmbFTPD 有二种模式,一个是 SMB mode,另一个是 Normal mode。在 SMB 模式中,SmbFTPD 会使用类似 Samba 的共享数据夹权限设定,系统会读取 ShareConfPath 中的使用者目录权限控制来设定他对于数据夹的存取权限。而 Normal 模式中,SmbFTPD 就像一般 FTP Daemon 一样。
这个选项的值可以是 Normal 或 SMB,预设为 Normal。
DefaultMode Normal
ExceptionList 设定不使用预设权限控制模式的使用者
您可以在 ExceptionList 中设定不要使用 DefaultMode 的使用者及群组。例如,您如果希望所有人都使用 SMB 模式,但群组 wheel 要使用一般模式,则请将 DefaultMode 设为 SMB,再在 ExceptionList 中设定 @wheel 即可。
ExceptionList 的参数可以是使用者或群组,如果是群组的话,请在群组名称前加上 @。例如:
ExceptionList user1,user2,@group1,@group2
ShareConfPath 设定数据夹权限设定文件位置
设定数据夹设定的 smbftpd_share.conf 所在路径。如果您设定 DefaultMode 为 SMB,或是 DefaultMode 为 Normal 但有 ExceptionList,则一定要指定 smbftpd_share.conf 的所在路径。
我们会检查 smbftpd_share.conf 中的下列关键词设定:
path:数据夹的路径。
rw:可以有写入权限的使用者或群组。
ro:可以有只读权限的使用者或群组。
browseable:资料夹是否要设为隐藏。若设为 no,则使用者在根目录 ls 时,将看不到该数据夹,但依然可以 cd 到该数据夹中。
disable_download:设定不可以下载的使用者。若使用者可以读取该资料夹内容,您还可以设定让它无法执行下载的动作。
disable_ls:设定在资料夹中执行 ls 时,不可以看到资料夹内容的使用者及群组。
disable_modify:设定不可以修改该资料夹中的档案或目录的使用者及群组。如果该使用者具有读写的权限,但又在此列表中,则该使用者只能上传档案或是建立新的目录,而无法执行 rename、delete、rmdir、chmod 等指令。
范例一:
这个范例是有一个数据夹名为 public,其所在目录为 /home/public,在 samba 群组中的使用者可以有只读的权限,而 root 可以有写入的权限。[public]
        path = /home/public
        rw = root
        ro = @samba
范例二:
数据夹名称为 private,只有 wheel 群组的人可以写入,而且这个数据夹是隐藏的,wheel 群组的人登入后使用 ls 看不到这个资料夹,但是可以 cd 进去资料夹中。[private]
        path = /root/ftp
        rw = @wheel
        browseable = no
范例三:
数据夹名称为 upload, 使用者「ftp」及「anonymous」只能上传档案或建立新目录,但是无法看到该数据夹中的内容,也不可以下载或是修改现有的档案。但在使用者「wheel」群组中的使用者可以具有全部的读写权限。[upload]
        path=/home/upload"
        rw=ftp,@wheel
        disable_ls=ftp
        disable_modify=ftp
        disable_download=ftp
请注意,匿名使用者「ftp」及「anonumous」会被对映到真实的使用者「ftp」,如果您要设定的是匿名的使用者「ftp」及「anonymous」,请使用「ftp」这个使用者。
如果您设定某个使用者对于某个数据夹有写入的权限,但该使用者却无法写入,因为除了 SmbFTPD 的权限控制外,您还必须对数据夹的 UNIX 权限做一些设定,让该数据夹的 UNIX 权限允许该使用者写入。
ShareConfPath /some/where/smbftpd_share.conf
ChrootSet 设定使用 chroot 的使用者
在这个列表中的使用者或群组会被 chroot 到您所指定的路径中,也就是让它将您所设定的路径做为根目录,使用者无法到该路径以外的地方。如果有需要,您可以同时设定多条 ChrootSet 的规则。
这个参数的第一个字段是使用者名称或群组,如果在名称之前加上 @,表示是群组,所有在该群组中的使用者都会被套用到群组的设定中。而另一个特别的用法是只有一个 @ 符号,表示所有使用者都会被套用到这个设定中。
请注意,被设定为 chroot 的使用者就算 DefaultMode 被归类为 SMB mdoe 也一定会被强制使用 Normal mode。
这里有几个设定的范例:
范例一:
使用者 ftp 登入时,将它 chroot 到 /var/spool/ftpChrootSet ftp /var/spool/ftp
范例二:
所有群组为 ftpgroup 的使用者都使用他们的家目录 (home) 做为根目录。例如,使用者 alex 的家目录为 /home/alex,则其根目录为 /home/alex,而 jack 则是 /home/jack。我们以 ~ 符号表示家目录,系统会自动转换为真正的路径。ChrootSet @ftpgroup ~
范例三:
所有 webusers 这个群组的人都以其家目录下的 public_html 为根目录。这对于您要开放 FTP 给某些使用者,但又不想让他们去存取系统中其它路径时十分有用。ChrootSet @webusers ~/public_html
范例四:
所有使用者都必须以其家目录为根目录。ChrootSet @ ~
ChrootSet @webusers ~/public_html
ChrootSet @ ~

15.7.4 匿名使用者控制
AnonymousLogin 是否支持匿名使用者登入
是否允许匿名使用者登入。匿名的使用者账号为 ftp 或 anonymous。如果您要允许匿名使用者登入,您必须先新增一个 ftp 的系统使用者。
这个选项的值可以是 Yes 或 No,默认值为 No。
AnonymousLogin No
AnonymousOnly 是否只允许匿名使用者登入
是否只允许匿名使用者登入。若设为 Yes,则一般使用者无法登入。
AnonymousOnly No

15.7.5 档案传输控制
TransferLog 设定上下传记录文件位置
这个选项用来设定使用者上传及下载的档案记录。您可以设定当使用者下载或上传档案时,将它所上传或下载的档名、传输时间、大小等数据写在这个档案中。
TransferLog /var/run/smbftpd.log
MaxDownloadRate 设定最大下传速度
您可以针对使用者及群组设定最大的下载频宽。频宽 rate 的单为是 KB/s。您也可以设定多条 MaxDownloadRate 规则。
这个选项的第一个参数可以是使用者或群组,如果是群组,则名称开头必须加上 @。而若只有一个 @ 符号,表示所有使用者都要套用到该规则。
MaxDownloadRate @group100 100
MaxDownloadRate ftp 20
MaxDownloadRate @friends 1000
MaxUploadRate 设定最大上传速度
您可以针对使用者及群组设定最大的上传频宽。频宽 rate 的单为是 KB/s。您也可以设定多条 MaxDownloadRate 规则。
这个选项的第一个参数可以是使用者或群组,如果是群组,则名称开头必须加上 @。而若只有一个 @ 符号,表示所有使用者都要套用到该规则。
MaxUploadRate @group100 100
MaxUploadRate ftp 20
MaxUploadRate @friends 1000

15.7.6 SSL/TLS 控制
SecurityPolicy 设定是否使用 SSL/TLS
这个选项可以让您设定是否要启用 SSL/TLS 加密。您可以 强制一定要使用加密联机,或是关闭加密功能,或是同时允许加密及非加密模式。各种模式的说明如下:
secure:只允许加密联机。
nosecure:只允许非加密联机。
both:同时允许加密及非加密联机。
您可以将 SecurityPolicy 设为 secure、nosecure、或 both,默认值是同时允许加密及非加密联机。
SecurityPolicy both
EncryptionType 设定加密类型
当您要使用加密联机时,您可以选择要支持哪一种加密模式。SmbFTPD 支持二种模式:SSL 及 TLS,您可以使用下列设定值以选择要使用另一种模式:
TLS:只使用 RFC 2228 所定义的 FTP-TLS 模式。
SSL:只支持 FTP-SSL 模式。
Both:同时支持 SSL 及 TLS。
默认值是同时支持 SSL 及 TLS。
EncryptionType both
NormalUserMustSecure 强制一般使用者使用加密联机
当 NormalUserMustSecure 设为「Yes」时,表示一般使用者登入时一定要使用加密的联机,否则无法登入。
我们在 FTP 服务中使用 SSL/TLS 的目的是为了避免使用者的机密数据在网络上以明码流传,为了强制所有使用者都使用比较安全的模式联机,您可以将这个选项设为「Yes」。
NormalUserMustSecure No
AnonymDisableSecure 设定不允许匿名使用者使用加密联机
当 AnonymDisableSecure 设为「Yes」时,系统将不允许匿名的使用者使用加密的联机。
既然 SSL/TLS 的目的是避免使用者数据在网络上流传,而匿名使用者是任何人都可以使用,保护匿名使用者的数据似乎比较不需要。所以您可以将这个选项设为「No」,以避免匿名使用者也使用加密联机登入,徒然耗费 CPU 的资源。
AnonymDisableSecure No
SSLCertFile 设定公开金钥位置
设定所要使用的凭证,这个凭证会被送到客户端做为加密用。如果您没有设定这个选项,预设会使用 /usr/local/etc/smbftpd/ssl.crt/server.crt。
您也可以和 Apache+SSL 共享凭证,Apache 的 SSL 凭证通常位于 /usr/local/etc/apache2/ssl.crt/server.crt。
SSLCertFile /usr/local/etc/smbftpd/ssl.crt/server.crt
SSLKeyFile 设定私密金钥位置
这个选项是用来设定您上述设定的凭证所对映的 private key。这个 private key 和凭证是成对的,预设是在 /usr/local/etc/smbftpd/ssl.key/server.key。
如果您使用 Apache SSL 凭证,则这里也必须设定使用 Apache 的 key,通常位于 /usr/local/etc/apache2/ssl.key/server.key。
SSLKeyFile /usr/local/etc/smbftpd/ssl.key/server.key
SSLDebugMode 是否启用 SSL 的除错模式
设定是否要启动 SSL 的除错模式,当设为「Yes」时,您还必须要设定记录文件位置 SSLDebugLog。
SSLDebugMode No
SSLDebugLog 设定除错记录文件位置
设定 SSL 除错模式的记录文件要放在什么地方。
SSLDebugLog /var/log/smbftpd-ssl.log

TOP

第十四章 网页服务器进阶应用
网页服务器架设之后,世界各地的使用者都可以经由因特网连到您的主机,如何维护网站安全是一大课题。管理者更需要知道网站的使用情形,系统资源、网络频宽是否足够。本章将说明网页服务器使用上常见的管理议题,并介绍一些好用的管理工具。读完本章后,您将进一步了解下列主题:
如何使用 SSL 建立安全的 HTTP 联机。
使用密码保护目录存取权限。
如何在一台主机上提供不同网址的网页。
如何管理一般使用者的个人网页。
加速 PHP scripts 的处理速度。
分析网页的使用情形。
网站使用流量分析。
14.1 HTTP 安全与 SSL 协定
当我们使用网络服务时,经由网络传送的数据都有可能被他人拦截窃听。简单的说,当您从网页上输入账号密码时,如果有人在您所使用的计算机和服务器之间拦截,就可以轻易的从网络封包中窃听到您所输入的数据。
随着网络的蓬勃发展,在线交易的使用量日益增加,对于数据的保护更是重要。如果一个在线交易的网站使用普通的 HTTP,则使用者输入的账号密码、交易数据、信用卡号等等都有可能会外泄,更别说交易数据被假造的风险了。为了解决 HTTP 的网络安全,发展出许多加密、认证的机制。其中最常见的就是使用金钥加密法的 HTTP over SSL (Secure Socket Layer),又称为 HTTPS,目前国内许多网络银行都是使用 HTTPS 作为交易安全的第一道关卡。
SSL 的加密方式是由服务器端提供了一组加解密用的金钥,在服务器端所使用的是私密金钥 (Private key),而客户端所使用的是公开金钥 (Public key)。在联机建立后,HTTP 服务器会将公开金钥传给客户端使用。公开金钥加密过的资料只能由私密金钥解密,在客户端要送出数据之前,会先使用公开金钥进行加密的动作,而服务器收到数据后,会使用私密金钥进行解密。
在 Apache 2 中,预设安装即支持 SSL,我们只需产生一组金钥,并设定启动 SSL 即可。
14.1.1 产生金钥
正确的凭证产生方法是先产生服务器用的公钥及 CSR (Certificate Signing Request),接着将 CSR 送给专门做凭证签发的公正单位做签章。或者,我们也可以自己做为一个凭证签发单位,自己为自己签发凭证。但由于我们自己产生的凭证不具公信力,所以使用者使用 HTTPS 连到网站时,会出现下列的警告讯息:
图 14-1

这个警告讯息并不影响加密,不过如果您所架设的是商用网站,您还是得交由公正单位作签证。
如果您要使用自我签发的凭证,第一步是要产生签发单位凭证,我们先建立一个目录名为 ssl,并将产生的凭证放在该目录下:# mkdir ssl
# cd ssl
# openssl genrsa -out ca.key 1024
# openssl req -new -key ca.key -out ca.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:TW
State or Province Name (full name) [Some-State]:Taiwan
Locality Name (eg, city) []:Taipei
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company
Organizational Unit Name (eg, section) []:Certificate Authority
Common Name (eg, YOUR name) []:MyCA
Email Address []:alex@alexwang.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:按 Enter 即可
An optional company name []:按 Enter 即可
# openssl x509 -days 365 -signkey ca.key -in ca.csr -req -out ca.crt
我们在第二个 openssl 指令中必须输入一些基本信息,最后产生一个有效期限 365 天的凭证。接着,必须产生 Apache 服务器用的凭证:# openssl genrsa -out server.key 1024
# openssl req -new -key server.key -out server.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:TW
State or Province Name (full name) [Some-State]:Taiwan
Locality Name (eg, city) []:Taipei
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company
Organizational Unit Name (eg, section) []:Web Team
Common Name (eg, YOUR name) []:www.alexwang.com
Email Address []:alex@alexwang.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:按 Enter 即可
An optional company name []:按 Enter 即可
# openssl x509 -days 365 -CA ca.crt -CAkey ca.key -in server.csr -req -out server.crt
同样的,我们必须输入关于这个凭证的一些数据,最后,我们使用之前所产生的凭证签发一个有效期限 365 天的服务器用凭证。必须注意的是,在 Common Name 必须输入您的主机名称,以避免联机时凭证名称和网页名称不符的警告。另外,我们在产生凭证时,当 OpenSSL 要求输入用来保护凭证的密码时,我们都没有输入密码。如果您输入密码,则以后 Apache 要启动时都必须输入密码才可以启动。
最后,我们将服务器用的凭证复制到 Apache 的设定文件位置:# mkdir /usr/local/etc/apache2/ssl.crt
# mkdir /usr/local/etc/apache2/ssl.key
# cp server.crt /usr/local/etc/apache2/ssl.crt/server.crt
# cp server.key /usr/local/etc/apache2/ssl.key/server.key
# chmod 400 /usr/local/etc/apache2/ssl.crt/server.crt
# chmod 400 /usr/local/etc/apache2/ssl.key/server.key
最后,请将我们制作过程中的凭证删除:# rm -rf ssl
凭证制作完成后,我们就可以开始设定支持 SSL 的 Apache 了。
14.1.2 设定及启动 HTTPS
首先,我们必须先修改 /usr/local/etc/apache2/ssl.conf 以设定 SSL,请先找到下列区段:
# General setup for the virtual host
DocumentRoot "/home/www"
ServerName www.example.com:443
ServerAdmin you@example.com
ErrorLog /var/log/httpd-error.log
TransferLog /var/log/httpd-access.log
我们必须修改 DocuemntRoot,并将它设为我们网页根目录,然后要修改 ServerName,将它设定为我们的主机名称。
为了要该 Apache 启动时可以支持 SSL,请在 /etc/rc.conf 中加入 Apache SSL 的设定:
apache2ssl_enable="YES"
最后,请重新启动 Apache 即可:# /usr/local/etc/rc.d/apache2.sh restart
接下来,您就可以使用 https://192.168.0.1 连到您的主机了。请注意,我们使用的联机方法是 https,而非 http。如果您联机的主机名称和凭证产生的名称不同,将会有名称不符的警告讯息。
图 14-2

14.2 对目录设定密码保护
在架设网站时,如果您有特殊需求,必须指定某个目录只能由某些使用者才能存取,我们可以使用 Apache 内建的目录保护功能,让使用者必须输入使用者名称及密码才能存取该目录。
在开始设定目录的保护之前,我们必须先修改 httpd.conf,允许使用者可以在网页目录中使用认证功能。首先,请编辑 /usr/local/etc/apache2/httpd.conf,找到网页目录设定的区段:
...
LoadModule auth_module libexec/apache2/mod_auth.so
...
        Options Indexes FollowSymLinks MultiViews ExecCGI
        AllowOverride AuthConfig
        Order allow,deny
        Allow from all
...
AccessFileName .htaccess
...
我们必须先确定 Apache 有加载 mod_auth.so 模块。接着,我们在网页目录的区段中 AllowOverride 的部份设定了使用 AuthConfig。如果 AllowOverride 设为 None 表示不允许使用者变更目录设定,设为 AuthConfig 表示可以使用 AuthDBMGroupFile、 AuthDBMUserFile, AuthGroupFile、AuthName、AuthType 等认证的功能。另外,在 AccessFileName 中,我们设定了用来保护目录的设定文件名称,预设为 .htaccess。
Apache 允许使用者在目录下放置一个档案来控制该目录的存取权限,预设是使用 .htaccess。我们可以自行用文书软件编辑一个文件名为 .htaccess 的档案来设定档案所在目录的权限。假设我们要保护的目录是 /home/www/private/ 这个目录,请新增一个文字文件 /home/www/private/.htaccess,内容如下:
AuthName "管理专区"
AuthType "Basic"
AuthUserFile "/var/http.pw"
require valid-user
其中请注意各参数的大小写。这里我们设定储存使用者账号及密码的档案是 /var/http.pw。
接下来我们就可以新增使用者及密码了。Apache 用来新增密码的指令为 htpasswd:# /usr/local/sbin/htpasswd -c /var/http.pw username
New password: 输入 username 的密码
Re-type new password: 再输入一次
上述指令会建立密码文件 /var/http.pw 并加入使用者 username。如果您还要再加入第二个使用者,不需要加参数 -c。
接着,我们使用使用浏览器连到该目录时,将出现下列画面:
图 14-3

此时输入你设定的使用者名称及密码即可。若输入的账号密码正确,即可正常看到该目录的内容,否则在输入三次错误之后,将出现禁止存取的页面。

小提示
在您通过身份认证后,浏览器会自动将身份认证的数据暂存起来,以便下次联机时使用。所以在通过认证后,您不会每次要连受保护的目录时都要输入账号密码。如果您将浏览器关闭后,下次再连到该页面时,才会再被要求输入密码。
14.3 虚拟主机
如果您想要使用一台主机管理多个不同名称的网页,例如,www.alexwang.comwww.twbsd.org 全都连到同一台服务器,我们可以经由 Apache 虚拟主机的功能,让不同的网址秀出不同的网页内容。其本上,就是在一台机器上设定多个主机名称或 IP,并依不同名称来决定其根目录所在。当使用者联机到我们的主机时,每一个不同的名称所看到的根目录都不同。
要达到这样的功能,我们必须先确定主机有多个 DNS 名称,这样别人打该主机名称才会对应到你的 IP。假设你的主机 IP 是 111.222.78.9 ,上面有二个主机名称,一个是 www.abc.com,另一个是 www.cde.net。您必须先在 DNS 中设定让这二个主机名称都可以对应到 11.22.78.9 这个 IP。
在确认 DNS 设定没问题后,我们就可以开始设定 Apache 虚拟主机的功能了。请编辑 httpd.conf,在虚拟主机的部份加入下列设定:
# 设定使用名称的虚拟本机
NameVirtualHost *:80
# 设定 www.abc.com 的管理者账号、存放网页的目录及log 所在
        ServerAdmin jack@abc.com
        DocumentRoot /home/www/abc
        ServerName www.abc.com
        ErrorLog /var/log/abc_error.log
        CustomLog /var/log/abc_access.log common
# 设定 www.cde.com 的资料
        ServerAdmin tom@cde.net
        DocumentRoot /home/www/cde
        ServerName www.cde.net
        ErrorLog /var/log/cde_error.log
        CustomLog /var/log/cde_access.log common
做完上面的设定后,就可以重新启动 Apache 了。如果你还有别的 Domain Name 指向 111.222.78.9 的话,例如 www.fgh.org ,但你并未设定其 Virtual Host 数据,Apache 将以第一个设定的 Virtual Host 数据为主。在这个范例里,当你打 www.fgh.org 会连到 www.abc.com 的设定。
必须要注意的是,有些客户端的联机软件并不支持 Name-Based 的虚拟主机,要支持 name-based virtual host,客户端必须送出 HTTP 的标头,也就是浏览器必须支持 HTTP/1.1。不过,请放心,我们常用的 IE、Netscape、lynx 都有支援。
14.4 网页记录分析
在我们将所制作好的网页放在网页服务器之后,我们会想知道每一个网页的浏览次数、使用者的停留时间等等,以做为改善网页的依据。这些信息都可以从 Apache 的联机记录文件中获得,但由于 Apache 的联机记录中,只有一笔一笔使用者浏览网页的记录,我们需要使用一些工具来分析记录文件,让这些记录文件能更易于阅读。
本章将介绍 Webalizer 这套软件。Webalizer 会读取 Apache 的联机记录文件,并将分析结果存成网页,让我们可以经由网页的图形更轻松的了解每一个页面的使用情形。由于 Webalizer 所进行的分析是经由读取 log 档,因此 log 文件的数据越多,分析出来的结果也就越详尽。
我们使用下列指令安装 Webalizer:# cd /usr/ports/www/webalizer
# make install clean
在安装完 Webalizer 之后,我们必须先做一些简单的设定。在 /usr/local/etc/ 有一个 Webalizer 的设定文件范例 webalizer.conf-dist,我们先将它复制一份再开始编辑:# cp /usr/local/etc/webalizer.conf-dist /usr/local/etc/webalizer.conf
# ee /usr/local/etc/webalizer.conf
以下我们将一一说明此设定档的内容,如果您想要更改其中的设定,请将该行开头的井字号移除再开始修改:
# 设定 Apache 联机记录文件的位置。
#LogFile        /var/lib/httpd/logs/access_log
LogFile        /var/log/httpd-access.log
# 设定 log 文件的型式,Webalizer 除了 Apache 外,还可以支持分析 FTP 软件
# 或 proxy 软件 squid 的 log 文件。LogType 预设的值是 'clf',表示分析
# 网页数据,你也可以设定为 ftp 或 squid。
#LogType        clf
# OutputDir 是我们想要输出分析数据的位置。请设定为网页根目录下的某一个
# 目录。例如我们的网页根目录是 /home/www,请先在该目录下建立一个子目录
# 名为 traffic,接着再设定 OutputDir 为 /home/www/traffic。
#OutputDir      /var/lib/httpd/htdocs/usage
OutputDir      /home/www/traffic
# HistoryName 可以让我们设定 webalizer 所产生的历史记录文件的文件名。这个档
# 可以用来产生 主要的 HTML 页面 (index.html),我们不需要修改。
#HistoryName        webalizer.hist
# 由于我们可能会设定某一段时间自动将 Apache 的 log 压缩或删除。而
# Incremental 这个变量可以让我们在产生分析资料时,只更新增加的部份
# 而分析过的资料就不再分析,以免覆盖了旧有的资料。
#Incremental        no
Incremental        yes
# 若您设定 Incremental 为 yes,IncrementalName 可以让您设定目前增加
# 的分析数据存放位置。
#IncrementalName        webalizer.current
# ReportTitle 是分析结果网页的标题。在该标题后会加上您的主机名称。
#ReportTitle    Usage Statistics for
# 设定您的主机名称。
#HostName       localhost
# HTMLExtension 是所产生的 HTML 档的扩展名。
#HTMLExtension  html
# PageType 可以让您设定何种扩展名结尾的页面要加入分析数据。因为在
# log 文件中有一些图片,而这些图版我们并不希望加入分析数据中,或者我
# 们也可以增加 PHP 页面的分析数据。所以在这里,我们加上一行用来分析
# PHP 页面的设定。
PageType        htm*
PageType        cgi
PageType        php
#PageType        phtml
#PageType        php3
#PageType        pl
# 如果您希望只使用 https 才可以连到分析页面,则将 UseHTTPS 设为 yes。
#UseHTTPS       no
# DNSCache 可以设定 DNS 快取的文件名称,在分析数据时,可能会一直需要
# 做 DNS 的分析,这个档可以提高 DNS 查询的效率。
#DNSCache        dns_cache.db
# DNSChildren 可以设定要使用多少 process 来做 DNS 查询,预设是 0,表示
# 不查询,我们可以设定的值从 1 到 100。最好不要设太多,以免消耗太多系统
# 资源。
#DNSChildren        0
# HTMLPre 是用设定每个 HTML 档案开头第一行要插入的字,最长 80 个字符。
#HTMLPre
# HTMLHead 可以让我们设定 HTML 页面  中间要插入的字。最长
# 也是 80 个字符。
#HTMLHead
# HTMLBody 会取代在 HTML 页面中的   这个标签。可以让我们设定网页
# 的一些属性。最长也是 80 个字符。
#HTMLBody
# HTMLPost 会将设定的字符串插入 HTML 第一个  标签之后,最长也是 80 个
# 字。
#HTMLPost        
# HTMLTail 可以设定 HTML 页面的结尾所要插入的字符串。最长 80 个字符。
#HTMLTail
# HTMLEnd可以设定 HTML 页面的最后结尾所要插入的字符串。我们最少要有
#  和  这二个标签,最长 80 个字符。
#HTMLEnd
# Quiet 可以让我们设定在分析时是否要输出讯息,因为我们会使用 crontab
# 定时执行,所以不要输出分析过程的讯息比较好。
Quiet                yes
# ReallyQuiet 可以设定档有错误产生时,是否要输出讯息。
#ReallyQuiet        no
# TimeMe 可以设定在分析之后是否要输出时间。
#TimeMe                no
# GMTTime 可以设定是否要使用 GMT (UTC) 时间而非本地时间。
#GMTTime                no
# Debug 可以设定是否要输出除错讯息。
#Debug                no
# FoldSeqErr 可以让 Webalizer 忽略读取 log 档的错误。
#FoldSeqErr        no
# VisitTimeout 可以设定 session 的到期时间,默认值是 30 分钟。
#VisitTimeout        1800
# IgnoreHist 请保持 no。
#IgnoreHist        no
# Country Graph 是用来显示分析资料中关于国家的统计资料是否要显示。
#CountryGraph        yes
# DailyGraph 及 DailyStats 是设定是否显示每日分析资料。
#DailyGraph        yes
#DailyStats        yes
# HourlyGraph 是 HourlyStats是设定是否显示每小时分析资料。
#HourlyGraph        yes
#HourlyStats        yes
# GraphLegend 是设定是否要显示彩色图表。
#GraphLegend        yes
# GraphLines 是用来设定图表的网格线数量,最多 20。
#GraphLines        2
# "Top" 的选项是每一个分格表格中,要显示多少笔前几名的资料。
#TopSites        30
#TopKSites       10
#TopURLs         30
#TopKURLs        10
#TopReferrers    30
#TopAgents       15
#TopCountries    30
#TopEntry        10
#TopExit         10
#TopSearch       20
#TopUsers        20
# The All* 可以让我们显示所有 log 文件中有记录的数据,而非只有前几名而
# 已。如果设定了某一个 All 的选项,webalizer 将会为该设定新增一个页面。
#AllSites        no
#AllURLs        no
#AllReferrers        no
#AllAgents        no
#AllSearchStr        no
#AllUsers       no
# Webalizer 会自动使用让网址 /somedir/ 可以连结到 /somedir/index.htm
# 如果你想要设定让除了 index. 结尾的网址有此效果外,还要让其它网
# 址也有同样效果,您可以在此设定。
#IndexAlias     home.htm
#IndexAlias        homepage.htm
# Hide*, Group*, Ignore* 及Include* * 可以设定让 Webalizer 忽略
# log 中的关键词,让 log 中某些记录不要被加入分析数据中。例如
# 有的搜寻引擎会自动连到您的网页来找数据,您可以设定忽略这样的
# 联机。请自行参阅说明。
… 略 …
# End of configuration file...  Have a nice day!
接着我们必须依您的设定在网页根目录中建立一个数据夹以储存 Webalizer 所产生的图表,假设我们的网页根目录是 /home/www,并在其目录下建立一个子目录名为 traffic:# mkdir /home/www/traffic
紧接着我们就可以使用下列指令来产生统计图表:# /usr/local/bin/webalizer
因为我们在 webalizer.conf 中设定了所要使用的 apache 使用记录的文件名及所产生的图表存放位置,所以在执行 webalizer 时不必再加任何参数。如果您想指定使用其它的联机记录文件来做分析,您可以在指令后面加上该记录文件的文件名,例如:# /usr/local/bin/webalizer /var/log/httpd-access.log
产生了图表之后,我们就可以使用浏览器输入 http://www.mydomain.com/traffic 连到该网页。连到该页面后,您可以看到下列画面:
图 14-5

我们可以看到八月份每天平均有 294 人造访,该月共有 7945 人。点选了该月份后,可以再看该月份更详细的数据。例如,一天中哪一个时间最多人造访、哪一个网页最点选最多次、使用者来源、进到本网站后第一个看的页面是什么等等。下图为最常被点选的页面统计:
图 14-6

最后,为了让分析图表能定时自动更新,我们可以使用 crontab 每小时定期执行一次分析。# crontab -e
13      *       *       *       *       /usr/local/bin/webalizer
在上述的 crontab 的设定中,我们让系统在每小时的第 13 分时执行一次 webalizer,您也可以依您的需求调整更新的时间。存盘离开之后,crontab 会自动加载新的设定,如此一来我们就可以随时拥有最新的统计信息了。
14.5 MRTG 流量分析
我们除了可以使用 Webalizer 来了解网页内容的使用情形外,网站管理者还必须知道目前网站频宽是否足够。如果您想要知道网站流量的使用情形,我们可以安装 MRTG 这套软件经由网页来监看网络流量。MRTG 会去收取 SNMP (Simple Network Management Protocol) 所产生的数据,因此所要记录的机器必须要安装 SNMP。在你的主机上安装 MRTG 后,你不仅可以收集自己的流量数据,也可以收集局域网络上其它可以接收到的 SNMP 数据。
14.5.1 安装 SNMP
在安装 MRTG 之前,我们先使用 ports 来安装 SNMP:# cd /usr/ports/net-mgmt/net-snmp
# make install clean
安装完成后,我们必须要先新增一个可以读取 SNMP 信息的 community name。所谓的 community name 是一个明码的字符串,我们可以将它视为 management station 和 agent 之间的密码,是 MRTG 和 net-SNMP 沟通时必须要先传送的字符串。我们可以依不同的网域或主机给予不同的权限,依 community name 的设定来决定不同权限。
一个网络组件可以有多个 community name,一般 SNMP Agent 所预设公开的 community name 是 public。我们不一定要将 community name 设定为 public,因为 public 是一般 SNMP 的默认值,为了安全的问题,我们不将它设为 public。这里我们将设定 community name 为 mrtg,而且只有 read only 的权限。
要设定 community name 请先新增一个文字文件 /usr/local/share/snmp/snmpd.conf 并加入下列设定:
rocommunity     mrtg
syslocation     Office
syscontact      alex@alexwang.com
上述设定中,mrtg 为只读的 community name,Office 是您机器所在位置,而 syscontact 所接的字符串是您的 Eamil。另外,我们还必须在 /etc/rc.conf 中加入下列这一行:
snmpd_enable="YES"
接着,请使用下列指令启动 SNMP:# /usr/local/etc/rc.d/snmpd.sh start
14.5.2 安装 MRTG
我们使用 ports 来安装 MRTG:# cd /usr/ports/net-mgmt/mrtg
# make install
接着要产生 MRTG 的设定档# cd /usr/local/etc/mrtg
# rehash
# cfgmaker mrtg@alexwang.com >mrtg.cfg
这里的 mrtg 是我们在安装 net-snmp 时所设定的值。如果你使用错的 community name,你可能会从要记录的设备上得到错误响应。而 alexwang.com 是你所要记录的主机位置。mrtg.cfg 就是所要产生的设定档名。
如果您想要记录多个主机,只要在 cfgmaker 时多加入主机名称即可,例如:# cfgmaker mrtg@alexwang.com public@ftp.alexwang.com >mrtg.cfg
这样就会同时记录上面二台主机的流量了。
产生基本的设定档后,我们可以再编辑刚才产生的设定档 ee mrtg.cfg,在档案开头的部份加入一些客制化的设定:
# 如果要使用中文的 MRTG 则加入下面这一行
Language: big5
# 设定你的 MRTG 要放在哪个目录,应该要放在网页可以
# 连结到的地方,我的网页根目录是 /home/www,所以我将
# MRTG 放在下面的目录。
WorkDIR:/home/www/mrtg
# 预设的 MRTG 所产生的图时间是由右到左
# 我喜欢由左到右,故加入下面这一行
Options[_]: growright
接着请建立一个你在 mrtg.cfg 中设定的 WorkDIR 的目录:# mkdir /home/www/mrtg
然后使用指令 indexmaker 来建立 MRTG 的首页:# indexmaker -title '流量统计' -output /home/www/mrtg/index.html mrtg.cfg
这里的参数 -title 是该 index.html 档的 title,而 -output 就是要输出的档案位置,预设是stdio(通常指的是屏幕) 。
输出的档案 index.html 你也可以使用其它的网页编辑软件再去修改美化它。接下来要将 MRTG 的一些图片文件复制到 mrtg 的目录里:# cd /usr/ports/net-mgmt/mrtg/work/mrtg*
# cd images
# cp * /home/www/mrtg/
最后执行 MRTG:# /usr/local/bin/mrtg /usr/local/etc/mrtg/mrtg.cfg
第一次执行上面的指令可能会有一些错误讯息,不要理它,因为是第一次执行 mrtg,所没有一些旧的图,只要再多执行几次就好了。没问题之后,使用指令 crontab -e 来让上述指令每 5 分钟执行一次,加入下面这一行:
*/5    *    *    *    *    /usr/local/bin/mrtg  /usr/local/etc/mrtg/mrtg.cfg
现在你可以使用 http://yourserver/mrtg 来连去看看。
图 14-7

最后别忘了移除安装过程的暂存档:# cd /usr/ports/net/mrtg/
# make clean

TOP

第十三章 网页服务器
我们最常使用的网络应用莫过于网页服务器了, 这里我们将介绍如何安装一个功能完整的网页服务器。读完本章后,您可以了解下列网页服务器的管理项目:
如何安装 Apache+PHP+MySQL+PostgreSQL。
如何设定 Apache 及 PHP。
如何查看网页服务器的使用状态。
测试服务器效能。
经由记录文件分析网页使用情形。
13.1 概论
Apache 是 UNIX 系统中普遍使用的网页服务器软件。根据  Netcraft 的统计 (
http://news.netcraft.com/archives/web_server_survey.html
),目前因特网中,有超过百分之六十的服务器是使用 Apache 来提供网页浏览的服务。Apache 可以说是目前世界上使用人数最多的网页服务器软件,它不仅可以在 FreeBSD、UNIX、Linux 中运行,也可以安装在 Windows 操作系统中。
Apache 和 FreeBSD 一样,在软件版本上也有多个分支,目前较稳定的版本有 1.3.33 及 2.0.x。Apache 1.3 系列开发已久,已经十分稳定了,不会再有重大的修改。而 Apache 2 系列是一个开发较活跃的版本,它和 1.3 最大的不同在于多执行绪 (multithreaded) 的支援。目前 Apache 2.0.x 是最主要的稳定版本,而 2.1.x 则还处于开发中的状态。笔者建议您使用 Apache 2.0 来做为您的网页服务器。
Apache 之所以风行的原因,除了免费、历史悠久、稳定外,它提供了弹性化的接口,可以让我们依需求加入各种模块,以提供更强大的功能。例如,我们可以在网页服务器上加入 PHP,以支持更多的网页应用。PHP 是一个用来写网页程序的软件,就像 ASP、JAVA servlet、CGI 等等有类似的用途,我们可以使用 PHP 建立留言版、电子相簿、购物车等应用。PHP 十分容易学习,程序代码也很简洁,速度更是没话说。如果你有些微的程序语言基础,不出二个礼拜,你就能对 PHP 有十足的认识,并且可以自己写出留言版、权限控制等简单的程序。
如果要使用 PHP,那你一定也要使用一套数据库系统做为程序后端的数据储存。在众多免费的数据库软件中,最有名的应该是 MySQL 和 PostgreSQL 了。不论是 MySQL 或 PostgreSQL,它们的功能及速度都令人赞赏。使用 PHP 加上数据库软件,你可以制作出网页的各式数据库,如会员管理、产品数据库等等。总之,我十分建议使用 Apache+PHP+数据库的组合,就算目前不会用到,不久的将来也会使用它们的功能。全部一股脑的装起来,省得日后麻烦。
目前 PHP 一样有二个主要的版本分支:4.x 及 5.x,4.4.0 是目前 4.x 的最新版本,而 5.0.x 则是 5.x 中的稳定版。我们将介绍如何使用 PHP 5.0 及数据库。
13.2 安装及设定 Apache
13.2.1使用 ports 安装
使用 FreeBSD port 安装 Apache  十分容易,我们只要使用下列指令即可完成安装:# cd /usr/ports/www/apache2
# make install clean
我们已经完成了最基本的 Apache 服务器安装,如果您不需要支持 PHP 及数据库,可以跳过下列步骤。
安装 PHP# cd /usr/ports/www/mod_php5
# make install clean
执行了上述指令后,会出现一个窗口让您选择进阶设定,请记得选取 APACHE2,如下图所示:
图 13-1

接下来我们必须安装一些常用的 PHP 模块,请执行下列指令:# cd /usr/ports/lang/php5-extensions
# make install clean
执行了 make install 后,会出现一个选单,除了预设的项目外,我们必须再选择下列几个常用的项目:CTYPE、EXIF、GD、ICONV、IMAP、PCRE、SESSION、ZLIB。这些项目非常常用,尤其是 SESSION。
安装完 PHP 后,我们将下来要安装数据库,您可以选择安装 MySQL 或 PostgreSQL,或者干脆二者都安装,以利日后使用不同的数据库应用。
安装 MySQL# cd /usr/ports/databases/mysql41-server
# make WITH_CHARSET=big5 WITH_XCHARSET=all install clean
# cd /usr/ports/databases/php5-mysql
# make install clean
安装 PostgreSQL# cd /usr/ports/databases/postgresql80-server
# make install clean
# cd /usr/ports/databases/php5-pgsql
# make install clean
安装了 MySQL 及 PostgreSQL 后,必须再进行数据库的细部设定。相关的数据库详细设定说明,请参考「数据库系统」一章的说明。
13.2.2 Apache 基本设定
安装完 Apache 后,我们必须先进行一些基本设定才可以开始使用。本节中,我们先介绍较常使用的设定项目,让您可以快速的设定好网页服务器,而更详细的 Apache 设定将于下一小节中说明。Apache 的设定档位于 /usr/local/etc/apache2/httpd.conf,请使用文章编辑软件打开 httpd.conf。
我们按照设定项目在 httpd.conf 中出现的顺序说明每一个项目,您可以使用搜寻的方式查找每一个项目的关键词,以进行设定。
ServerAdmin 设定管理者邮件
设定您的信箱,这个信箱地址当网页出现错误讯息时将出现在该页面上。以下范例为默认值:
ServerAdmin you@example.com
ServerName 设定主机名称及端口号
ServerName 可以让您设定您的主机名称,如果您没有主机名称,可以设定为您机器所使用的 IP。ServerName 会被用来重新转向网址,例如,当您输入一个网址 「http://www.example.com/dir」时,Apache 会参考您在 ServerName 中的设定,将 www.example.com 改成 ServerName,并在您所输入的网址后加上一个斜线「/」以连到 dir 目录中,也就是将网址转向到「http://www.example.com/dir/」。如果您的网址设定不正确,则使用者可能会连到一个不存在的地址。
所以,如果您没有主机名称,可以将这个值设定为 IP,让网址转向后还是可以连到正确的地方。在 ServerName 的设定中,我们也指定了 HTTP 的连接埠 80。
如果您的服务器是位于 NAT 后面,使用 NAT 做 Port Forwarding,建议不要设定这个项目,改将下一个设定选项 UseCanonicalName 设为 On,才不会在转向网址时导到错误的位置。
ServerName www.example.com:80
UseCanonicalName 设定导向网址的方式
Apache 在导向网址时,会参考您所设定的服务器名称及端口号,但当主机使用 NAT Port Forwarding 时,主机名称及端口号可能会不同,这时候我们必须将这个选项设为 On,以免 Apache 转向到错误的地址。
UseCanonicalName Off
DocumentRoot 设定网页根目录
DocumentRoot 可以让我们指定网页根目录的位置,也就是我们存放网页的目录。
DocumentRoot "/usr/local/www/data"
设定好 DocumentRoot 后,我们必须要再设定该目录的权限。在 DocumentRoot 之后,有下列区段:
   Options Indexes FollowSymLinks
   AllowOverride None
   Order allow,deny
   Allow from all
您必须将  也改成您的网页根目录位置。
DirectoryIndex 指定预设网页档名
当使用者使用网址「http://www.example.com/dir」连到一个目录中时,如果没有指定网页,Apache 会去查找 DirectoryIndex 中所设定的网页在不在,如果存在则秀出预设的网页。
预设的网页只有二个,我们可以再加上 index.htm、index.php 等常用的网页:
DirectoryIndex index.php index.htm index.html index.html.var
加入 PHP 支持
如果您要使用 PHP,则必须在 httpd.conf 中加入 PHP 的支持,请在 httpd.conf 档案最后加入下列内容:
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
上述设定完成后,您就可以存盘离开。
接下来,我们必在修改 /etc/rc.conf ,并加入下列设定以在开机时启动 Apache:
apache2_enable="YES"
最后,我们就可以使用下列指令以启动 Apache 了:# /usr/local/etc/rc.d/apache2.sh start
如果您要停止 Apache,可以使用下列指令:# /usr/local/etc/rc.d/apache2.sh stop
我们可以在网页根目录中新增一个档案来测试 PHP 是否有正常运作,请使用文书编辑软件开一个新文件 test.php,并加入下列内容:
接下来您就可以连到该网页 http://192.168.0.1/test.php (请将 192.168.0.1 改成您的主机 IP) 看看是否可以使用 PHP。如果有支持 PHP,则会显示 PHP 组态,如果没有,则只会出现上述档案内容。
13.3 http.conf 说明
/usr/local/etc/apache2/httpd.conf 是 Apache 的主要设定档。档案中有 # 为开头者是批注,用以说明设定的情形及方式,如果一行的开头有 # 的话,该行对 Apache 就不会产生作用。
我们按照 httpd.conf 中各选项出现的顺序说明几个重要的项目,比较不可能更动的项目我们就不在此说明。这些细部 Apache 的设定看起来有点无趣,但不看过一遍不知道有什么是我们可以调整的项目。建议您先大略浏览过即可,日后有调整的需要时,再回过头来参考即可。
ServerRoot 设定 Apache 执行的根目录
ServerRoot 用以设定 Apache 的根目录位置,记录文件、设定文件的相对目录位置。
ServerRoot "/usr/local"
必须注意的是,如果您的此目录设定为 NFS 或是其它以网络挂入的档案系统中,请先阅读
http://httpd.apache.org/docs-2.0/mod/mpm_common.html#lockfile
关于 LockFile 的说明,以避免一些不必须的问题发生。另外,请勿在 ServerRoot 的路径名称最后面加入 "/" 符号。
LockFile 设定 lock 文件的位置
LockFile 通常只有在您的网页数据使用 NFS 挂入时才会需要设定,否则使用默认值即可。如果您有设定 LockFile,LockFile 必须设定在非网络挂入的档案系统中。
#LockFile /var/log/accept.lock
我们看到 LockFile 这个项目被   包起来,这表示当没有使用 winnt 模块时这个设定才会生效。在下列其它设定中,我们会看到有其它的选项也是以   包起来,意思是一样的。
PidFile 设定 httpd.pid 位置
Apache 在启动时,会将自己的 process id 写入 PidFile 中。
PidFile /var/run/httpd.pid
Timeout 设定联机逾时
Timeout 设定了等待 Client 端响应的时间,以秒为单位。如果 Client 端在指定的时间内没有传送任何数据,即切断联机。
Timeout 300
KeepAlive 是否使用保持联机
设定是否使用保持联机的功能 (Presistent Connections)。当 KeepAlive 设为 On 时,一个已经建立的联机会用来处理多个 HTTP 的请求,也就是一个联机会用来传送多个档案,以避免每一个请求都要重新建立新的联机而降低效能。您可以将 KeepAlive 设为 Off 以关闭保持联机的功能。
KeepAlive On
MaxKeepAliveRequests 最多有几个保持联机
设定最多可以有几个 KeepAlive 的联机。您可以将这个项目设为 0 表示无限制。当有太多的保持联机时,会造成系统资源占用太多。但如果是一个忙录的服务器,建议您提高限制,以增加执行效率。
MaxKeepAliveRequests 100
KeepAliveTimeout 保持联机的逾时时间
同一个 Client 的「保持联机」功能,在多少秒后没有联机的请求即为联机逾时。如果二次请求的时间超过这个设定值,联机就会中断。
KeepAliveTimeout 15
prefork MPM 控制 process 数量
您会看到有很多个 StartServers、MinSpareServers、MaxClients 等设定,每个设定都使用   包起来。这是因为不同的平台会使用不同的模块,而设定就会依平台而有所不同。在 FreeBSD 中,我们使用的是 perfork 这个模块,因此,我们只要设定这个模块中的值即可。
在这个群组中,各个项目所代表的意义如下:
StartServers:设定 Apache 在启动时要产生多少个 process 来等待 Client 端的联机。我们使用默认值即可,除非您的服务器同时会有很多新的联机,则可以提高这个值。
MinSpareServers:最小要保持多少个空闲的 Apache process 以等待客户端的联机。除非您的网站真的很忙,否则这个值不需要设得太大,太大只会造成资源浪费。
MaxSpareServers:设定最多要有多少个空闲的 Apache process。如果您没有设定这个值,则 Apache 会自动将它设为 MinSpareServers+1。如果有太多闲置的 process,Apache 会自动将多余的 process 杀掉。
MaxClients:同时可以有多少个联机。MaxClients 应该是这个群组中最重要的设定,它关系着您的主机可以同时处理多少个联机。这个设定应该和您的系统资源相关,如果您的内存不大,而且同时处理很多联机,则 Apache 可能会需要用到 SWAP,而造成处理效能大幅下降。而设得太小时,却会使联机处理变慢。所以,MaxClients 应该由您的主机忙录情形及实际内存大小而决定。
MaxRequestsPerChild:当一个 process 联机处理了多少个联机要求后,要将它删除、回收,并启用新的 process 来接受新的要求。预设是没有限制。

StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxClients 150
MaxRequestsPerChild 0
Listen 设定接受联机的 IP 及埠号
设定 Apache 所要使用的连接埠号。预设的 HTTP 连接埠为 80,我们使用默认值即可,所以我们使用默认值即可。如果您希望 Apache 只接受连到某一个 IP 的联机 (当您同一台主机有多个 IP 时),可以设定只监听某一个 IP、埠号的联机。
例如,我们可以设定只接受客户端连到 192.168.0.1 的连接埠 8000,则可以设定为 192.168.0.1:8000。
Listen 80
LoadModule 动态加载的模块
Apache Dynamic Shared Object (DSO) 允许我们在启动 Apache 时动态加载模块,例如加载认证模块、PHP 模块等。在这个区段中,您可以看到 Apache 加载了很多模块。我们之后在设定虚拟主机、目录模限控制时,都必须检查 Apache 是否有加载我们想要的模块。这个部份的设定只要保持默认值即可。
LoadModule access_module libexec/apache2/mod_access.so
LoadModule auth_module libexec/apache2/mod_auth.so
LoadModule auth_anon_module libexec/apache2/mod_auth_anon.so
LoadModule auth_dbm_module libexec/apache2/mod_auth_dbm.so
... 略 ...
ExtendedStatus 显示详细状态信息
Apache 有一个 CGI 可以显示 Apache 服务器的状态信息 (server-status),当 ExtendedStatus 打开后,会显示更多信息。我们会在本章下一小节中说明如何使用这些信息。
#ExtendedStatus On
User Group 设定执行时的使用者及群组
系统要使用什么使用者名称及群组执行 Apache。使用 FreeBSD ports 安装后,预设的使用者及群组为 www。
User www
Group www
ServerAdmin 设定邮件
设定您的 Email。这个 Email 会显示在一些由 Apache 所产生的页面中。例如,当使用者连到一个不存在的网页、或是网页发生错误时,Apache 会秀出您所设定的 Email。
ServerAdmin you@example.com
ServerName 设定主机名称
ServerName 可以让您设定您的主机名称,如果您没有主机名称,可以设定为您机器所使用的 IP。ServerName 会被用来重新转向网址,例如,当您输入一个网址 「http://www.example.com/dir」时,Apache 会参考您在 ServerName 中的设定,将 www.example.com 改成 ServerName,并在您所输入的网址后加上一个斜线「/」以连到 dir 目录中,也就是将网址转向到「http://www.example.com/dir/」。如果您的网址设定不正确,则使用者可能会连到一个不存在的地址。
所以,如果您没有主机名称,可以将这个值设定为 IP,让网址转向后还是可以连到正确的地方。在 ServerName 的设定中,我们也指定了 HTTP 的连接埠 80。
如果您的服务器是位于 NAT 后面,使用 NAT 做 Port Forwarding,建议不要设定这个项目,改将下一个设定选项 UseCanonicalName 设为 On,才不会在转向网址时导到错误的位置。
ServerName www.example.com:80
UseCanonicalName 设定导向网址的方式
Apache 在导向网址时,会参考您所设定的服务器名称及端口号,但当主机使用 NAT Port Forwarding 时,主机名称及端口号可能会不同,这时候我们必须将这个选项设为 On,以免 Apache 转向到错误的地址。
UseCanonicalName Off
DocumentRoot 设定网页根目录
DocumentRoot 可以让我们指定网页根目录的位置,也就是我们存放网页的目录。除非您有使用 symbolic links 或是 aliases,否则所有的网页都会放在这个目录中。
DocumentRoot "/usr/local/www/data"
设定目录权限
接下来的几个区段中,您会看到   的设定。这个设定是用来指定某个目录的存取权限,例如是否允许执行 CGI、是否要列出该目录下的所有档案等等。
我们以之前所设定的网页根目录「DocumentRoot」为例,当您修改了网页根目录后,您也必须将这个区段中的  改成您的网页目录。由于 Apache 将一般的网页和 CGI 分别放在不同的目录,所以您的 DocumentRoot 设定和这里的设定稍有不同。但您可以将  及 DocumentRoot 都改成 /home/www。
#
# Possible values for the Options directive are "None", "All",
# or any combination of:
# Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
#
# Note that "MultiViews" must be named *explicitly* --- "Options All"
# doesn't give it to you.
#
# The Options directive is both complicated and important. Please see
# http://httpd.apache.org/docs-2.0/mod/core.html#options
# for more information.
#
    Options Indexes FollowSymLinks
#
# AllowOverride controls what directives may be placed in .htaccess files.
# It can be "All", "None", or any combination of the keywords:
# Options FileInfo AuthConfig Limit
#
    AllowOverride None
#
# Controls who can get stuff from this server.
#
    Order allow,deny
    Allow from all
我们后续再来说明一下   这个区段中每个项目的用途。
Options 设定目录可以使用的功能
我们在   中指定了要设定哪一个目录后,可以再使用 Option 来设定该目录可以使用哪些功能。以下为功能的列表及说明:
All:允许使用除了 MultiViews 以外的所有功能,此项目为默认值。
ExecCGI:允许在此目录中执行 CGI。
FollowSymLinks:允许在目录中使用 Symbolic links。使用者可以在此目录中建一个 symbolic link 连结到网页根目录以外的地方。例如,如果你在网页根目录中建一个 symbolic link 到 /etc/master.passwd,则使用 http://192.168.0.1/master.passwd 就可以看到 /etc/master.passwd 的内容。建议您将这个项目移除,以避免安全性问题产生。
Includes:允许使用 Server-side includes (SII)。
IncludesNOEXEC:允许使用 SII,但不可以使用 #exec 去执行系统指令或是 CGI。
Indexes:当目录中没有 DirectoryIndex 所设定的网页时 (如 index.html),是否要由 Apache 自动产生目录中的档案列表。除非您的网页是要开放改使用者下载档案,并希望由 Apache 产生档案列表,否则建议您关闭这项功能。
MultiViews:允许使用 Content negotiated 的功能,自动经由服务器和 Client 的内容协商,决定要使用哪一种语言的档案。
SymLinksIfOwnerMatch:如果 symbolic link 所指向的档案拥有者符合 Apache 执行的使用者,则允许使用 symbolic link。
当我们对目录设定 Option 的项目后,它的子目录也会继承该目录的设定值。如果我们同时设定一个目录及其子目录的 Option 的设,会以最接近的目录设定为主。例如,我们为 /home/www 及 /home/www/photo 设定权限如下:
    Options Indexes FollowSymLinks
    Options Includes
我们设定了 /home/www 可以使用 Indexes 及 FollowSymLinks,但 /home/www/photo 只能使用 Includes。虽然 /home/www/photo 是 /home/www 的子目录,但是其目录的设定只会以自己的 Options 为主,也就是不具有 Indexes 及FollowSymLinks,只有 Includes 的权限。
如果您希望子目录可以继承上一层的设定,可以使用 + 及 - 的符号表示。例如:
    Options Indexes FollowSymLinks
    Options +Includes -Indexes
我们在 /home/www/photo 的 Option 中使用了 + 及 -,所以它会继承 /home/www 的设定,但是加上 Includes 的功能,并取消 Indexes,所以最后 /home/www/photo 的权限就是 Includes 及 FollowSymLinks。
AllowOverride 设定 .htaccess 中可以使用的项目
Apache 允许使用者对于目录中使用 .htaccess 文件来控制权限,例如使用密码保护、设定权限等。我们会在下一章中说明如何使用 .htaccess 来做密码保护。
您可以将 AllowOverride 设成 All 或 None 来表示允许或不允许。或者,您也可以指定只允许下列某几个功能:
AuthConfig:允许设定不同的认证方式。
FileInfo:允许设定档案类型。
Indexes:允许设定列出目录索引时所要使用的选项。
Limit:允许使用 Allow、Deny、Order 来设定存取权限。
Options:允许设定目录权限。
Order 设定 Allow 及 Deny 的顺序
我们可以在目录中设定允许 (Allow) 及拒绝 (Deny) 的规则先后顺序,当二者抵触时,以后者为主。以下列范例为例,我们先设定了 Order 为 Deny, Allow,再设定拒绝所有联机,但只允许 192.168.0.2 来存取 /home/www/mp3。
    Order Deny,Allow
    Deny from all
    Allow from 192.168.0.2
UserDir 设定使用者个人网页
在 mod_userdir 区段中,包含了使用者个人网页的设定。使用者可以使用 http://www.example.com/~username 连到个人网页。预设的设定是每个使用者都可以在自己的家目录中建立一个名为 putblic_html 的目录,该目录就使用者的个人网页目录。UserDir 这个项目即定义了使用者个人网页的路径名称。如果您觉得这个名称太长,更改它的设定,但记得要修改  中的相对设定。
如果您不想让使用者有个人网页,可以将这个区段前面使用 # 批注起来。
UserDir public_html
UserDir disabled root toor daemon ..... pop www nobody mailnull smmsp
#
# Control access to UserDir directories. The following is an example
# for a site where these directories are restricted to read-only.
#
    AllowOverride FileInfo AuthConfig Limit Indexes
    Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
   
        Order allow,deny
        Allow from all
   
   
        Order deny,allow
        Deny from all
   
DirectoryIndex 设定预设网页档名
当使用者使用网址「http://www.example.com/dir」连到一个目录中时,如果没有指定网页,Apache 会去查找 DirectoryIndex 中所设定的网页在不在,如果存在则秀出预设的网页。
预设的网页只有二个,我们可以再加上 index.htm、index.php 等常用的网页:
DirectoryIndex index.php index.htm index.html index.html.var
HostnameLookups 设定将客户端 IP 转为 hostname
是否要在 Apache 的记录文件中将 Client 的 IP 转成 hostname。由于将 IP 转成 hostname 需要一点时间,将这个功能设为 On 会造成联机的效率变慢很多。
HostnameLookups Off
ErrorLog 指定错误记录文件位置
设定 Apache 错误讯息的记录文件位置。
ErrorLog /var/log/httpd-error.log
CustomLog 指定联机记录文件位置
设定 Apache 联机记录文件的位置。
CustomLog /var/log/httpd-access.log combined
Alias 设定别名
我们可以为一个目录或联机的 URI 设定别名,以简化目录名称。例如,您可以将 /home/alex/mp3/ 取一个别名为 /mp3/,让使用者在联机到
http://www.example.com/mp3/
时,指向 /home/alex/mp3/。
Alias /mp3/ /home/alex/mp3/
别名可以设定很多个,您可以依需求简化连结的位置。设定的别名目录不一定要是 DocumentRoot 的子目录,我们可以指定网页根目录以外的目录。

小提示
为了精准起见,我们使用 /mp3/ 而非 /mp3,以免将 /mp3files 变成了 /home/alex/mp3files。也就是多加了一个 "/" 在 mp3 之后。
AliasMatch 使用常规表示的别名
除了一般的别名外,我们还可以使用常规表示来设定别名。例如,我们要设定所有要使用 *.php 的档案都连到 /usr/local/php 目录中,则可以使用:
AliasMatch ^(.+\.php)$ /usr/local/php$1
ScriptAlias 设定 CGI 目录
ScriptAlias 可以让我们设定 CGI 的所在目录,它的功用其实看 Alias 差不多。下面的范例就是当使用者要连到 http://www.example.com/cgi-bin/ 时,我们将 cgi-bin 指向 /usr/local/www/cgi-bin/ 目录中。
ScriptAlias /cgi-bin/ "/usr/local/www/cgi-bin/"
ErrorDocument 指定错误讯息页面
当使用者连到一个不存在的网页,或是网页发生错误时,Apache 预设会帮我们产生一个错误讯息的网页。我们可以修改这个设定,以秀出我们自己设定的页面。例如,当您连到 YAHOO! 时,如果网页不存在,它的页面中还是秀出一些 YAHOO 自己的信息。
在 ErrorDocument 之后,首先要加的是错误代码。错误代码 404 在 HTTP 协议中表示找不到页面。在下列设定中,我们设定当找不到页面时,就秀出 /missing.html。/missing.html 的「/」指的并非系统的根目录,而是您网页的根目录。
ErrorDocument 404 /missing.html


小提示
修改 httpd.conf 是调校 Apache 的第一步,更多关于 Apache 的调校,可以参考 Apache 的使用手册,或是参考
http://httpd.apache.org/docs/2.0/misc/perf-tuning.html

13.4 PHP 进阶设定
php.ini 是 PHP 的设定档,若您使用 ports 安装,则你必须将设定文件范例 /usr/local/etc/php.ini.dist 复制成 /usr/local/etc/php.ini。我们可以经由修改 php.ini 来调整 PHP 的功能。
在 php.ini 中,开头为 ";" 的项目为批注、以 [ ] 包起来的是区段的名称,二种都不会代表任何意义。在修改完 php.ini 后,我们必须也要重跑 Apache 才可以有作用。
以下就让我们针对最常调整的几个项目做说明。
max_execution_time
这个选项设定了 PHP scripts 最长的执行时间,如果您的 PHP 程序需要执行很长的时间,则可以将它延长。预设的最长执行时间是 30 秒。
max_execution_time = 30
memory_limit
设定每一个 scripts 所能耗用的内存大小,预设是 8 MB。
memory_limit = 8M
error_reporting
预设的错误回报内容为何。这个选项设定了 PHP scripts 在发生何种错误时要回报讯息。预设是除了 NOTICE 及 STRICT 的错误以外都回报。这个选项的设定使用了 bit operation,在 php.ini 运算表示式可以使用「|」表示 bit OR、「&」表示 AND、「~」表示 NOT。以下列范例而言,就是 E_ALL AND (NOT E_NOTICE) AND (NOT E_STRICT)。
error_reporting = E_ALL & ~E_NOTICE & ~E_STRICT
error_log
我们可以将错误讯息记录在档案中,或是使用 syslog 将错误记录在 /var/log/messages 中。以下的范例即是使用 syslog。
error_log = syslog
register_globals
PHP 自从 4.1.0 开始,支持一种比较安全的变量传递方式。原本我们在写 PHP 程序时,从窗体以 POST 方式传入 PHP 程序时,PHP 可以直接拿来使用。例如,有一个窗体是下面这个样子:
当上述的 HTML 按了送出之后,在 test.php 这个程序就会有一个变量名为 $username,其值是我们所填入的名称。
但是使用者也可以直接在网址列输入 http://url/test.php?username=myname 来设定 $username 这个变量的值为 myname。
这会有什么问题呢?让我们以 PHP 4.1.0 release note 所提出的例子来说明。假设我们有一个程序如下:
使用者可以经由网址列输入一个变量 $authenticated=true,这样一来,不管是否通过 authenticate_user() 的检查,$authenticated 永远都是 true。
所以在 4.1.0 之后,有一个新的方式可以让我们使用,就是将传进来的变量全部都存在数组中。以第一个例子而言,我们以 POST 的方式从窗体传来变量 $username,新的取得变量方式是:$_POST["username"],也就是说所有以 POST 传递过来的变量全部存在 $_POST 这个数组中。详细说明请参考
http://www.php.net/release_4_1_0.php

在 4.2.0 之前,新旧二种方式都可以使用,但是在 4.2.0 之后,Default 只能使用新的方式来传递变量。所以如果你安装的了新 PHP 而发现无法使用旧的 PHP 程序,别惊讶。
如果您还是要以旧的方式来传递变量,请修改 php.ini,将原本的 register_globals = Off 改成下列这个样子,并移除开头的批注符号 ";":
; register_globals = Off
register_globals = On
post_max_size
当使用者从网页中使用 HTML FORM 以 POST method 送出数据时,最大的数据上限为何。默认值是 8 MB。
error_log = syslog
file_uploads
是否允许使用者以 HTTP 上传档案。预设为 On。
file_uploads = On
upload_max_filesize
当使用者从网页中使用 PHP 上传档案时,档案最大的大小为何。预设是 2 MB。
upload_max_filesize = 2M
13.5 Apache 服务器状态与管理
身为系统管理者,必须时常查看系统状态,检查、注意主机是否有异常的情形发生。Apache 提供了详细的系统记录文件,我们可以经由这些档案了解服务器、网页是否有异常的情形。另外,Apache 也提供了一些工具,可以让我们了解服务器的运作情形。
13.5.1 Apache 状态信息
在安装完 Apache 后,如果您所管理的是一个大型的网页服务器,您一定会需要了解服务器的系统负荷是否足以处理庞大的网络流量。Apache 内建了 server-status 及 server-info 二种观看服务器信息的方法。
server-status 服务器状态信息
server-status 可以让我们了解 Apache 目前运作的情形,包括占用的系统资源、目前联机数量等。在使用 server-status 之前,我们必须先修改 httpd.conf,以打开此功能。
...
LoadModule status_module libexec/apache2/mod_status.so
...
#
# ExtendedStatus controls whether Apache will generate "full" status
# information (ExtendedStatus On) or just basic information (ExtendedStatus
# Off) when the "server-status" handler is called. The default is Off.
#
ExtendedStatus On
...
#
# Allow server status reports generated by mod_status,
# with the URL of http://servername/server-status
# Change the ".example.com" to match your domain to enable.
#
    SetHandler server-status
    Order deny,allow
    Deny from all
    Allow from 192.168.0.
...
首先要确认的是 Apache 有载入 mod_status.so 这个模块,接着我们将 ExtendedStatus 设为 On,以显示详细的服务器状态。最后是找到 server-status 的区段,并移除开头的 #。在 server-status 区段中,我们设定了 Deny、Allow,以限制只有从某个地方联机进来的使用者可以查看服务器状态。在上述的范例中,我们限制只有从 192.168.0.x 的使用者才可以看到 server-status。
修改完 httpd.conf 后,我们必须使用下列指令重新启动 Apache:# /usr/local/etc/rc.d/apache2.sh restart
接下来,我们就可以使用浏览器连到 http://192.168.0.1/server-status。请将 192.168.0.1 改成您的主机 IP。连到 server-status 后,您可以看到下列画面:
图 13-2

server-status 的输出中每个字段所代表的意义如下:
字段
说明
Server Version
Apache 服务器的版本。
Server Built
Apache 服务器编译安装的时间。
Current Time
目前的系统时间。
Restart Time
Apache 重新启动的时间。
Parent Server Generation
Apache 父程序 (parent process) 的世代编号,就是 httpd 接收到 SIGHUP 而重新启动的次数。
Server uptime
Apache 启动后到现在经过的时间。
Total accesses
到目前为此 Apache 接收的联机数量及传输的数据量。
CPU Usage
目前 CPU 的使用情形。
_SWSS....
所有 Apache process 目前的状态。每一个字符表示一个程序,最多可以显示 256 个程序的状态。
Scoreboard Key
上述状态的说明。以下为每一个字符符号所表示的意义:
_:等待连结中。
S:启动中。
R: 正在读取要求。
W:正在送出回应。
K:处于保持联机的状态。
D:正在查找 DNS。
C:正在关闭连结。
L:正在写入记录文件。
G:进入正常结束程序中。
I:处理闲置。
.:尚无此程序。
Srv
本程序与其父程序的世代编号。
PID
本程序的 process id。
Acc
分别表示本次联机、本程序所处理的存取次数。
M
该程序目前的状态。
CPU
该程序所耗用的 CPU 资源。
SS
距离上次处理要求的时间。
Req
最后一次处理要求所耗费的时间,以千分之一秒为单位。
Conn
本次联机所传送的数据量。
Child
由该子程序所传送的数据量。
Slot
由该 Slot 所传送的数据量。
Client
客户端的地址。
VHost
属于哪一个虚拟主机或本主机的 IP。
Request
联机所提出的要求信息。
我们在查看 server-status 时,可以在输入的网址中加上参数 refresh 来让网页自动更新。例如,您可以输入 http://192.168.0.1/server-status?refresh=5,让网页每 5 秒钟自动重新加载。
server-info 服务器组态信息
server-info 和 server-status 的设定类似,我们可以经由 server-info 知道 Apache 的组态信息,包括版本、加载的模块等。
同样的,在使用 server-info 之前,我们必须先修改 httpd.conf,以打开此功能。
...
LoadModule info_module libexec/apache2/mod_info.so
...
#
# Allow remote server configuration reports, with the URL of
# http://servername/server-info (requires that mod_info.c be loaded).
# Change the ".example.com" to match your domain to enable.
#
    SetHandler server-info
    Order deny,allow
    Deny from all
    Allow from 192.168.0.
...
server-info 所使用的模块是 mod_info.so,我们先要确认的是 Apache 有该模块。接着我们找到 server-info 的区段,并移除开头的 #。在 server-info 区段中,我们一样设定了 Deny、Allow,以限制只有从某个地方联机进来的使用者可以查看服务器组态设定。
修改完 httpd.conf 后,我们必须使用下列指令重新启动 Apache 才可以使用:# /usr/local/etc/rc.d/apache2.sh restart
最后您就可以使用 http://192.168.0.1/server-info 连到 Apache 的服务器组态信息页面:
图 13-3

在 server-info 中,我们可以看到最上方是 Apache 所有己加载的模块信息,接着是 Apache 主要的设定状态,而最下方是目前 Apache 设定文件和默认值不同的地方。在本页面的其它部份为每一个已加载的模块状态供您参考。
13.5.2 效能测试
Apache 提供了一个测试 Apache 效能的工具 - ab。你可以使用 ab 针对某个 URL 来模拟出连续的联机请求 (不限本地主机),并设定同时间要模拟多少联机。
以下为 ab 这个指令比较常用的参数说明:
参数
说明
-n requests
要做多少次联机请求,requests 为次数。
-c concurrency
同时有多少个联机,concurrency 为个数。
-t timelimit
最多等待回应的秒数。
-p postfile
要以 POST 方法联机所欲送出的参数档案。postfile 为存放参数的文件名称。
例如,我要对自己的机器中的 index.php 作测试,模拟 1000 次请求,每次最多同时 20 个联机,只要在命令列执行指令:# /usr/local/sbin/ab -n 1000 -c 20 http://127.0.0.1/index.php
等了几秒之后出现:
This is ApacheBench, Version 2.0.41-dev  apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient).....done
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Finished 1000 requests
Server Software: Apache/2.0.54
Server Hostname: 192.168.0.4
Server Port: 80
Document Path: /index.php
Document Length: 3803 bytes
Concurrency Level: 20
Time taken for tests: 9.543791 seconds
Complete requests: 1000
Failed requests: 1002
(Connect: 0, Length: 1002, Exceptions: 0)
Write errors: 0
Total transferred: 6286345 bytes
HTML transferred: 6124788 bytes
Requests per second: 104.78 [#/sec] (mean)
Time per request: 190.876 [ms] (mean)
Time per request: 9.544 [ms] (mean, across all concurrent requests)
Transfer rate: 643.25 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 3 62 106.7 28 771
Processing: 13 125 163.3 55 860
Waiting: 5 89 120.1 46 786
Total: 26 187 229.5 94 1558
Percentage of the requests served within a certain time (ms)
50% 94
66% 168
75% 198
80% 218
90% 488
95% 772
98% 898
99% 950
100% 1558 (longest request)
您可以增加最多同时联机数目及联机次数,操看看你机器的上限在哪里。
还有更多的参数,详细用法请 man ab。
13.5.3 维护服务器记录文件
查看服务器记录文件可以让我们了解服务器的运作情形。Apache 预设会有二个记录文件,一个是所有联机的记录,预设的名称是 /var/log/httpd-access.log;另一个是联机错误记录文件,预设的位置是 /var/log/httpd-error.log。记录文件的位置及文件名是由 httpd.conf 决定,如果您修改过记录文件的设定,则路径可能就不太一定。以下为 httpd.conf 关于记录文件的设定:
...
ErrorLog /var/log/httpd-error.log
...
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
...
CustomLog /var/log/httpd-access.log combined
...
我们来看一下 httpd-access.log 的内容:
图 13-4

我们截取一条记录加以说明。第一行开头的部份是客户端的 IP,接下来是联机的时间、所查看的网页、及所使用的操作系统、浏览器等。在存取记录中要显示什么信息是由 httpd.conf 中的 LogFormat 所控制。因为我们设定了 CustomLog 所使用的格式是 combined,而 combined 在 LogFormat 中的设定就是显示上述格式。LogFormat 的格式中,每一个字段使用都可以用 %X 表示,例如 %h 表示客户端的 IP。
基本上我们比较少直接查看 access log,我们会使用一些外挂软件来析记录文件。例如,统计每个网页的使用量、哪一个网页最常被存取、每天有多少联机等等。下一章中,我们会介绍如何安装使用网页分析软件。
我们可能比较常看的是错误记录文件。经由查看错误记录文件,我们可以知道网页中没有有连结是坏的、使用者有没有尝试连到一个不存在的网页。我们选三条错误记录来说明:
[Fri Dec 10 19:45:45 2004] [error] [client 163.30.0.2]
File does not exist: /home/www/style.css
[Fri Dec 10 20:55:44 2004] [error] [client 220.165.54.39]
request failed: URI too long
[Fri Dec 10 20:56:09 2004] [error] [client 220.165.54.39]
File does not exist: /home/www/c/winnt/system32/cmd.exe
第一个错误记录是有人要存取 style.css,但却找不到该档案,这可能是我们网页的 HTML 中有错误的连结。第二、三条记录看来应该是 Windows 的病毒,它试着去存取 system32/cmd.exe,想要找 Windows 网页服务器的漏洞。您可以在错误记录文件中看到很多这种病毒的讯息,很庆幸我们是使用 FreeBSD + Apache,不需要担心病毒的入侵。
随着使用人数的增加,网站的 log 档可能会越来越大,我们可以使用 FreeBSD 的 newsyslog 来把旧的 log 备份起来。在 newsyslog 中,我们可以指定要备份多少个 log 档,超过之后会自动删除最旧的档案。
首先编辑 /etc/newsyslog.conf 加入下列二行:
/var/log/httpd-access.log 644  7   *  $W0D1  J  /var/run/httpd.pid
/var/log/httpd-error.log  644  7   *  $W0D2  J  /var/run/httpd.pid
以上二行的意义是将 /var/log/httpd-access.log 这个档案做备份,备份后的文件名称像这样 httpd-access.log.0.bz2 。备份后该档案的权限是 644,最大的数字到 7,也就是最多八个档案,不限制档案多大时要备份,选在每周日半夜 1 点时备份,并将该档以 bzip2 压缩。在备份完后,要将 /var/run/httpd.pid 所记录的 Process ID 重新启动。

TOP

第十二章 NAT 及防火墙
如果您家中有多台计算机需要同时上网,但却只有一个 IP 可以使用,这时 NAT 就派上用场了。NAT 可以让很多计算机经由一台 FreeBSD 服务器上网,而且还可以让 FreeBSD 的防火墙功能保护内部网络的计算机。本章将介绍以 FreeBSD 架设 NAT 服务器及使用 FreeBSD 防火墙功能。读完本章后,您将了解下列主题:
如何使用 FreeBSD 架设 NAT 服务器。
如何限制每一台计算机的最大上下传频宽。
如何架设防火墙。
如何架设具封包过滤功能的桥接器。
12.1 概论
这个部份我们将说明如何以 FreeBSD 做为防火墙,介绍 FreeBSD 内建的封包过滤功能。欲建立一台防火墙,就是要将一台机器放在二个网域的中间,并经由它来做封包过滤的工作。因此我们必须先确定网络封包能通过这台防火墙,再来设定要阻文件的规则。以 FreeBSD 作为二个网域中间的连接器,可以用路由器 (router)、网关、或是桥接器的方式来实作,再在该机器上设定防火墙的规则。当然,我们也可以只在一台单机上设定防火墙规则,以取代原本只能监控 inetd 服务的 TCP Wrapper。
我们举二种最常被应用结合防火墙设定来保护整个网络的方法,一个是 NAT,另一个是具封包过滤的桥接器。
12.1.1 NAT
所谓的 NAT 就是 (Network Address Translation),它可以让你在只有一个 IP 的情形下让多台计算机一起连上网络。举个实例而言,一个公司有三十台计算机,而 ISP 所提供的 ADSL 却只有八个实体 IP,这种情况下,我们可以将每台计算机的 IP 设定为 private IP,再让它们经由一台有实体 IP 的 NAT 服务器连上网络即可。
Private IP 是 RFC 所定义的私人 IP,这些 IP 不能够直接在因特网中出现,所以必需经由 NAT 的转换,将它们伪装成是由 NAT 服务器连向外部网络。这些可以用的私人 IP 如下:
Class
范围
子网掩码
Class A
10.0.0.0 ~ 10.255.255.255
255.0.0.0
Class B
172.16.0.0 ~ 172.31.255.255
255.255.0.0
Class C
192.168.0.0 ~ 192.168.255.255
255.255.255.0
我们只需在 NAT 服务器中做好设定,再将其它使用 private IP 的计算机设定 gateway 为该服务器的 IP 即可。另外,我们也可以在服务器中设定一些防火墙的规则,来保全内部网络。
12.1.2 具封包过滤的桥接器
如果我们的网络中有多台不同网域的计算机,这些计算机都有它们的 IP 及网络设定,我们可以将 FreeBSD 设定成为桥接器 (bridge),让这台桥接器作封包过滤的工作。这种做法对于网域内其它计算机原本的网络设定不会有影响,如果没有设定任何防火墙规则,对它们而言几乎不会发现桥接器的存在。我们可以使用桥接器来过滤同一个网域内的网络交通,如果您有一个很大的网域,想要降低同一网域内彼此网络封包的交互影响,却又不想将这个大网域分割成数个小网域,您可以使用具封包过滤功能的桥接器来达成网络封包分割的功能。我们也可以使用路由器来取代桥接器,但是路由器只能遶送二个不同网域,而且设定比较复杂,因此,我会使用桥接器来做为防火墙。
FreeBSD 内建有 ipfw 这个程序可以让我们轻易的设定一个简单的防火墙,我们只要在 kernel 中加上一些设定就可以打开它。在这里我们也将简单的介绍一些防火墙的语法,让我们可以保护我们不想、不需要被外界使用的网络服务。
在设定防火墙之前,有个观念必须先厘清。防火墙并不能够完全保护我们的网络安全,防火墙只是限制我们不想公开的服务、限制已知的 IP。就算架了防火墙,没有适当的管理也是枉然。
12.2 NAT
这里我们假设使用二张网络卡,一张是对外的网卡,代号是 fxp0;另一张是对内的网卡,代号 fxp1。以下的设定中请依您的网卡代号来加以修改。当然,你也可以只使用一张网络卡,将所有的计算机及对外网络都接在一台 HUB 上,再利用 alias 的功能将一张网卡设定二个 IP。在开始前,请先参考「网络设定」一章中的说明设定好第一张对外的网络卡喔。
在开始设定之前,请先检查一下内部网络的配置是否正确。我们内部网络的线路应该如图 12-1 所示。
图 12-1

上图中,内部网络的计算机全部都接到同一个 HUB 中,而 FreeBSD 有二个网络卡,对内的网络卡 fxp1 接在内部的 HUB 上,而对外的网络卡直接接在 ADSL Modem 或是对外的 HUB 上。上图的网络配置只是一个建议,您也可以将 fxp0、fxp1、及 ADSL Modem 全部接在内部的 HUB 上,只是这样 FreeBSD 就没有真正的隔离内外部网络了。
12.2.1 设定 kernel
首先,我们必须先确定核心有支持 NAT 及防火墙功能。FreeBSD 预设的 GENERIC 核心并未加入此功能,因此,请先编辑您的核心设定档,加入下列设定,并重新编译核心。如果您不知道如何修改核心设定,请参考「编译核心」一章的说明。假设我们要修改的核心设定档为 /usr/src/sys/i386/conf/GENERIC,先 cd /usr/src/sys/i386/conf/,再 ee GENERIC 加入下列几行:
# 防火墙
options IPFIREWALL
# 支援 NAT
options IPDIVERT
# 下面这一行是预设允许所有封包通过,如果没有这一行,
# 就必须在 /etc/rc.firewall 中设定封包的规则。
# 这条规则内定编号是 65535,也就是所有规则的最后一条
# 如果没有加这一条规则,内定就是拒绝所有封包,
# 只允许规则中允许的封包通过。
options IPFIREWALL_DEFAULT_TO_ACCEPT
# 这一行是让你可以在 ipfw 中设定要记录哪些封包,
# 如果没有这一行,就算设定了要留下记录也不会有作用。
options IPFIREWALL_VERBOSE
# 这一行是限制每一条规则所要记录的封包数量,
# 因为同样的规则可能有许多记录,加上这一条可以使
# 同样的记录重复数减少,以避免记录文件爆增。
options IPFIREWALL_VERBOSE_LIMIT=10
# 下面这一行是用来支援封包转向,
# 当你要使用 fwd 动作时必须要有这一项设定。
options IPFIREWALL_FORWARD
# 如果要使用 pipe 来限制频宽,必须加入下列选项以支持 dummynet。
options DUMMYNET
我们在上述设定中加入了许多项目,基本上,一定要有的项目为 IPFIREWALL 及 IPDIVERT,其它项目是为了支持限制频宽或记录信息使用。编辑完核心设定后,请重新编译并安装新的核心,重开机之后核心就己经支持防火墙及 NAT 了。
12.2.2 设定 rc.conf
请先参考「网络设定」一章,设定好您的第一张网络卡,并确定可以上网后,才开始下列设定。我们要修改 /etc/rc.conf 以启动 NAT 功能。我们假设网络卡代号是 fxp0 及 fxp1,请自行变更成您的网络卡代号:
# 设定第二张网络卡的 IP。
ifconfig_fxp1="inet 192.168.0.1  netmask 255.255.255.0"
# 设定启用 gateway 的功能。
gateway_enable="YES"
# 设定启用防火墙功能,并设定防火墙类型为 OPEN。
# FreeBSD 的防火墙设定档会自动为 NAT 加入相关的设定。
firewall_enable="YES"
firewall_type="OPEN"
# 设定 NAT 所使用的对外网络卡
natd_interface="fxp0"
natd_enable="YES"
设定结束之后,重开机应该就可以设定其它计算机使用这台 NAT 服务器来连上网络了。
12.2.3 设定 rc.firewall
我们在 /etc/rc.conf 中设定 firewall_type="OPEN",如果是使用原本 /etc/rc.firewall 的话,这样就已经就已经驱动了 NAT 的功能。
如果您想要加上更多的防火墙规则,可以编辑 /etc/rc.firewall ,并在档案最后加上您的设定。例如,我们要设定每一个内部计算机 (192.168.0.0/16) 最多只能使用的上传频宽为 64 Kb/s,下传频宽为 256 Kb/s,则可以在 rc.firewall 中加入下列设定:
# 限制频宽
/sbin/ipfw pipe 20 config bw 64Kbits/s
/sbin/ipfw pipe 21 config bw 256Kbits/s
/sbin/ipfw add pipe 20 ip from 192.168.0.0/16 to any
/sbin/ipfw add pipe 21 ip from any to 192.168.0.0/16
修改完后,执行 sh /etc/rc.firewall 就可以更新防火墙的设定了。其它关于防火墙规则的详细说明,请 man ipfw 或参考下一节的说明。
12.2.4 client 端的设定
在内部其它计算机方面,我们必须要再做一些设定才能让它们经由 FreeBSD 上网。首先,你的网络架构应该如图 12-1 所示。
而内部的其它的计算机设定方面,我们必须将其它计算机的 IP 设定为和 FreeBSD 服务器同一个子网络。以上列设定为例,您必须将其它计算机的 IP 设为 192.168.0.X (除了 192.168.0.1 以外的其它 IP)、子网掩码是 255.255.255.0,gateway 设定为 FreeBSD 连到局域网络的网络卡 IP,在此范例中是 192.168.0.1。然后再设定你的 DNS 为你 ISP 的 DNS 即可。
完成上述的设定后,我们就能享受以 FreeBSD 为NAT上网了。
如果您的其它计算机还是无法上网,您可以依下列步骤除错:
从 FreeBSD ping 因特网上的 IP,看看 FreeBSD 连到因特网是否正常。如果 ping 不到,表示 FreeBSD 对外网络设定有误。
从内部其它计算机 ping FreeBSD 对内的 IP。如果 ping 不到,请检查二方的 IP 及子网络设定是否正确,或是防火墙是否设定无误。
从内部计算机 ping 因特网上的 IP,如果 ping 不到,可能是 NAT 的设定有误。
12.2.5 NAT Port Forwarding
NAT 还有一个功能叫作 Port Forwarding,它的用途在于从连到本机的封包导向到别的计算机或本机其它连接埠。例如,我们对外有一台防火墙,在 DNS 设定方面,我们设定了 ftp.mydomain.com 及 www.mydomain.com 都指向这台防火墙。但我们希望所有 HTTP 联机都重新导向到内部的 192.168.0.2 这台机器上,而所有 FTP 联机都交由 192.168.0.3 来处理。这时候我们就可以使用 port forwarding 的方式来达成。
首先,我们知道 HTTP 使用 TCP 协议 port 80,而 FTP 使用了 TCP 协议 port 20 及 port 21,接着我们就可以在 /etc 目录下新增一个 NAT 的设定档,名为 natd.conf,并编辑内容如下:
redirect_port tcp 192.168.0.2:80 80
redirect_port tcp 192.168.0.3:20 20
redirect_port tcp 192.168.0.3:21 21
第一行的目的就是将 port 80 的 tcp 联机重新导向到 192.168.0.2 的 port 80,而二、三行是将 port 20 及 port 21 的联机交由 192.168.0.3 来处理。在 192.168.0.2 及 192.168.0.3 这二台机器上,我们只要设定它们的 gateway 为防火墙的 IP,例如 192.168.0.1 即可。
接下来我们必须在 /etc/rc.conf 中加入下列这一行,让 natd 在启动时能读取 /etc/natd.conf 的设定:
natd_flags="-f /etc/natd.conf"
重新启动后,您就可以进行测试了。假设防火墙的对外 IP 是 11.22.33.44,当我们从外部网络使用 HTTP 联机到该 IP 时,虽然该服务器并未架设 HTTP server,但你却可以看到网页,表示网络封包有被重导至内部的另一台服务器。

小提示
Port Forwarding 的功能是将外部联机转向到内部的计算机。所以,如果您从内部计算机连到 NAT 服务器时,并不会被转向到内部 IP 喔。
12.3 防火墙
ipfw 是 FreeBSD 内建的防火墙指令,我们可以用它来管理进出的网络交通。如果防火墙服务器是扮演着路由器 (gateway 例如上一篇中的 NAT 服务器) 的角色,则进出的封包会被 ipfw 处理二次,而如果防火墙扮演的是桥接器 (bridge) 的角色,则封包只会被处理一次。这个观念关系着我们以下所要介绍的语法,有的语法并不适用于桥接器。
另外,我们在设定防火墙时有二种模式,一种模式是预设拒绝所有联机,再一条一条加入允许的联机;另一种是预设接受所有联机,加入几条拒绝的规则。如果是非常强调安全性,应该是使用预设拒绝所有联机,再一条一条加入我们允许的规则。
我们会将 firewall 的设定写在 /etc/rc.firewall 中,每一条设定都是以先入为主 (first match wins) 的方式来呈现,也就是先符合的规则 (rules) 为优先。所有进出的封包都会被这些规则过滤,因此我们会尽量减少规则的数量,以加速处理的速度。
在 kernel 中,关于防火墙的设定有下列几条:
# 防火墙
options IPFIREWALL
# 支援 NAT
options IPDIVERT
# 下面这一行是预设允许所有封包通过,如果没有这一行,
# 就必须在 /etc/rc.firewall 中设定封包的规则。
# 这条规则内定编号是 65535,也就是所有规则的最后一条
# 如果没有加这一条规则,内定就是拒绝所有封包,
# 只允许规则中允许的封包通过。
options IPFIREWALL_DEFAULT_TO_ACCEPT
# 这一行是让你可以在 ipfw 中设定要记录哪些封包,
# 如果没有这一行,就算设定了要留下记录也不会有作用。
options IPFIREWALL_VERBOSE
# 这一行是限制每一条规则所要记录的封包数量,
# 因为同样的规则可能有许多记录,加上这一条可以使
# 同样的记录重复数减少,以避免记录文件爆增。
options IPFIREWALL_VERBOSE_LIMIT=10
# 下面这一行是用来支援封包转向,
# 当你要使用 fwd 动作时必须要有这一项设定。
options IPFIREWALL_FORWARD
# 如果要使用 pipe 来限制频宽,必须加入下列选项以支持 dummynet。
options DUMMYNET
ipfw 也支持状态维持 (keep-state) 的功能,就是可以让符合设定的规则以动态的方式来分配增加规则 (地址或连接端口) 来让封包通过。也就是说防火墙可以记住一个外流的封包所使用的地址及连接端口,并在接下来的几分钟内允许外界响应。这种动态分配的规则有时间的限制,一段时间内会检查联机状态,并清除记录。
所有的规则都有计数器记录封包的数量、位数、记录的数量及时间等。而这些记录可以用 ipfw 指令来显示或清除。
在说明 ipfw 规则的语法之前,我们先来看这个指令的用法。ipfw 可以使用参数:
指令
说明
ipfw add [rule]
新增一条规则。规则 (rule) 的语法请参考下一节的说明。
ipfw delete [number]
删除一条编号为 number 的规则。
ipfw -f flush
清除所有的规则。
ipfw zero
将计数统计归零。
ipfw list
列出现在所有规则,可以配合下列参数使用。
-a
使用 list 时,可以列出封包统计的数目。
-f
不要提出确认的询问。
-q
当新增 (add)、归零(zero)、或清除 (flush) 时,不要列出任何回应。当使用远程登入,以 script (如 sh /etc/rc.firewall) 来修改防火墙规则时,内定会列出你修改的规则。但是当下了 flush 之后,会立即关掉所有联机,这时候响应的讯息无法传达终端机,而规则也将不被继续执行。此时唯一的方法就是回到该计算机前重新执行了。在修改防火墙规则时,最好在计算机前修改,以免因为一个小错误而使网络联机中断。
-t
当使用 list 时,列出最后一个符合的时间。
-N
在输出时尝试解析 IP 地址及服务的名称。
-s [field]
当列出规则时,依哪一个计数器 (封包的数量、位数、记录的数量及时间) 来排序。
12.3.1 ipfw 规则
我们在过滤封包时,可以依据下列的几个封包所包含的信息来处理该封包:
接收或传送的接口,可以使用接口名称或地址。
方向,流入或流出。
来源或目的地的 IP 地址,也可以加上子网掩码。
通讯协议,TCP,UDP,ICMP 等。
TCP flags。
IP fragment flag。
IP options。
ICMP 的类型。
和封包相关的 socket User/group ID。
使用 IP 地址或 TCP/UDP 的端口号来做为规则可能蛮危险的,因为这二种都有可能被以假的信息所蒙骗 (spoof)。但是这二种却也是最常被使用的方法。
下列为 ipfw rules 的语法:[number] action [log] proto from src to dist [interface_spec] [option]
使用 [ ] 包起来的表示可有可无,我们一一为大家说明它们的意义:
number:
number 是一个数字,用来定义规则的顺序,因为规则是以先入为主的方式处理,如果你将规则设定放在一个档案中 ( 如 /etc/rc.firewall ),规则会依每一行排列的顺序自动分配编号。你也可以在规则中加上编号,这样就不需要按顺序排列了。如果是在命令列中下 ipfw 指令来新增规则的话,也要指定编号,这样才能让规则依我们的喜好排列,否则就会以指令的先后顺序来排。这个编号不要重复,否则结果可能不是你想要的样子。
action:
action 表示我们这条规则所要做的事,可以用的 action 有下列几个:
命令
意义
allow
允许的规则,符合则通过。也可以使用 pass,permit, accept 等别名。
deny
拒绝通过的规则。
reject
拒绝通过的规则,符合规则的封包将被丢弃并传回一个 host unreachable 的 ICMP。
count
更新所有符合规则的计数器。
check-state
检查封包是否符合动态规则,如果符合则停止比对。若没有 check-state 这条规则,动态规则将被第一个 keep-state 的规则所检查。
divert port
将符合 divert sock 的封包转向到指定的 port。
fwd ipaddr[,port]
将符合规则封包的去向转向到 ipaddr,ipaddr 可以是 IP 地址或是 hostname。如果设定的 ipaddr 不是直接可以到达的地址,则会依本机即有的 routing table 来将封包送出。如果该地址是本地地址 (local address),则保留本地地址并将封包送原本指定的 IP 地址。这项设定通常用来和 transparent proxy 搭配使用。例如: # ipfw add 50000 fwd 127.0.0.1,3128 tcp from \
  192.168.1.0/24 to any 80
如果没有设定 port ,则会依来源封包的 port 将封包送到指定的 IP。使用这项规则时,必须在 kernel 中设定选项 IPFIREWALL_FORWARD。
pipe pipe_nr
传递封包给 dummynet(4) "pipe",用以限制频宽。使用本语法必须先在核心中加入 option DUMMYNET。请 man ipfw 及 man dummynet。
基本语法是先将要设定频宽的规则加入: ipfw add pipe pipe_nr ....
再设定该规则的频宽:ipfw pipe pipe_nr config bw B delay D queue Q plr P
这里的 pipe_nr 指的是 pipe 规则编号,从 1~65535;B 是指频宽,可以表示为 bit/s、Kbit/s、Mbit/s、Bytes/s、KBytes/s、或 MBytes/s。D 是延迟多少 milliseconds (1/1000)。Q 是 queue size 的大小 (单位为 packages 或 Bytes)。P 是要随机丢弃的封包数量。
例如我们要限制内部网域的计算机对外上传的最大频宽是 20 KBytes:ipfw add pipe 1 ip from 192.168.0.1/24 to any in
ipfw pipe 1 config bw 20KBytes/s
log:
如果该规则有加上 log 这个关键词,则会将符合规则的封包记录在 /var/log/security 中。前提是在核心中有设定 IPFIREWALL_VERBOSE 的选项。有时因为同样的封包太多,会使记录文件保有大量相同的记录,因此我们会在核心中再设定 IPFIREWALL_VERBOSE_LIMIT 这个选项,来限制要记录多少相同的封包。
proto:
proto 表示 protocol,即网络协议的名称,如果使用 ip 或 all 表示所有协议。可以使用的选项有 ip,all,tcp,udp,icmp 等。
src 及 dist:
src 是封包来源;dist 是封包目的地。在这二个项目可以用的关键词有 any, me, 或是以 [ports] 的方式明确指定地址及端口号。
若使用关键词 any 表示使这条规则符合所有 ip 地址。若使用关键词 me 则代表所有在本系统接口的 IP 地址。而使用明确指定地址的方式有下列三种:
IP 地址,指定一个 IP,如 168.20.33.45。
IP/bits,如 1.2.3.4/24,表示所有从 1.2.3.0 到 1.2.3.255 的 IP 都符合规则。
IP:mask,由 IP 加上子网掩码,如 1.2.3.4:255.255.240.0 表示从 1.2.0.0 到 1.2.15.255 都符合。
而在 me, any 及 指定的 ip 之后还可以再加上连接埠编号 (ports),指定 port 的方法可以是直接写出 port ,如 23;或给定一个范围,如 23-80;或是指定数个 ports,如 23,21,80 以逗点隔开。或者是写出在 /etc/services 中所定义的名称,如 ftp,在 services 中定义是 21,因此写 ftp 则代表 port 21。
interface-spec:
interface-spec 表示我们所要指定的网络接口及流入或流出的网络封包。我们可以使用下列几个关键词的结合:
关键词
意义
in
只符合流入的封包。
out
只符合流出的封包。
via ifX
封包一定要经过接口 ifX,if 为接口的代号,X 为编号,如 vr0。
via if*
表示封包一定要经过接口 ifX,if 为接口的代号,而 * 则是任何编号,如 vr* 代表 vr0,vr1,...。
via any
表示经过任何界面的封包。
via ipno
表示经过 IP 为 ipno 界面的封包。
via 会使接口永远都会被检查,如果用另一个关键词 recv ,则表示只检查接收的封包,而 xmit 则是送出的封包。这二个选项有时也很有用,例如要限制进出的接口不同时:ipfw add 100 deny ip from any to any out recv vr0 xmit ed1
recv 接口可以检查流入或流出的封包,而 xmit 接口只能检查流出的封包。所以在上面这里一定要用 out 而不能用 in,只要有使用 xmit 就一定要使用 out。另外,如果 via 和 recv 或 xmit 一起使用是没有效的。
有的封包可能没有接收或传送的接口:例如原本就由本机所送出的封包没有接收接口,而目的是本机的封包也没有传送界面。
options:
我们再列出一些常用的 option 选项 ,更多选项请 man ipfw:
选项名称
意义
keep-state
当符合规则时,ipfw 会建立一个动态规则,内定是让符合规则的来源及目的地使用相同的协议时就让封包通过。这个规则有一定的生存期限 (lift time,由 sysctl 中的变量所控制),每当有新的封包符合规则时,便用重设生存期限。
bridged
只符合 bridged 的封包。
established
只适用于 TCP 封包,当封包中有 RST 或 ACK bits 时就符合。
uid xxx
当使用者 uid 为 xxx 则符合该规则。例如,我们如果要限制 Anonymous FTP 的下载速度最大为 64KB/s,则可以使用:ipfw pipe 1 config bw 512Kbit/s
ipfw add pipe 1 tcp from me to any uid 21
上列规则第一行是先建一个编号为 1 的 pipe,限制频宽为 512 Kbit/s (也就是 64 KByte/s),接着第二条是当使用者 uid 为 21 时,从本机 (me) 下载的 tcp 封包都使用编号 1 的 pipe。因为 Anonymous FTP 的使用者是 ftp,它的预设 uid 为 21,所以这条规则会被套用在 Anonymous FTP user 上。
setup
只适用于 TCP 封包,当封包中有 SYN bits 时就符合。
以上的说明只是 man ipfw 中的一小部份。如果你想要对 ipfw 更了解,例如如何使用 ipfw 来限制频宽等,建议你 man ipfw。
不知道您看了这么多的规则是否觉得眼花撩乱,如果不了解 TCP/IP 的原理,彻底了解 ipfw 的设定还真不容易。没关系,我们下面将举几个简单、常用的设定,这些范例应该够平常使用了。
12.3.2 范例
我将原本的 /etc/rc.firewall 备份成 rc.firewal.old,并将它改成下列内容,请注意,这里只是范例,只供参考:
# 设定我的 IP
myip="1.2.3.4"
# 设定对外的网络卡代号
outif="vr0"
# 设定对内的网络上代号
inif="vr1"
#清除所有的规则
/sbin/ipfw -f flush
# Throw away RFC 1918 networks
${ipfw} add deny ip from 10.0.0.0/8 to any in via ${oif}
${ipfw} add deny ip from 172.16.0.0/12 to any in via ${oif}
${ipfw} add deny ip from 192.168.0.0/16 to any in via ${oif}
# 只允许内部网络对 192.168.0.1 使用 telnet 服务
/sbin/ipfw add 200 allow tcp from 192.168.0.1/24 to 192.168.0.1 telnet
# 拒绝其它人连到 port 23,并记录尝试联机的机器
/sbin/ipfw add 300 deny log tcp from any to me 23
# 拒绝任何 ICMP 封包
/sbin/ipfw add 400 deny icmp from any to any
# 下面这台机器是坏人,不让它进来,并记录下来
/sbin/ipfw add 1100 deny log all from 211.21.104.102 to any
# NAT 的设定
/sbin/ipfw add divert natd all from any to any via vr0
# 限制内部网域对外下载最大频宽为 20KBytes/s,上传最大频宽为 5KBytes/s
ipfw pipe 20 config bw 20KBytes/s
ipfw add pipe 20 ip from any to 192.168.0.1/24 out
ipfw pipe 30 config bw 5KBytes/s
ipfw add pipe 30 ip from 192.168.0.1/24 to any in
# 允许本机对任何地方联机
/sbin/ipfw add check-state
/sbin/ipfw add 2000 allow udp from ${myip} to any keep-state
/sbin/ipfw add 2100 pass ip from ${myip}  to any
# 允许外界使用邮件服务
/sbin/ipfw add 3000 pass tcp from any to ${myip} 25 in via ${outif}
# 不允许内部的 IP 从外部连进来
/sbin/ipfw add 1200 add deny ip from ${myip}/24 to any in via ${oif}
# 其它都拒绝,如果没有在 kernel 中设定
# IPFIREWALL_DEFAULT_TO_ACCEPT 则内定就有下列这一条
/sbin/ipfw 65535 add deny all from any to any
存盘后就可以使用 sh rc.firewall 来执行新的规则了。如果您将规则放在 /etc/rc.firewall 中,则开机时会自动执行。
12.3.3 一些小建议
在建立一个封包过滤的防火墙时,应该尽可能阻挡一些不必要的服务。避免开放 port 1024 以下的 TCP 服务,例如只通过 SMTP 封包 (port 25) 给邮件服务器;拒绝所有 UDP 联机 (只有少部份服务如 NFS 会用到);一些只有内部才会使用的服务,如数据库等也不必对外开放。
另外,同样的防火墙限制可以使用不同的语法来展现,应该要试着让规则数量越少越好,以加快处理速度。
在更新 firewall 规则时,如果规则没有写好,而你又是以远程登入的方式修改规则,很可能会因此无法继续登入。因此建议更新规则时最好在 console 前执行,若迫不得已一定要使用远程登入,建议您执行 /usr/share/examples/ipfw/change_rules.sh 这支程序来编辑规则:# cd /usr/share/examples/ipfw
# sh change_rules.sh
接着会出现文书编辑软件并最动加载 /etc/rc.firewall 让你编辑,结束离开后,会询问是否要执行更新。如果执行新的规则后造成断线,它会自动加载旧的规则,让我们可以再次联机。
12.4 封包过滤桥接器
如果您有三台机器全部都有 public IP,而您想使用其中一台做为防火墙,在不改变另外二台机器的设定下,我们可以使具封包过滤的桥接器来架设防火墙。只要将这台桥接器放在另外二台和对外网络之间即可。
另外,当我们的内部网络有不同 class 的主机时,例如内部有 140.115.2.3 及 140.115.5.6 这二台计算机时,就无法使用传统的防火墙。如果要在这二台机器连到因特网中途中使用防火墙,我们必须使用新的方式,也可以使用这里介绍的桥接器。
我们可以使用 FreeBSD 为桥接器,利用它来做封包过滤的动作,而丝毫不影响内部的主机原本的设定。为了达到这个功能,我们必需要有二张支持 promiscuous mode 的网络卡,现在的网络卡大部份都有支持。二张网络卡当中,一张需要设定 IP,另一张不需要。至于您要将 IP 设定在哪一张卡都可以,建议是设在对外的网络卡上。
首先,我们必须在核心中加入关于桥接器的设定:
# 支援桥接器
options BRIDGE
# 防火墙设定
options IPFIREWALL
options IPFIREWALL_VERBOSE
# 我们这里不将防火墙预设为接收所有封包
#options IPFIREWALL_DEFAULT_TO_ACCEPT
如果您要让桥接器具有流量控制的功能,则可以加上之前提到的选项「options DUMMYNET」。重新编译核心后,在重开机前,我们先设定一下 /etc/rc.conf:
firewall_enable="YES"
firewall_type="open"
还有一件事要做,当在以太网络上跑 IP 协议时,事实上使用二种以太网络协议,一个是 IP,另一个是 ARP。ARP 协定是当机器要找出给定 IP 地址所对应的以太网络地址时使用的。ARP 并不是 IP 层的一部份,只是给 IP 应用在以太网络上运作。标准的防火墙规则中并未加入对于 ARP 的支持,幸运的是,高手们的在 ipfirewall 程序代码中加入了对封包过滤桥接器的支持。如果我们在 IP 地址 0.0.0.0 上建立一个特别的 UDP 规则,UDP 端口的号码将被使用来搭配被桥接封包的以太网络协议号码,如此一来,我们的桥接器就可以被设定成传递或拒绝非 IP 的协议。请在 /etc/rc.firewall 中接近文件顶端处理 lo0 的那三行之下(就是有写 Only in rare cases do you want to change these rules 的地方)加入下面一行:
${fwcmd} add allow udp from 0.0.0.0 2054 to 0.0.0.0
现在我们就可以重新开机了。重开机之后,先执行下列指令来启动桥接器:
如果您使用的是 FreeBSD 4.x:# sysctl -w net.link.ether.bridge_ipfw=1
# sysctl -w net.link.ether.bridge=1
如果您使用的是 FreeBSD 5.x:# sysctl -w net.link.ether.bridge.ipfw=1
# sysctl -w net.link.ether.bridge.enable=1
现在我们可以将机器放在内外二个网域之间了。因为我们之前在 /etc/rc.conf 中,设定防火墙完全打开,不阻挡任何封包,所以放在二个网域之间时,运作应该没有问题。我们之前只设了一张网络上的 IP,而在执行了上述的指令之后,第二张网络卡便开始运作。
下一步就是将我们启动桥接器的指令放在 /etc/rc.local 中,让系统在开机时自动执行。或者,我们可以在 /etc/sysctl.conf 中加入下面二行:
# 如果您使用的是 FreeBSD 4.x
net.link.ether.bridge_ipfw=1
net.link.ether.bridge=1
# 如果您使用的是 FreeBSD 5.2 以后的版本
net.link.ether.bridge.enable=1
net.link.ether.bridge.ipfw=1
接下来我们就可以依自己的需求在 /etc/rc.firewall 文件的最后面加上我们自己想要的防火墙规则了。以下是一个简单的设定规则,假设桥接器的 IP 是 140.115.75.137,内部有二台主机,一台提供网页服务,一台是 BBS:
us_ip=140.115.75.137
basrv_ip=140.115.3.4
bbs_ip=140.115.5.6
oif=fxp0
iif=fxp1
ipfw="/sbin/ipfw"
# Things that we've kept state on before get to go through in a hurry.
${ipfw} 1000 add check-state
# Throw away RFC 1918 networks
${ipfw} 1100 add deny ip from 10.0.0.0/8 to any in via ${oif}
${ipfw} 1200 add deny log ip from 172.16.0.0/12 to any in via ${oif}
${ipfw} 1300 add deny log ip from 192.68.0.0/16 to any in via ${oif}
# 允许桥接器本身所有想做的联机 (keep state if UDP)
${ipfw} 1400 add pass udp from ${us_ip} to any keep-state
${ipfw} 1500 add pass ip from ${us_ip} to any
# 允许内部网络任何想做的联机 (keep state if UDP)
${ipfw} 1600 add pass udp from any to any in via ${iif} keep-state
${ipfw} 1700 add pass ip from any to any in via ${iif}
# 允许任何的 ICMP 联机
${ipfw} 1800 add pass icmp from any to any
# 不允许使用 port 888 联机
${ipfw} 2000 add deny log tcp from any to ${bbs_ip} 888
# TCP section
# 任何地方都可以建立 TCP 联机
${ipfw} 3000 add pass tcp from any to any via ${oif}
# Pass the "quarantine" range.
${ipfw} 3100 add pass tcp from any to any 49152-65535 in via ${oif}
# Pass ident probes. It's better than waiting for them to timeout
${ipfw} 3200 add pass tcp from any to any 113 in via ${oif}
# Pass SSH.
${ipfw} 3300 add pass tcp from any to any 22 in via ${oif}
# Pass DNS. 当内部网络有名称服务器时才需要
#${ipfw} add pass tcp from any to any 53 in via ${oif}
# 只传递 SMTP 给邮件服务器
${ipfw} 3400 add pass tcp from any to ${bbs_ip} 25 in via ${oif}
${ipfw} 3500 add pass tcp from any to ${basrv_ip} 25 in via ${oif}
# UDP section
# Pass the "quarantine" range.
${ipfw} 4000 add pass udp from any to any 49152-65535 in via ${oif}
# Pass DNS. 当内部网络有名称服务器时才需要
#${ipfw} 4100 add pass udp from any to any 53 in via ${oif}
# 其它的都拒绝
${ipfw} 60000 add deny ip from any to any

TOP

第十一章 X Window 的使用
在 UNIX 的世界中,一样有图形化的接口可以使用。本章将介绍 UNIX 中最有名的窗口软件:X Window。X Window 提供了 FreeBSD 图形化的接口,但它只提供了图形化的能力,我们还必须另外安装一些常用的图形化程序及工具。读完本章后,您将了解下列主题:
X Windows 的介绍及安装。
KDE 窗口管理接口的使用。
中文化的图形接口。
11.1 安装 X Window
X11 是在 UNIX 系统下的窗口软件,它分为二种版本,一个是原本 FreeBSD 5.2.1 以前用的 XFree86,另一个是 FreeBSD 5.3 以后预设使用的 Xorg。
原本的 X11 是以 XFree86 为主,但最近由于版权争议及管理问题,分裂成二套软件。事实上,Xorg 也发展了很久,许多 Xorg 的人都是 XFree86 的开发者。在近期分裂时,Xorg 及 XFree86 的原始码做过同步,日后的开发才会有比较明显的差异。您可以选用 Xorg 或是 XFree86,不过 FreeBSD 预设是用 Xorg,而像 Redhat Linux 也都是使用 Xorg。照趋势及 Xorg 的开发愿景看来,似乎较多人会选用 Xorg。
我们在本章中会以 Xorg 设定为主,如果您使用 FreeBSD 5.2.1 以前的版本,您可以参考本章的设定,并将指令或设定名为 Xorg 的都改成 XFree86 即可。
X11 是一个 Client/Server 架构的软件,之所以会是 Client/Server 架构是因为在一开始设计 X 时,为了做到网络集中管理。「X Server」指的是有鼠标及键盘的机器,而「X Client」是画面显示的机器。不过我们在安装时,会将 Client 及 Server 都安装在同一台机器上。
X11 只是用来做基本的图形显示,我们除了介绍安装 X11 外,另外我们会再加装窗口管理软件,如果没有了它,X Windows 就只能看到白白一片。在众多的窗口管理软件中,我们选用 KDE,因为它提供了很多常用的工具,例如浏览器、Office 软件等。因此,我们将安装 X Windows + KDE 3 及并将其界面中文化。当然您也可以选用 GNOME 等其它的窗口管理接口。
您可以使用 port 来安装 X Window 及 KDE 3,但是必须花费很长的一段时间来进行编译。为了加快安装,我们使用 sysinstall 经由 packages 来快速安装。
Step1:安装X Window
在安装 FreeBSD 时,我们应该己经选择要安装 X Windows 套件,如果您安装 FreeBSD 时并未安装该套件,您可以在开机后执行 sysinstall 来进入安装时的选单。进入安装画面后,选择 [Configure]->[Distributions]->[X.Org],如图 11-1 所示。
图 11-1

接下来会出现一个选单让您选择所要安装的 X.Org 套件,如图 11-2 所示,请进入每一个目录选取 ALL。
图 11-2

接着选择 [EXIT] 回到选择安装来源。因为 X Window 已包含在 Installation CD 中,所以您可以选择 CD/DVD 为安装来源并放入本书所附的第一片 CD即可开始安装 X Window。
Step2:安装KDE 3
我们可以使用 Package 或 Ports 来安装 KDE,但是由于 Package 只会在 FreeBSD release 时产生,如果您之前有更新过 Port Tree,并安装过很多软件,则在使用 Package 安装 KDE 时,可能会发生无法安装的情形。而如果使用 Ports 来安装,光编译可能就要花很长的时间喔,大概要一、二天吧。所以,我们先试着使用 Package 来安装,以节省时间。
首先,请先将本书的第二片光盘放入光驱,并执行下列指令,以挂入光驱,并进入 sysinstall:# mount /cdrom
# sysinstall
进入 sysinstall 后,请选择 [Configure] -> [Packages] -> [CD/DVD] -> [kde] -> [kde-3.4.2]。选了 kde-3.4.2 后,系统会自动帮您选择其它需要的套件。接下来就可以按 OK 并回到上一页按 [Install] 开始安装。
万一您安装失败,可能是因为之前有安装过其它软件,造成冲突。这时候,我们可以改用 Port 来安装 KDE。如果您要使用 Port 安装,请使用下列指令:# cd /usr/ports/x11/kde3
# make BATCH=yes WITH_KDE_PATCHES=yes install
在使用 Ports 安装时,您可能会遇到有软件安装过其它类似的版本,结果就造成安装中断。这时候,您可以在 make 时,加上 「FORCE_PKG_REGISTER=y」,以强迫安装。
Step3:安装中文化字型
接着我们要让 KDE 支持中文的选单及讯息,我们必须先安装中文讯息文件 (i18n):# cd /usr/ports/chinese/kde3-i18n-zh_TW
# make install clean
接下来,我们要安装中文字型。XWindow 支持 TrueType 的字型,而在 MS Windows 上,我们常使用的细明体就是 TrueType 的字型。因此,您可以支接将「C:\WINDOWS\Fonts\mingliu.ttc」复制到 FreeBSD 的「/usr/X11R6/lib/X11/fonts/TrueType」目录中即可使用:# mkdir /usr/X11R6/lib/X11/fonts/TrueType
# cp mingliu.ttc /usr/X11R6/lib/X11/fonts/TrueType/
由于 mingliu.ttc 中实际上包含了二个字型:细明体及新细明体。KDE 在判断字型宽度及大小时有点问题,造成字型有点难看,所以,我们必须编辑 ~/.fonts.conf,并加入下列内容,以改善字型:
   
        MingLiU
        true
        true
        false
   
   
        MingLiU
        12
        false
        true
   
   
        MingLiU
        false
   
   
        MingLiU
        0
   
您可以在直接打开本书电子文件,并使用复制贴上的方式来编辑上列档案,以节省时间。
Step4:产生设定档
我们接着要执行 Xorg -configure 来产生设定档 XF86Config.new,然后将它搬到 /etc/X11/:# Xorg -configure
# cp /root/xorg.conf.new /etc/X11/xorg.conf
接着编辑 /etc/X11/xorg.conf,在 FontPath 区段最前面加入 TrueType 及 local 二个路径,以期使 X Window 能找到正确的字型路径:
Section "Files"
       RgbPath      "/usr/X11R6/lib/X11/rgb"
       ModulePath   "/usr/X11R6/lib/modules"
       FontPath     "/usr/X11R6/lib/X11/fonts/TrueType/"
       FontPath     "/usr/X11R6/lib/X11/fonts/local/"

       FontPath     "/usr/X11R6/lib/X11/fonts/misc/"
       FontPath     "/usr/X11R6/lib/X11/fonts/TTF/"
       FontPath     "/usr/X11R6/lib/X11/fonts/Type1/"
       FontPath     "/usr/X11R6/lib/X11/fonts/CID/"
       FontPath     "/usr/X11R6/lib/X11/fonts/75dpi/"
       FontPath     "/usr/X11R6/lib/X11/fonts/100dpi/"
EndSection
如果您有滚轮鼠标,您可以在下列「InputDevice」区段中加入「ZAxisMapping "4 5"」,以支援滚轮:
Section "InputDevice"
       Identifier  "Mouse0"
       Driver      "mouse"
       Option      "Protocol" "auto"
       Option      "Device" "/dev/sysmouse"
       Option      "ZAxisMapping" "4 5"
EndSection
接下来,我们来设定屏幕的分辨率等。请先找到 Section "Monitor" 的部份,并查看 Identifier 那行已经找到您所使用的屏幕。如果有,您可以不必设定水平及垂直更新频率。如果没有,请参考您的屏幕使用手册,并将 Horizsync(水平更新频率) 及 VerRefresh(垂直更新频率) 设定一个适合您的范围。
Section "Monitor"
        Identifier "Monitor0"
        VendorName "Monitor Vendor"
        ModelName "Monitor Model"
        Horizsync 30-70
        VertRefresh 50-100
接着要设定屏幕的分辨率,我希望以 16bit 色彩显示,1024x768 而且不要虚拟桌面。则请先找到 Section "Screen" 的部份:
Section "Screen"
        Identifier "Screen0"
        Device     "Card0"
        Monitor    "Monitor0"
        DefaultColorDepth 16
        SubSection "Display"
                Viewport   0 0
                Depth     1
        EndSubSection
        .......略......
        SubSection "Display"
                ViewPort 0 0
                Depth 16
                Modes "1024x768"
                Virtual 1024 768

        EndSubSection
我们加入了 DefaultColorDepth 16,表示内定以16 bit 的色彩显示。接着找到 Depth 16 的部份,加入了 Modes 及 Virtual。这二行表示可以用 1024x768 的分辨率、虚拟桌面为 1024x768。接着存档离开。
Step 5:进入 X Window
为了一进入 X Window 即有 KDE 要先编辑 ~/.xinitrc 加入下列二行:
#!/bin/sh -
export LANG=zh_TW.Big5  # 设定使用中文
exec /usr/local/bin/startkde
接着我们就可以执行 startx 来进入 X Window 了。如果您找不到 startx 的指令,请先执行来 rehash 更新指令,再执行一次 startx。
进入 X Window 后,画面会出现 KDE 的桌面设定选单,您只要依画面提示即可完成 KDE 的安装。设定完后,您就可以看到完整的 KDE 了:
图 11-3

如果您在X Window中无法使用鼠标,请先同时按 [Ctrl] + [Alt] + [Backspace] 离开 X Windows,再执行 sysinstall 来设定鼠标。设定鼠标的位置在 [Configure]->[Mouse],先设定 [Type] 选择鼠标的类型,再选 [Enable] 让一开机即驱动鼠标。
进入 KDE 后,您可以在控制中心里调整字型,建议您先将所有字型调为细明体 (MingLiu)。如果您要调整字型,请按画面左下角的 K 图示,并选择「控制中心」,即出现下列画面:
图 11-4

调整后,请重新启动 X Window。
在 KDE3 中有许多的附属软件,从简单的文字编辑器、绘图软件,到常用的办公室软件、浏览器及邮件软件都有。由于是图形接口,您可以自行摸索尝试。KDE 的浏览器是 Konqueror,它的使用接口和 IE 差不多,除了是网页浏览器外,也结合了档案总管的功能,下图即 Konqueror 的画面:
图 11-5

您也许会发现 KDE 简直可以和MS Windows 抗衡,它的办公室软件功能齐全,不论是 KWord、KExcel、KPowerPoint 都是威力强大的软件。
图 11-6


11.2 X Window下的中文软件
11.2.1 中文终端机
KDE 所附的终端机 Konsole 已经支持中文的显示,而且还有许多强大的功能。例如我们可以设定终端机背景、字型等,而且操作十分容易。只要您在 ~/.xinitrc 中有设定 LANG 为为 zh_TW.Big5 即可显示中文。
图 11.7

11.2.2 中文输入
我们安装的 X Window 目前为止只能看到中文,但无法使用中文输入,如果要使用中文输入,必须安装 Xcin 这套软件。xcin 是 X Chinese Input 的缩写,这个软件提供许多输入法,例如注音、大易、仓颉、简易、酷音、行列等。他们的网址是
http://xcin.linux.org.tw
,您可以在这里获得更多信息。
xcin 采用标准的 XIM 协议,XIM 协议是 X Window 下中文输入的标准,只要支持 XIM 的软件,我们都可以使用 xcin 来输入中文。而在 KDE 中,除了 Konsole 外,其它常用的软件都支持 XIM 中文输入。
安装 xcin 十分容易,我们可以使用 Ports 来安装:# cd /usr/ports/chinese/xcin25
# make install
安装完 Xcin 后,我们还要修改 ~/.xinitrc 来加入中文输入法的设定,请使用文书编辑软件来编辑 ~/.xinitrc 这个档案:
#!/bin/sh -
export LANG=zh_TW.Big5  # 设定使用中文
# 加入下列二行
export XMODIFIERS=@im=xcin
xcin2.5&

# 启动 KDE
exec /usr/local/bin/startkde
修改完后存盘,接着进入 X Window 您将看到输入法的窗口,然后我们就可以执行支持其它软件来输入中文了。例如我们开启 Konsole 的窗口后,就可以使用 Ctrl+Space 来切换中英文输入法。其它像 Konqueror 或 Kword 下的中文输入也没问题,如下图。
图 11-8

在输入法的切换方面,我们可以使用下列几个预设的热键来切换:
Ctrl+Space
中文 / 英文的切换
Ctrl+Shift
依序切换输入法 (正向切换)。
Shift+Ctrl
依序切换输入法 (反向切换)。
Ctrl+Alt+数字
选择输入法,数字部份由 1~8
预设的 XCIN 在输入中文时,输入法窗口不会在最上方,所以我们必须修改一下 XCIN 的设定档。设定文件的位置是 /usr/X11R6/etc/xcinrc,使用文书编辑软件打开后,找到 "OVERSPOT_WINDOW_ONLY" 的部份,并修改成 YES:
;  XIM Input Style Adjustments.
(define INPUT_STYLE            '(Root OverTheSpot))
(define OVERSPOT_USE_USRCOLOR   "YES")
(define OVERSPOT_USE_USRFONTSET "YES")
(define OVERSPOT_WINDOW_ONLY    "YES")
接着重新启动 X 窗口,当要输入中文时,只要以 Ctrl+Space 就可以打开输入法窗口。
在 X Window 中,有一些使用上的小技巧,例如您可以使用 Ctrl+Alt+Backspace 来强迫离开 X Window。如果您要使用鼠标在 Konsole 中来做复制贴上,你只要用鼠标选取所要复制的地方,就已完成复制的动作,接着再按 Shift+Insert 即可贴上。你可以发掘更多的小技巧喔。

TOP

第十章 软件安装
安装了 FreeBSD 后,您一定还会需要安装其它非 FreeBSD 内附的软件。在 FreeBSD 上安装软件有许多种方法,我们将一一为各位介绍。
本章包含了下列软件安装必备的课题:
各种安装方式的优缺点。
如何使用 package。
如何使用 port。
如何使用传统安装方法自行编译软件。
10.1 概论
传统上,要在一个 UNIX 系统上安装其它软件时,有几个步骤:
下载该软件,有可能是 binary 档或是原始码。
解压缩该档案,通常是以 tar 或 gzip 压缩的。
读一下该目录中的说明文件,可能是 readme 或是 doc/ 的文件,来了解如何安装该软件。
如果所下载的是原始码,可能要先编辑一下 Makefile 或是执行 configure,接着再编译该软件。
最后再测试与安装。
当然,我们可以在 FreeBSD 上使用传统的方式来安装软件,但是还有更简单的选择。FreeBSD提供了 package 和 ports 这二种简单的安装软件方式。
所谓的 pakcage 是别人帮你将程序编译成 binary 文件,并定义了该安装在什么地方。我们只要下载一个压缩档,并使用 pkg_add 这个指令就可以快速的将软件安装在 FreeBSD 上。这是安装软件最简单的步骤,所安装的东西也是最标准的,和自己依需求修改并编译原始码比较起来较缺乏弹性。
而 port 就是使用原始码来安装软件。我们只要进入 /usr/ports/ 里想要安装的软件目录中,打指令 make install 就可以完成安装了。FreeBSD 己经帮我们定义了安装该软件所须的步骤、所要求的其它套件。不管是 package 或是 ports,当安装的软件需要依靠其它软件才能继续安装时,它们会自动帮你安装该软件。所有安装好的软件都将记录在 /var/db/pkg 中,日后如果我们想要移除软件时,可以用一个简单的指令 pkg_delete 加上软件名称就可以了。
即然 port 这么好用,为什么 FreeBSD 要同时有 package 和 ports 呢?我们来比较一下 ports 和 package 的优点:
package 的优点:
一个己经编译过的压缩档通常比包含原始码的档案还要小。
使用 pakcage 并不需要再做任何的编译动作,如果你的计算机速度很慢,在安装像 KDE、GNOME 等大型软件时,不用编译可以省下很多时间。
使用 package 来安装软件时,你不必事先了解在 FreeBSD 上编译时所使用的软件及其过程。
ports 的优点:
package 为了要在多数的计算机执行,考虑兼容性问题,通常编译的比较保守。而使用 ports 你可以依自己的系统修改,例如选择使用 Pentium III 或是 Athlon 的处理器。
在编译 package 时,就已经限制了该软件的功能,无法再依自己需求扩充。例如 Apache 这套软件就有许多的功能可以在编译时挂进来,使用 ports 来安装时,你可以依自己的需求来加以修改。
我们可以经由更新 Port Tree 来使用较新的软件,而 package 通常只和系统一起 release。
有些软件不允许使用 binary 文件的方式散播,只能下载原始码。
有了原始码,你可以自己修改并加以应用。
有的人喜欢拥有原始码,他们可以读它、从中学习。
接着我们就针对 package 及 ports 来说明它们的使用方式。   
10.2 使用 package
10.2.1 安装 Package
安装package 有二种方式,第一种是使用 sysinstall (也就是我们安装 FreeBSD 时所看到的画面) 来安装,另一种是使用手动安装。使用 sysinstall 安装时,我们必需选择安装的来源,最常使用的来源是网络及光盘片。但是由于光盘片容量有限,所以在 FreeBSD 安装光盘中所含的 package 软件数量并不多,因此我通常都选择使用网络安装。而使用手动安装必须自行抓回所需的档案,并以指令安装。以下我们就分别针对这二种方式来说明:
方式一:使用 sysinstall
假设我们要安装在 FreeBSD 上收信的软件 pine,首先我们要执行 sysinstall 以进入安装时的画面:# sysinstall
图 10-1

接着选取 Configure选项,进入图 10-2 的画面:
图 10-2

我们选 Packages 选项来安装 package:
图 10-3

在图 10-3 中,我们必须选择安装来源,在这里我们选择 FTP ,从 FTP 中我们可以找到较多的软件。选择了 FTP 之后,将出现图 10-4 的画面,让我们选择要使用哪一个 FTP 站台:
图 10-4

我们选择「URL」来自订要使用的 FTP 站台。接着便会出现一个要求我们输入站台地址的窗口,如图 10-5 所示,假设我们要使用交大资工的站台,则输入 freebsd.csie.nctu.edu.tw/pub/releases/i386/:
图 10-5

输入站台后,会问您是否要使用目前的网络设定。如果我们己经连上网络,则选 YES,否则请选 NO 来设定网络。接着会出现一个软件分类选单,这一份分类选单将各个软件分门别类放在不同的选项下,其中 All 是所有软件的所在,如图 10-6。
图 10-6

我们以安装邮件软件 pine 为例,由于 pine 位于 mail 分类下,所以我们选择mail。如果您要安装中文版本的 pine ,应该选择 Chinese 选项而非 mail。选择了 mail 之后,将出现 mail 分类下的所有软件,我们选 pine-4.58 这一项,如图 10-7:
图 10-7

选了pine 之后,就可以选 OK 回到前一个分类画面,接着按照这种方式选了其它我们要安装的软件之后,就可以选「Install」来安装了。选了 Install 之后,将出现所有我们已选取的软件列表,如图 10-8,如果要继续安装则选 OK 即可。
图 10-8

方式二:使用手动安装
如果以手动的方式安装,我们必须先取回所要安装的package。只要是 package ,它的扩展名就是 .tgz。我们可以用 pkg_add 这个指令来安装它。下面是一个简单的范例,使用 package 来安装 lsof-4.66.1.tgz:# ftp -a freebsd.csie.nctu.edu.tw
Connected to freebsd.csie.nctu.edu.tw.
220---------- Welcome to Pure-FTPd ----------
220-You are user number 139 of 200 allowed.
220-Local time is now 17:49. Server port: 21.
220-Only anonymous FTP is allowed here
220-IPv6 connections are also welcome on this server.
220 You will be disconnected after 15 minutes of inactivity.
331 Any password will work
230 Any password will work
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd /pub/FreeBSD/ports/packages/sysutils/
250 CWD command successful.
ftp> get lsof-4.71.tgz
local: lsof-4.71.tgz remote: lsof-4.71.tgz
227 Entering Passive Mode (140,113,17,209,189,16)
150-Accepted data connection
150 96.1 kbytes to download
100% |*********************************************************| 98372 136.87 KB/s 00:00 ETA
226-File successfully transferred
226 0.362 seconds (measured here), 265.35 Kbytes per second
98372 bytes received in 00:00 (136.70 KB/s)
ftp> bye
221-Goodbye. You uploaded 0 and downloaded 97 kbytes.
221 Logout.
# pkg_add lsof-4.71.tgz
要使用 package 安装软件,首先必须取得想要安装的软件。我们可以先 ftp 到各大学 FTP 站台去取得。packaeg 的副档案是 .tgz,可以在各 FTP 站台的 ports/packages 中取得。以交大资工的 FTP 站而言是放在 ftp://freebsd.csie.nctu.edu.tw/pub/ports/packages ;而中央资工的 FTP 是放在 ftp://freebsd.csie.ncu.edu.tw/FreeBSD/ports/packages 。当进入 ports 的目录后,我们会发现还有一堆目录,您可以依您的系统版本选择要使用哪一个目录,其中 packages 这个目录包含了最新的 packages。如果您想要使用 packages-5.4-release 的 packages,我们就可以选择进入 packages-5.4-release 这个目录。进入这个目录后,又有一堆目录,这里的目录结构和你系统中 /usr/ports/ 下的目录一样,每个目录都是软件的分类,而 All 这个目录是所有软件。
如果您只知道想要安装的软件名称,却不知道版本及完整的档名,例如您要下载 popa3d 这个软件,但不知道是哪一版的,你可以先进入 All 的目录下,再以下列方式查询:ftp> ls popa3d*
227 Entering Passive Mode (140,113,209,200,159,54)
150 Opening ASCII mode data connection for /bin/ls.
-r--r--r-- 1 FTP CSIE 19007 Nov 11 12:43 popa3d-0.6.4.1.tgz
226 Transfer complete.
ftp> get popa3d-0.6.4.1.tgz
找到了想要下载的版本是 0.6.4.1,接着就以 get 指令去取回该软件,最后下 exit 离开。
接着你就可以使用 pkg_add popa3d-0.6.4.1.tgz 来安装该软件。
10.2.2 管理 Package
如果我们后悔了,想要移除之前安装过的软件,可以下指令 pkg_delete popa3d-0.6.4.1 来移除 popa3d-0.6.4.1 这套软件,所有我们安装过的软件都会记录在 /var/db/pkg 的目录中。
我们可以使用 pkg_info 这个指令来得到软件的信息。例如在我们下载完一个 package 后,你想要知道这个软件的信息,以 popa3d-0.6.4.1.tgz 而言,如果我们想知道它的信息,你使用下列指令来取得:# pkg_info popa3d-0.6.4.1.tgz
您也可以只打 pkg_info 来得知所有你安装过的软件有哪些。
10.3 使用 ports
如果你要使用 ports 安装软件,你必须先确认 /usr/ports 这个目录是否有安装。如果没有的话,使用 /stand/sysinstall 来安装 ports 的目录:
以 root 执行 /stand/sysinstall
选择 Configure 后按 Enter
选择 Distributions 后按 Enter
选择 ports 后按空格键
选择 Exit 后按 Enter
选择你要从 CDROM 或 FTP 安装等
跟着选单照做,最后离开 sysinstall
或者我们也可以到 http://www.freebsd.org/ports/ 去手动抓回 port.tar.gz 这个档案,将它放在 /usr/ 下。并以下列指令来安装:# cd /usr
# tar zxvf port.tar.gz
现在可以进入 /usr/ports 的目录中,安装软件了。
通常每一个软件都有一个独立的目录,而目录中都存在着一些档案,每个档案都有其特定用途,我们简列如下:
Makefile
安装软件的编译设定,您可以修改这个档案来设定我们在编译及安装软件时的参数。
README.html
我们可以经由浏览 README.html 来查看所有 ports 目录下的软件说明。
distinfo
说明安装所需要的档案及其 MD5 的检查数据。
pkg-comment
简单的软件描述。
pkg-descr
较详细的描述,我们通常可以在里面找到该软件网页的位置,使我们能到该网页得到更多信息。
pkg-plist
列出软件将安装的清单,安装后会放在硬盘中的什么地方。
如果您想安装某一个软件,却不知道它的目录位置,您可以使用 whereis 这个指令来找出它来。例如我们想安装 qpopper ,可以使用 whereis qpopper 来找出它所在的目录。 或者果我们只知道某个程序的关键词,确不知道它放在哪个目录,我们可以使用下列指令:# cd /usr/ports
# make search key='关键词'
进入该目录后,最简单的安装方式是直接打 make install,系统就会自动去网络上抓取需要的软件回来安装。安装 ports 时,make 时找档案的顺序是:先去 /usr/ports/distfiles 、再去找 /cdrom/ports/distfiles、最后是网络中下载。如果您不使用网络安装的话,您可以自己去抓回软件,并将它放在 /usr/ports/distfiles/ 下,这样子在我们打 make install 时,就不会去网络上抓取档案。如果您所需档案存在光盘中,在安装软件之前,必须先将光驱 mount 在 /cdrom 中。。但有的软件并不会到光盘中去寻找档案,所以建议您还是将光盘中 /ports/distfiles 目录内容复制到 /usr/ports/distfiles 目录中,或者先连上网络吧。
当使用网络取得档案时,预设抓取档案的服务器通常在国外,因此,您可以修改 /etc/make.conf 来指定使用国内的 FTP 站台,例如编辑 /etc/make.conf 并加入:
MASTER_SITE_BACKUP?= \
   ftp://freebsd.csie.ncu.edu.tw/distfiles/${DIST_SUBDIR}/ \
   ftp://freebsd.csie.nctu.edu.tw/pub/distfiles/${DIST_SUBDIR}/
MASTER_SITE_OVERRIDE?=    ${MASTER_SITE_BACKUP}
当安装完 ports 后,我们可以再下指令 make clean 来清除编译过程产生的档案,建议最好这么做,否则有的过程中产生大量档案可是很惊人的。如果您安装了一堆软件之后,才想到之前没有 make clean,没关系,在安装 ports 时,编译过程的档案都存在于该软件目录下的 work 目录中。我们可以使用下列指令来找出所有未 make clean 的软件,并将暂存数据删除:# find /usr/ports -depth -name work -exec rm -rf {} \;
如果您使用网络安装,它会将所下载的原始码存在 /usr/ports/distfiles 中,当你下 make clean 后,并不会将它们清除。
当你安装完后,想要移除该软件时,只要在该软件的 ports 目录中打 make deinstall 即可。请注意,不要在 /usr/ports 的目录中打 make deinstall,这样可是会将 "所有" 软件都移除喔。
还有一些较不常用的 make 方式,简述如下:
make fetch:抓回所需的原始档。
make fetch-list:显示安装所需的档案。
make checksum:抓回原始档并以 MD5 检查其正确性。
make extract:抓回并解开原始档。
make configure:进行组态,但不继续编译。
make all install:抓回原始档、编译且安装。
make reinstall:若先前发生意外中断,以此命令继续尝试安装。
make package:将做好的 ports 打包制作成 packages。
如果安装完新的软件之后,如果使用的 Shell 是 Csh 或 Tcsh,我们可能必须执行指令 rehash 来重建 hash table,之后才能在所设定的指令路径中找到刚安装的程序,不然的话就必须输入该程序的完整路径或重新登入才能使用。
我们可以在 /var/db/pkg 的目录中看到我们已安装的软件,每一个软件有一个目录,目录中存放着软件安装的信息,包含了软件说明、安装到哪些目录中。有的软件要安装前,会要求先安装某一套软件,如果你事先没有安装它所要求的软件,通常该软件会自动帮你安装。所以我们会在 /var/db/pkg 下看到一些不是我们主动安装的软件。既然软件之间可能会相互依赖,我们要如何得知这些软件彼此间的关系呢?pkg_tree 这套软件可以让我们检视软件间的关系。我们可以使用 port 来安装这套软件:# cd /usr/ports/sysutils/pkg_tree
# make install clean
之后我们就可以使用 pkg_tree | more 来看各个软件之间的关系了 (别忘了要 rehash 喔)。
10.4 更新 port tree
当 FreeBSD release 时,会事先测试过 ports 目录中的所有软件是否能正常安装。因为不同软件之间时常是相互依赖的,有的时候我们要安装 A 软件,系统会自动抓取所需要的其它软件。这些软件对于彼此的版本可能会有相互依赖,所以在 release 之前,ports 会暂停更新各个软件的版本,以确保 release 的版本能正常运作。
但在 release 之后,ports 目录中的软件版本可能已有更新,有的软件版本更新可能只是增加新的功能,而有的更新更涉及系统安全。如果您想使用 ports 安装软件最新的版本,在安装软件之前,我们可以先使用一些工具来更新整个 port tree。
有时候更新了 port tree 之后,因为版本相依问题,有些软件可能会因此而无法顺利安装,您只要在过几天后重新做一次 port tree 的更新应该就可以解决了。
更新 port tree 的方法很简单,我们可以使用 CVSup 来保持 ports 在最新状态。CVSup 是一套用来维持软件原始码和开发团队同步的工具,在我们执行了 CVSup 之后,它会经由网络向所设定的软件服务器检查并更新原始码的版本。我们可以使用 CVSup 来更新 port tree,也可以用来更新 /usr/src 目录下的 FreeBSD 原始码。
首先,我们必须安装 CVSup,因为我们不使用图形接口,所以安装 cvsup-without-gui:# cd /usr/ports/net/cvsup-without-gui
# make install clean
在系统中有一份以 CVSup 更新 port tree 的设定文件范例,您可以直接加以修改或着先复制一份后再修改。我们将该设定文件范例复制到 /root 之后再加以修改:# cp /usr/share/examples/cvsup/ports-supfile /root/
接着请以文书编辑软件打开 /root/ports-supfile 后,找到 host 的部份来设定所要使用的 CVSup 服务器。
# Defaults that apply to all the collections
#
# IMPORTANT: Change the next line to use one of the CVSup mirror sites
# listed at http://www.freebsd.org/doc/handbook/mirrors.html.
*default host=cvsup.tw.freebsd.org
*default base=/usr
*default prefix=/usr
*default release=cvs tag=.
*default delete use-rel-suffix
# If your network link is a T1 or faster, comment out the following line.
*default compress
## Ports Collection.
#
# The easiest way to get the ports tree is to use the "ports-all"
# mega-collection.  It includes all of the individual "ports-*"
# collections,
ports-all
# These are the individual collections that make up "ports-all".  If you
# use these, be sure to comment out "ports-all" above.
#
# Be sure to ALWAYS cvsup the ports-base collection if you use any of the
# other individual collections below. ports-base is a mandatory collection
# for the ports collection, and your ports may not build correctly if it
# is not kept up to date.
#ports-base
#ports-archivers
#ports-astro
#ports-audio
#ports-benchmarks
………略…………
上面的范例中,我们将 CVSup 服务器设为 cvsup.tw.freebsd.org,这一台服务器是由交大资工所维护,您可以依您所在位置使用其它 cvsup1 ~ cvsup13.tw.freebsd.org 的服务器。例如 cvsup3 位于中山大学,cvsup13 是 giga 和信超媒体的服务器。最后一行的 ports-all 表示我们要更新 /usr/ports 目录下的所有档案。您也可以只更新其中的部份目录,只要将 ports-all 以井字号 "#" 标示起来,并将档案中 ports-base 那一行的 # 移除,接着您就可以依您所要更新的目录来要移除其它的 # 字号。例如,我们只要更新 /usr/ports/www 这个目录,将 ports-all 以 # 标示起来之后,我们还要移除 ports-base 及 ports-www 开头的 #。
设定完毕之后,我们就可以开始进行 ports 的更新了。# cvsup -g -L 2 /root/ports-supfile
上述指令中,参数 g 表示不使用图形接口,而参数 L 及其后所跟随的数字 2 表示我们要看到更新过程的记录的详细程度,数字可以从 0 ~ 2,最后的档名表示所要使用的设定档。
在使用 ports 安装软件之前,先执行 CVSup 是一个不错的习惯,您可以随时取得软件的最新版本,不过您的机器一定要连上因特网才能进行更新。
10.5 使用 portupgrade 更新软件
在使用 Port 安装了一堆软件后,如果软件有新的版本出来怎么办?FreeBSD 的 ports 管理工具中有一个好用的软件 - portupgrade。
通常 ports 中的软件都有相依性,例如安装 Apache 会自动安装 libexpat、安装防垃圾信软件会自动安装一堆 Perl 模块。而在更新软件时,我们必须要确定更新过后,相依的软件都一并更新,才不会造成更新后有东西不能运作的情形。不过这并不表示我们一定要常常更新软件,建议您只有在必要时才使用 portupgrade 来更软件,不要有事没事就跑一次。因为软件并不是最新的就最好,没有人能保证更新的软件是否还维持您原本期望的行为。
portupgrade 在更新软件时,会保留您原本的设定档。例如,在更新 Apache 时,它会保留 httpd.conf 的设定。使用 portupgrade 是更新 ports 软件比较安全的方式。
在您使用 cvsup 更新 port tree 后,我们可以使用下列指令查看目前安装的软件版本是否和 port tree 中的版本一样:# pkg_version -v
ispell-3.2.06_12 = up-to-date with port
jasper-1.701.0 = up-to-date with port
jpeg-6b_3 = up-to-date with port
kde-3.3.0
上列输出中需要更新的软件会有「# cd /usr/ports/sysutils/portupgrade
# make install clean
如果您只想要升级某一个软件本身,而非所有相依的软件,只要使用 portupgrade pkgname 即可。如果您要升级所有和该软件相依的其它软件,则可以加上参数 -r。如果您要更新包含相依软件的相依软件,则可以使用参数 -R。另外,您可以使用参数 -m 来要求编译 (make) ports 时多传入一些参数,还可以使用参数 -f 要求就算版本一样也强制更新。
假设我们要更新的软件是 perl-5.8,我们可以使用下列指令来更新:# portupgrade -rf "perl-5.8.*" -m "ENABLE_SUIDPERL=yes"

小提示
笔者并不建议您使用 portupgrade 来安装所有软件,尤其不建议使用参数 -a 来更新所有软件。一方面新的软件不一定会更好,另一方面,我们很难保证更新后的软件会正常运作。而且我们在安装软件时,并不一定只使用 make install,还有可能在 make 后加上一些参数以支持更多的功能,直接使用 portupgrade 并不一定还能保留这些功能。我们介绍 portupgrade 的目只是为了让您在安装 Open WebMail 时更新 perl 时更顺畅。
10.6 传统安装方式
我们介绍了 FreeBSD 独有的 package 及 port 安装方式后,接下来我们还是要详细说明一下传统上在 UNIX 机器上安装软件的方式。
有的时候,我们要想要装的软件可能不在 port 里,或者 port 中的软件版本尚未更新,这时候我们就必须使用传统的安装方式来安装软件。基本上,传统安装方式就像本章开头所说的,大多必须要有下列步骤:
从该软件网站或其它 FTP 站台下载该软件,有可能是 binary 档或是原始码。
解压缩该档案,通常是以 tar 或 gzip、bzip2 压缩的。
读一下该目录中的说明文件,可能是 readme 或是 doc/ 的文件,来了解如何安装该软件。
如果所下载的是原始码,可能要先编辑一下 Makefile 或是执行 configure,接着再编译该软件。
最后再测试与安装。
我们以 MySQL 这个软件为例。
下载及解压缩
首先我们到 MySQL 网站上下载最新的原始码。一般原始码大多以指令 tar 包成一个档案,再压缩成 gzip 或是 bzip2 格式。所以您下载的档案扩展名大多为 .tar.gz、.tgz、或是 .tar.bz2。
扩展名为 .tar.gz 或是 .tgz 的档案为 tar + gzip 格式,MySQL 的原始码就是这一种类型。我们可以使用下列指令来解压缩:# tar zxvf mysql-4.1.13.tar.gz
如果扩展名为 .tar.bz2 的档案,则是 tar + bzip2 的格式,遇到这种格式时,我们可以使用下列指令解压缩:# tar jxvf mysql-4.1.13.tar.bz2
我们可以看到上述二种格式都可以使用 tar 来解压缩,只是 gzip 格式必须使用参数 z,而 bzip2 的格式必须使用参数 j。指令 tar 的其它参数所代表的意义为:x 是解开的意思、v 是要观看解开的过程、f 是指定要解压缩的文件名称。
解开之后,我们就可以进入下一步开始安装。
查看说明档
每个软件在安装上大同小异,但有的软件除了一般安装流程外,可能还有自己独特步骤。所以在安装之前,我们必须先看一下说明档,以了解如何进行安装。
大部份的开放原始码软件都会有 README 或是 INSTALL 这二个档案,用以说明安装的步骤。有的软件可能有其它档案,但我们可以从档名了解应该要看哪一个说明档。以 MySQL 为例,在它的原始码包装中,有一个档名为 INSTALL-SOURCE 的档案,应该就是我们要看的安装说明档。我们使用文书编辑器打开该档后,可以看到一些关于安装的说明。MySQL 的说明档写的蛮详细的,但我们可以将重点放在 Installation 的地方:
2.8.1 Source Installation Overview
----------------------------------
The basic commands you must execute to install a MySQL source
distribution are:
    shell> groupadd mysql
    shell> useradd -g mysql mysql
    shell> gunzip  cd mysql-VERSION
    shell> ./configure --prefix=/usr/local/mysql
    shell> make
    shell> make install
    shell> cp support-files/my-medium.cnf /etc/my.cnf
    shell> cd /usr/local/mysql
    shell> bin/mysql_install_db --user=mysql
    shell> chown -R root  .
    shell> chown -R mysql var
    shell> chgrp -R mysql .
    shell> bin/mysqld_safe --user=mysql &
我们可以看到它的安装步骤写的很详细,还有指令范例。简单来看,应该就是要先增加一个使用者为 mysql,并增加 mysql 群组。接着再解压缩原始码、进行编译、安装、并做一些安装后的设定。
编译
在 MySQL 的安装步骤中,编译前要先进行 configure。事实上,大多数的开放原始码软件编译流程都使用下列三个步骤:# ./configure
# make
# make install
第一个指令是 configure,这个指令可以用来检查您目前系统的设定,并依您的使用环境决定要不要加入某些功能。您也可以使用下列指令查看 configure 指令中可以使用哪些参数:# ./configure --help | more
原则上,除非有特殊要求,否则我们直接执行 configure 即可。以 MySQL 为例,我们在 configure 指令后面加上下列参数:# ./configure --prefix=/usr/local/mysql \
    --with-low-memory \
    --with-charset=big5
我们使用 --prefix 以指定要安装的路径,这是所有使用 configure 的软件都会有的参数。另外,我们还指定编译时不要使用太多内存 (--with-low-memory),并设定 MySQL 支持中文字集 (--with-charset=big5)。
执行完 configure 检查环境并设定安装的项目后,我们就可以使用 make 来进行编译。指令 make 会呼叫编译器 gcc 来将原始码转换成执行档。
安装
编译完后,我们可以使用下列指令安装:# make install
您可以看到程序安装的过程。安装完成后,我们必须依不同的软件要求进行安装后的设定。以 MySQL 为例,我们必须先使用 mysql_install_db 以初始化数据库,并将一些目录的拥有者设定为 mysql。
最后就可以启动 mysql 了。而如果我们要在开机时启动 MySQL,必须将它的启动指令加入 /etc/rc.local 中,或是在 /usr/local/etc/rc.d 中加入一个 mysql.sh 并将启动的指令写在该档案中,然后将 mysql.sh 设为可执行。如此一来,FreeBSD 在开机时就会自动执行它。
以上就是一般传统软件安装的流程:configure、make、make install,其实使用上也不太难。

小提示
传统的安装流程比较容易遇到的问题可能是在执行 make 时发生错误,如果您遇到问题,可以在 google 上查找 make 所产生的第一个错误的关键词,应该可以找到类似的问题及解决的方法。

TOP

返回列表