작성자 : 김칠봉[닉: 산이] san2 [at] linuxchannel [dot] net
2001.02.26 : 1차 완료

-------------------------------------------------------------------------
이 문서는 리눅스 커널 수준에서 구동되는 kHTTPd 0.1.6(웹서버)와 아파치 연동을
위한 기초적인 팁문서입니다.
이 문서의 최신 버전은 다음에 싸이트에서 찾을 수 있습니다.
http://www.linuxchannel.net/docs/
이 문서의 저작권은 GNU GPL에 따릅니다.
-------------------------------------------------------------------------

*주)
문맥상 간혹 경어를 생략했습니다. 양해해 주시길 바랍니다.
kHTTPd에 대해서 그리 많은 해박한 지식이 없기 때문에 문서상 보완이나 잘못
된내용이 있으면 언제든지 환영합니다.
-------------------------------------------------------------------------

목차

1. 배경
2. 관련 문서
3. kHTTPd 소개
3-1. 간단한 소개
3-2. kHTTPd가 제공하는 조건
3-3. 커널 컴파일 요구 사항
3-4. kHTTPd 설정 파라미터
3-5. kHTTPd 시작과 종료
4. 아파치와 연동
4-1. kHTTPd를 어떤 용도로 사용할 것인가?
4-2. [팁] PHP 함수 이용
4-3. [팁] 아파치 rewrite 모듈 이용
5. 간단한 성능 테스트
6. 질문과 답변
7. 마치며
8. 부록 - kHTTPd 제어 쉘스크립트

1. 배경

필자는 예전부터 아파치 서버를 운영해 오면서 가장 불만(?)이었던 것이 바로
느리게 로딩되는 그림이미지였다.
제우스 웹서버처럼 어떻게 빨리 로딩하는 방법이 없을까 하는 생각에 골머리를
앓던 중에 리눅스 커널 수준에서 구동되는 kHTTPd를 알게 되었다.
리눅스 커널 개발버전(2.3.x)이 한참 진행중에 관련 문서가 적어 한동안 실패 만 거듭하다가 드디어
커널을 2.4.x로 올리고 그럭저럭 설정에 성공했다.
결과는 100% 만족하지는 않지만, 아직 kHTTPd의 버전이 0.1.6이라는 점에서 앞으로 계속 주목하고자 한다.
또한 관련 문서가 인터넷상에 그리 많지 않아 이 문서를 작성하게 되었다.

2. 관련 문서

kHTTPd와 관련된 문서는 그리 많지 않습니다.

kHTTPd 관련 홈페이지 : http://www.fenrus.demon.nl/
kHTTPd 관련 문서 : /usr/src/<커널2.3.14이상>/net/khttpd/README
메일링 리스트 : khttpd-users@zgp.org 또는 khttpd@fenrus.demon.nl
기타 :

필자가 아는 문서는 이것밖에 없군요. T.T

3. kHTTPd 소개

"linux httpd accelerator"
kHTTPd는 리눅스 커널 수준에서 구동되는 HTTPd 가속기입니다.

(C) 1999 by Arjan van de Ven
Licensed under the terms of the GNU General Public License

3-1. 간단한 소개(README 문서에 의하면)

kHTTPd는 리눅스용 http 데몬(웹서버)이며, 리눅스 커널에 내장되어 있다는 점에서
다른 웹서버와 다르다. 커널 컴파일시 모듈로 설정하거나 커널에 정적으로 컴파일하여 사용한다.

- 1999년 Arjan van de Ven에 의해서 시작되었다.
- kHTTPd는 오직 정적인 웹페이지(html/txt/images/compress file/moviesfile/...)만 제공한다.
- 동적인 페이지는 다른 웹서버(아파치나 제우스)로 넘긴다.
- 정적인 페이지는 커널차원에서 처리하기 때문에 속도가 빠르다.
- 커널 2.3.14 이상.
- 현재 버전은 0.1.6c까지 나와 있지만 커널 2.4.1에서는 0.1.6의 내용이 적용.
- 기타.

3-2. kHTTPd가 제공하는 조건

kHTTPd는 파일이 다음과 같은 조건일 경우에 만 서비스한다.

1) URL에 질의("?")가 없을 경우
2) URL이 "/"으로 시작할 경우
3) URL에 정확한 파일을 요청할 경우
4) 파일이 읽기 모드일 경우(*)
5) 파일이 디렉토리가 아닌경우, 파일에 실행 퍼미션이 없을 경우, Sticky-bit로 설정되어 있지 않은 경우(*)
6) URL이 "forbidden" 문자열을 포함하지 않을 경우, ".."와 "cgi-bin"(*)
7) mime-type을 알 경우(*)
8) 가상호스트는 지원하지 않음
9) 그외 동적인 페이지는 모두 다른 웹서버로 전달된다.

(*) 표시된 항목은 sysctl 파라미터를 통해서 설정가능한 경우로, /etc/sysctl.conf
설정파일에 의해서 시스템이 부팅되면서 /proc/sys/net/khttpd의 각 파라미터에 설정한다.

3-3. 커널 컴파일 요구 사항

kHTTPd를 사용하기 위해서는 다음과 같은 커널 컴파일이 요구된다.
최소한 리눅스 커널 2.3.14 이상의 버전이 필요하다.
(커널 2.4.1 기준)

