Linux 系管師進階班講義

作者:李忠憲 shane@mail.spps.tp.edu.tw

2003/03/21 修訂

本文是假設您已經使用 Linux 一段時間,隨著硬體的升級或空間不足,必須要升級 Linux 系統,抑或是想提供更多的網路服務給參觀者,因應這個需求而編寫的,如果您不是進階管理員,請不要看這篇文章!

壹、調整虛擬記憶體:

Linux 上是使用 swap 技術將硬碟空間挪用為虛擬記憶體,當伺服器建置完成使用一段日子以後,有可能會擴充硬體,其中又以擴充主記憶體來改善執行效能最為普遍,在這種情形下,就需要增加 swap 虛擬記憶體的容量。

由於 swap LVM 機制一樣能將多塊磁碟分割區虛擬成一塊,因此我們並不需要將舊的 swap 磁區先移除,或是直接修改 swap 磁區大小,而是可以採用追加 swap 磁區的方式來配置。做法如下:

mkswap  /dev/hdx2(將新磁區格式化為 swap

swapon  /dev/hdx2(立即啟用新的 swap 磁區)

修改 /etc/fstab 加入下面這一行

/dev/hdx2    swap    swap    defaults    0 0

如果硬碟已經沒有剩餘空間,而且無法加裝新的硬碟,這種情況下,我們沒辦法變更 swap 磁區來滿足需求,但是可以挪用已經掛載的分割區一部分空間,以檔案的形式來追加 swap 虛擬記憶體的容量:

dd  if=/dev/zero  of=/swapfile  bs=1024  count=65536(建立 /swapfile 檔案,單位為 KB,所以這是 64MB

mkswap  /swapfile(將該檔案空間格式化為 swap

swapon  /swapfile(立即啟用新的 swap 檔案)

修改 /etc/fstab 加入下面這一行

/swapfile    swap    swap    defaults    0 0

 Linux 並沒有辦法搬移 swap 磁區,如果想要把 swap 作成單一一個磁區,必須先將舊 swap 磁區移除,再加入新的 swap 磁區,如果先加入新磁區,則新舊磁區會聯合運作,造成舊磁區無法移除的現象。移除 swap 磁區的方法如下:

swapoff  /dev/hdx2(關閉 swap 功能)

修改 /etc/fstab 移除 /dev/hdx2 那一行

貳、加掛硬碟與檔案系統轉換:

當硬碟不敷使用時,需要加掛新的硬碟到系統上,加掛硬碟的做法很簡單,先使用 fdisk parted 將磁區分割好,接著使用 mkfs 指令來格式化硬碟,最後修改 /etc/fstab 讓系統重開機後能自動掛載新的硬碟。

fdisk 的使用方法如下:

#> fdisk /dev/hdb(假設要加掛的硬碟,是接在第一條排線的第二個位置)

The number of cylinders for this disk is set to 2498.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., LILO)
2) booting and partitioning software from other OSs
(e.g., DOS FDISK, OS/2 FDISK)

Command (m for help): m
Command action

a
b
c
d
l
m
n
o
p
q
s
t
u
v
w
x
toggle a bootable flag
edit bsd disklabel
toggle the dos compatibility flag
delete a partition
list known partition types
print this menu
add a new partition
create a new empty DOS partition table
print the partition table
quit without saving changes
create a new empty Sun disklabel
change a partition's system id
change display/entry units
verify the partition table
write table to disk and exit
extra functionality (experts only)

 

Command (m for help):

先用 l 指令列出所有已分割好的磁區,你可以使用 d 指令將不要的磁區刪除,或使用 t 指令將磁區的檔案系統改為 Linux 用的 82swap 83ext2,ext3),假如硬碟是空的尚未分割任何磁區,這時候請用 n 指令建立磁區,所有需要的修改完成後,輸入 w 指令將設定儲存起來,然後重開機讓修改生效,以便進行後續動作。

磁區分割好了以後,必須針對每個不同檔案系統將磁區格式化,swap 磁區格式化的方法前面已經提過,而作為一般用途的磁區,建議直接格式化為 ext3

/sbin/mkfs  -t  ext3  /dev/hdb1(將空白磁區格式化為 ext3

ext3 是從 ext2 改良而來,主要是挪用 ext2 一些 inode 拿來做成日誌檔(.journal),因此它與 ext2 只有些微不同,兩種系統也可以很容易互相轉換(轉換完仍需自行修改 /etc/fstab 組態):

/sbin/mke2fs  /dev/hdb1(將空白磁區格式化為 ext2

/sbin/tune2fs  -j  /dev/hdb1 (將 ext2 轉為 ext3,轉換時順便建立日誌檔)

當新磁區格式化好了之後,就可以將它掛載上來,您可以直接指定要掛載的磁區型態:

/sbin/mount  -t  ext3  /dev/hdb1  /mount/point(指定掛載 ext3 磁區到 /mount/point 目錄)

或先修改 /etc/fstab 然後再掛載,修改 /etc/fstab 的方法是插入下面這一行:

/dev/hdb1        /mount/point        ext3        defaults        0 0

接著掛載時不需指定磁區型態及裝置名稱,指令如下:

/sbin/mount  /mount/point

已經格式化為 ext3 的磁區,如果要掛載到 6.X版以前的系統上使用,必須將格式改回 ext2,變更方法如下:

/sbin/tune2fs  -O  ^has_journal /dev/hdb1 (通知 kjournald 關閉日誌檔功能)

mount  -t  ext2  /dev/hdb1  /mount/point(將 ext3 掛載為 ext2

rm  -f  .journal(刪除日誌檔)

ext2 轉換成 ext3 有許多好處,包括速度快、安全、高可用性、修復省時......等等優點。簡單的講,所謂 journal 就是把檔案讀寫動作逐項紀錄下來,當硬碟未正常關機(unclean shutdown)時,不需要檢查硬碟(e2fsck)直接可以掛載(mount),如果以 fsck 強制修復硬碟,則直接從日誌檔讀取需要修復的磁區資料,而不需要整顆硬碟都檢查。由於這些優點,我們也建議不要再使用舊的 ext2 格式。

掛載好後,如需進行資料移轉,可以使用 cp -Rp 指令,參數 R 表示連子資料夾一起備份,參數 p 表示要保留所有檔案權限設定,例如:

cp  -Rp  /home  /home1

參、進階磁碟系統:

LVM 邏輯磁區

事實上新版 Linux 由於提供 LVM Logical Volume Manager)功能,可以將多個磁區組合成一個 VGVolume Group),然後將一個 VG 掛載成單一一個目錄,這樣就可以做到磁區合併的效果,省掉轉移資料的麻煩,要使用這項功能,首先在安裝 Linux 時,必須先將可能會事後擴充的磁區做成 LVM 磁區型態(代號是 8e),如果您在安裝時沒有啟用這項功能想要事後補做,那樣可行不通,因為修改磁區型態將會造成所有資料遺失!

如果是新硬碟上的磁區,請用 fdisk 修改好磁區型態後,利用以下指令來做起始化的動作,在底下的例子裡,我們會把新硬碟上的三個磁區合併成一個,並在稍後加入第四個磁區以擴充容量(透過這些步驟,可以了解當初 Linux 安裝程式幫我們裝 LVM 時,到底做了哪些事情):

/sbin/pvcreate  /dev/hdb1

/sbin/pvcreate  /dev/hdb2

/sbin/pvcreate  /dev/hdb3

然後需建立 VG,建立好的 VG 將被視為一個裝置名稱,事後可以用  /dev/VG_name 來引用它:

/sbin/vgcreate  new_home  /dev/hdb1  /dev/hdb2  /devhdb3

對於 VG 這種裝置來說,仍必須進一步在上面分割邏輯磁區才能使用,我們不妨把 VG 想像成是一個外掛的 SCSI 磁碟陣列,對主機板來說,他被視為單一一顆硬碟(LVM 並不是真正的 RAID 系統,因為它只能實作 RAID0,事實上 2.4.x 版的 kernel 另外還提供 softRAID 功能,在後面說明)。既然它是一種裝置,當然無法直接掛載使用,必須先進一步作虛擬分割及格式化的動作, 下面的例子裡,我們僅分割單一一個磁區:

/sbin/lvcreate  -L  30g  new_home(將 new_home 虛擬裝置中的 30 GB 空間割成一個虛擬延伸磁區)

使用 lvcreate 指令除了可以分割l邏輯延伸磁區(所謂延伸是指可以動態變大,當然變小也是可以,但應該沒有人會這麼做),還可以分割一種稱為快照的磁區,這可以用來自動備份某塊邏輯延伸磁區,而這種備份是 自動進行的,並不需要人力介入管理。

一但邏輯磁區分割好了,依照慣例仍然得先將磁區格式化,一般是格式化成 ext3

/sbin/mkfs  -t  ext3  /dev/new_home/lvol1(由於當初分割磁區時未使用 -n 參數來指定名稱,因此系統會自動編號)

格式化好的磁區就可以直接掛載使用:

mkdir  /home2

mount  -t ext3  /dev/new_home/lvol1  /home2

接下來進行資料轉移:

cp  -Rp  /home  /home2(將使用者資料從實體磁區拷貝到 lvm 磁區)

以光碟片開機進入 rescue mode

rm  -rf  /home (將 /home 刪除)

mkdir  /home (建立掛載點)

mount  -t ext3  /dev/new_home/lvol1  /home (重新將 /dev/new_home/lvol1 掛載到 /home

rmdir  /home2(刪除掛載點)

緊接著修改 /etc/fstab 來掛載這個新作好的邏輯磁區:

/dev/new_home/lvol1        /home        ext3        defaults        0 0

重開機後,系統會嘗試掛載該虛擬磁區,如果掛載失敗,請在 /etc/rc.d/rc.local 加入以下指令:

vgchange -a y new_home
mount /dev/new_home/lvol1 /home

假如使用一段時間後, /home  的空間不足,這時我們可以動態加入新的實體磁區(以 /dev/hdb4 為例)來擴充空間:

fdisk 修改 /dev/hdb4 的磁區類型為 8e

/sbin/pvcreate  /dev/hdb4 (邏輯磁區起始化)

/sbin/vgextend  new_home  /dev/hdb4(將實體磁區加入到虛擬裝置上)

/sbin/lvextend  -L +10g  /dev/new_home/lvol1  /dev/hdb4(從該實體磁區擴充 10GB 空間至邏輯磁區)

完成以上步驟後,現在的 /home 空間容量已經變成 40GB!然而使用 df 指令去查看 inode,卻發現空間沒有增加,經過測試後發現必須重新 mkfs 才能使用新的空間,這個缺點讓 LVM 有點美中不足。

SoftRAID 軟體磁碟陣列

使用軟體磁碟陣列應該在安裝 Linux 時,直接透過 Disk-Druid 來設定比較方便,如果事後想要手動加上去,步驟比較繁雜,首先和 LVM 系統一樣,你必須先使用 fdisk 將預先割好要作磁碟陣列的分割區改為 fd 類型,千萬不要拿已經有資料的 Linux ext2 swap 來改,否則資料會全部遺失,修改方法請自行參考前面的解說。特別要注意的是,要作磁碟陣列的分割區其容量必須一致,不可以有大有小!

改好磁區類型後,請用底下指令建立軟體磁碟陣列組態檔:

touch /etc/raidtab

該檔案內容如下:

raiddev                           /dev/md0 //定義磁碟陣列的裝置名稱
raid-level                        1 //定義磁碟陣列的等級,RAID 1 就是 Mirror
nr-raid-disks                   2 //定義磁碟陣列是由多少實體分割區組成的
chunk-size                      64k //定義 chunk 大小,由於是軟體陣列所以是使用系統主記憶體來進行 chunk,這個數值設大一點雖然對磁碟陣列效能有幫助,但卻會耗掉系統資源,建議使用預設值就好了
persistent-superblock       1//啟用 superblock,這是用來作磁碟定址,它能幫助 kernel 在偵測 RAID 磁碟時不會誤判
nr-spare-disks                 0 //定義備用的磁區
    device                        /dev/hda1 //定義組成 RAID 的第一塊實體分割區
    raid-disk                     0
    device                        /dev/hdc1 //定義組成 RAID 的第二塊實體分割區
    raid-disk                     1

以上面這個例子來說,作好的磁碟陣列在寫入資料時,兩個實體分割區都會寫入資料,讀取資料時,則只要其中一個磁區能正常讀取即可,這樣就可以充分利用磁碟陣列的好處來進行資料保全。做好組態設定以後,接下來請以下列指令開始製作磁碟陣列:

mkraid /dev/md0

磁碟陣列一但製作好了,依然得先將磁區格式化,一般是格式化成 ext3

/sbin/mkfs  -t  ext3  /dev/md0

格式化好的磁區就可以直接掛載使用:

mkdir  /secure_data

mount  -t ext3  /dev/md0  /secure_data

資料保全測試:

使用 fdisk 將 RAID 磁碟陣列其中一個實體分割區刪除後,重新開機,發現 RAID 啟動時出現錯誤訊息,警告我們有部分磁碟損毀,但儲存的資料仍然具全沒有遺失

如果開機訊息閃得太快沒有看清楚,可以使用底下指令來觀察:

lsraid -a /dev/md0

將該分割區重新分割並修改格式為 fd 後,進行資料復原工作:

raidhotadd /dev/md0 /dev/hdc1(將空白磁區 /dev/hdc1 加入 RAID 中並復原資料)

完成以上步驟後,再使用 lsraid 指令來觀察,發現 RAID 裝置已經恢復正常。

 

、工作排程:

Linux 提供四種自動執行程式的機制,包含:cronanacronat batch。使用時機分述如下:

cron 主要用來做周期性工作的排程,會根據系統時間來判斷程式是否該執行,萬一系統時間設定不正確將會造成排程錯亂。
anacron cron 一樣也是用來做周期性工作的排程,但是它不檢查系統時間,而改以讀取時間戳記來計算間隔日數,依間隔日數判斷是否該執行,適用於每天、每週或每月只執行一次的工作。
at 讓指定程式在某個時間點到達時自動執行,適用於只執行一次的工作。
batch 指定工作在系統閑置時執行,可用來避開高負載時段。

使用 cron 前請先確定伺服程式是否已經執行,可以使用以下指令來查看:

/sbin/service  crond  status

雖然 cron 允許使用者自行安排自己的工作,以方便在結束連線後,程式能自動運作,但這類工作對於已經提供多種網路服務的伺服器來說負擔太大,因此建議不要教使用者使用它,本文也不討論這類的事情,畢竟我們的伺服器只是 PC,不是 main frame

cron 的主要設定檔 /etc/crontab 內容如下:

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

# run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly

前面幾行是定義 cron jobs 執行時的環境,我們不需要去修改它,底下四行是用來定義工作排程,上面看到的是系統排程的定義區分為七個欄位,分別代表:分、時、日、月、星期、執行時的身分、要執行的 script,而一般的工作則只區分為六個欄位,前五個欄位與系統排程相同,最後一個欄位則是要執行的工作。

欄位 有效數值
0~59 * 代表每分鐘都要執行,1-4 是指前四分鐘各要執行一次,如果執行的時間不是連續的,可以用逗號來區隔,例如:5,10,15,20 代表第五分鐘、第十分鐘、第十五分鐘、第二十分鐘時要執行,如果每隔五分鐘要執行一次,可以簡寫為 */5
採用 24 時制,有效數值為 0~23,可以使用 * - , / 等通配字元,意義同上。
1~31,如果使用 30,則每逢二月會跳過不執行,如果使用 31,會變成大月時才執行,因此對於每月都得執行一次的工作,請安排在 28 日以前執行。當月份有指定時,必須為有效日期,否則該工作將永遠不執行。通配字元使用方式同上。
1~12,也可以直接用英文縮寫:janfeb......等。 通配字元使用方式同上。
星期 0~7,其中 0 7 都代表星期天,也可以使用英文縮寫:sunmon......等。 通配字元使用方式同上。

如果要執行的工作是屬於每天、每週或每月執行一次,建議改用 anacron 以確保一定會執行,如果是每小時要執行,建議直接在 /etc/cron.hourly 目錄內直接新增一個定義檔,語法需與 /etc/crontab 相同。 其它情形則把定義檔放置在 /etc/cron.d,這裡的定義檔將會每分鐘都檢查一次。

anacron 的設定檔位於 /etc/anacrontab,如前所述它是以檢查時間間隔的方式來決定是否執行,因此不受系統時間設定的影響,為了要檢查時間間隔必須紀錄每個工作每次執行時的時間戳記(timestamp),這些檔案會放置在 /var/spool/anacron 目錄裡面。

anacron 設定檔分為間隔週期、執行延遲時間、工作識別名稱、 要執行的工作四個欄位,說明如下:

欄位 使用說明
間隔週期 每次執行工作時應相隔幾天,小於一天的請改用 cron
執行延遲時間 當距離上次執行的時間超過時間間隔,這表示中間有執行失敗的情形,這種情形下在延遲幾分鐘後,該工作會再嘗試執行一次。
工作識別名稱 用來識別不同工作,同一名稱不能重複使用。
要執行的工作 通常是一個命令或 script

anacron 的設定檔預設內容如下:

SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin;/usr/local/sbin;/usr/local/bin

# These entries are useful for a Red Hat Linux system.
1     5     run-parts /etc/cron.daily
7     10   run-parts /etc/cron.weekly
30   15   run-parts /etc/cron.monthly

這個設定可以用來確保 cron job 一定會如期執行。

at 指令用來執行一次性的工作而非週期性的工作,我們可以指定要執行的時間,它和 cron 一樣會檢查系統時間的設定,因此設定錯誤會造成工作無法正確執行,設定方式如下:

at  16:00 011503 ENTER](排定執行時間是 2003115日下午4點)

at> perl /root/backup.plCtrl-D

我們可以使用 atq  指令來查詢現在尚未執行的預定工作。

如果想根據主機負載情形來決定執行時間,必須使用 batch 指令,實際上 batch 指令算是 at 的特殊應用,使用方式如下:

batch ENTER](不用指定執行時間)

at> perl /root/backup.plCtrl-D

伍、Email

Email 術語

電子郵件系統的發展源遠流長,早從網路萌芽階段就被實作出來,早期電子郵件系統僅能應用在 ARPANET 網路上(1972年,當時 Internet 尚未誕生,而且是使用 FTP 傳送電子郵件),要參與交換郵件的主機都 必須安裝 sendmail,要看信必須 telnet 到主機上才看得到。在 1982 年時因應網際網路的誕生,制定 SMTP 協定作為不同網路系統間交換郵件的標準,當然在這樣的年代裡,還沒有病毒信和垃圾郵件的困擾。

電子郵件普及後,連一般無法安裝 sendmail 的工作站也都有寄信和收信的需求,這時就需要開發另一種通訊協定來應付這個需求,那就是 POP,這個通訊協定用來讓工作站可以連上郵件伺服器,進行帳號認證 後下載自己的郵件,並能將伺服器上的郵件刪除,目前是使用第三個版本稱為 POP3。另外還有一個功能更強大的通訊協定稱為 IMAP,它除了收信外還可以進行郵件信箱管理,多半應用於網頁郵件系統,例如:SquirrelMail......

由於 SMTP 通訊協定當初在設計時並未考量使用者認證的問題(僅設計了遞送功能),另一方面能提供使用者認證的 POP3 卻又未設計信件上傳功能(僅設計下載功能),這樣的設計當然會衍生出許許多多的弊病,包括郵件來源不明、反覆多餘的濾信機制、郵件轉寄難以防堵、郵件帳號驗證有安全漏洞、郵件容易偽裝......等等弊端。 而這些問題必須從通訊協定著手改良才行,目前新版的 SMTP 通訊協定已經加入了認證與安全連線機制足以應負此需求。

在實際安裝設定之前,先介紹幾個電子郵件系統的術語:

MUA 使用者透過這個程式與郵件伺服器溝通,包括收信(以 POP3 連接收信伺服器程式 imapd)或寄信(以  SMTP 連接 MTA),例如: Outlook Express......等。
MTA 使用 SMTP 通訊協定將信件傳遞到不同郵件主機上面,例如: sendmail, postfix, Qmail......等。
MSA 是新版 sendmail 發展給 SSMTP 進行 TLS/SSL 連線的 client 端代理器。
MDA 收到信後將信件分配到不同使用者信箱內,算是 MTA 的一個子系統,譬如 BBS 從定義上來說也算是 MDA BBS 功能複雜,當然不僅僅是 MDA),有些 MDA 被設計來進行濾信動作,它們必須在 local 端運作,因此又被稱為 LDA,例如: procmail......等。
MailBox 尚未被使用者下載的郵件,會暫存在伺服器的硬碟空間裡,稱之為信箱。所有使用者信箱的總合必須約等於該分割區總容量的一半,以避免造成信箱尚有空間但郵件系統卻無法運作的現象。
ail Gateway 是一種特殊的郵件伺服器,通常扮演代理器的角色,負責統籌某機構內所有信件的收發,並分配郵件給下屬的郵件伺服器們,透過這個機制能夠加速郵件的交換,並且能夠進行一致的濾信控制。

sendmail 是最多人使用的 MTA,但同時也是安全漏洞最多的系統,如果您安裝 sendmail,那麼定期更新程式是免不了的工作,為了這個原因有許多版本的 Linux 改採 postfix 作為內建電子郵件程式,如果安全需求更高則可以考慮購買商業版的 Qmail,這支程式到目前為止尚未被發現有任何安全漏洞。 本文將只介紹大家最常用的 sendmail,同時請大家務必下載最新版本(8.12以後的版本)來安裝。

電子郵件結構

下表是一封完整的電子郵件內容,你可以在 Outlook Express 中在信件上按右鍵選「內容」來觀察。當電子郵件在郵件主機之間傳送時,會紀錄詳細的傳送過程,稱為信封。信封是給郵件主機追蹤郵件用的,對一般使用者意義並不大,因此通常會被 MUA 應用程式隱藏起來。信件本文則又區分為標頭和內文兩個部分:標頭用來紀錄寄信人、收信人、信件主旨、優先等級......等等,這些都會用來作為郵件索引,以方便使用者搜尋想閱讀的信件;郵件內文就是我們看到的信件內容,它允許使用 MIME 格式來夾帶檔案。

當郵件主機收到信件時,會先進行郵件剖析將各個部分分離出來以方便進行後續處理,所謂後續處理包含:網址偽裝、使用者偽裝、檢查寄信人及收信人欄位是否完整、檢查是否轉信、分信、濾信......等等,這些過程將在後面討論。

mail envelope(信封)
Return-Path: <spps@mail.spps.tp.edu.tw>
Received: from www.spps.tp.edu.tw (www.spps.tp.edu.tw [192.57.1.2])
(authenticated bits=0) by mail.spps.tp.edu.tw (8.12.8/8.12.5) with ESMTP id h2K3qpnv011171 for <shane@mail.spps.tp.edu.tw>; Thu, 20 Mar 2003 11:52:51 +0800
Received: from mail pickup service by www.spps.tp.edu.tw with Microsoft SMTPSVC;
Thu, 20 Mar 2003 11:40:30 +0800
mail content件本文)
 
Header(信件標頭)
From: spps@mail.spps.tp.edu.tw
To: <shane@mail.spps.tp.edu.tw>
Subject:
修繕報修通知
Date: Thu, 20 Mar 2003 11:40:30 +0800
Body(信件內文)
●報修者姓名:林XX,他的E-mail是:xxx@mail.spps.tp.edu.tw
●問題類別:技術問題
●問題主旨:114電腦一直當機
●問題內容:
●請系統管理師盡速處理。

啟動 IMAP

請參考基礎班講義,自行修改 xinetd 設定,將 imap pop3 服務啟動,這樣使用者才能連上來收信!

如果要啟用 SSL 安全通道,讓支援 spop3 simap MUA 能夠以更安全的方式來連線,請執行底下的指令,以便建立安全憑證:

cd  /usr/share/ssl/certs

make  imapd.pem

配合 SPOP3 的使用,請修改 outlook express 的設定:

手動測試 POP3 Server