Code maturity level options --->
[*] Prompt for development and/or incomplete code/drivers

General setup --->
[*] Sysctl support

Networking options --->
<*> Kernel httpd acceleration (EXPERIMENTAL)

File systems --->
[*] /proc file system support

*주)
필자의 테스트 환경(RedHat 6.2의 커널 2.4.1)에서는
<M> Kernel httpd acceleration (EXPERIMENTAL)모듈로 설정한후 모듈을 적재할때 에러를 발생했다.
따라서 필자가 테스트한 경우는 커널에 정적으로 컴파일하여 테스트한 경우임.

만약, /usr/src/linux/.config 파일이 존재한다면,
CONFIG_KHTTPD=y 부분 확인.

3-4. kHTTPd 설정 파라미터

[모듈로 컴파일했을 경우]

무사히 커널 컴파일을 모두 마쳤다는 가정입니다.
만약 khttpd를 모듈로 컴파일했다면 구동하기 전에 모듈이 존재하는지 다음과 같이 알아본다.

# ls /lib/modules/`uname -r`/kernel/net/khttpd/khttpd.o
khttpd.o
#

*주)
`uname -r`에서 ` 문자는 ' 문자가 아닌 ~ 문자가 있는 자판키입니다.

모듈로 컴파일했기 때문에 khttpd을 구동하기 전에 메모리에 이 모듈을 올려야 합니다.

모듈 올리기 :
# modprobe khttpd
모듈 내리기 : (먼저 khttpd를 stop 해야함)
# rmmod khttpd

*주의)
만약 sysctl.conf 파일을 이용해서 시스템이 부팅할때 자동으로 모듈을 올리려면
/etc/rc.d/rc.sysinit 파일을 열어 "sysctl -p /etc/sysctl.conf" 부분을 찾아 그 이전에 모듈을 올리는
명령을 추가해줘야 함.

[커널에 정적으로 컴파일했을 경우]

# ps -ef | grep khttpd
root 8 1 0 Feb19 ? 00:00:00 [khttpd manager]
root 566 8 0 Feb19 ? 00:00:01 [khttpd - 0 <defunct>]
#

위와 같은 내용을 볼 수 있을 겁니다.

그럼 이제 kHTTPd를 설정하기 전에 어떤 내용을 설정해야하는지 알아봅시다.

# ls -l /proc/sys/net/khttpd
-rw-r--r-- 1 root root 0 Feb 22 07:31 clientport
-rw-r--r-- 1 root root 0 Feb 22 07:31 documentroot
-rw-r--r-- 1 root root 0 Feb 22 07:31 dynamic
-rw-r--r-- 1 root root 0 Feb 22 07:31 logging
-rw-r--r-- 1 root root 0 Feb 22 07:31 maxconnect
-rw-r--r-- 1 root root 0 Feb 22 07:31 perm_forbid
-rw-r--r-- 1 root root 0 Feb 22 07:31 perm_required
-rw-r--r-- 1 root root 0 Feb 22 07:31 serverport
-rw-r--r-- 1 root root 0 Feb 22 07:31 sloppymime
-rw-r--r-- 1 root root 0 Feb 22 07:31 start
-rw-r--r-- 1 root root 0 Feb 22 07:31 stop
-rw-r--r-- 1 root root 0 Feb 22 07:31 threads
-rw-r--r-- 1 root root 0 Feb 22 07:31 unload
#

/proc/sys/net/khttpd에 13개의 kHTTPD 커널 파라미터가 있습니다.
각각의 파라미터에 설정값을 입력하는 형식은 다음과 같습니다.

예)
# echo "/home/httpd/html" > /proc/sys/net/khttpd/documentroot

하나하나씩 알아봅시다.

- serverport [8080]
kHTTPd가 사용할 포트번호를 의미하며, 기본값은 8080포트를 사용합니다.
만약 serverport를 80 포트로 설정할 경우는 clientport를 80 포트 외의 포트 를 사용해야 합니다(필수설정).

- clientport [80]
kHTTPd가 아닌 다른 웹서버(예:아파치)가 사용할 포트 번호를 의미합니다.
기본값은 80 포트로 설정되어 있으며 serverport와 반대로 서로 포트가 같지 않게 설정해야 합니다(필수설정).

- documentroot [/var/www]
kHTTPd가 제공할 기본 DocumentRoot를 의미합니다. 아파치 서버를 사용한다면 아파치 서버에서 설정한 기본
DocumentRoot와 같게 설정할 수도 있습니다.
물론 다른 용도로 사용한다면 해당 DocumentRoot를 지정하면 됩니다.
기본값은 /var/www 입니다(필수설정).

- start [0]
kHTTPd의 시작(구동)을 설정하는 부분으로 1로 설정하면 kHTTPd가 시작된다.
1로 설정하면 stop은 1로 설정(필수설정).

- stop [0]
kHTTPd의 종료를 설정하는 부분으로 1로 설정하면 kHTTPd는 종료된다.
마찬가지로 1로 설정하면 start은 0으로 설정(필수설정).

- dynamic [cgi-bin ..]
동적으로 움직이는 페이지(URL)를 설정하는 항목으로 이 부분은 다른 웹서버로 전달
됩니다. cgi-bin이나 php 등등이 이에 해당됨.

- logging [0]
kHTTPd가 로그를 기록할 것인가의 여부이다. 0으로 설정하면 로그를 기록하지 않고
1로 설정하면 로그를 기록한다.
그러나 0.1.6 버전은 기본적으로 로그를 기록하지 않는다. 다만 0.1.6c 버전에서는
로그를 기록하도록 되어 있으나 이때는 khttpdlog 와 같은 데몬이 필요하다.
http://www.fenrus.demon.nl/ 를 방문하면 sample khttpdlog가 있습니다.
필자는 아둔하게도 kHTTPd를 0.1.6c 패치하고 이 sample khttpdlog를 빌드하여
테스트해 보았으나 로그 기록에 실패했다. 말 그대로 sample 데몬임.
실력있는 분은 0.1.6c로 패치하고 sample khttpdlog를 수정(?)하여 테스트해 보시길 바랍니다.
참고로, 커널 2.4.1에서 kHTTPd 0.1.6c 버전으로 패치하는 파일은 아래 싸이트에 있습니다.

http://ftp.linuxchannel.net/devel/khttpd/patch-khttpd-0.1.6c-for-
2.4.1.txt

- maxconnect [1000]
최대 동시 접속자 수를 설정하는 부분입니다. 아파치의 MaxClients와 비슷한 설정이며
기본값은 1000으로 되어 있음.

- perm_forbid [dir+sticky+execute]
"forbidden"에 대한 퍼미션 매스크 설정. 기본값(?)은 16969임.
자세한 내용은 System calls "man 2 stat" 참고.

참고)
The `sticky' bit (S_ISVTX) on a directory means that a file in that directory can be renamed or deleted
only by the owner of the file, by the owner of the directory, and by root.