想要知道 POP3 伺服器是否有正常運作,我們可以直接以 telnet 來進行測試,這樣做可以直接看到伺服器的反應,假設使用 Outlook Express 來測試,則伺服器的回應訊息大部分都會被隱藏起來,只有當發生問題時才會以蹦現視窗通知你,這樣比較無法達到學習效果,請依照下列步驟實際操作練習:(有關 Outlook Express 錯誤訊息的意義,請參考附錄 B

$ telnet 127.0.0.1 110
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
+OK POP3 localhost.localdomain v2001.78rh server ready //POP3 歡迎訊息
USER shane //要求以 shane 登入
+OK User name accepted, password please
PASS mypasswd //輸入密碼
+OK Mailbox open, 1 messages //信箱裡有一封信
LIST  //列出信件大小
+OK Mailbox scan listing follows
1 741 //第一封信共 741 Byte
.
RETR 1 //下載第一封信
+OK 741 octets
Return-Path: <mailer@mail.spps.tp.edu.tw>
Received: from www.spps.tp.edu.tw (www.spps.tp.edu.tw [192.57.1.2])
by mail.spps.tp.edu.tw (8.12.8/8.12.5) with SMTP id h2EAfGkf032324
 for <shane@mail.spps.tp.edu.tw>; Fri, 14 Mar 2003 18:41:16 +0800
From: mailer@mail.spps.tp.edu.tw
Received: from mail pickup service by www.spps.tp.edu.tw with Microsoft SMTPSVC;
Fri, 14 Mar 2003 18:29:44 +0800
To: <shane@mail.spps.tp.edu.tw>
Date: Fri, 14 Mar 2003 18:29:44 +0800
X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4807.1700
Message-ID: <WWWXf2LTrpwACkWHZqY000008b2@www.spps.tp.edu.tw>
X-OriginalArrivalTime: 14 Mar 2003 10:29:44.0578 (UTC) FILETIME=[A1464E20:01C2E]
Status:

寄信單位:5年04班 寄信人:黃元奎

.
DELE 1 //刪除已經下載的信件
+OK Message deleted
QUIT //結束連線
+OK Sayonara
Connection closed by foreign host.

sendmail 設定檔

使用 RPM 裝好 sendmail 後,會建立 /etc/mail 資料夾,這個資料夾是用來擺放 sendmail 會用到的各種設定檔,其中最主要的設定檔是 sendmail.cf,由於這個檔非常複雜,一般是不建議直接修改它,我們可以修改 sendmail.mc 這個檔案。使用 sendmail.mc 之前,你必須先用 RPM 安裝 sendmail-cf 這個套件,這樣才能使用巨集處理器 m4 來幫我們自動產生 sendmail.cf,指令如下:

m4  sendmail.mc  >  sendmail.cf

有關於 m4 巨集的介紹,請自行參考說明文件(/etc/share/sendmail-cf),底下我們直接來看一份樣本,並說明其中幾個對我們比較有用的設定值,這個樣本是由 sendmail 提供的。

divert(-1)
dnl This is the macro config file used to generate the /etc/sendmail.cf
dnl file. If you modify the file you will have to regenerate the
dnl /etc/sendmail.cf by running this macro config through the m4
dnl preprocessor:
dnl
dnl m4 /etc/sendmail.mc > /etc/sendmail.cf
dnl
dnl You will need to have the sendmail-cf package installed for this to
dnl work.

dnl 以上為註解說明,下面一行用來載入 sendmail 的巨集定義,必須將其中的路徑改為絕對路徑 /usr/share/sendmail-cf/m4/cf.m4,否則將會發生錯誤!
include(`../m4/cf.m4')dnl

dnl 定義 sendmail 以何種身分執行 ,預設值為 1:1 建議改為 mail:mail 比較不會出錯
define(`confDEF_USER_ID',``1:1'')dnl

dnl 宣告作業系統類型,這與 sendmail 會用到的各種目錄路徑的設定有關,我們不需去修改它
OSTYPE(`linux')dnl

dnl 取消不會用到的訊息系統,例如:newsbitnetfax......等等
undefine(`UUCP_RELAY')dnl
undefine(`BITNET_RELAY')dnl

dnl 一些不需修改的網路連線設定
define(`confALIAS_WAIT', `30')dnl 讀取 aliases 組態檔時的時間限制
define(`confTO_CONNECT', `1m')dnl 完成連線的時間限制
define(`confDONT_PROBE_INTERFACES',true)dnl 不要自動偵測網卡,我要自己定義 IP

dnl 宣告濾信 LDA 的路徑
define(`PROCMAIL_MAILER_PATH',`/usr/bin/procmail')dnl

dnl 定義 MDA 將如何分信: interactive, background, or queued 預設值是 background
dnl define(`confDELIVERY_MODE', `i')

dnl 定義送出的信件如何進行郵件偽裝(如果要配合 DNS 中的 MX 設定,特別需要修改)
FEATURE(always_add_domain)dnl 進行網址偽裝時,一律加上網域名稱
FEATURE(`limited_masquerade')dnl 不要對來自子網域的信件進行網址偽裝
FEATURE(`masquerade_envelope')dnl 對信封(envelope)進行網址偽裝
MASQUERADE_AS(`mail.spps.tp.edu.tw')dnl 把來自本機的信件其寄信人欄位改寫為這個網域名稱
FEATURE(redirect)dnl 啟用 aliase .REDIRECT 功能,aliases 是用來作使用者偽裝的
FEATURE(use_cw_file)dnl 啟用 sendmail.cw 組態檔

dnl 這是為了避免讓 smmsp 在分信時使用一般的 shell,因功能太強大而造成安全威脅(有人說這是 shell 牢籠)
FEATURE(`smrsh',`/usr/sbin/smrsh')

dnl 定義各種 mail gateway 會用到的機制,有關底下各種 table 的功能,請參考下一小節的說明
FEATURE(mailertable)
FEATURE(`virtusertable',`hash -o /etc/mail/virtusertable')
FEATURE(genericstable)
FEATURE(`relay_based_on_MX')dnl 當收到的信件,其收信人欄位的網域名稱符合 MX 紀錄時(MX紀錄用來指定要給哪個網域的信,送到哪個伺服器處理),要接受 relay
define(`confTRY_NULL_MX_LIST',true)dnl mail gateway 在收到信後,嘗試直接連線到下屬郵件主機,不要將信件保存在 mail gateway /var/spool/mail 中,注意:這樣設定有可能造成郵件流失

dnl 定義各種存取管控,包括要不要濾信,要不要檢查黑名單.......等等, 其中三行有網址的組態,是用來下載垃圾郵件公司清單的,有幾個組織負責蒐集這類的公司行號,sendmail 能根據清單上的內容,防止這些公司轉寄垃圾信件,但對於我們國內而言,設了也沒用,只是在降低效能而已!
FEATURE(local_procmail)dnl 這一行會啟用 LDA 濾信程式,預設是 procmail
FEATURE(`access_db')dnl 這一行會啟用 access.db 資料庫,這樣將可針對寄信人欄位進行過濾
FEATURE(`blacklist_recipients')dnl 這一行用來防止測試帳號被拿來寄信,例如: nobody@foo.bar.com
dnl FEATURE(dnsbl, `blackholes.mail-abuse.org', `Rejected - see http://www.mail-abuse.org/rbl/')dnl 網址黑名單檢查
dnl FEATURE(dnsbl, `dialups.mail-abuse.org', `Dialup - see http://www.mail-abuse.org/dul/')
dnl FEATURE(dnsbl, `relays.mail-abuse.org', `Open spam relay - see http://www.mail-abuse.org/rss/')
FEATURE(`delay_checks')dnl 啟用 check_mail check_relay 功能,這讓 sendmail 在接收信件時,能針對各個欄位進行廣泛的分析比對

dnl 定義要不要做 SMTP 帳號認證,目前新版 SMTP 已經可以提供帳號認證功能。以下選項也決定進行認證時可以使用的驗證機制,其中 LOGIN 是指傳統 POP3 認證,使用 base64 來編碼,PLAIN 則是傳輸明碼,完全不編密,事實上這兩種方式都不安全,建議不要啟用!
TRUST_AUTH_MECH(`GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')
define(`confAUTH_MECHANISMS', `GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')
dnl 定義認證實施方式,其中的 A 代表要求認證,p 則是用來阻止 sendmail 接受純文字密碼,如果不加 p 密碼很容易透過封包監聽來取得!
define(`confAUTH_OPTIONS', `Ap')

dnl 定義 TLS/SSL 安全通道,以便啟用 SSMTP 通訊協定,這種才是真正安全的方法,但請記得安裝最新版本 openSSLSSL 3.0),因為舊版已經被破譯了
dnl define(`CERT_DIR', `MAIL_SETTINGS_DIR`'certs')dnl CERT_DIR 的變數值設為 /etc/mail/certs
dnl define(`confCACERT_PATH', `CERT_DIR')dnl 設定 SSL 主目錄
dnl define(`confCACERT', `CERT_DIR/CAcert.pem')dnl 設定可信賴 CA 組織的憑證
dnl define(`confSERVER_CERT', `CERT_DIR/MYcert.pem')dnl 設定郵件主機的憑證
dnl define(`confSERVER_KEY', `CERT_DIR/MYkey.pem')dnl 設定郵件主機的金鑰
dnl define(`confCLIENT_CERT', `CERT_DIR/MYcert.pem')dnl 設定用來連上 mail gateway 時的使用者憑證
dnl define(`confCLIENT_KEY', `CERT_DIR/MYkey.pem')dnl 設定用來連上 mail gateway 時的金鑰

dnl 這是設定要啟用 MSA 功能,要注意的是當位址設為 127.0.0.1 時,將只有主機能收發信件,所有透過網路傳送的寄信要求將通通被丟棄,這雖然可以避免郵件主機被當成垃圾信轉信站台,但缺點是所有使用者將只能透過 web-base 來收發信件。如果把位址設為本機網卡的 IP,效果則反過來,本機不能寄信,透過網路反而可以寄,目前很多電腦書的作者都叫人家這樣設,這會造成 web-base mail 程式無法正常運作,學員們不可不知,如果想同時支援 MUA web-base 介面,可以直接將 Addr 參數整個移除,這樣就可以了!
DAEMON_OPTIONS(`Port=smtp, Addr=127.0.0.1, Name=MTA')
DAEMON_OPTIONS(`Port=587, Name=MSA, M=E')

dnl 啟用警告信功能,可以使用參數列舉方式設定發生哪些狀況時要送出警告信
define(`confPRIVACY_FLAGS',`goaway,restrictqrun,restrictmailq')

dnl 這是用來防止 sendmail 洩漏自己的版本號碼,建議將 SMTP_LOGIN_MSG 改為空字串
dnl define(`confSMTP_LOGIN_MSG', `$j server ready at $b')

dnl 定義會用到的 MDA 程式
MAILER(smtp)
MAILER(procmail)

dnl 定義本機所管理的網域名稱,通常是不需修改(可以省略不寫),因為 sendmail 自己會從 /etc/hosts 及系統設定取得自己本機的網域名稱,除此之外也會去讀取 /etc/mail/local-host-names 設定檔,如果要簡化郵件地址為網域名稱可在前述檔案中加入網域名稱

Cwlocalhost

有關各項功能設定的涵義,請參考附錄

其它設定檔

access 定義哪些網域或 ip 來的信可以被接受,哪些不行,當某個主機一直對我們寄出垃圾郵件,我們可以使用此機制來阻擋它,通常 access 會同時檢查收信人與寄信人的郵件地址,只要其中一個符合就算是比對成功,新版 sendmail 推出後大幅擴充 access 的功能,顯得 relay-domains 有點多餘(有將被淘汰的感覺),但其實它們各有各的好處
relay-domains 定義哪些網域或 ip 可以要求寄信,如果您要允許使用者透過其它 ISP 使用 MUA 連上伺服器寄信,您必須先將該 ISP IP 範圍加到這個設定檔內,與 access 不同的是這個檔不用雜湊成 db 資料庫,設定上也比較簡易
domaintable 用來產生網域名稱對應,通常是當學校的網域名稱改變時,為了讓使用舊地址的信件也能正常遞送,因此才設定
local-host-names 定義主機的所有別名
mailertable 定義分信路由,把收到的信依照郵件地址樣式的比對,分給外掛濾信程式處理或轉送給濾信主機處理
virtusertable 定義如何轉送要給虛擬網域或虛擬使用者的信件,這類信件將會轉送給某個真實存在的帳號 ,主要用來讓多個不同網域可以使用同一台郵件主機,對 ISP 公司來說很需要
genericstable 由於 8.12 版的 sendmail 已不再接受郵件地址不完整的信件(例如:shane@my_hostname),因此這類不完整的名稱必須改寫成合法的名稱, 這個檔案用來定義要把哪些名稱改為哪一個名稱,它也可以用來改寫 @ 前面的帳號名稱,作此用途時其作用與 userdb 相同
userdb 當本機是 mail gateway 時,透過這個檔可以得知哪些使用者是位於哪一台郵件主機上,分信時會分給該主機,而非分到本機的 /var/spool/mail 中,這個功能也可以用 aliases 達成
aliases 這個檔也是用來作郵件轉寄,一般拿來作別名對應或郵寄清單來應用,事實上 sendmail 上的轉寄機制很多,而且只要稍微修改設定也都能彼此取代,但我們應該明白其原始設計的用意,盡量不要去混用它們,以避免轉寄規則過於複雜,造成事後除錯的痛苦

以上設定檔均擺放在 /etc/mail 目錄,其中 accessdomaintablemailertablevirtusertablegenericstable 等五檔案必須將資料雜湊至資料庫內才能讓 sendmail 引用,我們使用以下指令來進行:

makemap  hash  /etc/mail/access  <  /etc/mail/access(前一個檔案是指 access.db 省略了附加檔名,後一個是指純文字檔的 access

userdb 必須以 btree 建立索引才能 sendmail 引用,我們使用以下指令來進行:

makemap  btree  /etc/mail/userdb  <  /etc/mail/userdb.txt

使用 MX 紀錄來簡化郵寄地址

希望讓郵件寄出時能夠直接使用網域名稱而非主機名稱來寄信,例如:shane@spps.tp.edu.tw,這必須修改 /etc/mail/sendmail.mc 中的 Masquerade 設定,修改成:

FEATURE(always_add_domain)dnl
FEATURE(`masquerade_entire_domain')dnl
FEATURE(`masquerade_envelope')dnl
FEATURE(`allmasquerade')dnl
MASQUERADE_DOMAIN(`spps.tp.edu.tw')dnl
MASQUERADE_AS(spps.tp.edu.tw)dnl

要讓寄到 shane@spps.tp.edu.tw 的信件能正確分信,除了在 /etc/mail/sendmail.mc 需包含 FEATURE (`relay_based_on_MX') 設定外,還必須在 DNS 中加入 MX 紀錄,由於加入 DNS 紀錄後必須等三天才能生效(DNS 預設值未修改的話),因此不用急著去測試!

請參考下圖,MX紀錄中應包含三個欄位,首先是郵件遞送的目的地(以網域名稱來判斷),接著指定要處理信件的伺服器,最後是優先權,數字越小越優先。一般觀念中認為 MX 紀錄是用來讓對方寄信給我們時查詢用的,這觀念並不完全正確,事實上當我們的郵件主機嘗試寄信時也會去查詢 MX 紀錄,以便得知是否要將信件傳遞給某台特定主機由它統一轉信,這個機制是用來實作 mail gateway,請用這個觀點來理解 sendmail.mc 中跟 MX 相關的選項,這樣觀念才不會錯誤!

實作 Mail Gateway

使用 MX 紀錄最主要的目的,是要實作 Mail Gateway,簡化郵寄地址只能算是副產品,假設校園內有兩台郵件主機 mail.spps.tp.edu.tw stu.spps.tp.edu.tw,現在已經在 DNS 內加入 MX 紀錄,將 spps.tp.edu.tw 的郵件交換主機設為 mail.spps.tp.edu.tw,所有寄到 s61533@spps.tp.edu.tw 的信件都將由 mail.spps.tp.edu.tw 來接收,這樣 stu.spps.tp.edu.tw 上的使用者就無法享受簡化郵寄地址的便利了!

解決的方法就是讓 mail.spps.tp.edu.tw 成為 stu.spps.tp.edu.tw mail gateway,首先在 mail.spps.tp.edu.tw 主機上將 spps.tp.edu.tw 加入到 /etc/local-host-names,也可以修改 sendmail.cw 或直接在 sendmail.mc 加入 Cwlocalhost mail.spps.tp.edu.tw spps.tp.edu.tw,這些做法結果都相同,這樣 sendmail 就會把要給 s61533@spps.tp.edu.tw 的信件視為本機郵件,但是要怎樣把信件轉送到 stu.spps.tp.edu.tw 上呢?請修改 /etc/mail/userdb.txt ,如下:

s61533    s61533@stu.spps.tp.edu.tw

寫好後不要忘記要用 makemap btree 來建立 userdb.db 檔,這個功能也可以用 virtusertablegenericstablealiases 來做,但建議不要這樣做,因為當出現問題需要除錯時將會很痛苦!

到這裡已經解決了收信的問題,寄信的問題稍微有點麻煩:首先請在 stu.spps.tp.edu.tw 主機上設定 Smart Host,請在 sendmail.mc 加入 define(`SMART_HOST', `mail.spps.tp.edu.tw')、MASQUERADE_DOMAIN(`spps.tp.edu.tw') MASQUERADE_AS(spps.tp.edu.tw),這樣所有從 stu.spps.tp.edu.tw 寄出的信件將會被轉送到 mail.spps.tp.edu.tw,同時會使用簡化的郵寄地址來寄信。不要忘記 sendmail 預設會擋 relay,因此當 stu.spps.tp.edu.tw 把信件轉送給 mail.spps.tp.edu.tw 時會被拒收,這時我們必須修改 mail.spps.tp.edu.tw 的設定對 stu.spps.tp.edu.tw 主機開放 relay 才行,開放 relay 可以直接把 stu.spps.tp.edu.tw ip 直接寫入 /etc/relay-domains 中,或是使用 access 來控制,也可以直接在 sendmail.mc 加入RELAY_DOMAIN(`stu.spps.tp.edu.tw'),這些做法結果是相同的。

使用 mail gateway 最大的好處是可以統一濾信,擋垃圾信或病毒信的工作只要在 mail gateway 上設定就可以了,不用同時去修改下屬郵件主機,萬一這種機器很多的話,工作負擔會很重。

使用 postfix 取代 sendmail

由於 sendmail 過去的名聲很不好,因此也有些版本的 Linux 直接以 postfix 取代 sendmailRed Hat 公司也感覺到這股潮流不可擋,因此也提供 postfix sendmail 的 轉換機制,在 Red Hat Linux 上要從 sendmail 轉換成 postfix 是很容易的,直接輸入 redhat-switchmail 指令,然後選擇要轉換的 MTA 即可,轉換後不要忘記將舊的服務停掉,並啟動新的服務,例如:

service  sendmail  stop
service  postfix  start

postfix 的組態檔是在 /etc/main.cf /etc/master.cf,請自行參考 postfix 相關系統文件進行設定。

如何防止垃圾郵件

在 sendmail 上,防止垃圾郵件轉寄的問題,可以透過以下四個機制來調整:

  1. 預設不作轉信,換句話說,寄信人或收信人其中之一必須是來自本機的 Domain Name 才受理
  2. 對寄信人的網址進行 DNS 查詢
  3. 透過 /etc/mail/access.db 進行存取控管
  4. 透過信件標頭的特徵比對,來過濾垃圾郵件

以上四種方法其實很難防止垃圾郵件的攻擊,原因是新一代的廣告信發信程式,早已針對這些措施擬出應對的策略,例如:

  1. 將寄信人地址偽裝成來自本機網域
  2. 寄信給本機網域的使用者,同時將要大量發信的對象使用 BCC 標頭以隱密副本方式發送
  3. 使用偽裝的  IP 位址來寄信,以規避 DNS 反查(缺點是這樣將無法確認是否交寄成功)
  4. 透過 socket proxy 交寄郵件來躲避防火牆稽核
  5. 透過後門程式從防火牆內模擬合法使用者交寄郵件

就是因為廣告信發信程式「道高一尺,魔高一丈」,因此造成系管師人人自危,視提供郵件服務為畏途。事實上 sendmail 複雜的送信機制是造成垃圾郵件之所以難以預防的主因,然而這些送信機制對於郵件的遞送處理又是不可或缺的,想要徹底阻擋垃圾郵件,不能不了解 sendmail 的送信機制,在前幾個小節已經詳細交代 sendmail 裡可以使用的功能和微調選項,筆者特別整理下表來幫助大家了解 sendmail 到底在做些什麼事:

工作內容 處理步驟 相關功能選項
信件標頭欄位剖析 檢查標頭欄位是否完整
改寫寄信人欄位
check_mail
是否需要改寫 domain always_add_domain
local_no_masquerade
limited_masquerade
masquerade_entire_domain
accept_unresolvable_domains
是否需要改寫 username ldap_routing
accept_unqualified_senders
檢查寄信人網域是否完整 nocanonify
檢查寄信人網域是否存在 nodns
改寫收信人欄位
check_rcpt
是否需要改寫 domain domaintab
allmasquerade
local_no_masquerade
use_cw_file
是否需要改寫 username virtusertable
genericstable
redirect
userdb
檢查收信人網域是否完整 nocanonify
轉信存取控制檢查
check_relay
如何進行轉信存取控制檢查 promiscuous_relay
delay_checks
檢查哪些 domain 可以 Relay relay-domains
access
relay_entire_domain
relay_hosts_only
relay_based_on_MX
relay_mail_from
relay_local_from
blacklist_recipients
dnsbl
enhdnsbl
lookupdotdomain
檢查哪些 user 可以 Relay use_ct_file
blacklist_recipients
是否通過帳號驗證 auth_options
遞送信件 將待寄信件寫入 mail queue
分信處理 給本機的信件要如何進行分信 mailertable
是否為虛擬信箱 aliases
是否需要轉信 .forward

利用 access.db 對轉寄要求進行存取控管是 sendmail 裡最重要的功能之一,從底下範例來介紹 access 的設定方法:

spammer@aol.com REJECT
cyberspammer.com REJECT
TLD REJECT
192.168.212 REJECT
IPv6:2002:c0a8:02c7 RELAY
IPv6:2002:c0a8:51d2::23f4 REJECT
核對寄信人或收信人信箱是否為 spammer@aol.com
核對寄信人或收信人網域是否為
cyberspammer.com
核對寄信人或收信人網域是否為 TLD 開頭的名稱
核對提出寄信要求的
IP 是否為 192.168.212 開頭
核對提出寄信要求的
IP 是否為 ipv6 格式
核對提出寄信要求的
IP 是否為 ipv6 格式中的子網域

除了使用 REJECT 來拒絕轉信要求外,也可以使用 RELAY 來接受轉信要求,如果想讓被拒絕轉信的網域中某些單機仍然可以轉信,或是某個被拒絕的網段中的某個 IP 允許轉信,這兩種情形下可以設定成 OK,類似的情形下想讓某個網段中的某個 IP 或某個網域中的某台主機不要進行比對,則可以使用 SKIP,DISCARD 用來將信件完全丟棄,與 REJECT 不同的是將不會產生退信通知,ERROR 也是用來 REJECT 轉信,但是可以指定退信通知的訊息內容,應用範例如下:

cyberspammer.com ERROR:550 "We don't accept mail from spammers"
okay.cyberspammer.com OK
sendmail.org RELAY
128.32 RELAY

使用 access 除了單純樣本比對外,還可以指定比對欄位,事實上使用這種方式來比對,對於防止垃圾郵件更為有效,舉例來說:

mail.spps.tp.edu.tw RELAY

這條規則會允許假冒寄信人地址為 user@mail.spps.tp.edu.tw 的信件,能夠成功透過本機進行轉寄,如果改為:

To:mail.spps.tp.edu.tw RELAY
Connect:192.57 RELAY

則保證只有收信人地址是 user@mail.spps.tp.edu.tw 的信件,本機才接受,另配合 ip 的比對來讓校內機器可以正常寄信,由於限定比對連線者(Connect)的 ip,所以即使把寄信人地址改為 user@[192.57.1.2] ,本機還是會擋掉不 Relay,這比起單純的樣式比對擋得更徹底。更複雜的應用如下面的例子:

From:spammer@some.dom REJECT
To:friend.domain RELAY
Connect:friend.domain OK
Connect:from.domain RELAY
From:good@another.dom OK
From:another.dom REJECT

當啟用 FEATURE(`delay_checks') 選項時,可以附加以下兩個選項:

FEATURE(`delay_checks', `friend')
FEATURE(`delay_checks', `hater')

這時候在 access.db 裡,就可以使用下列語法來宣告垃圾郵件的同路人,sendmail 將會在退信通知中,提示對方郵件主機遭人利用轉信的訊息,底下語法分別是比對郵寄地址、使用者名稱和網域名稱。

Spam:abuse@my.domain FRIEND
Spam:abuse@ FRIEND
Spam:spam.domain FRIEND

想要完全防堵垃圾郵件,最有效的方法就是使用 SMTP AUTH 功能,當你啟用此功能後,如果對方能通過帳號密碼驗證,就可以取得 Relay 的權限,但透過其他方式 Relay 仍然是被接受的,例如:通過 access.db 的檢查、透過 relay-domains 的宣告、透過 MX 紀錄或通過 trusted-user 的宣告......等等。因此想徹底防禦垃圾郵件,第一件事就是必須把其他功能關閉或做最大限制,筆者的做法是:

  1. 不使用 MX 紀錄
  2. trusted-user relay-domains 保持淨空
  3. access 中僅包含 127.0.0.1 RELAY localhost RELAY localhost.localdomain RELAY 三行
  4. 設定驗證機制時,不開放 LOGIN PLAIN

在這種嚴格的限制下,學校老師不管在家裡寄信或在學校寄信(透過 WEB 介面除外),都必須修改 outlook express 的設定,設定如下:

手動 RELAY 測試

想要知道自己架設的郵件主機是否設定正確,沒有 Relay 的問題,可以使用 telnet 工具作測試,先以 help 查詢可以使用的指令:

#  telnet  127.0.0.1  25
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
220 ESMTP
  //sendmail 版本訊息已經被隱藏
help
214-2.0.0 This is sendmail version 8.12.8
//但是打 help 還是看得到版本訊息,這個問題請修改 /etc/mail/helpfile 來解決
214-2.0.0 Topics:
214-2.0.0 HELO  EHLO  MAIL  RCPT  DATA
214-2.0.0 RSET  NOOP  QUIT  HELP  VRFY
214-2.0.0 EXPN  VERB  ETRN  DSN  AUTH
214-2.0.0 STARTTLS
214-2.0.0 For more info use "HELP <topic>".
214-2.0.0 To report bugs in the implementation send email to
214-2.0.0 sendmail-bugs@sendmail.org.
214-2.0.0 For local information send email to Postmaster at your site.
214 2.0.0 End of HELP info
helo test.com
  //嘗試假冒自己身份為 test.com
250 mail.spps.tp.edu.tw Hello localhost.localdomain [127.0.0.1],
//這裡一定會顯示正確的連線位置
pleased to mee
t you.
mail from: spam@test.com
//假裝寄信人是 spam@test.com
250 2.1.0 spam@test.com... Sender ok
rcpt to: spam@test.com
//假裝收信人也是 spam@test.com
250 2.1.5 spam@test.com... Recipient o
//居然被接受了,其實因為是從 127.0.0.1 連線,所以會這樣
quit
221 2.0.0 mail.spps.tp.edu.tw closing connection
Connection closed by foreign host.

$  telnet  192.57.1.7  25  //這次從別台主機連上來測試
Trying 192.57.1.7...
Connected to 192.57.1.7.
Escape character is '^]'.
220 ESMTP
helo test.com
//假冒自己的身分
250 mail.spps.tp.edu.tw Hello stu.spps.tp.edu.tw [192.57.1.6], pleased to mee
t you.  //顯示正確的連線位置
mail from: spam@test.com
//假裝寄信人是 spam@test.com
250 2.1.0 spam@test.com... Sender ok
rcpt to: spam@test.com
//假裝收信人是 spam@test.com
550 5.7.1 spam@test.com... Relaying denied. Proper authentication required.
//果然被要求要先登入
rcpt to: shane@mail.spps.tp.edu.tw
//改寄給本機帳號 shane@mail.spps.tp.edu.tw
250 2.1.5 shane@mail.spps.tp.edu.tw... Recipient ok
//被接受了,事實上單純收信是不會擋 RELAY,當然前提條件是寄信人 spam@test.com access.db 中不可以被 REJECT
data
  //開始輸入信件內容
354 Enter mail, end with "." on a line by itself
From: 你抓不到我@test.com //透過這個標頭, 可以取代 MAIL 指令所設定的郵件信箱地址,以避免被追蹤
To: 你抓不到我@test.com //透過這個標頭, 可以取代 RCPT 指令所設定的郵件信箱地址,以避免被追蹤
S
ubject: hello

hi, how are you?
.
//結束輸入,必須另起一行然後輸入英文句號
250 2.0.0 h284YtkF025941 Message accepted for delivery
//信件被接受並進行分信處理
quit
221 2.0.0 mail.spps.tp.edu.tw closing connection
Connection closed by foreign host.

$  telnet  192.57.1.7  25
Trying 192.57.1.7...
Connected to 192.57.1.7.
Escape character is '^]'.
220 ESMTP
auth plain
//嘗試以純文字密碼登入
504 5.3.3 AUTH mechanism plain not available //這種驗證機制已經被移除
auth login
//嘗試以 POP3 方式登入
334 VXNlcm5hbWU6
//提示輸入 username,之所以看不懂是因為被編成 base64
shane //直接輸入帳號是錯的 ,請先使用底下指令找出 base64 字串:
perl -MMIME::Base64 -e 'print encode_base64("要編密的字串");'

334 UGFzc3dvcmQ6
//提示輸入 password
123456 //與帳號相同,要先編成 base64
535 5.7.0 authentication failed
//由於 base64 編碼事實上並未加密,最好還是不要用
auth digest-md5
//嘗試其他驗證機制存不存在
504 5.3.3 AUTH mechanism digest-md5 not available
starttls
//嘗試 TLS/SSL 安全傳輸層有沒有啟用
454 4.3.3 TLS not available after start
help dsn
//查詢進階指令
214-2.0.0 MAIL FROM: <sender> [ RET={ FULL | HDRS} ] [ ENVID=<envid> ]
214-2.0.0 RCPT TO: <recipient> [ NOTIFY={NEVER,SUCCESS,FAILURE,DELAY} ]
214-2.0.0 [ ORCPT=<recipient> ]
214-2.0.0 SMTP Delivery Status Notifications.
214-2.0.0 Descriptions:
214-2.0.0 RET Return either the full message or only headers.
214-2.0.0 ENVID Sender's "envelope identifier" for tracking.
214-2.0.0 NOTIFY When to send a DSN. Multiple options are OK, comma-
214-2.0.0 delimited. NEVER must appear by itself.
214-2.0.0 ORCPT Original recipient.
214 2.0.0 End of HELP info
ehlo test.com  // EHLO 指令打招呼,就可以使用進階指令,事實上進階指令有很多安全漏洞
250 mail.spps.tp.edu.tw Hello stu.spps.tp.edu.tw [192.57.1.6], pleased to mee
t you.
mail from: spam@mail.spps.tp.edu.tw
//嘗試假裝自己是本機使用者
250 2.1.0 spam@mail.spps.tp.edu.tw... Sender ok
rcpt to: hp2013@ms8.hinet.net
//能不能寄垃圾信到 hinet
550 5.7.1 hp2013@ms8.hinet.net... Relaying denied. Proper authentication requir
ed. //結果被拒絕了,跟上一次的測試不同的是,現在是要寄信出去所以當然會擋 RELAY,況且剛才嘗試登入也沒成功
quit
221 2.0.0 mail.spps.tp.edu.tw closing connection
Connection closed by foreign host.

procmail 濾信程式

procmail 是一支功能強大用途廣泛的濾信程式,當 sendmail 收到 給本機的信件進行分信時,會先處理 aliases 別名對應,處理完 aliases procmail 就會被呼叫執行,procmail 將會根據比對規則進行信件標頭(Header)或信件內文(Body)的特徵比對,比對規則是採用正規表達式的形式,若比對成功則進行相對應的處理,包括:轉信給另一個帳號、轉存到檔案、轉給另一支程式處理......等等,其餘未符合條件之信件則繼續進行比對,直到所有比對規則比對完畢為止,最後比對未成功的信件,則會交由 sendmail 內建的 MDA 分信給收信人。系統預設的比對規則應該擺放於 /etc/procmailrc 檔案內,或者是 /etc/procmailrcs 資料夾內,這些規則在收到每一封信時都會被載入比對,接著 procmail 才會去讀取使用者自行建立在自己家目錄內的 .procmailrc 檔案,以便針對個人的信件進行比對,當然本文並不討論一般使用者運用 procmail 的範例,也不建議教使用者去利用這個功能,筆者建議濾信工作應該由系管師統一規劃實施。

底下介紹幾個範例來說明 procmail 的用法,更多的範例可以參考 http://www.iki.fi/era/procmail/links.html 網站的說明。procmailrc 的語法格式如下:

:0<旗標>:<鎖定檔檔名>
* <特殊比對字元> <正規表示式-1>
* <特殊比對字元> <正規表示式-2>
* <特殊比對字元> <正規表示式-N>
<特殊處理字元><處理標的>

在說明語法涵義之前,先來看底下幾個例子,以便了解應用的方式與效果:

:0:
all_mail_stored.here

上面這個範例將會建立鎖定檔,建立鎖定檔可以保證信件寫入到 all_mail_stored.here 的同時,不會有其它程序存取此檔案,由於範例中未指定鎖定檔檔名,所以該檔名將由 procmail 自行命名,另外範例中省略比對演算,也就是說所有新收到的郵件都符合比對條件(無條件),都會進行進一步的處理,處理方式是將信儲存於 all_mail_stored.here 檔案中,處理過的信件將不會分信給收信人。事實上這個範例一旦執行,所有的信件都會被儲存於單一檔案中,沒有人會再收到信件。

:0c
! spy@some.where

與前一個範例不同的是,這個範例不會建立鎖定檔,同時由於使用旗標 c,因此比對成功後處理的是複製信,這個範例會將此伺服器所有收到的信件,轉寄給 spy@some.where 信箱,但收信人仍然可以正常收到信件,並無法得知信件被轉寄到其它地方以便檢查內容。

:0
* ^From: spammer@some.where
/dev/null

這個範例不會建立鎖定檔,範例中有比對演算式,會比對寄信人是否為 spammer@some.where,若是則進行後續處理,處理方式是將信丟到黑洞裡,該信將會徹底消失!

底下逐一說明語法結構中每種參數的意義:

旗標 決定比對生效的方式
A 進行 and 比對,當上一次比對(沒有 A a 旗標的那一次)比對成功的情形下才進行此次比對
a 同上,但會先確認前一次的處理動作是否處理成功,若是才進行此次比對
B 比對信件內文是否符合條件
b 進行處理動作時,例如:轉寄給某人或轉存到檔案,是否要包含信件內文,預設要包含
c 在處理比對之前,是否先複製一份,並比對複製的那一份,若比對成功時,則僅處理複製信,原始信件仍會繼續進行後續比對,或比對完畢後由 MDA 分信給收信人
D 指定比對時要區分大小寫,預設值是不區分
E 進行 else 比對,當上一次比對(沒有 E e 旗標的那一次)比對不成功的情形下才進行此次比對
e 同上,但會先確認前一次的處理動作是否處理失敗,若是才進行此次比對
f 指定將 | 符號視為管道而非 OR
H 比對信件標頭是否符合條件
h 進行處理動作時,例如:轉寄給某人或轉存到檔案,是否要包含信件標頭,預設要包含
w 要求 procmail 進行下一個比對之前,先等待處理動作處理完畢,通常是用於呼叫外掛處理程式的情形下,這是為了避免該外掛程式未執行完畢卻被反覆啟動,造成 IO 衝突
特殊比對字元 運用於正規表達式無法處理的比對場合
! 表示要做反向比對,比對不符合條件的信件
< 比對信件大小是否小於指定 Bytes
> 比對信件大小是否大於指定 Bytes
正規表示法 請自行參考 regular expression 說明文件
特殊處理字元 決定如何進行信件的處理,如果省略此字元,意思是要轉存到一個檔案裡
! 轉寄給某個指定的信箱
$ 轉寄給某個預先設定好的變數其所指定的信箱
| 轉交給其他程式處理(任何可執行的程式,例如:shell scriptperl、二進位檔案......等等)
{} 進行巢狀處理,該信件將會被保留並繼續進行後續比對,詳細用法可參考底下 HTML 剖析範例的內容
處理標的 檔名、信箱或外掛程式的名稱

formail 郵件產生器

這個工具是用來重新改寫信件標頭,或是用來產生信件內文,procmail 結合 formail 就可以用來寄發警告信、通知信或是用來設計自動回信機制,由於應用方式稍嫌複雜,在此課程中不介紹,請有興趣的學員自行研究。

過濾病毒信範例

早期利用病毒信的特徵,可以過濾一些簡單的病毒,隨著病毒不斷的衍生進化,病毒信已經沒有一定的特徵可供比對,這時候就只能透過附加檔案的延伸檔名來判斷該附加檔案是否可以執行,如果可以執行就會有傳播病毒的危險性,一律將它丟棄,這類的檔案包含:wshbatexepif......等,但曾幾何時隨著微軟 MIME 偽裝的漏洞出現後,有許多可執行檔化身為圖形檔以躲避防毒軟體的過濾,而此類檔案卻會被微軟的 MIME 剖析器開啟執行,導致病毒氾濫。除此之外,更多的病毒檔案隱藏在 HTML 編碼中,在遠端伺機而動,等待使用者開啟郵件時自動下載執行,這類的病毒需要能剖析 HTML 語法的濾信程式才能過濾,幸運的是有個公益組織已經利用 procmail 的機制寫出可以剖析 HTML 的濾信演算法,推薦大家安裝使用,該站台網址為 http://www.impsec.org/ ,目前最新的版本為 1.318 請按這裡 procmail-sanitizer.tar.gz 下載。(下載石牌國小 PROCMAILRC

啟用 procmail 日誌

請在 /etc/procmailrc 檔頭加入

LOGFILE="/var/log/procmail"

接著自己用 touch 指令建立該檔案,這樣就會啟用日誌功能,對於除錯很有幫助!

別名與郵寄群組

sendmail 檢查信件的收信人欄位,當發現收信人的網域名稱為本機網域時就會開始進行分信,所謂本機網域指的就是定義在 /etc/mail/local-host-names 中的網域名稱(舊版本使用 sendmail.cw),分信之前會先檢查 aliases 別名檔,看看是否有定義虛擬信箱,所謂虛擬信箱就是指不是給使用者使用的信箱,這些信箱多半是有特殊用途,例如:系統管理用的、郵寄群組用的......等等。也有人把 aliases 別名檔拿來作使用者全名的對應,例如:Shane.Lee 對應成 shane,雖然這也是一種應用的方式,但按照 sendmail 設計的原意,應該是使用 genericstable 去做這件事比較正確,兩者不同的地方在於:genericstable ruleset 2 進行收信人欄位改寫時就直接處理了,不會等到分信時才處理,而且按照 aliases 的設計必須要能載入 include、呼叫執行 script,並且允許使用遞迴別名,這都會降低處理效能,如果只是單純要作全名對應使用 aliases 比較不划算!

當安裝 sendmail 時系統會自動幫我們產生 aliases 別名檔,同時會把系統上的服務帳號對應給 root,這是因為服務帳號是給應用程式使用的,當應用程式執行過程中遇到某些突發狀況時,或網路上的其他管理人員需要聯絡該應用程式的管理人時,有時候會寫信給這些帳號,透過 aliases 別名檔的作用,這些信件就會分到 root 的個人信箱以免沒人處理。但在實際環境中,為了避免 root 密碼在網路上傳輸遭到駭客竊取,不管是透過 outlook express 或是透過 web 介面,我們都不該去收取 root 的信件,而應該在 aliases 別名檔中將 root 的信件分給實際管理該機器的使用者,而且為了避免駭客查出誰是真正的管理員,這個檔案的權限應該設成 600。預設別名檔的內容節錄如下:

#
# Aliases in this file will NOT be expanded in the header from
# Mail, but WILL be visible over networks or from /bin/mail.
#
# >>>>>>>>>> The program "newaliases" must be run after
# >> NOTE >> this file is updated for any changes to
# >>>>>>>>>> show through to sendmail.
#
# Basic system aliases -- these MUST be present.
mailer-daemon: postmaster
postmaster:  root

# General redirections for pseudo accounts.
bin:       root
daemon:     root
============中間省略===================

# trap decode to catch security attacks
decode:    root

# Person who should get root's mail
#root:    marc <==請去掉 Remark 並改成自己的帳號

aliases 除了用來將虛擬信箱對應給真實的帳號外,還可以將信件儲存在備份檔案內,這樣做的目的是希望信件被收走後,能留一份在伺服器上備查,例如我們可以把上例解說過的那一行改為:

root:   shane,/var/log/backup-mail

除此之外,aliases 也可以用來轉寄信件,例如下面的設定會將信件轉寄出去,以便確定 shane 一定收得到:

root:   shane,shane@ms8.hinet.net,shane@tmtc.edu.tw,shane@tp.edu.tw

當要轉寄的信箱很多時,全部寫成一行還真是困難,譬如想寄同一封信給全校所有老師,但不想一個一個輸入收信人地址,透過 aliases 的幫助,我們只需要建立一個 teachers 虛擬信箱,接著準備一個空的純文字檔,把全校老師的信箱地址打進去,一個地址一行,最後得留一行空白行。檔案做好後,我們就可以將別名設定改成:

teachers:   ":include:/etc/mail/all_teachers.txt"

利用這個方式,想同時寄信給一群人再容易不過了。但是,當郵寄群組很多而且成員相互重疊時,想要維護郵寄清單的正確性就會很痛苦,好比除了全校教師外,我們另外還有各學年教師、科任教師、行政人員、主任等多個清單,學期末老師退休或學期初新進同仁加入,這麼多清單要同時檢查修改不能遺漏,這工作可累了!還好 aliases 提供了遞迴參照的功能,讓我們可以將清單分批建立,並以參照方式建立聯集,工作就輕鬆多了,例如:

headship:    lee       (校長)
director:   suelan,wang,............(主任)
manager:    maggy,young,..........(組長)
grade1:    jack,mary,helen,........(一年級老師)
grade2:    vicky,johnny,,,,,,,......(二年級老師)
..........................................................(省略)
course:              sean,marc,.................(科任)
administer:     headship,director,manager(行政人員)
teachers:     administer,grade1,grade2,grade3,grade4,grade5,grade6,course(全校老師)

在更複雜的應用中,aliases 還可以結合外掛的程式提供更進階的服務,例如:郵件訂閱、自動回信系統(auto reply)、討論群組(mailing list......等。例如:

check:   "| perl /usr/libexec/subscribe.cgi"

如果您想建立討論群組但不想花精神維護它,建議您安裝 smart list,這個套件雖然陽春但是非常簡易好用,它包含:信件訂閱、取消訂閱、討論文件索引備分、查詢討論清單與內容、自動清除遞送有問題之訂閱者......等等。如果您想讓使用者都能建立自己的討論群組,majordomo 是第一選擇,這個軟體不但使用者眾多,相關統計分析工具也已經開發得很完善,這些套件在 rpm 安裝時會自動修改 aliases 組態,需要手動修改的情況不多,因此不在此討論。

設定好 aliases 之後,必須以 newaliases 指令來雜湊該檔案以利 sendmail 讀取應用,由於 aliases 是隨用隨讀,因此並不需要重新啟動 sendmail 伺服器,它會立即生效。

自動轉信機制

aliases 雖然好用,但是必須具有管理員身分,才有機會去設定它,一般使用者如果想要讓系統幫忙轉信,唯有使用 .forward 機制了,所謂 .forward 機制就是當 MDA 進行分信時,會讀取使用者家目錄下的 .forward 檔,並像 aliases 中定義的 include 一樣,逐一將信件轉寄出去。這個檔案的用法與 include 相同,請自行參考前一小節的說明。

查看待寄郵件佇列

新版 sendmail 在啟動時,會執行兩支 Deamon,新增的 Deamon 叫做 sm-client,它是專門用來處理待寄信件的(Queue),如果這支程式沒有被正常執行,將會導致要寄出的信件堆積在佇列裡無法遞送的情形,然而卻不會影響 sendmail 的正常運作,收信和分信是正常的。這樣的設計,可以避免因為伺服器被利用作為廣告信轉信站台,而導致整個 sendmail 當掉,對郵件主機的管理人員來說,可說是個天大的好消息。

當信件無法寄出時,應先使用 ps 指令檢查 sm-client 是否正常運作,如果 sm-client 被關閉了,就有可能是被大量轉信了,這是我們可以使用 mailq 指令來查看待寄信件清單,範例如下:

# mailq
/var/spool/mqueue (1 request)
-----Q-ID-----
-------- --Size-- -----Q-Time----- ------------Sender/Recipient-----------
h27HOmkF013807
    1725 Sat Mar 8 01:24 <spps@mail.spps.tp.edu.tw>
(Deferred: Connection timed out with mfa.vip.mail.tpe.yahoo.c
om)
                                                                       <kkkwwwff@kimo.com>
        Total requests: 1

如果發現有大批信件賭塞,而且全都來自同一個寄信人,我們就可以斷定該寄信人是 spammer,當然二話不說,立刻將他加入到 access 中並 REJECT 起來(不要忘記雜湊成 access.db),接著切換到 /var/spool/mqueue 目錄中,將堆積的信件刪除,如果不想費心一封一封核對,直接 rm -rf * 也可以,做完這些動作後再重新啟動 sendmail 讓它上線服務。

陸、網頁伺服器

HTTP 1.1 通訊協定

當歐洲高等物理實驗室開發出網頁伺服器時,當時是使用 HTTP 1.0 版通訊協定,市場上支援得最好的瀏覽器大概就是 Netscape Navigator及Communicator,Netscape 公司在產品成熟後緊接著推出 Gold 版開始收費販賣,在 Gold 版中他們提出了線上編輯網頁的概念(編好後要用 FTP 上傳就是了),為了實現這個概念必須要發展新的 HTTP 通訊協定,當然沒多久 Netscape 從市場消失,大家開始改用微軟公司的 IE 以及 FrontPage,微軟公司基於簡單易用的考量, 積極參與新版本 HTTP 通訊協定的制定,這就是後來我們看到的 HTTP 1.1

HTTP 1.1 版通訊協定的改版幅度相當大,例如:增加檔案 zip 壓縮功能,增加 MD5 編密傳送功能......等等,其中對微軟公司最重要的就是,他們提案的 PUT DELETE 指令被接受了,PUT 指令用來新增網頁、修改網頁內容或變更檔名,DELETE 指令則用來刪除網頁或目錄,透過這個機制就可以很容易用 HTTP 80 埠來直接更新網站內容,這就是微軟產品 FrontPage Server Extension 的目標,目前除了 FrontPage 支援 PUTDELETE 指令外,還有 W3C 開發的 Winie 也可以用來上傳網頁(支援 Linux 平台,Server 端則由 Apache mod_put 負責)。底下簡要的說明 HTTP 1.1 版各個指令的用途:

指令 用途
OPTIONS 查詢或設定 URI 旗號,透過這個機制伺服器得以和瀏覽器協商傳輸資料時要不要壓縮、要不要 Cache ......等等
GET 取得網頁資料。必須使用絕對網址來要求資料,如果使用相對路徑,則必須以 Host: 標頭標示目的網址,這跟 1.0 版有很大的不同
HEAD GET 很像,但只會取得網頁標頭,不包含網頁內文(除錯用)
POST 取得網頁資料前,先上傳前一個網頁的表單資料,POST GET 的差別在於上傳資料的方式不同,使用 GET 可以在網址後方添加資訊(?user=xxps&test=on......),但資訊的量無法超過一行的限制,使用 POST 上傳沒有上限。POST 除了用來上傳表單資料(上傳檔案)外,還可以:
  1. Server 上的資料來源建立註解
  2. 提供資料給表單中的動態資料連結項目(DataField
  3. 新增資料到資料庫(通常是另一個網頁或純文字資料庫)

FrontPage 上可以製作這種進階表單,在此不作詳細說明

PUT PUT 指定的網頁不存在時,會自動新增網頁,否則就是要取代舊網頁或變更名稱
DELETE 刪除指定的網頁或空目錄
TRACE 用來做應用層的 loopback 追蹤,可以配合 OPTIONS 指定 Max-Forwards 來決定追蹤的深度,使用此指令將追蹤出所經過的 Proxy(除錯用)
CONNECT 是給 Proxy 伺服器用來建立 SSL 通道的,當瀏覽器透過 Proxy 使用 HTTPS 連上網頁時,需要在 Proxy 上建立 SSL 通道才能提供服務給 Client

了解 HTTP 回應狀態碼的涵義(RFC 2068),對於理解 Apache 伺服器的行為和運作機制有很大的幫助,同時當網頁出現狀況無法正常顯示時,瀏覽器也會秀出這些錯誤訊息,了解這些錯誤訊息您就可以判斷出問題的成因,因此在附錄 C 特地收錄了一般常見的各種狀態碼的表列,當作補充教材請學員細心閱讀。

新版 Apache 的特色

RedHat 8.0 版隨附的 Apache 伺服器是 2.0 版,相較於過去推出的 1.3 版有非常大幅度的改變,2.0 版的 Apache 不但支援多重處理器系統、支援 ipv6,也重新改寫了函式庫。新版 Apache 內的模組全部使用新的函式庫來編譯,使得所有模組都能支援 DSO 動態載入。(DSO 不算是新東西,過去一直不是 Apache 預設的做法,在前版 Apache 上想要使用 DSO 必須自己重新編譯 Apache)。除此之外,新版 Apache 也支援一種稱為過濾器(Filter)的全新模組,過去使用的舊模組則被稱為掌舵者(Handler)模組。

說到 filter 我想經常使用 Linux 指令的人一定不陌生,當一次使用多個 shell 指令時,我們會使用管道符號來串接指令,而在 Linux 上管道符號就被稱為 filter 符號,這意味著,這些模組可以像 shell 指令一樣串接在一起,例如:ls | grep a | less,透過多個程式接力運作最後可以得出比較複雜有彈性的結果。過去使用的 Handler 模組,在處理完程式網頁的內容後,會直接將處理結果推送回瀏覽器端;而 Filter 模組則在處理完後,將處理結果送回給 Apache core module,以便交給其它 Filter 模組進行後續處理。事實上這個新的轉變在 Microsoft IIS 上已經行之多年,它能帶來最大的好處,就是網頁伺服器將有能力去處理混用多種 script 語言所設計出來的複雜網頁,這在過去被認為用途不大,但隨著 Web Computing 的風行,這已經成為不得不然的趨勢事實上 Apache 這樣的轉變,將有助於吸納原來 IIS JAVA 伺服器的使用者,因為使用 ASP JSP 的網頁在 Apache 上剖析執行已經不再只是夢想。

除了這些重大的改變以外,2.0 版在組態設定上有一些改變,這個改變是好是壞就見仁見智了,筆者認為預設的組態對於中文世界的使用者特別是中小學來說是相當不友善的,必須要經過蠻多修改才能使用,與過去 1.3 版相比改變還真大!底下就來說明組態檔中新舊版本不同的地方:

conf.d

新版的 Apache 將各種模組會用到的組態檔集中擺放在 /etc/httpd/conf.d 資料中,例如:mod_perlmod_sslmod_php......等,因此在組態檔中有這一行:

Include  conf.d/*.conf

如果您的 Apache 是從舊版升級上來的,記得把這一行加到原來的組態檔中。

IP 與埠號繫結

舊版 Apache 是使用 BindAddress Port 來指定伺服器提供服務的位置,新版的 Apache 則是使用 Listen 來宣告要傾聽的埠號,使用 ServerName 指定埠號的方式來宣告是由哪個 DN 來提供該服務,好處是一台 Web 將可以同時服務多個 Port,甚至可以利用埠號的不同來設計虛擬站台(過去有所謂 IP basename base 虛擬站台,現在又多了 Port base,有關虛擬站台在後面章節說明),例如:

1.3 2.0
BindAddress 192.168. 1.2
Port 12000
ServerName wam.spps.tp.edu.tw
Listen 12000
ServerName wam.spps.tp.edu.tw:12000

Multi-Processing ModulesMPMs

MPMs 是一群特殊的模組,和其它模組不同它們是無法動態載入的(DSO), 它們必須在安裝 Apache 時就決定要用哪一個,目前 MPMs 有三種 ,分別是:preforkworker perchild。像過去 1.3 版那樣在 Apache 啟動時,即預先將要提供服務的 StartServers 一併 fork 好,這種做法就稱為 prefork,其它兩種作業模式 RedHat 8.0 尚未提供,必須等新的 rpm 出來後才能安裝使用。

三個模組分別採用不同的記憶體管理方式,其中 perchild 使用執行緒來提供服務,prefork 使用子程序來提供服務,而 worker 則兼用兩種方法,它們的差異在於:執行緒可共用記憶體,並使用記憶體與其它執行緒溝通;子程序則獨立使用記憶體,且利用檔案與其它子程序溝通。前者效能較高,後者比較安全穩定。

三個模組被設計用來應付不同的效能需求,小型實驗網站使用 perchild,它會同時啟動 5 Server,每個 Server 最多執行 10 個執行緒,因此可同時應付 50 條連線,假設有開啟 KeepAlive 功能,則最多可同時服務  5000 個要求,相當於 IIS 中的 1000 人以下存取量(在 IIS 中也可以進行效能調整,兩者相互對照比較容易理解 MPMs 機制),預設的 prefork 是提供給中量級網站使用,最多可同時接受 3000 條連線,服務 30000 個要求,重量級網站則使用 worker,最多可同時接受 22500 條連線,約可服務 20 萬個要求。

直接受此改變影響的包含:StartServersMinSpraeServersMaxSpareServersMaxClientsMaxRequestsPerChildNumServersStartThreadsMinSpareThreadsMaxSpareThreadsMaxThreadsPerChild....等 ,預設值如下:

##
## Server-Pool Size Regulation (MPM specific)
##

# prefork MPM
# StartServers: number of server processes to start
# MinSpareServers: minimum number of server processes which are kept spare
# MaxSpareServers: maximum number of server processes which are kept spare
# MaxClients: maximum number of server processes allowed to start
# MaxRequestsPerChild: maximum number of requests a server process serves
# NumServers: constant number of server processes
# StartThreads: initial number of worker threads in each server process
# ThreadsPerChild: constant number of worker threads in each server process
# MinSpareThreads: minimum number of worker threads which are kept spare
# MaxSpareThreads: maximum number of worker threads which are kept spare
# MaxThreadsPerChild: maximum number of worker threads in each server process
<IfModule prefork.c>
StartServers 8
MinSpareServers 5
MaxSpareServers 20
MaxClients 150
MaxRequestsPerChild 1000
</IfModule>

# worker MPM
<IfModule worker.c>
StartServers 2
MaxClients 150
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestsPerChild 0
</IfModule>

# perchild MPM
<IfModule perchild.c>
NumServers 5
StartThreads 5
MinSpareThreads 5
MaxSpareThreads 10
MaxThreadsPerChild 20
MaxRequestsPerChild 0
</IfModule>

Dynamic Shared ObjectDSO

新版 Apache 已經全面採用 DSO,過去 DSO 是編譯 Apache 的選項之一,由於一直未被各版本 Linux 支援,因此如果想要使用必須自行下載原始檔編譯,Apache 模組全面改寫應該與全面採用 DSO 有很密切的關連。如前所述,由於 Apache 模組改以過濾器的方式運作,因此有許多模組被合併、分割、移除或改名,模組之間串接的順序也變得更為重要,因此 Apache 允許模組可以指定自己的順序,過去於組態檔中提供的 AddModule ClearModuleList 已經被取消不再使用,LoadModule 指令的順序也被忽略。安裝 mod_perlmod_sslmod_php...... RPM,也不用再去新增 LoadModule 設定,因為它們會自動被載入。另外,過去用來偵測哪些模組被載入的 HAVE_XXX 巨集命令,也不再使用了,因為現在的模組是動態載入的。

個人網頁目錄

中小學架設 Apache 主要是為了提供師生個人網頁空間,可惜新版 Apache 預設將此功能關閉,必須手動自行修改才能啟用:

UserDir  disable

改為

UserDir  public_html(或其它想使用的名稱)

預設語言與字元集

新版 Apache 裝好後預設會使用荷蘭語系和西歐字元集,這樣就造成網頁看到亂碼,過去舊版本使用哪種語系是由瀏覽器來決定,新版改為由 Apache 和瀏覽器來協商,因此就算設計網頁時有指定 Big-5 字元集,但瀏覽器卻接受 Apache 的指派,而不再理會網頁內容本身的設定,這對我們會造成很大的困擾,因此安裝完 Apache,一定要記得改底下這些選項:

DefaultLanguage tw
............................(中間省略)........................
LanguagePriority tw en da nl et fr de el it ja kr no pl pt pt-br ltz ca es sv
............................(中間省略)........................
AddDefaultCharset Big5

如果這些都改好後仍然出現亂碼,請檢查 IE 網際網路選項中的進階設定,是否有開啟 UTF-8 功能,目前發現某些情形下使用該功能會導致網頁亂碼,將它移除後就正常了。

常用組態設定

分類 組態名稱 預設值 使用說明
基本設定 ServerRoot /etc/httpd Apache 主程式所在目錄,這是不需要修改的。
Timeout 300 用來設定連線等待時間,包含:連線完成後,瀏覽器應於多少時間內送出 GET 指令、瀏覽器送出 POST PUT 指令後,應於多少時間內送出網頁或表單資料、伺服器回應網頁資料後,瀏覽器應於多少時間內回覆收到。這個設定是以秒作為單位。
KeepAlive off 是否允許同一連線送出多個要求,通常一個要求會起始一條連線,這樣雖會耗用較多的系統資源,但是回應比較迅速,當連線數太多系統資源不足時,可以考慮使用此功能。
MaxKeepAliveRequests 100 設定每條連線最多可接受多少要求,設得越高重啟連線的機率就越低,對改善 KeepAlive 的效能很有幫助。
KeepAliveTimeout 15 當一條連線服務完一個要求後,會等待一段時間以便接受下一個要求,如果逾時就關閉連線,這個設定值與前面介紹的 Timeout 意義完全不同,可千萬別搞混了。
Listen 80 和舊版的 Port 不同,它允許一個伺服器可以同時傾聽多個通訊埠,當埠號被設定少於 1024 的情形下,可以允許一般使用者將 Apache 安裝在個人家目錄下,成為個人專屬伺服器,像這種站台地下化的情形,系管人員應該要留意追查。
User apache 預設啟動帳號,事實上 Apache 啟動時還是以 root 身分進行準備工作,直到接受服務時才改用此帳號。為了安全考量,公開的 WEB 服務不應使用 root 身分來提供服務。
Group apache 預設啟動群組。
ServerAdmin 請務必修改為該伺服器的實際負責人信箱。
ServerName 用來提供服務的網址及埠號,當省略不設定時,預設會使用 hostname 80 port
HostnameLookups off 要不要對連線的客戶端進行 DNS 查詢驗證,這是為了避免駭客用假 IP 攻擊主機,但進行 DNS 查詢會降低伺服器效能,特別是當網站非常受歡迎的情況下,問題將會很嚴重
DefaultLanguage nl 預設語系
LanguagePriority 協商語系時的優先順序
AddDefaultCharset iso-8859 預設字元集
AddType 用來新增 MIME 格式,當 Apache 將檔案傳輸給 Client 時,必須告知 Client 該檔案屬於何種格式,這樣瀏覽器才能正確顯示或播放該檔案,常用的格式都已預先設好,因此除非要作特殊應用否則不需設定(有些站台故意隱藏正確的附加檔名,來限制某些檔案的下載)
AddHandler 定義 Apache Handler 模組所對應的附加檔名,當附加檔名吻合時,會交由該模組處理。目前支援的 Handler 模組,主要有 cgi-scriptperl)、imap-fileimagemap)、type-map(多語系)......等,這些設定都不需修改。(有些書教大家在 AddHandler cgi-script .cgi 的後面加上 .pl,這是多餘的,因為按照 perl 的慣例 .pl 檔案會被引入到 .cgi 中,本身並不會單獨執行,因此這樣設是多餘的)
AddOutputFilter 屬於新版 Apache 支援的 Filter 模組,應該使用 AddOutputFilter 而非 AddHandler,例如過去屬於 Handler 模組的 SSI,現在已經變成 Filter 模組,因此設定由
AddHandler server-parsed .shtml
改成
AddOutputFilter INCLUDES .shtml
AddPathInfo on 這個選項用來讓 Filter core 模組在傳送剖析過的網頁資料時,能使用 PATH_INFO 環境變數來傳遞 basedir,以免相對路徑無法對應正確
特異功能 Action 這個功能的設計相信是絕大多數網站經營者的福音,它允許為某種 MIME 類型或某個 Handler 設定前導執行程式,透過這個功能將可以為站台中的每個檔案進行權限檢查和過濾,以防堵不肖業者砍站的行徑,以前使用者從後門偷檔的情形也將受到遏止,設定方式如下:
Action media/type /cgi-script/location
Action handler-name /cgi-script/location
網頁目錄設定 DocumentRoot /var/www/html 根網站的主目錄
UserDir public_html 個人網頁的主目錄,建議改成 www 比較容易被學生接受
DirectoryIndex index.html 設定首頁的名稱,為了配合 FrontPage 教學,請修改成 index.html index.htm default.htm default.html
AccessFileName .htaccess .htaccess 是用來做目錄存取控制的,如果您修改了它的檔名,不要忘記一併修改底下的設定:
<Files ~ "^\.ht">
Order allow,deny
allow from all
</Files>
Alias 用來設定虛擬目錄,可以將某個目錄虛擬成根網站內的子目錄
ScriptAlias 功能與 Alias 相同,但為了讓程式能正常執行,該資料夾內的檔案權限應設為 755
Redirect 原本是用來幫助使用者連上網頁的新網址,但大多應用來對應位於不同主機的虛擬目錄
目錄權限設定 <Directory ......>
</Directory>
用來規範網頁目錄的權限,可以設定 OptionsAllowOverrideOrderAllowDeny 等各種權限,除此之外還能內含 <Files .....><Limit .....> 等標籤進行進一步設定。特別要注意的是,目錄本身可以使用 * 通配字元,例如:
<Directory /home/*/public_html>
是表示
/home 目錄下所有命名為 public_html 的子目錄,都要套用此權限設定
Options Indexes
Includes
FollowSymLinks
可以選用的功能如下:
Indexes
表示當找不到首頁時,要顯示目錄清單
Includes
啟用 SSIServer Side Include<!--#exec= --><!--#include= --> 功能
IncludesNoExec 啟用 SSI 中的 include 但忽略 exec
FollowSymLinks 允許用 Link 檔案連結網頁目錄外的實體檔案
SymLinksifOwnerMatch 當實體檔案與
Link 檔案屬於同一個人擁有時,才允許連結
ExecCGI 允許執行
CGI 程式
Multiviews 啟用多語言網頁功能(網頁應以語系作為附加檔名
, 例如 index.html.zh_tw
None 關閉所有功能
All 除了 Multiviews 以外的全部功能
AllowOverride None 是否允許 .htaccess 中的設定值取代 Options 的設定,可以選用的功能如下:
Options 啟用
.htaccess 中的 Options 設定
FileInfo 啟用
.htaccess 中的 Files 設定,請參考 <Files ....> 標籤
AuthConfig
啟用 .htaccess 中的 Auth 相關設定
Limit
啟用 .htaccess 中的 Limit 設定,請參考 <Limit ....> 標籤
None 不允許使用 .htaccess
All 允許忽略 Options 設定,改由 .htaccess 來進行存取控制
Order Allow,Deny 進行連線來源的網址或 IP 過濾時,是採用白名單(預設值)還是黑名單
Allow from all 誰可以存取這個資料夾,all 表示任何人都可以,這個欄位可以使用網址、網域名稱、IP、省略尾碼的 IP、網路號碼/遮罩 等等方式來作過濾
Deny from all 哪些人不允許存取這個資料夾,設定方式同上
<Files ......>
</Files>
這個標籤可以內嵌在 <Directory ......> 中,也可以獨立存在,兩者的作用範圍不同。它和 <Directory ......> 相同也可以使用 Order、AllowDeny 作存取控制,不同的地方是可以使用正規表達式來匹配檔案,而且可以用 ~ 作反向匹配,例如:
<Files ~ "^\.ht">
Order allow,deny
allow from all
</Files>
<Limit ......>
</Limit>
這個標籤必須內嵌在 <Directory ......> 中,主要是用來限制某些 HTTP 1.1 指令,例如:HEADPUTDELETETRACECONNECT 等,範例如下:
<Limit GET POST OPTIONS>
Order allow,deny
Allow from all
</Limit>
<LimitExcept GET POST OPTIONS>
Order deny,allow
Deny from all
</LimitExcept>
<Location ......>
</Location>
這個標籤允許針對 Client 身分進行權限管理,可以使用的關鍵字有:AuthTypeAuthNameAuthUserFileAuthGroupFilerequire......等等,以上設定的詳細用法在後面說明。
除此之外在
Location 內也能使用 OrderAllowDeny 來進行存取控制,並且允許使用部分網域名稱來進行比對,例如:
Allow  from  .spps.tp.edu.tw
目錄清單設定 IndexOptions FancyIndexing 當一個目錄找不到首頁時,可以選擇要不要由 Apache 幫忙製作目錄清單,這個選項用來控制該目錄清單的功能,預設值 FancyIndexing 會啟用目錄清單各欄位的排序功能,其它可設定的功能包括:IconHeightIconWidthIconsAreLinksVersionSortNameWidth......等等。
IconHeightIconWidth 用來指定圖示大小
IconsAreLinks 讓小圖示也變成超連結
VersionSort 當檔案名稱後面附有版本號碼時,根據版本號碼排序
NameWidth 指定檔名顯示幾個英文字
AddIconByEncoding AddIcon 用來設定檔案格式與小圖示的對應關係,ByEncoding 意思是要比對 MIME 中的 Encoding 欄位,MIME 格式如下:
 
檔名(Filename) 類型(Type) 編碼(Encoding)
*.z application/octet-stream x-compress
*.gz application/octet-stream x-gzip
AddIconByType 根據檔案的 MIME Type 來決定使用哪一個小圖示
AddIcon 根據檔案的副檔名來決定使用哪一個小圖示
DefaultIcon /icons/unknown.gif 當以檔案格式比對不到符合條件的小圖示時,預設使用這個圖示
ReadmeName README.html 產生出來的目錄清單,結尾會加上這個檔案的內容
HeaderName HEADER.html 同樣也是用來附加資訊,但是會加在目錄清單的上方
IndexIgnore 用來定義哪些檔案不要顯示在目錄清單上,包含: . 開頭、~ # 結尾...
虛擬站台 NameVirtualHost 用來設定 name base 虛擬站台,所謂 name base 是指該虛擬站台與預設站台使用同一個 IP 但不同網址,這時就可以透過網址來區分 Client 所要求的哪一個站台的資料,使用 name base 必須先在 DNS 做好 A 紀錄,NameVirtualHost 用法與 ServerName 完全相同
<VirtualHost ......>
</VirtualHost>
用來設定虛擬站台的各項參數,例如:
<VirtualHost
192.57.1.10:12000>
ServerAdmin w
am@test.tp.edu.tw
DocumentRoot /usr/libexec/wam
ServerName
wam.spps.tp.edu.tw
ErrorLog logs/
wam-error_log
CustomLog logs/
wam-access_log common
DirectoryIndex wam.cgi
 <Directory />
  
Options ExecCGI
  AllowOverride None
  
Order allow,deny
  
Allow from 192.57
  Deny from all
 
</Directory>
</VirtualHost>
快取伺服器設定 CacheNegotiateDocs Off Apache 預設會要求 Proxy 不要快取網頁,如果您的網頁沒有提供互動功能,那麼開啟這項功能將有助於改善網路環境
ProxyRequests On 通常這一行會被 remark 起來,這是用來開啟 Apache 內附的 Proxy Server
ProxyVia On 用來定義 Via 標頭是否要使用,Via 用來提供 Apache Proxy 資訊給 Client 端,On 提供 hostnameFull 提供 hostname versionOff 不作任何處理,Block 則會將 Via: 標頭去除
<Proxy *>
</Proxy>
定義 Proxy 功能的權限控制,可以使用 OrderAllowDeny 作細部設定
CacheRoot /etc/httpd/proxy 快取網頁擺放的資料夾
CacheSize 5 快取網頁所能使用的磁碟空間,預設是 5KB
CacheGcInterval 4 設定快取檢查的頻率,當檢查到快取空間已經超過 CacheSize 的設定時,則刪除比較舊的檔案
CacheMaxExpire 24 正常的快取網頁保留 24 小時
CacheLastModifiedFactor 0.1 當快取的網頁未設定過期期限時,則以 (今天 - 網頁最後更新時間)*0.1 作為過期期限
CacheDefaultExpire 1 當取得檔案的通訊協定無法支援過期設定時(FTP),該檔案視為 1 小時後過期
NoCache 設定不要快取的網站或網域

mod_proxy  模組

這個模組是用來實作 Proxy 功能,Apache 所提供的 Proxy 功能完全符合 HTTP 1.1 的標準,算是 Proxy Server 的原型,但實際上卻很少人去利用,畢竟那樣的 Proxy 實在是太陽春了,有關 Proxy 功能的各種設定已經在上表詳細說明,不在贅述。

mod_ssl  模組

這個模組是用來實作 SSL 安全伺服器,因此必須先在系統上安裝 open_ssl 套件,open_ssl open_ssh 一樣都是用來建立加密的傳輸層(TCP/IP 四層架構的第三層),也都是採用對稱式金鑰演算法來進行編密傳輸,但他們的應用範圍卻不同,open_ssh 支援 r servertelnetftp,而 open_ssl 則支援 mail web,有關 open_ssh 的詳細說明請閱讀 Linux 基礎班講義。在此要先提醒學員,SSL 2.0 已經被發現有安全漏洞,因此應該要升級為 3.0 才對(需自行從 RedHat 站台取得新的 RPM)。

open_ssl 安裝好後會自動在 /etc/httpd/conf 目錄下建立底下五個目錄:

資料夾 用途
ssl.crl 用來擺放被撤銷的憑證
ssl.crt 用來擺放伺服器的憑證
ssl.csr 用來擺放申請憑證用的申請表
ssl.key 用來擺放伺服器的金鑰
ssl.prm 用來擺放參觀者的個人憑證

open_ssl 會順便幫我們建立測試憑證和金鑰,這組憑證和私鑰僅供測試使用,如果要公開對外服務最好是使用合法憑證,底下就來說明取得合法憑證的方法:

  1. 首先刪除測試用憑證和金鑰,否則 open_ssl 會拒絕產生新的金鑰

    rm  /etc/httpd/conf/ssl.key/server.key
    rm  /etc/httpd/conf/ssl.crt/server.crt
     
  2. 重新產生金鑰,產生金鑰時會詢問 PEM 密碼,如果輸入密碼,將來在伺服器重新啟動時每次都會詢問,萬一是從停電狀態重開機,由於沒有人去輸入密碼,Apache 就會停止運作,因此建議直接按 Enter 不要設密碼,記得將私鑰的檔案權限設為 700

    cd  /etc/httpd/conf
    make  genkey
     
  3. 金鑰產生完畢後,才能產生憑證申請表,事實上金鑰中的公鑰會隨著該申請表傳送給 CA 認證機構,如果順序顛倒了,將來公鑰和私鑰會匹配不起來,這樣麻煩可大了

    make certreq
     
  4. 產生好的申請表必須傳送給 CA 組織來核發憑證,向 CA 組織申請核發憑證雖然不需要付費,但申請手續麻煩並且必須以機關名義提出申請(蓋學校關防),在這裡就不介紹了。其實 open_ssl 也允許核發憑證給自己,有點像 windows 2000 中的 CA Server 自己核發憑證給自己,但這個憑證將不會被瀏覽器信任,導致 Client HTTPS 連上網站時,會詢問參觀者要不要信任該網站,這會讓參觀者卻步。要自己發憑證給自己請輸入:

    make testcert
     
  5. windows 2000 CA Server 取得憑證,請先安裝 CA 伺服器


     
  6. CA 伺服器會被安裝在 IIS 預設網站的 certsrv 虛擬目錄內,請打開 IE 連上伺服器,點選要求憑證


     
  7. 如果點選使用者憑證要求,則可以線上提出個人憑證的申請,伺服器請點選進階要求


     
  8. 憑證申請表已經做好,因此點選第二個選項使用檔案來提出要求


     
  9. 點「瀏覽」,這時會詢問是否要執行 ActiveX,按確定,從表單上按「瀏覽」按鈕,出現開啟檔案對話框後,請找出在 Linux 上預先作好的 server.csr 檔案,最後按「讀取」即可


     
  10. 憑證要求被讀取出來後,就直接提交,等候伺服器核准



     
  11. 請在伺服器上開啟憑證管理員,核發剛剛提出的申請


     
  12. 底下介紹安裝授權憑證的方法,打開 IE 後連上 CA Server,並點選第三項


     
  13. 按下一步後可以看到已被核准的憑證,點選該憑證


     
  14. 下載憑證後,請將憑證改名為 server.crt 並拷貝到 Linux

mod_ssl 模組的相關組態設定可以在 /etc/httpd/conf.d 目錄中找到,檔名為 ssl.conf ,預設值如下:

LoadModule ssl_module modules/mod_ssl.so

Listen 443 //此埠號可以自行修改,但如果不是使用預設值,則在使用瀏覽器時需自行輸入埠號(例如: https://wam.spps.tp.edu.tw:12000),否則會找不到站台

AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl .crl

SSLPassPhraseDialog builtin //當讀取憑證需要密碼時,讓 Apache 自動引用 Deamon 啟動時輸入的密碼
SSLSessionCache dbm:/var/cache/mod_ssl/scache //定義 SSL 連線時的 cache 路徑,尚未以私鑰解密的網頁會暫時放在這裡
SSLSessionCacheTimeout 300 //定義 SSL 連線逾時限制為 300
SSLMutex file:logs/ssl_mutex //定義 SSL 連線日誌檔的路徑
SSLRandomSeed startup builtin //定義產生一次性密碼時,亂數種子由系統自動提供
SSLRandomSeed connect builtin //定義產生一次性密碼時,亂數種子由系統自動提供

<VirtualHost _default_:443> //這裡設定為 _default_ 代表使用預設網站的 IP 和網址

DocumentRoot "/var/www/html" //由於主目錄與預設網站相同,如果不想再提供預設網站的 HTTP 想改用 HTTPS,請在 httpd.conf 中加入這一行
Redirect  http://wam.spps.tp.edu.tw/  https://wam.spps.tp.edu.tw/

ServerName wam.spps.tp.edu.tw:443
ErrorLog logs/ssl_error_log
TransferLog logs/ssl_access_log
CustomLog logs/ssl_request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
SSLEngine on //啟用 SSL 引擎
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL //設定加密機制與金鑰類型,這一行和上一行是同一行,因為太長自動折行了
SSLCertificateFile /etc/httpd/conf/ssl.crt/server.crt //定義伺服器憑證的路徑
SSLCertificateKeyFile /etc/httpd/conf/ssl.key/server.key //定義伺服器私鑰的路徑
<Files ~ "\.(cgi|shtml|phtml|php3?)$">
  SSLOptions +StdEnvVars
</Files> //以檔名來判斷該網頁是否是程式,並讓它們可以引用環境變數
<Directory "/var/www/cgi-bin">
  SSLOptions +StdEnvVars
</Directory> // /var/www/cgi-bin 資料夾裡的程式可以引用環境變數
SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0 //設定向下相容舊版 IE 瀏覽器,和上一行是同一行,因為太長自動折行了

</VirtualHost>

.htaccess mod_auth 系列模組)

mod_auth 模組用來實作 .htaccess 機制,當某個資料夾底下的內容需要進行權限認證,以避免資料被公眾讀取時,這個工作就可以交給 .htaccess 來負責,在該資料夾下建立 .htaccess 檔案,舉例如下:

AuthType Basic //驗證傳送方式,Basic 會使用 uuencode 加密來傳送密碼
AuthName "private"  //驗證領域,用來區分是否已通過認證,當不同資料夾使用同一個領域名稱時,已經通過該驗證的使用者不須再輸入一次帳號密碼,直接可以瀏覽網頁
AuthUserFile /home/shane/.htuser //擺放使用者 資訊的檔案
AuthGroupFile /home/shane/.htgroup //擺放 群組資訊的檔案
Require valid-user //表示所有 .htpasswd 的使用者都可以登入,也可以直接寫要給權限的帳號,中間以空白隔開,例如:Require  user george  mary,如果使用者眾多也可以使用群組,例如:Require  Group iwantcash
以上功能可不可以使用,視 <Directory ......> AllowOverride 是否有設定 AuthConfig 來決定
Satisfy any //當該資料夾被多個驗證領域所管理時,只要登入其中一個就行了,如果把 any 改為 all,則必須逐一登入成功才行
Options +ExecCGI
SetHandler cgi-script //設定 CGI 程式的執行權限
以上功能可不可以使用,視
<Directory ......> AllowOverride 是否有設定 Options 來決定

<Limit PUT DELETE TRACE>
 Order deny,allow
 
Allow from 192.57
 Deny from all
</Limit>
以上功能可不可以使用,視 <Directory ......> AllowOverride 是否有設定 Limit 來決定
<Files "^\.ht">
Order deny,allow
Deny from all
</Files>
以上功能可不可以使用,視 <Directory ......> AllowOverride 是否有設定 FileInfo 來決定

.htaccess 的使用者 及群組資訊檔是以純文字檔形式來存放,但為了避免使用者密碼外洩,因此在存放時會先將使用者密碼加密,這個工作由 htpasswd 來負責。能採用的加密格式如下:

加密格式 語法 用途
MD5加密 htpasswd -m windows 平台上使用時,此為預設值
呼叫 crypt 函式 htpasswd -d Linux 平台上使用時,此為預設值(通常不是 MD5 就是 DES
SHA加密 htpasswd -s 支援 Netscsape LDAP 伺服器
不加密 htpasswd -p 最不安全的方法

由於 Apache 預設會對 .ht 開頭的檔案加以保護,因此不要忘記把紀錄使用者和群組的資訊檔以 .ht 開頭來命名,以免這些檔案被參觀者盜取或瀏覽,建立使用者資訊檔的方法如下:

htpasswd -c /home/shane/.htuser george

檔案建立後請加入使用者,如下:

htpasswd /home/shane/.htuser mary

如果要刪除使用者,請以文書編輯器直接開啟使用者資訊檔,找到要刪除的使用者,直接將該行刪除後儲存即可。如果需要以群組來進行管理,請先建立群組資訊檔:

touch /home/shane/.htgroup

檔案內容如下:

iwantcash: george mary

由於 .htaccess 是在提供服務時,才載入記憶體,因此任何修改都是立即生效,不需要重新啟動 Apache

採用 Basic 驗證傳送方式,當使用者從瀏覽器輸入帳號密碼時是以 uuencode 編密後再傳送,這種加密方式只是把 8 bit 字元改用 7 bit 字元來表示,本身並沒有任何秘密可言,只要監聽網路封包很容易就可以竊取密碼。針對這個問題 Apache mod_auth_digest 模組提供 MD5 編密傳送來解決,想採用這種方法,請將 .htaccess 中的 AuthType 設定修改如下:

AuthType Digest

建立使用者資訊檔時請不要再使用 htpasswd,而是改用 htdigest

htdigest -c /home/shane/.htuser private george // private 是驗證領域名稱,請參考上面 .htaccess AuthName 設定

檔案建立後請加入使用者,如下:

htdigest /home/shane/.htuser private mary

如果要刪除使用者,請以文書編輯器直接開啟使用者資訊檔,找到要刪除的使用者,直接將該行刪除後儲存即可。至於群組設定檔的使用方式,則與上面介紹過的  mod_auth 模組相同。關於使用 DIGEST 驗證傳送還有一件事要注意,目前有支援這種驗證方式的瀏覽器,包括:Opera 4.0IE 5.0Mozilla 1.0.1Netscape 7 及以上的版本,請在登入前告知你的參觀者,以免參觀者無法登入時不知所措。

由於在純文字檔內搜尋使用者資訊速度非常慢,因此有必要改用資料庫索引的方式來儲存,然而關聯式資料庫系統雖然好用,但程式龐大且耗用大量系統資源,想要開發 WEB 介面程式來管理使用者,門檻也很高。在各種資料庫系統中,就以 DB DBM 最為簡單,mod_auth_dbm 模組便是採用 DB DBM 格式作為解決之道。DB 是柏克萊大學研發的一種純文字資料庫,它可以支援 btreehash ......等索引方式,由於程式輕薄短小幾乎不耗用系統資源,因此在 Unix Linux 上被廣為採用,例如先前介紹的 sendmail 有許多組態就採用 DB 格式。DBM DB 的改良品,當資料量較大時使用 DBM 效能比較高,也有許多系統採用 DBM 來儲存帳號資訊,例如成功大學開發的 Openwebmail等,由於著手改良 DB 的程式設計師眾多,因此所謂 DBM 也存在許多不同版本,常見的 DBM 包括:DB2NDBMGDBMSDBM mod_auth_dbm 模組僅支援 DBGDBMSDBM

底下的範例說明使用 mod_auth_dbm .htacces 的設定方式:

AuthType Basic
AuthName "private"
AuthDBType default //指定資料庫版本,預設為 default
AuthDBMUserFile /home/shane/.htuser
AuthDBMGroupFile /home/shane/.htgroup
Require valid-user

使用 htdbm 指令來建立使用者資料庫檔案,請輸入:

htdbm -c /home/shane/.htuser george //建立資料庫時會自動建立兩個檔案,其中 .htuser.pag 是資料檔,而 .htuser.dir 是索引檔

檔案建立後請加入使用者,如下:

htdbm /home/shane/.htuser mary

如果要刪除使用者,請輸入:

htdbm -x /home/shane/.htuser george

列出資料庫中的使用者,請輸入:

htdbm -l /home/shane/.htuser

檢查使用者是否已經建立,請輸入:

htdbm -v /home/shane/.htuser mary

建立群組資料庫方法與建立使用者資料庫相同,但是使用者名稱欄位變成群組名稱,而密碼欄位變成使用者列表,每個使用者以空格隔開,例如:

htdbm -cbp /home/shane/.htgroup iwantcash george,mary //參數中 b 代表批次模式,這樣就可以同時輸入使用者名稱(對群組檔來說是群組名稱)和密碼(對群組檔來說是使用者列表)兩個欄位,p 表示密碼欄位不加密

移除群組請輸入:

htdbm -x /home/shane/.htgroup iwantcash

使用 Perl 程式來管理使用者,範例如下:

use DB_File;
tie %database, 'DB_File', "passwords.dat"  || die "Can't initialize database: $!\n";

$username = 'rbowen';
$password = 'mypassword';
@chars=(0..9,'a'..'z');
$salt = $chars[int rand @chars] . $chars[int rand @chars];

$crypt = crypt($password, $salt);
$database{$username} = $crypt;

untie %database;

上面程式片段用來讓使用者從網頁直接變更密碼,由於牽涉程式設計,不在這個課程範圍內,往後如果有開程式設計班再講解!

mod_auth_mysql 模組

這個模組和其它 mod_auth 系列模組一樣是用來進行使用者認證,但它用 MySQL 伺服器作為儲存使用者資訊的後端資料庫,同時這個模組僅能在 httpd.conf 裡設定,請不要在 .htaccess 中使用它。由於本課程裡並不打算詳細介紹關聯式資料庫,因此不作詳細解說。

在設定 httpd.conf 之前,請以下列步驟進行資料庫部分的準備 工作:

mysql -u root -p mysql
mysql> GRANT ALL PRIVILEGES ON *.* TO web@localhost;
mysql> GRANT ALL PRIVILEGES ON *.* TO web@"%";
mysql> CREATE DATABASE http_users;
mysql> USE http_users;
mysql> CREATE TABLE user_info (
user_name CHAR(30) NOT NULL,
user_passwd CHAR(20) NOT NULL,
user_group CHAR(10),
PRIMARY KEY (user_name)
); // SQL 語法建立 users 資料表,資料表中包含三個欄位,user_name 為帳號欄位最多 30 個英數字元,user_passwd 為密碼欄位最多 20 個英數字元,user_group 為群組欄位最多 0 個英數字元,此資料表以帳號作為主索引,一個使用者僅允許加入一個群組
mysql> INSERT INTO user_info VALUES ('testuser',PASSWORD('mypasswd'),'users');
mysql> INSERT INTO user_info VALUES ('testadmin',PASSWORD('mypasswd'),'admins');
//以上兩行,會建立一般使用者測試帳號及管理員測試帳號

請修改 httpd.conf,加入以下設定值:

LoadModule mysql_auth_module modules/mod_auth_mysql.so
AddModule mod_auth_mysql.c

<Location /var/www/html/private/> //要使用 mysql 驗證保護的資料夾
 AuthName "MySQL authenticated zone"
 AuthType Basic

 AuthMySQLHost locahost //定義提供 MySQL 服務的主機,如果是別台電腦請輸入 IP
 AuthMySQLCryptedPasswords On //定義使用者 密碼要不要以 MySQL MD5 編密
 AuthMySQLUser web //定義 以何身分連線到 MySQL 伺服器,web MySQL 提供給 Apache 使用的預設帳號
 AuthMySQLDB http_users //定義 所使用的資料庫
 AuthMySQLUserTable user_info //定義 使用者資料表的名稱

 require valid-user //通過驗證的使用者才能瀏覽此資料夾
</Directory>

筆者撰寫了底下的 PHP 程式碼來示範如何進行使用者管理,該程式片段用來變更使用者密碼,其它應用不在這裡討論:

<?php

$username = "web";
$password = "";
$hostname = "localhost";
$databasename = "http_users";
$tablename = "user_info";

if (!($link = mysql_connect($hostname, $username, $password) ) ) {
  printError( sprintf("以使用者 %s 連結主機 %s 時,發生錯誤", $username, $hostname) );
  exit();
}
if (!mysql_select_db($databasename, $link) ) {
  printError( sprintf("開啟 %s 資料庫時,發生錯誤 %d %s", $databasename,
  mysql_errno($link), mysql_error($link) ) );
  exit();
}
$sql = "Update $tablename Set user_passwd = PASSWORD('$passwd') Where user_name = '$user'";
if (!(result = mysql_query($sql, $link) ) {
  printError( sprintf("無法修改使用者 %s 的密碼,錯誤 %d %s", $user,
  mysql_errno($link), mysql_error($link) ) );
  exit();
}

?>

mod_auth_pgsql 模組

這個模組和其它 mod_auth 系列模組一樣是用來進行使用者認證,但它用 Postgre SQL 伺服器作為儲存使用者資訊的後端資料庫,同時這個模組僅能在 httpd.conf 裡設定,請不要在 .htaccess 中使用它。由於本課程裡並不打算詳細介紹關聯式資料庫,因此不作詳細解說。

在設定 httpd.conf 之前,請先登入 PostgreSQL 伺服器,進行下列準備動作:

CREATE DATABASE auth; // SQL 語法建立資料庫,資料庫名稱為 auth

\c auth //開啟資料庫,以下 SQL 指令將在此資料庫中執行

CREATE TABLE users (
user_name CHAR(30) NOT NULL,
user_passwd CHAR(32) NOT NULL,
PRIMARY KEY (user_name)
); // SQL 語法建立 users 資料表,資料表中包含兩個欄位,user_name 為帳號欄位最多 30 個英數字元,user_passwd 為密碼欄位最多 32 個英數字元,此資料表以帳號作為主索引,一個使用者僅允許出現在一筆紀錄中

CREATE TABLE groups (
user_name CHAR(30) NOT NULL,
user_group CHAR(20) NOT NULL,
PRIMARY KEY (user_name, user_group)
); // SQL 語法建立 groups 資料表,資料表中包含兩個欄位,user_name 為帳號欄位最多 30 個英數字元,user_group 為群組欄位最多 20 個英數字元,此資料表以帳號+群組作為主索引,因此允許同一個使用者加入多個群組

CREATE USER apache; //建立 Postgre 使用者帳號,帳號名稱乾脆就叫 apache,比較不會忘記
GRANT SELECT ON users TO apache; // users 資料表授權給 apache
GRANT SELECT ON groups TO apache; // groups 資料表也授權給 apache

INSERT INTO users VALUES ('testuser', '179ad45c6ce2cb97cf1029e212046e81'); //建立測試帳號 testuser,密碼為 MD5 編密,你可以使用 echo -n 'mypasswd' | md5sum 指令將 mypasswd 編成 MD5 字串,這樣就能使用此 SQL 語法來建立帳號
INSERT INTO groups VALUES ('testuser', 'user'); // testuser 加入 user 群組
INSERT INTO users VALUES ('testadmin', '179ad45c6ce2cb97cf1029e212046e81');
INSERT INTO groups VALUES ('testadmin', 'admin');
INSERT INTO groups VALUES ('testadmin', 'user');

請修改 httpd.conf,加入以下設定值:

LoadModule auth_pgsql_module modules/mod_auth_pgsql.so

<Directory /var/www/html/private> //要使用 pqsql 驗證保護的資料夾
 AuthName "PostgreSQL group authenticated zone"
 AuthType Basic

 Auth_PG_database auth //定義所使用的資料庫名稱
 Auth_PG_pwd_table users //定義使用者資料表的名稱
 Auth_PG_uid_field user_name  //定義使用者欄位的名稱
 Auth_PG_pwd_field user_passwd //定義密碼欄位的名稱
 Auth_PG_grp_table groups //定義群組資料表的名稱
 Auth_PG_gid_field user_group //定義群組欄位的名稱
 Auth_PG_hash_type MD5 //定義編密方式為 MD5

 require group user //user 群組的使用者才能瀏覽此資料夾
</Directory>

mod_perl 模組

Apache 上使用 perl 這件事可以說歷史悠久,但使用傳統 CGI 方式來發展互動式網站有很大的缺點,包括:

  1. 由於一支 CGI 程式會同時被多人存取,而每次的存取都是獨立的行程,因此會耗用 N 倍的記憶體,N 就等於連線人數
  2. CGI 程式需讀取檔案時,由於多人同時存取,因此 I/O 衝突難以避免
  3. 每次連線都得反覆載入、剖析語法、編譯執行,浪費太多時間,尤其是程式很大時

以上這些缺點使得許多互動式站台不得不改用微軟公司的 IIS,因為 IIS 支援的 ASP 具有以下優點:

  1. ASP IIS 行程內執行,因此不會造成系統資源的浪費
  2. 使用同一行程來存取同一檔案,不會造成 I/O 衝突
  3. 執行過的 ASP 會常駐在記憶體,不用反覆載入、反覆剖析語法、反覆編譯

mod_perl 就是以讓 perl CGI 執行起來像 ASP 一樣為目標來開發,因此這個模組的標準化,讓人對 Apache 又有了信心,使用 perl 模組進行程式設計,即使對經常從事程式創作的人來說,門檻也是不低,在本課程裡並不適合詳細解說,底下僅舉 WAM 2.0 的部分設定值來說明如何進行設定:

PerlModule WAM::menu //用來向 Apache 註冊 menu.pm 程式檔,Apache 在有需要時會動態載入該程式
<Location /wam> //將該程式對應到 wam 虛擬目錄,當以 http://站台名稱/wam 連上站台時,就會觸動 Apache 載入該程式
AuthName "WAM"
AuthType Basic
PerlAuthenHandler WAM::AuthenPasswd //使用此 pm 來檢查使用者是否通過驗證,若否則跳出登入視窗要求登入
require valid-user
SetHandler perl-script //設定 mod_perl 程式的執行權限
PerlHandler WAM::menu //設定要執行的 pm 程式檔
PerlSendHeader On //允許 Perl 自行產生 HTTP 檔頭,而非由 Apache 核心模組產生檔頭,這樣做程式的彈性比較大
</Location>

PHP  模組

PHP 也是大家之所以要使用 Apache 的動機之一,底下設定在 Apache 安裝時就一併設定好了,不需修改,這個設定與舊版差蠻多的,主要是因為 PHP mod_include 一樣已經變成 Filter 了!

LoadModule php4_module modules/libphp4.so

<Files *.php>
SetOutputFilter PHP
SetInputFilter PHP
LimitRequestBody 524288
</Files>

DirectoryIndex index.php

虛擬站台設定

虛擬站台功能算是 Apache 遙遙領先 IIS 的地方,因為 IIS 僅提供 IP-base 的虛擬站台,而 Apache 多提供 Name-base Port-base 兩種虛擬站台,三者之間的不同如下:

Port-base 每個虛擬站台僅擁有獨立的埠號(不能重複),但共用同一個 IP 和網址。
Name-base 每個虛擬站台擁有獨立的網址和埠號(不能重複),但共用同一個 IP。只要在 DNS 上為該 IP 設定多筆 A 紀錄或增加 CNAME 紀錄就能支援。
IP-base 每個虛擬站台擁有獨立的 IP、網址和埠號(可以重複)。該 Linux 主機必須在一片網卡上設定多個不同 IP,並且完成 DNS 設定,才能實作此種虛擬站台。

Port-base 虛擬站台最容易實作,只要定義好 Apache 傾聽的埠號,接著以 <VirtualHost ...> 標籤來定義組態就可以了,範例如下:

Listen 12000
<VirtualHost _default_:12000> //default 意思就是與預設站台使用同一個 IP 和網址
ServerAdmin w
am@test.tp.edu.tw
DocumentRoot /usr/libexec/wam
ServerName
wam.spps.tp.edu.tw
ErrorLog logs/
wam-error_log
CustomLog logs/
wam-access_log common
DirectoryIndex wam.cgi
 <Directory />
  
Options ExecCGI
  AllowOverride None
  
Order allow,deny
  
Allow from 192.57
  Deny from all
 
</Directory>
</VirtualHost>

使用這個機制雖然很容易可以利用不同埠號,提供不同的網站資訊,但參觀者必須知道埠號才能連上該虛擬站台,使用上不太方便,另外還有一個小缺點,就是無法和預設站台一起提供 SSL 安全連線,這是因為一個 IP 僅被允許執行一份 SSL。預設站台是使用 443 埠來提供 HTTPS 安全連線,如果想讓 Port-base 使用 HTTPS 安全連線,就必須先將 443 埠關閉,同時移除 <VirtualHost _default_:443> 標籤的內容,如果在 httpd.conf 中找不到上述內容,可能是放在 /etc/httpd/conf.d/ssl.conf 中,接著修改上面的範例,加入粗體字部分的內容:

Listen 12000
<VirtualHost _default_:12000>
ServerAdmin w
am@test.tp.edu.tw
DocumentRoot /usr/libexec/wam
ServerName
wam.spps.tp.edu.tw
ErrorLog logs/
wam-error_log
CustomLog logs/
wam-access_log common
DirectoryIndex wam.cgi
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile /etc/httpd/conf/ssl.crt/server.crt
SSLCertificateKeyFile /etc/httpd/conf/ssl.key/server.key
<Files ~ "\.(cgi|shtml|phtml|php3?)$">
  SSLOptions +StdEnvVars
</Files>
SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0

 <Directory />
  
Options ExecCGI
  AllowOverride None
  
Order allow,deny
  
Allow from 192.57
  Deny from all
 
</Directory>
</VirtualHost>

Name-base 虛擬站台是透過 Apache 解析 HTTP 通訊協定中的 Host: 標頭來判斷要存取的網站資訊,因此它能允許不同站台使用同一個 IP,有關 Host: 標頭將在下一小節介紹。設定 Name-base 站台除了埠號的設定與 Port-base 相同外,尚須以 NameVirtualHost 來宣告網址別名,該別名必須事先定義在 DNS 伺服器上,設定範例如下:

Listen 12000 //如果想和預設站台一樣以 80 埠提供服務,請刪除此行
NameVirtualHost *
<VirtualHost *
:12000> //如果想和預設站台一樣以 80 埠提供服務,請刪除 :12000
ServerName wam.spps.tp.edu.tw

ServerAdmin w
am@test.tp.edu.tw
DocumentRoot /usr/libexec/wam
............................................................ //設定與前例相同,因此省略
</VirtualHost>

由於 Name-base Port-base 一樣是使用預設的 IP,因此在 SSL 連線的應用場合裡會與預設的 443 埠發生衝突,請參考 Port-base 的說明和範例來設定虛擬站台的 HTTPS 安全連線。

IP-base 虛擬站台是三種虛擬站台中功能最齊全也最常使用的,但在設定上卻是最麻煩的。首先必須在同一片網卡上虛擬出多個 IP,方法如下:

# ifconfig eth0:0 192.168.1.10 //設定第一個假 IP
# ifconfig eth0:1 192.168.1.20 //設定第二個假 IP
# ifconfig //查看 IP 是否已經設好
eth0      Link encap:Ethernet HWaddr 00:50:8D:47:AA:FF
            inet addr:192.168.1.2 Bcast:192.168.1.255 Mask:255.255.255.0
            UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
            RX packets:18347596 errors:0 dropped:0 overruns:0 frame:0
            TX packets:17827505 errors:0 dropped:0 overruns:0 carrier:0
            collisions:0 txqueuelen:100
            RX bytes:1387340808 (1323.0 Mb) TX bytes:3378133984 (3221.6 Mb)
            Interrupt:11 Base address:0x3000
eth0:0   Link encap:Ethernet HWaddr 00:50:8D:47:AA:FF
            inet addr:192.168.1.10 Bcast:192.168.1.255 Mask:255.255.255.0
            UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
            RX packets:18347596 errors:0 dropped:0 overruns:0 frame:0
            TX packets:17827505 errors:0 dropped:0 overruns:0 carrier:0
            collisions:0 txqueuelen:100
            RX bytes:1387340808 (1323.0 Mb) TX bytes:3378133984 (3221.6 Mb)
            Interrupt:11 Base address:0x3000
eth0:1   Link encap:Ethernet HWaddr 00:50:8D:47:AA:FF
            inet addr:192.168.1.20 Bcast:192.168.1.255 Mask:255.255.255.0
            UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
            RX packets:18347596 errors:0 dropped:0 overruns:0 frame:0
            TX packets:17827505 errors:0 dropped:0 overruns:0 carrier:0
            collisions:0 txqueuelen:100
            RX bytes:1387340808 (1323.0 Mb) TX bytes:3378133984 (3221.6 Mb)
            Interrupt:11 Base address:0x3000
# service network restart //讓網卡重新啟動,以便啟用所有設定好的 IP

接著必須在 DNS 上新增 A 紀錄,這和 Name-base 虛擬站台使用 CNAME 紀錄是不同的(Name-base 當然也可以使用 A 紀錄,不過通常是使用 CNAME 紀錄為主)。上述準備工作做好後,接下來必須修改 httpd.conf 設定,這部分反而比較簡單:

Listen 12000 //如果想使用 80 埠提供服務,請刪除此行
<VirtualHost 192.168.1.10:12000> //注意:這個地方是使用 IP 來區分而非使用網址,如果想使用 80 埠提供服務,請刪除 :12000
ServerName
wam.spps.tp.edu.tw
ServerAdmin wam@test.tp.edu.tw
DocumentRoot /usr/libexec/wam
............................................................ //設定與前例相同,因此省略
</VirtualHost>

手動測試 HTTP

$ telnet 127.0.0.1 80
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
GET / HTTP/1.1
//輸入要連結的相對網址
Host: mail.spps.tp.edu.tw
// Host: 標頭告知 base URL,要結束標頭必須連按兩次 Enter

HTTP/1.1
200 Ok
Date: Sat, 15 Mar 2003 07:34:11 GMT
Server: Apache/2.0.40 (Red Hat Linux)
Accept-Ranges: bytes
Content-Length: 2898
Content-Type: text/html; charset=Big5
Content-Language: zh-tw

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
<TITLE>Test Page for the Apache Web Server on Red Hat Linux</TITLE>
 </HEAD>
<!-- Background white, links blue (unvisited), navy (visited), red (active) -->
<BODY BGCOLOR="#FFFFFF">
....................................................(中間內容省略)...........................................................
 </BODY>
</HTML>
Connection closed by foreign host.

 

$ telnet 127.0.0.1 80
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
GET
http://mail.spps.tp.edu.tw/ HTTP/1.1 //輸入絕對網址時,不需要使用 Host: 標頭

HTTP/1.1
200 Ok
....................................................(其餘內容省略)...........................................................

 

$ telnet 127.0.0.1 80
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
HEAD http://mail.spps.tp.edu.tw/ HTTP/1.1
//HEAD 指令用來取得 HTTP 標頭,不會傳輸本文

HTTP/1.1
200 Ok
Date: Sat, 15 Mar 2003 07:40:10 GMT
Server: Apache/2.0.40 (Red Hat Linux)
Connection: close
Content-Type: text/html; charset=iso-8859-
1
Connection closed by foreign host.

 

$ telnet 127.0.0.1 12000 //連線到 WAM 伺服器
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
GET /wam.cgi?step=menu&user=shane&password=
mypasswd HTTP/1.1 // URL 傳值進行登入
Host: mail.spps.tp.edu.tw

HTTP/1.1 200 OK
Date: Sat, 15 Mar 2003 07:45:13 GMT
Server: Apache/1.3.19 (Unix)
Set-Cookie: uid=868
//登入成功,伺服器要求我們紀錄 Cookie
Set-Cookie: pid=%241%2458760616%24fZoQL
9RRFOC3VOWA1B6KY2
Transfer-Encoding: chunked
Content-Type: text/html

<head><meta http-equiv='Content-Type' content='text/html; charset=big5'>
<META HTTP-EQUIV="Pargma" CONTENT="no-cache">
<title>主選單</title><link rel='stylesheet' type='text/css' href='test.css'>
<script>
....................................................(其餘內容省略)...........................................................

 

$ telnet 127.0.0.1 12000 //再次連上 WAM 伺服器
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
GET /wam.cgi?step=m
ail HTTP/1.1
Host: mail.spps.tp.edu.tw
Cookie: uid=868; //傳送剛才的 Cookie 給伺服器
Cookie: pid=%241%2458760616%24fZoQL9RRFOC3VOWA1B6KY2;

HTTP/1.1 200 OK
Date: Sat, 15 Mar 2003 07:45:13 GMT
Server: Apache/1.3.19 (Unix)
Transfer-Encoding: chunked
Content-Type: text/html

<head><meta http-equiv='Content-Type' content='text/html; charset=big5'>
<META HTTP-EQUIV="Pargma" CONTENT="no-cache">
<title>網路郵局</title><link rel='stylesheet' type='text/css' href='test.css'>
<script>
....................................................(其餘內容省略)...........................................................

管理 apache log

Apache 執行一段時間之後,log 檔會膨脹得很厲害,動不動就是幾百MB,這會造成很大的困擾,尤其是為了分析存取狀況,大家都會安裝 webalizer 套件,因此 log 必須一個月才能清除一次,這時我們可以利用 rotatelogs 指令來進行轉檔工作,將超過一個月的資料轉出來,如果不需保留也可以逕行刪除,以免浪費硬碟空間,進行轉檔的指令如下:

# rotatelogs /var/log/httpd/access_log 259200 //30 天轉檔一次

用這個方法將日誌轉出後然後刪除,不需要停掉 Apache 服務。自己手動轉檔也是蠻累的,我們可以修改 httpd.conf 中的 CustomLog 來替我們作這動作:

CustomLog "|bin/rotatelogs /var/logs/access_log 259200" combined

這樣轉出來的檔案,仍然必須手動刪除,透過 cron job 將刪除動作自動化,也是個不錯的點子。底下再來介紹一個更好的方法,我們可以透過 syslog 輕鬆地管理 Apache 的日誌,syslog 是一個系統套件,其中 logrotate 機制不但能自動幫我們轉出日誌檔,也會自動幫我們清除過期的日誌,可以說是超級簡單好用的工具,請找到 /etc/logrotate.d/httpd 檔案,修改如下:

/var/log/httpd/*log {
monthly //自己加上這一行,這表示一個月要轉檔一次
rotate 1 //自己加上這一行,這表示只保留一份舊日誌檔在硬碟,超過的就刪掉
compress //如果希望將轉出的日誌檔壓縮起來的話,自己加上這一行
missingok
notifempty
sharedscripts
postrotate
  /bin/kill -HUP `cat /var/run/httpd.pid 2>/dev/null` 2> /dev/null || true
endscript
}

附錄:

A. sendmail.mc 組態設定

常用的 sendmail 功能選項(使用 FEATURE

功能名稱 作用
use_cw_file 啟用 sendmail.cwsendmail.cw 是用來設定郵件主機的管理網域,如果管理網域經常會異動,直接修改 snedmial.cf 中的 Cw 設定有點小題大作,這時候直接修改 sendmail.cw 比較方便
use_ct_file 啟用 /etc/mail/trusted-users,這個組態檔是用來讓服務帳號(例如:apache)也可以寄信,而不會收到警告信
redirect 當某個使用者的信箱已經轉移到另一台主機時,通常會直接退信並告知對方 user unknow,如果啟用這個功能,只要在 aliases 中加入 shane:  shane@new_school.tp.edu.tw.REDIRECT,退信時就會告訴寄信人:shane 已經搬到 shane@new_school.tp.edu.tw 去了,請嘗試用新地址連絡!
nocanonify 用來關閉對寄信人郵件地址的完整性檢查,允許收發郵件地址欄位缺少網域名稱的信件(例如:from: root),通常在當傳真機時才用得到,使用這個選項會有安全上的漏洞,建議用genericstable 將不完整名稱改寫成完整名稱,這樣比較安全
always_add_domain 要求將 localhost 信件改寫為完整的網域名稱,shanemail --> shane@mail.spps.tp.edu.tw
allmasquerade 對收件人欄位也進行郵件地址偽裝(預設只對寄件人欄位進行處理)
limited_masquerade 只對 MASQUERADE_DOMAIN 所列出的網域名稱進行偽裝(預設會對所有本機網域名稱進行處理)
masquerade_entire_domain 檢查 MASQUERADE_DOMAIN 所列出的網域名稱時,要包含子網域一起處理(預設只處理完全匹配的網域名稱)
local_no_masquerade 不要對由本機寄給本機的信件進行郵件地址偽裝
ldap_routing 透過 ldap 查詢使用者信箱的設定進行郵件轉寄,須配合 LDAP 伺服器使用
nodns 進行網址轉譯時時不要透過 DNS 伺服器,當校內沒有安裝 DNS 時使用
local_lmtp 啟用 /usr/libexec/mail.local 作為預設 LDA
local_procmail 啟用 /usr/local/bin/procmail 作為預設 LDA(也可以在參數指定別家過濾軟體,例如:maildrop scanmails......等等,預設是 procmail
promiscuous_relay 允許 Relay,使用這個功能將使 access 形同虛設
relay_entire_domain 允許本機網域的所有子網域,可以透過本機進行 Relay,當本機是作為 mail gateway 時才使用
relay_hosts_only 與前一個功能相反,必須完全匹配的網域才進行 Relay
relay_based_on_MX 根據 MX 紀錄來進行 Relay,與前兩個功能不同的地方是:可以不用指明 RELAY_DOMAIN 有哪些,sendmail 會自動根據 DNS 上的紀錄來決定
relay_mail_from 當信件中的寄信人欄位吻合 access 中標示為 RELAY 的紀錄時,則允許 Relay
relay_local_from 當信件中的寄信人欄位標示為本機網域時,允許進行 Relay,這個功能將會帶來無窮後患,建議不要啟用
accept_unqualified_senders 允許使用者不提供寄信人的網域名稱就可以寄信,這個功能將會導致垃圾郵件為所欲為,建議不要啟用
accept_unresolvable_domains 允許使用者以不完整或不存在的網域名稱寄信,這個功能將會導致垃圾郵件為所欲為,建議不要啟用
blacklist_recipients 啟用黑名單檔信功能,所謂黑名單是指公認的不合法郵件地址,例如:nobody@foo.comguest@bar.com......等等
delay_checks 這是 8.12 版的新功能,如果使用這個選項,當 client 連上來寄信時,會進行 check_mail check_relay 程序。預設值將僅進行 check_rcpt 程序(只針對收信人欄位進行檢查),為了要有效阻擋垃圾信,強烈建議使用 delay_checks
dnsbl 啟用 DNS 黑名單功能,sendmail 會透過指定的網站取得黑名單列表,以便進行擋信。提供此服務的站台 blackholes.mail-abuse.org 已經改為會員制,您不能沒有註冊就使用它。
enhdnsbl DNS 黑名單的進階版本
lookupdotdomain 當核對 access 上的存取控制時,允許使用 .spps.tp.edu.tw 語法來含括子網域,不可與relay_hosts_only 合用
authinfo 當對方的郵件主機支援 TLS/SSL 時,我方會根據 /etc/mail/authinfo.db 組態檔的定義來進行連線和認證,要使用此功能必須先向 CA 組織取得合法憑證
no_default_msa 不啟用 MSA,這會讓 TLS/SSL 相關功能無法運作,話說回來,目前公開的郵件主機幾乎沒有人採用 SSMTP,因此應該是沒什麼影響

其它可微調選項(使用 define

巨集變數名稱 [預設值]及說明
confCW_FILE [/etc/mail/local-host-names]指定本機網域名稱組態檔的路徑,以前是使用 /etc/sendmail.cw 在新版本裡已不再使用
confCT_FILE [/etc/mail/trusted-users]指定能收發郵件的服務帳號組態檔路徑
confCR_FILE [/etc/mail/relay-domains]指定要提供轉信的網域組態檔路徑
confMIN_FREE_BLOCKS [100]設定最小保留空間,當空間少於此數值 sendmail 會自動停止運作
confMAX_MESSAGE_SIZE [infinite]設定單封信件可容許的大小(以Byte 為單位),預設是無限制
confBIND_OPTS [undefined]設定如何進行 DNS 查詢,預設會先詢問 /etc/hosts 然後再問 DNS Server
confFORWARD_PATH [$z/.forward.$w:$z/.forward]設定 .forward 轉信機制組態檔路徑
confLOG_LEVEL [9]設定 mail 日誌的詳盡程度
confCHECK_ALIASES [False]設定要不要對 aliases 組態檔內的郵件地址進行 DNS 查詢驗證
confQUEUE_FILE_MODE [0600]設定待寄郵件暫存檔的檔案權限
confTO_INITIAL [5m]起始連線時的等待回應時限,超過時限就予以斷線
confTO_CONNECT [0]等待連線建立完成的時限
confTO_HELO [5m]執行 HELO EHLO 指令時的等待回應時限
confTO_MAIL [10m]執行 MAIL 指令時的等待回應時限
confTO_RCPT [1h]執行 RCPT 指令時的等待回應時限
confTO_DATAINIT [5m]執行 DATA 指令時的等待回應時限
confTO_DATABLOCK [1h]完成 DATA 指令的等待回應時限
confTO_DATAFINAL [1h]執行 . 指令時的等待回應時限
confTO_RSET [5m]執行 RSET 指令時的等待回應時限
confTO_QUIT [2m]執行 QUIT 指令時的等待回應時限
confTO_MISC [2m]執行 QUIT 以外的其它指令時的等待回應時限
confTO_COMMAND [1h]等待指令執行結果的時限
confTO_IDENT [5s]執行 IDENT 指令時的等待回應時限
confTO_FILEOPEN [60s]載入別名組態檔( aliases)中的引入檔(include)的時限
confTO_LHLO [2m]執行 LHLO 指令時的等待回應時限
confTO_AUTH [10m]執行 AUTH 指令時的等待回應時限
confTO_STARTTLS [1h]執行 STARTTLS 指令時的等待回應時限
confTO_CONTROL [2m]執行 CONTROL 相關指令時的等待回應時限
confTO_QUEUERETURN [5d]等候無法分信通知的時限
confTO_QUEUEWARN [4h]等候退信警告動作的時限
confTO_HOSTSTATUS [30m]提供主機狀態訊息的更新頻率
confDEF_USER_ID [1:1] sendmail 預設的執行帳號,建議改為 mail:mail
confQUEUE_LA (8 * numproc)處理待寄信件時的負載平衡,預設是處理器的 8
confREFUSE_LA (12 * numproc)處理拒絕收信時的負載平衡,預設是處理器的 12
confDELAY_LA [0]接受下個連線的延遲時間(sleep),0 表示無限制
confMAX_ALIAS_RECURSION [10]  aliases 中引用別名的遞迴限制,預設最多 10
confMAX_DAEMON_CHILDREN [undefined] sendmail fork 子程序的數量限制
confMAX_RCPTS_PER_MESSAGE [infinite]一封信最多可以有幾個收信人
confCONNECTION_RATE_THROTTLE [undefined] 每個子程序每秒鐘所能處理連線的數量限制
confDIAL_DELAY [0s]撥接失敗時的重試間隔,當你的郵件主機是透過撥接上線時,每次有人交寄郵件就會自動撥接,由於撥接需要撮合時間來協調雙方的傳輸速率,因此如果延遲設太短會造成撮合到一半自動斷線的情形,0 是表示失敗後不要重撥的意思
confDONT_EXPAND_CNAMES [False]當進行 DNS 查詢驗證時,如果查到的網域名稱是 CNAME 紀錄時,要不要追查 A 紀錄,預設是要
confDONT_INIT_GROUPS [False]分信時要不要載入 /etc/group 檔,預設是要,如果你使用 NIS 來管理帳號,應該設成不要
confUNSAFE_GROUP_WRITES [False]要不要檢查 aliases 中的 include 檔及 .forward 檔的權限設定是否為 group writable,預設是不載入 group writable 的組態檔
confAUTH_MECHANISMS [GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5 LOGIN PLAIN]認證時使用何種驗證機制,建議將 PLAIN LOGIN 移除
confAUTH_OPTIONS [undefined]定義認證功能選項:
A 表示通過認證者可以寄信,設定此選項後可以追加底下的功能
a 保護驗證機制不會受到主動式攻擊(嘗試錯誤攻擊)
c 要求 client 提供憑證
d 不允許驗證機制受到被動式字典攻擊法的感染(有系統的竊取加密密碼)
f 對每條連線採取隱密措施,破解一條連線並不能破解其它連線
p 不允許驗證機制受到被動式攻擊法的感染(竊取未加密密碼)
y 不允許採用可以匿名登入的驗證機制

B. Outlook Express 錯誤代碼表

錯誤碼 意義
一般  
0x800C0131
0x800C013E
可能是 Folders.dbx 檔案屬性錯誤或損壞,請參考:收信正常,但要送信時卻出現這個程式執行無效即將關閉...
0x800CCC00 身份驗證(Authentication)未載入
0x800CCC01 認證(Certificate)內容錯誤
0x800CCC02 認證日期錯誤
0x800CCC03 使用者已連線
0x800CCC05  未連線到伺服器
0x800CCC0A 郵線下載未完成
0x800CCC0B 伺服器忙碌中
0x800CCC0D 找不到主機(檢查你的SMTP伺服器是不是設錯,亦可能是對方Server 的問題,例如 Mail Server 沒有開機、對方的DNS 伺服器死掉了等等)
0x800CCC0E 連線到伺服器失敗,無法與主機建立連線。可能對方主機正在維護中、或是網路連線品質不好、伺服器關機、郵件伺服器尚未啟動等等,等一段時間再試。

如果你的防毒軟體有類似「電子郵件防護」這類的功能,建議先關閉「電子郵件防護」再做收發郵件的測試,從經驗中得知,有時會因為防毒軟體的「電子郵件防護」的干擾,會產生不能收發郵件的情形。

0x800CCC0F 伺服器結束連線(對方伺服器負荷過重、網路傳輸壅塞易造成此現象,可以試著增加你連線逾時的等候時間試試看,或是換一連線品質較佳的 ISP)
0x800CCC10 伺服器無法辨認此郵件位址
0x800CCC11 伺服器無法辨認的 Mailing list
0x800CCC12  無法傳送 Winsock request
0x800CCC13  無法接收 Winsock reply
0x800CCC14 無法起始 Winsock
0x800CCC15 無法開啟 Windows Socket
0x800CCC16 無法辨認使用者帳號,使用者帳號錯誤
0x800CCC17  使用者中斷操作
0x800CCC18 登入失敗
(例如:不需要安全密碼認證登入,但卻設了安全密碼認證登入)
0x800CCC19  作業逾時
0x800CCC1A 無法以 SSL 建立連線
Winsock 錯誤  
0x800CCC40 Network subsystem 無法使用
0x800CCC41  Windows Sockets 不支援此應用程式
0x800CCC43 Bad address.
0x800CCC44 Windows Sockets 無法載入
0x800CCC45 Operation now in progress.. 
SMTP 錯誤  
0x800CCC60 不合法的回應
0x800CCC61 不明的錯誤代碼
0x800CCC62 收到語法錯誤
0x800CCC63 語法參數不正確
0x800CCC64 指令不完整
0x800CCC65  不正確的指令序列
0x800CCC66 指令不完整
0x800CCC67  沒有這個指令
0x800CCC68 郵件信箱被鎖住或忙碌中
0x800CCC69  找不到郵件信箱
0x800CCC6A 處理要求錯誤
0x800CCC6B  郵件信箱不在此伺服器上
0x800CCC6C 已無空間儲存郵件
0x800CCC6D 已超過限制的儲存容量上限 
0x800CCC6E  不合法的郵件信箱名稱
0x800CCC6F Transaction error,出現這訊息,可能是伺服器不接受你的郵件,請跟你的 ISP 聯絡。
0x800CCC78 不明的寄件者,或郵件回覆(reply-to)地址不正確,或需要身分認證﹙Yahoo 郵件需要 SMTP 認證﹚。
0x800CCC79 收件者被伺服器拒絕(Relay Denied:最常發生於 Outlook Express 的 SMTP 設定不正確,請使用提供你連線服務的ISP公司之SMTP伺服器來寄信,)
0x800CCC7A 沒有指定寄件者
0x800CCC7B 沒有指定收件者
POP3 錯誤  
0x800CCC90 登入郵件伺服器發生錯誤,檢查一下你是不是有使用該伺服器的權限。或者:不需要安全密碼認證登入,但卻設了安全密碼認證登入
0x800CCC91 使用者名稱錯誤或找不到此使用者
0x800CCC92  帳號、密碼錯誤
0x800CCC93 無法解釋回應
0x800CCC94  需要指令
0x800CCC95 伺服器上已無郵件
0x800CCC96 沒有郵件標記為要下載
0x800CCC97  Message ID 超出範圍
NNTP 錯誤  
0x800CCCA0  新聞伺服器回應錯誤,可能你沒有擁有可使用該伺服器的權限。
0x800CCCA1 讀取新聞群組失敗
0x800CCCA2 要求伺服器郵件清單失敗
0x800CCCA3 無法顯示清單
0x800CCCA4 無法開啟群組
0x800CCCA5  伺服器無此群組
0x800CCCA6 郵件不在伺服器上
0x800CCCA7 找不到件標題
0x800CCCA8 找不到郵件本文
0x800CCCA9 無法發佈到伺服器上
0x800CCCAA 無法開啟下封郵件
0x800CCCAB 無法顯示日期
0x800CCCAC 無法顯示標題
0x800CCCAD 無法顯示 MIME 標題
0x800CCCAE  使用者名稱或密碼不正確
RAS 錯誤  
0x800CCCC2 未安裝撥號網路
0x800CCCC3 找不到撥號網路
0x800CCCC4 撥號網路錯誤
0x800CCCC5  Connectoid 壞或遺失
0x800CCCC6 取得撥號設定時錯誤
IMAP 錯誤  
0x800CCCD1  登入失敗
0x800CCCD2  Message tagged
0x800CCCD3 Invalid response to request.
0x800CCCD4  語法錯誤
0x800CCCD5 不是 IMAP 伺服器
0x800CCCD6  Buffer 已超過上限
0x800CCCD7 Recovery error
0x800CCCD8  資料不完整
0x800CCCD9 連線被拒
0x800CCCDA 不明的回應
0x800CCCDB User ID 已更改
0x800CCCDC User ID 指令失敗
0x800CCCDD Unexpected disconnect
0x800CCCDE Invalid server state
0x800CCCDF  無法認證用戶端

C. HTTP 回應狀態碼

底下是 HTTP 回應狀態碼的涵義與說明(RFC 2068),注意:下文所說的 Client 有可能是 Proxy Server(精確的講是一個 user agent 或瀏覽器,Server 則有可能是 Web Server Proxy Server,由於 Proxy 介於瀏覽器與網頁伺服器之間因此同時扮演兩種角色

分類 狀態碼 說明
資訊 100 Continue 催促 Client 送出後續要求,當 Client 提出的請求不完整時會產生此訊息(當 Client 上傳大檔案時,會將檔案切細再傳,Server 回應此訊息告訴 Client:前面部分已收到,請繼續送出後續資料)
101 Switching Protocols Server 接受 Client 變更應用層通訊協定的請求,用來回應 Client 端送來的 OPTIONS 請求
完成 200 OK Client 的請求已被接受並處理,僅用來回應 GETHEADPOSTTRACE 請求
201 Created 新網頁已經建立,僅用來回應 PUT 請求
202 Accepted Server 已接收請求,但處理需要時間完成,Client 可以斷線不用等待
203 Non-Authoritative Information Client 端送出的請求未包含 Web-Authoritative 標頭,送出此回應後瀏覽器會要求使用者登入
204 No Content 處理 Client 端的請求僅需回覆標頭時,Server 會回覆此訊息
205 Reset Content Client 端要求重設表單資料,Server 已接受並清除上次上傳的資料
206 Partial Content 因為頻寬限制,Server 將較大的網頁或檔案分次傳送,由於僅能傳輸部分內容,因此以此訊息通知 Client 資料尚未傳完
轉向 300 Multiple Choices 要求的網頁提供多重選擇,Client 可以根據參觀者的需要選取適合的網頁(多語系支援)
301 Moved Permanently 要求的網頁已經永久改變網址了,Server 會以 Location: 標頭告知新網址
302 Found 要求的網頁暫時改變網址,Client 下次連線時應優先嘗試原網址。由於 RFC 1945 2068 禁止 Client 在網頁重導向時變更指令(POST 變成 GET),因此是否須變更指令必須由 Server 告知,為了釐清此需求,多增加了兩個回應訊息 303 307 (前者要變,後者不變)
303 See Other 通知 Client 連到另一個網址去查看上傳表單的結果(POST 變成 GET),當使用程式作網頁轉向時,會回應此訊息
304 Not Modified 網頁 Expired 標頭顯示已過期,因此 Client 要求 reload 該網頁,但其內容並沒有變更,回應附加標頭的 GET 請求
305 Use Proxy 要求的網頁必須透過 Server 指定的 proxy 才能觀看
306 (Unused) 1.0 版使用,現在已經取消不用
307 Temporary Redirect 要求的網頁暫時改變網址,Client 下次連線時應優先嘗試原網址(設計用來取代 302,但因為有些 Client 僅支援 1.0 版,因此 302 還是保留)


端錯誤
400 Bad Request Server 看不懂 Client 的請求,通常是語法錯誤、打錯字或打成小寫
401 Unauthorized 該網頁必須通過使用者驗證才能取得(另外,當 Client 上傳的檔案太大時,Server 可以回應此訊息拒收)
402 Payment Required 預計給新版本用的
403 Forbidden 權限不足因此 Client 的請求被拒絕
404 Not Found Client 嘗試連結的網頁不存在
405 Method Not Allowed 該目錄禁止使用 Client 送來的指令
406 Not Acceptable 該網頁含有 Client 無法支援的語系、字元集、編碼方式或多媒體串流格式時,Server 以此訊息回應
407 Proxy Authentication Required 類似於 401,但這是給 Proxy 使用的,當 Client 透過 Proxy 觀看某些特定網頁時,Proxy 會要求先通過認證(配合 305 來使用,可以讓眾多站台統一透過同一台 Proxy 進行會員管理)
408 Request Timeout Server 苦等不到 Client 送來的請求
409 Conflict 當版本管理被啟用,而 Client 要求 PUT 的網頁正被修改中(Locked)或網頁版本比現有的還舊,Server 將回應此訊息,請參考 FrontPage Server Extension 中的版本管理功能
410 Gone 該網頁已遷移,但不知道移去哪裡
411 Length Required Client 上傳的表單資料(或檔案)沒有計算大小,Server 拒絕接受
412 Precondition Failed Client 提出的請求中某些標頭所設定的值,經測試後無法正確執行
413 Request Entity Too Large Client 一次送出的請求太多,Server 無法處理逕行斷線
414 Request-URI Too Long Client 上傳資料的標頭,包含太多資訊,Server 無法處理
415 Unsupported Media Type Server 不支援 Client 要求的檔案類型(譬如:某些 third-party 開發的 Server 不支援 JAVA
416 Requested Range Not Satisfiable Client 對某個多媒體串流提出下載某範圍內容的要求,但 Server 無法提供時必須回應此訊息(該串流必須從頭觀看)
417 Expectation Failed 某些先進的 Server 支援獨家的標頭(例如:Netscape Enterprise),當 Client 要求這類的延伸標頭而伺服器不支援時,應該回覆此訊息


端錯誤
500 Internal Server Error 無法預期錯誤(通常是 CGI 程式語法錯誤造成)
501 Not Implemented Client 所要求的指令在 Server 上沒有被實作出來
502 Bad Gateway Proxy 從上游伺服器得到的回應無法辨識時,回應此訊息給 Client
503 Service Unavailable 伺服器因為系統維護或負載太重,無法提供服務
504 Gateway Timeout Proxy 無法從上游伺服器取得 Client 要求的網頁時,回覆此訊息給 Client
505 HTTP Version Not Supported Server 不能支援或不想支援 Client 提出的指令版本