- perm_required [S_IROTH]
최소한의 퍼미션 설정. 기본값은 4(read)임.
자세한 내용은 System calls "man 2 stat" 참고.

참고)
S_IROTH 00004 others have read permission

- sloppymime [0]
마임타입에 관한 설정입니다. 알지 못하는 마임타입에 대해서 0으로 설정하면 text/html으로 설정되고,
1로 설정하면 다른 웹서버(예:아파치)로 넘겨집니다.
기본값은 0입니다.

- threads [2]
kHTTPd의 쓰레드 수이다. 비교적 작은 웹싸이트 일 경우 CPU당 1을 곱한 수를 설정하고 비교적 큰 규모일 경우
CPU당 2를 곱한 수가 적당함. 기본값은 2.

- unload [0]
kHTTPd를 커널의 모듈로 컴파일했을 경우에 해당되며 메모리에서 모듈을 제거할 경우에는 1로 설정한다.
기본값은 0.

주의)
kHTTPd를 커널에 정적으로 컴파일했다면 0으로 계속 설정해 놓는다.
반면 모듈로 컴파일하여 khttpd 모듈을 메모리에서 제거하려면 kHTTPd를 반드시 종료하고 unload 1로 설정해야 함.


3-5. kHTTPd 시작과 종료

그럼 실제로 kHTTPd를 구동하고 멈춰보자.

주의) 아파치와 같이 연동한다면 아파치를 실행하기 전에 kHTTPd를 먼저 실행 해야 함.

[kHTTPd를 모듈로 컴파일했을 경우]

kHTTPd를 모듈로 컴파일했다면 먼저 khttpd를 메모리에 적재해야한다.

- kHTTPd 시작
# modprobe khttpd
# echo 1 > /proc/sys/net/khttpd/start

- kHTTPd 확인
# ps -ef | grep khttpd
root 8 1 0 Feb19 ? 00:00:00 [khttpd manager]
root 23803 8 0 Feb22 ? 00:00:00 [khttpd - 0]
root 23804 8 0 Feb22 ? 00:00:00 [khttpd - 1]
#

khttpd 매니저와 두개의 프로세스가 더 있음을 알 수 있다.

- kHTTPd 종료
# echo 1 > /proc/sys/net/khttpd/stop
# echo 1 > /proc/sys/net/khttpd/unload
# rmmod khttpd

[kHTTPd를 커널에 정적으로 컴파일 했을 경우]

위와 동일하되 modprobe와 unload, rmmod 내용은 생략된다. 즉,

- kHTTPd 시작
# echo 1 > /proc/sys/net/khttpd/start

- kHTTPd 종료
# echo 1 > /proc/sys/net/khttpd/stop

지금까지 기본적의 kHTTPd의 시작과 종료에 대해서 알아보았습니다.
보다 간편하게 kHTTPd를 쉘 스크립트로 작성해서 제어할 수 있습니다.

예제1. kHTTPd를 보조 서버로 사용할 경우
---------------------------------------------------
#!/bin/sh
modprobe khttpd
echo 80 > /proc/sys/net/khttpd/clientport
echo 8080 > /proc/sys/net/khttpd/serverport
echo /var/www > /proc/sys/net/khttpd/documentroot
echo php3 > /proc/sys/net/khttpd/dynamic
echo shtml > /proc/sys/net/khttpd/dynamic
echo 1 > /proc/sys/net/khttpd/start
----------------------------------------------------

예제2. kHTTPd를 메인 서버로 사용할 경우
----------------------------------------------------
#!/bin/sh
modprobe khttpd
echo 8080 > /proc/sys/net/khttpd/clientport
echo 80 > /proc/sys/net/khttpd/serverport
echo /var/www > /proc/sys/net/khttpd/documentroot
echo php3 > /proc/sys/net/khttpd/dynamic
echo shtml > /proc/sys/net/khttpd/dynamic
echo 1 > /proc/sys/net/khttpd/start
-----------------------------------------------------

이와 같이 직접 명령라인에서 설정하는 방법외에 /etc/sysctl.conf 파일을 이용하여 시스템이 시작하면서
자동으로 실행하는 방법이 있습니다.
이때는 앞서 얘기했듯이 모듈로 컴파일 했다면, /etc/rc.d/rc.sysinit 파일을열어 "sysctl -p /etc/sysctl.conf" 부분을
찾아 그 이전에 모듈을 올리는 명령을추가해줘야합니다.
커널에 정적으로 컴파일했다면 /etc/rc.d/rc.sysinit 파일에 추가 할 필요는 없습니다.

예제)
------ /etc/sysctl.conf -------------------------------
net.khttpd.clientport = 80
net.khttpd.serverport = 8080
net.khttpd.dynamic = php3
net.khttpd.documentroot = /var/www
net.khttpd.start = 1
------------------------------------------------------

눈치가 빠르면 대충 net.khttpd가 어떤 것인지를 알 수 있을 겁니다.
즉 /proc/sys/net/khttpd 를 의미합니다(디렉토리를 dot(.)으로 구분?).

참고)
"8. 부록"을 참고하면 필자가 엉망으로 작성해 놓은 쉘 스크립트가 있습니다.
이는 kHTTPd를 커널에 정적으로 컴파일해 놓은 상태에서 kHTTPd를 아파치 웹서버의 보조역할을 하기 위한 것입니다.
참고로하되 자신의 환경에 맞게 고쳐서 사용하시길 바랍니다. 실력있는 분은 아예 무시하시길...............

4. 아파치와 연동

그럼 이번에 실제로 아파치와 연동하여 kHTTPd를 사용해 봅시다.

4-1. kHTTPd를 어떤 용도로 사용할 것인가?

우선 kHTTPd를 어떤 용도로 사용할 것인지에 대해서 결정해야합니다.
즉 80 포트 설정에 따라서 kHTTPd가 메인서버가 될 수 있고, 보조 서버가 될수 있습니다.

kHTTPd의 용도 결정의 기준(?)
1) 동적인 페이지는 아파치가 서비스한다.
2) 정적인 페이지는 kHTTPd가 서비스한다.
3) 가상호스트를 포함한 모두 웹페이지가 원활하게 운영되어야 한다..
4) 비교적 적은 중노동(?)이 수반되어야 한다.
5) 기타

모드1) kHTTPd is 메인서버, "Apache" 보조서버,
serverport -> 80
clientport -> 8080 (or whatever)

모드2) kHTTPd 보조서버, "Apache" 메인서버,
serverport -> 8080 (or whatever)
clientport -> 80

모드1의 경우는 kHTTPd가 메인서버가 되므로 아파치 설정파일에서는,

- port 8080
- UseCannonicalName Off
- 모든 가상호스트 섹션에 ":8080" 추가

으로 수정 또는 추가해 주어야 한다.

주의)
만약, UseCannonicalName On으로 설정하면 아파치는 설정한 포트(8080)를 참조 해서 URL을 재구성하므로
정적인 페이지는 kHTTPd로 넘어가지 않는다.
따라서 당연이 이 기능을 Off 해놓아야 함.

장점 :
특별하게 HTML 코드를 수정없이 정적인 페이지는 조건이 만족한다면 모두 KHTTPd가 빠르게 제공할 것이다.
불필요한 중노동(?)이 없음. ^.^

단점 :
역시 가상 호스트를 지원하지 않으므로 메인 DocumentRoot 외는 유명무실하다.
즉 가상호스트로 웹페이지를 제공한다면, 모두 다음과 같은 URL이 필요할 것이다.
http://www.maindomain.com/
http://www.customer1.com:8080/
http://www.customer2.com:8080/
http://www.customer2.com:8080/
조언 :
가상 호스트로 운영되는 페이지가 거의 없거나 비교적 정적인 페이지가 많은 경우에 유리하다.

모드2의 경우도 생각해 보자.
이 경우는 kHTTPd가 보조서버이고 아파치가 메인서버이므로 보조서버로서의 역할을 미리 결정해야한다.
예를 들면 정적인 페이지만 kHTTPd가 제공하도록 아파치나 HTML에서 설정해 주어야 합니다.

장점 :
웹 표준 포트인 80번을 아파치가 사용하므로 가상호스트 운영은 예전 그대로 운영할 수 있다.

단점 :
kHTTPd가 보조서버이므로 정적인 웹페이지는 모두 kHTTPd가 제공하도록 강제적(?)으로 링크 또는
HTML 코드를 수정해 줘야 하는 중노동(?)이 있다.

조언 :
가상 호스트로 운영되는 페이지가 많거나, 비교적 간단하게 HTML을 수정해서 정적인 페이지를
kHTTPd가 서비스할 수 있는 조건에 적당하다.(필자는 이 방법을 적용)
이 방법을 사용하기 위해서는 다음 절의 [팁]을 참고로 웹 페이지와 아파치 설정파일 을 조금 수정해
주시길 바랍니다.

참고로 필자는 kHTTPd(8080)를 아파치(80)의 보조 웹서버로 설정하여 운영하고 있습니다.

4-2. [팁] PHP 함수 이용

이 팁은 kHTTPd를 아파치의 보조 서버로 활용하기 위해서 아파치 차원에서 정적인 페이지를 모두
kHTTPd로 전달하기 위한 팁입니다.
즉, 동적인 페이지인 PHP 페이지에서 정적으로 링크 또는 로딩할 내용을 모두kHTTPd를 이용해서 빠르게
실행하기 위함입니다. 또한 PHP 페이지에서 비교적 쉽게 아래의 함수를 사용할 수 있는 조건이면 더욱 좋습니다.
그렇지 않으면 중노동(?)이 수반.....^.^

아파치가 80 포트로 운영될 경우 :
<img src="/any/path/to/foobar.gif"> : 아파치가 실행
<img src="http:www.anydomain.com:8080/any/path/to/foobar.gif"> : kHTTPd가 실행

즉 이 팁은,
PHP를 이용해서 전자의 경우를 모두 후자의 경우로 링크하기 위함이며, 기존의 PHP에 A 태그나 IMG 태그를
모두 PHP 함수로 만들어 사용했을 경우에 유용한 경우입니다.
그렇지 못할 경우에는 이 팁은 무용지물이며 모두 A 태그와 IMG 태그를 손수수작업해야 합니다.....T.T

-------------------------------------------------------------------------

// kHTTPd 8080 포트 사용
function GET_KHTTPD($port="8080") {
$serv = "123.123.123.123"; // 메인서버 IP 주소나 호스트 이름으로 설정
//$serv = getenv("HTTP_HOST");
return "http://${serv}:${port}";
}

// kHTTPd 사용을 위한 자동 링크 함수
//
// 즉, URL을 ^/(.+)로 시작하는 정적인 페이지로 자동 링크해 줍니다.
// 하룻동안 헤메면서 이 함수를 만들었습니다.(T.T)..
// 워낙 제홈이 X판이라서 모두 적용시킬려고 하니...쩝
// case "$link": 다음과 같은 경우에 모두 해당됨
// (./)foobar.(gif|jpg|txt|html|tar|gz|Z|zip)
// (./)foobar/foobar.(gif|jpg|txt|html|tar|gz|Z|zip)
// (./)foobar/
// (./)/
// (./)/foobar/
// (./)/foobar/foobar.(gif|jpg|txt|html|tar|gz|Z|zip)
// ---
// (./)foobar 형식의 파일이 아닌 디렉토리와 http:// 인 경우는 제외되었음
//
function GET_LINK($link) {

// $link 값이 http:// 시작하지 않고 gif/jpg/txt/html 로 끝난 경우,
// 즉 정적인 파일만 요청할 경우
if(!eregi("^(http|ftp)://(.+)",$link)) {
// $baseurl은 시작은 "/", 마지막은 "/"
$baseurl = dirname(getenv("SCRIPT_NAME"));
if($baseurl != "/") { $baseurl .= "/"; } // Root(/)URL 이 아닐 경우 "/" 추가
$kHTTPd = Get_kHTTPd();

// *** 주의 ***
// 만약 확장자(?)가 html로 끝난 파일안에 PHP 코드가 있다면 // 다음 if 문에서 "html|"을 삭제요함.
//
if(eregi("([^?].+).(gif|jpg|txt|html|tar|gz|Z|zip|mp3|mpg|avi)$",$link)) {

if(eregi("^/(.+)",$link)) {
$link = "$kHTTPd"."$link"; //DocumentRoot를 기준으로 상대경로일 경우
} else {
$link= "$kHTTPd"."$baseurl".eregi_replace("^/(.+)$","\1",$link);
}

} else if(eregi("^(.*)/$",$link)) { // 끝이 "/"으로 끝난 경우

// index.html/index.txt 파일 존재 여부 체크
if(ereg("^/(.*)",$link)) { // "/"으로 시작할 경우
$baseurl = "$link";
} else {
$baseurl .= "$link";
}

$basedir = getenv
("DOCUMENT_ROOT")."$baseurl";
if(file_exists("${basedir}index.html")) {
$link= "$kHTTPd".$baseurl."index.html";
} else if(file_exists("${basedir}
index.txt")) {
$link= "$kHTTPd".$baseurl."index.txt";
}
}
}
return $link;
}

// IMG TAG 함수, 예: $arc = abc.gif
// $img_w = $imgsize[0];
// $img_h = $imgsize[1];
// $imgsize[3] = "$imgsize[0] $imgsize[1]";
// $arch는 "/imgaes/foobar.gif" 형식은 DocumentRoot를 기준으로 절대경로
//
function HTML_IMG_SRC
($arch,$border="0",$alt="0",$width="0",$height="0",$align="0",$valign="0") {
if(!$alt) { $alt = ""; }
if($align) { $align = " align="$align""; } else { $align= ""; }
if($valign) { $valign = " valign="$valign""; } else {$valign = ""; }

$docroot = getenv("DOCUMENT_ROOT");
$imgurl = GET_LINK($arch);

// $arch가 DocumentRoot를 기준으로 절대경로
if(!$width && !$height) {
if (eregi("^/(.+)$",$arch)) { $imgarch= "$docroot"."$arch"; }
else { $imgarch = "$arch"; }
$imgsize = @GetImageSize("$imgarch");
} else {
$imgsize[3] = "width="$width" height="$height"";
}

$img_src = "<img src="$imgurl" $imgsize[3]border="$border" alt="$alt"$align$valign>";
return $img_src;
}

// 자바 스크립트 window.status A 태그
//
Function TAG_A($str,$link, $target="0", $winstatus="0") {
if($winstatus) {
$status = " onMouseOver="window.status='$winstatus';
return true" onMouseOut="window.status=''; return true"";
$title = " TITLE=$winstatus";
}
// 2001.02.18 일 추가
$link = GET_LINK($link);

if($target) { $link = "<A HREF="$link" target="$target"$status$title>$str</A>"; }
else { $link = "<A HREF="$link"$status$title>$str</A>"; }
return $link;
}
-------------------------------------------------------------------------

[사용법]

일반 HTML일 경우 :

<IMG src="anypath/foobar.gif" width="100" height="20" alt="foobar">
<A href="anypath/foobar.html">string</A>

위의 PHP 함수를 사용할 경우 :
<?
echo html_img_src("anypath/foobar.gif");
echo tag_a("anypath/foobar.html");
?>

모든 작업이 끝났으면,
아파치 로그파일을 모니터링하면서 직접 웹브라우저로 정적인 파일들을 요청해봄으로써 로그 파일에
기록하는지 기록하지 않은지 확인해 보시길 바랍니다.
만약 아파치 로그파일에 방금 호출한 정적인 페이지(이미지나 txt 파일) 접근기록이 있다면
kHTTPd로 전달하지 않고 아파치 수준에서 실행한 경우므로 처음부터 작업을 다시해야 한다........
(뭔가 잘못되어 있다.)

예:
# tail -f /usr/local/apache/logs/access_log

4-3. [팁] 아파치 rewrite 모듈 이용

이 방법은 kHTTPd를 보조 웹서버로 이용하고 아파치는 80 포트 즉 메인서버로운영할 경우에 해당된 내용입니다.
즉 아파치에서 rewrite 모듈을 이용해서 정적인 내용은 모두 kHTTPd로 보내기위함이 그 목적입니다.

아파치 rewrite 모듈을 사용가능한지 먼저 확인해 보자.

# httpd -l (또는 # /usr/local/apache/bin/httpd -l)
Compiled-in modules:
http_core.c
mod_env.c
mod_log_config.c
mod_mime.c
mod_negotiation.c
mod_status.c
mod_include.c
mod_autoindex.c
mod_dir.c
mod_cgi.c
mod_asis.c
mod_imap.c
mod_actions.c
mod_userdir.c
mod_alias.c
mod_rewrite.c <---------------확인사항
mod_access.c
mod_auth.c
mod_setenvif.c
mod_php.c
#

또는 RPM으로 설치했다면, 아파치 설정 파일(httpd.conf)에

...
LoadModule rewrite_module modules/mod_rewrite.so
...
AddModule mod_rewrite.c
...

부분이 있는지 확인한다.
만약 rewrite 모듈을 사용할 수 없는 경우라면 다음과 같은 방법으로 아파치에 rewrite 모듈을 추가해 줘야 한다.

[DSO 모듈로 직점 컴파일 할 경우]

방법1)
# apxs -i -a -c /any/path/to/src/modules/standard/mod_rewrite.c
apxs 유틸리티 사용할 경우

방법2)
--enable-module=rewrite --enable-shared=rewrite
rewrite를 enable 시키고 DSO 모듈로 enable 시킴

방법3)
--enable-module=all --enable-shared=rewrite
모든 모듈을 enable 시키고 mod_rewrite만 DSO 방식으로 추가

방법4)
--enable-module=all --enable-shared=max
모든 모듈을 enable 시키고 httpd_core와 mod_so를 제외한 나머지 모듈(mod_rewrite가 포함됨)을 DSO 방식으로 추가

방법5)
--enable-module=rewrite --enable-shared=max
mod_rewrite를 enable 시키고 나머지 enable된 모듈과 함께 DSO 방식으로 추가

방법6)
--enable-shared=remain
아직 enable되어 있지 않은 mod_rewrite 모듈을 포함한 나머지 기본 enable
모듈을 enable시키고 httpd_core와 mod_so를 제외한 나머지 모듈(mod_rewrite가 포함됨) 을 DSO 방식으로 추가

참고)
--enabl/disable-shared=max 옵션
바로 이전 옵션에서 enable 되어 있는 모듈에 대해서만 DSO 방식으로 enable/disable.

--enable-shared=remain 옵션
바로 이전 옵션에서 enable 되어 있지 않은 모듈을 enable 시키고 이 모듈에 대해서만 DSO 방식으로 enable.

[정적으로 직점 컴파일 할 경우]
--enable-module=rewrite

이제 아파치에서 rewrite 모듈을 사용가능하면 다음과 같이 두 줄 정도의 설정 내용이 필요할 것입니다.

------------ httpd.conf ---------------------------------------------
# main host 또는 가상호스트 섹션 안에 다음 추가
#
## 2001.02.22 For kHTTPd
#
RewriteEngine
on

RewriteRule ^/([^?].+)(txt|html|gz|tar|Z|zip|gif|jpg|mp(3|eg|g)|wav|avi|rpm|iso)$  http://www.maindomain.com:8080/$1$2 [R,L]
#
---------------------------------------------------------------------

주의)
요청되는 웹페이지 안에 PHP와 같은 동적인 스크립트가 없어야 한다. 만약 HTML 파일안에 PHP 코드가
들어 있다면 그 부분은 무시되어 아무것도 표시되지 않는다.

제대로 rewrite 모듈이 작동하는지 테스트해 본다.
아파치를 재가동하고, URL에

http://www.maindomain.com/any/path/to/foobar.txt

을 요청하면

http://www.maindomain.com:8080/any/path/to/foobar.txt

으로 redirect 될 것이다.

주의)
앞의 경우처럼 직접 아파치 80 포트에 URL 요청이 있었기 때문에 아파치 log파일에는
그 접근 기록이 남아 있습니다. 물론 곧바로 kHTTPd로 전달되기는 하지만...

참고) rewrite 모듈에 관한 정보
- 아파치 제공 문서 - Module mod_rewrite URL Rewriting Engine :
http://www.apache.org/docs/mod/mod_rewrite.html
- 아파치 제공 문서 - Rewriting Guide :
http://www.apache.org/docs/misc/rewriteguide.html
- 아파치 제공 문서 - Dynamically configured mass virtual hosting :
http://www.apache.org/docs/vhosts/mass.html
- A Users Guide to URL Rewriting with the Apache Webserver :
Ralf S. Engelschall <rse@apache.org>
http://www.engelschall.com/pw/apache/rewriteguide/
- URL manipulation with Apache Forwarded :
Ralf S. Engelschall, Christian Reiber
http://www.heise.de/ix/artikel/E/9612149/

5. 간단한 성능 테스트

테스트 환경이 공평하지 않아(제가 있는 네트워크 환경), 객관적인 테스트가되질
않기 때문에 이 부분은 기록하지 못했습니다(오해의 소지가 많을 듯 해서...).

직접 ab(ApacheBench)와 Lynx로 각각의 웹서버에서 구동되는 정적인 페이지를요청해서
시간을 재어보시길 바랍니다.

참고) 테스트 기준
- 같은 URL/크기의 파일.
- 아파치에서 로그기록을 하지 않도록 설정.
- 같은 Remote host에서 테스트.
- 소로 포트를 바꾸어 가면서 같은 포트에 대해서 테스트.
- 기타 가능하다면 같은 조건에서.

- ab(예:/usr/local/apache/bin/ab)로 테스트할 경우(ab의 사용법은 ab를 입력하세요.)

사용형식 : ab -n 요청회수 요청URL
# ab -n 100 http://www.domain.com/any/path/to/foobar.txt

참고로 결과를 HTML로 출력하고자 한다면,

# ab -n -w 100 http://www.domain.com/any/path/to/foobar.txt > result.html

- Lynx를 이용할 경우
# time lynx --sourec http://www.domain.com/any/path/to/foobar.txt  >/dev/null
쉘 스크립트 작성이 가능하다면 스크립트로 작성해서 테스트해 보시길...

(참고로 필자가 운영하는 리눅스의 약 15KB HTML 파일 요청시 Localhost에서 전송 속도가
약 6배 차이가 났다....물론 아파치 로그기록은 하지 않은 상태에서).
문제는 네트워크 대역폭!!!

6. 마치며

(......................).+

7. 질문과 답변

[질문]
kHTTPd도 자체 로그를 기록합니다.
[답변]
현재 0.1.6버전까지는 기록하지 않습니다. 다만 0.1.6c 버전부터는 로깅하도록 되어있으나
이때는 khttpdlog 와 같은 데몬이 필요합니다.
http://www.fenrus.demon.nl/ 을 방문하면 sample khttpdlog 데몬을 찾을 수 있을 겁니다.

[질문]
kHTTPd를 꼭 8080 포트로 설정해야합니까?
[답변]
꼭 8080 포트로 설정하지 않아도 됩니다. 8000번 포트도 추천할 만 합니다.

[질문]
kHTTPd의 8080포트로 접근했다는 기록은 어디에서 볼 수 있습니까?
[답변]
/var/log/messages 파일을 열어보면,

.... webcache connection attempt from 211.xxx.xxx.xxx

라는 기록을 볼 수 있을 겁니다.
즉, webcache라는 서비스이름을 /etc/services 파일에서 8080 포트로 설정했기 때문입니다. 만약,
다음과 같이 /etc/services 파일을 편집하고, khttpd 8080/tcp

# /etc/rc.d/init.d/network restart

네트워크를 재 시작한 다음, 다시 URL에 요청하면,

.... khttpd connection attempt from 211.xxx.xxx.xxx

의 기록을 확인할 수 있을 겁니다.

8. 부록 - kHTTPd 제어 쉘스크립트

------------------------------------------------------------------------
#!/bin/sh

##
## 2001.02.18 Chilbong, Kim  <san2 [at] linuxchannel [dot] net>
## static kHTTPd, NOT Modules
## Default setting :
## "Apache" is main webserver, kHTTPd is assistant
## Apache Port($set_cport) : 80
## kHTTPd Port($set_sport) : 8080
## kHTTPd Logging($set_loggging) : 0(no)
##
##
## How to using
## 1) this file name is 'khttpd'.
## 2) chmod 704 khttpd ; chown root.root khttpd
## 3) cp khttpd /usr/local/bin/ (or /usr/sbin/ or include in $PATH)
## 4) you should be 'apache shoutdown' before khttpd starting.
## 5) khttpd start : you type 'khttpd start'
## 6) khttpd stop : you type 'khttpd stop'
## 7) khttpd status : you type 'khttpd status'
## 8) more help : you type 'khttpd' or 'khttpd --help'
##

# Require setting !!!!!!!!
# hub !!! not good
#
apache_htdocs="/home/wwwhome/linuxchannel.net/newhome"
khttpdlog="/usr/local/bin/khttpdlog"
#
# end setting

khttpd_help() {
echo "Usage... khttpd [start|stop|status]"
echo " khttpd start [documentroot] [port] [1(loggingyes)|0(logging no)]"
exit 0
}

khttpd_status() {
echo " + kHTTPd Port : $1"
echo " + kHTTPd DocumentRoot : $2"
echo " + Another Server Port : $3"
echo " + logging [ 0=no, 1=yes ] : $4"
}

kill_khttpdlog() {
if [ "$1" -ge "1" ] ; then
killall khttpdlog >/dev/null 2>/dev/null
fi
}

khttpd="/proc/sys/net/khttpd"
serverport="${khttpd}/serverport"
clientport="${khttpd}/clientport"
threads="${khttpd}/threads"
documentroot="${khttpd}/documentroot"
dynamic="${khttpd}/dynamic"
start="${khttpd}/start"
stop="${khttpd}/stop"
logging="${khttpd}/logging"

START=$(cat $start 2>/dev/null)
STOP=$(cat $stop 2>/dev/null)
DOCROOT=$(cat $documentroot 2>/dev/null)
SPORT=$(cat $serverport 2>/dev/null)
CPORT=$(cat $clientport 2>/dev/null)
LOGGING=$(cat $logging 2>/dev/null)

RUNLOGGING=`ps -ef | grep khttpdlog | grep -v grep | wc -l`

if [ "$START" = "1" -a $STOP = "0" ] ; then khttpd_run="1"
fi

if [ "$1" = "" ] ; then
khttpd_help
fi

case "$1" in
start)

if [ "$khttpd_run" = "1" ] ; then

echo "kHTTPd RUNNING !!! please, khttpd stop"
exit 0

else

# $2, kHTTPd DocumentRoot
if [ "$2" = "" ] ; then
set_docroot="$apache_htdocs"
else
set_docroot="$2"
fi

# $3, kHTTPd Port default 8080 port
if [ "$3" = "" -o "$3" = "8080" ] ; then
set_sport="8080"
set_cport="80"
else
set_sport="$3"
set_cport="8080"
fi

# Notes
****************************************************
# 1) This version works ONLY for kHTTPd 0.1.6c
# 2) You must configure kHTTPd to log BEFORE STARTING
it
# 3) The logging-daemon must be running BEFORE
STARTING kHTTPd
# from http://www.fenrus.demon.nl/
# $4, if not given, default set logging "0(no)"
#
if [ -x $khttpdlog ] ; then
if [ "$4" = "1" ] ; then
# check khttpdlog
#if [ "$RUNLOGGING" -ge "1" -a
$LOGGING = "0" ] ; then
# killall khttpdlog
2>/dev/null
#fi
# force down khttpdlog
kill_khttpdlog "$RUNLOGGING"

# start khttpdlog,
see /var/log/khttpd.log
echo 1 > $logging
$khttpdlog >/dev/null 2>/dev/null &
else
echo 0 > $logging
fi
else
echo 0 > $logging
fi

echo $set_sport > $serverport
echo $set_cport > $clientport
echo 2 > $threads
echo "$set_docroot" > $documentroot
echo php3 > $dynamic
echo php > $dynamic
sleep 1
echo 0 > $stop
sleep 1
echo 1 > $start
fi
;;
stop)
echo 1 > $stop
sleep 1
echo 0 > $start
sleep 1
kill_khttpdlog "$RUNLOGGING"
;;
status)
if [ "$khttpd_run" = "1" ] ; then
echo " kHTTPd RUNNING !!!"
khttpd_status "$SPORT" "$DOCROOT" "$CPORT" "$LOGGING"
else
echo "kHTTPd NOT running !!!"
fi
;;
*)
khttpd_help
;;
esac

exit 0
------------------------------------------------------------------------

---- kHTTPd-with-Apache.txt 내용 --------------------------

제목 : [kHTTPd] with Apache 1.3

작성자 : 김칠봉[닉: 산이] <san2 [at] linuxchannel [dot] net>
2001.02.26 : 1차 완료

----------------------------------------------------------------------------
이 문서는 리눅스 커널 수준에서 구동되는 kHTTPd 0.1.6(웹서버)와 아파치 연동을 위한 기초적인 팁문서입니다.
이 문서의 최신 버전은 다음에 싸이트에서 찾을 수 있습니다.
http://www.linuxchannel.net/docs/
이 문서의 저작권은 GNU GPL에 따릅니다.
----------------------------------------------------------------------------

*주)
문맥상 간혹 경어를 생략했습니다. 양해해 주시길 바랍니다.
kHTTPd에 대해서 그리 많은 해박한 지식이 없기 때문에 문서상 보완이나 잘못된 내용이 있으면
언제든지 환영합니다.
-----------------------------------------------------------------------------

관련 링크: http://linuxchannel.net/

+ Recent posts