강좌

  • 웹서버
  • 아파치
  • 톰켓
HOME > 강좌 >
강좌| 리눅스 및 오픈소스에 관련된 강좌를 보실 수 있습니다.
 
Tomcat 3.1 설치
조회 : 7,026  



김민식 <minskim@bawi.org> 김세곤 <sehkone@bawi.org>

2000년 6월 16일

요약

Tomcat은 Java Servlet 2.2 및 JSP 1.1을 구현하여 아파치 및 여러 웹써버에서 이용하고자 하는 프로젝트이다. 이 글에서는 아파치 웹써버에서 Tomcat 3.1을 사용하기 위한 과정을 설명한다.

소개

Tomcat은 웹써버에서 자바 써블릿과 JSP를 사용할 수 있도록 하려는 프로젝트이다. 사실 Tomcat은 Jakarta 프로젝트에 속한 작은 프로젝트이고, Jakarta는 자바 기반의 보다 포괄적인 플랫폼을 제공하는 것을 목표로 진행중이다.

현재 Tomcat 외에 아파치 웹써버에서 자바 써블릿을 쓰는 방법 중 가장 널리 쓰이는 것은 JServ일 것이다. 하지만 JServ는 반드시 JSDK 2.0을 사용해야 한다는 제약이 있고, JSP를 쓰기 위해서는 GNUJSP와 같은 별개의 프로그램을 필요로 한다. 반면 Tomcat은 Java Servlet 2.2와 JSP 1.1을 동시에 지원하고 있으며, JServ의 개발자들은 물론 Sun이나 IBM과 같은 기업에서도 참여하고 있으므로 앞으로는 JServ보다는 Tomcat을 필두로 한 Jakarta가 더욱 빨리 성장할 것이다.

필요한 것

아파치에서 Tomcat을 사용하려면 다음과 같은 것들이 필요하다.

이 중에서 mod_jserv.so는 미리 컴파일된 것(인텔 리눅스용)을 그대로 받아 이용해도 되고, 직접 컴파일해도 된다. 직접 컴파일하려면 Tomcat source를 받아서 아무 디렉토리에서나 압축을 풀고, jakarta-tomcat/src/native/apache/jserv/로 이동하여 다음 명령을 수행하면 된다.
$ apxs -c -o mod_jserv.so *.c
만일 apxs를 찾지 못한다면 아파치를 설치한 곳의 bin디렉토리에 있으므로 경로를 모두 써 주어 실행시키면 된다.

아파치는 DSO를 지원하도록 컴파일되어야 mod_jserv.so을 동적으로 로드할 수 있다. 배포본에 포함된 것이라면 대부분 DSO를 지원하도록 되어 있으므로 문제가 없으나 직접 컴파일을 하는 경우라면 configure 실행시에 반드시 --enable-module=so 옵션을 주어야 한다.

설치

Tomcat을 사용하려면 먼저 아파치가 제대로 설치되어 있어야 한다. 이 글에서는 아파치가 /usr/local/apache에 설치되어 있는 것으로 가정하겠다.

Tomcat은 자바로 작성되어 있어서 이미 컴파일 된 상태로 배포되므로 따로 컴파일 과정을 거치지 않아도 된다. 적당한 곳에 jakarta-tomcat.tar.gz의 압축을 푸는 것만으로 설치가 끝난다. /usr/local에서 압축을 풀었다면 /usr/local/jakarta-tomcat이란 디렉토리가 생겼을 것이다.

Tomcat과 아파치가 서로 통신할 수 있도록 해 주는 모듈이 mod_jserv.so이다. 이 파일을 아파치의 동적 모듈을 저장하는 디렉토리로 복사하고 아파치를 다시 실행시키면 자동으로 모듈을 읽어들이게 된다. 동적 모듈을 저장하는 디렉토리는 아파치가 설치된 곳 밑에 있는 libexec이란 디렉토리이다. /usr/local/apache에 아파치를 설치했다면 /usr/local/apache/libexec이 여기에 해당한다. 배포본에 포함된 것은 다른 디렉토리를 사용하기도 하므로 알맞은 디렉토리를 찾아야 한다. /usr/lib/apache가 있다면 이곳을 이용하고, 그렇지 않다면 mod_*.so 형태의 파일들이 있는 곳을 찾도록 한다.

이제 설정 파일을 추가할 차례이다. Tomcat의 설정 파일은 Tomcat을 설치한 곳의 conf 디렉토리 안에 있다. tomcat.conf는 아파치를 위한 것이고, server.xml이 Tomcat을 위한 것이다. tomcat.conf는 아파치의 httpd.conf의 맨 끝에서 다음과 같이 불러들이면 된다.

Include /usr/local/jakarta/jakarta-tomcat/conf/tomcat.conf

Tomcat과 아파치의 통신을 위해서는 별개의 포트가 필요한데, 이 포트 번호는 tomcat.conf와 server.xml 양쪽에 명시해 주어야 한다. tomcat.conf에는

ApJServDefaultPort 8007
과 같이 되어 있고, server.xml에는
<Parameter name="handler"
  value="org.apache.tomcat.service.connector.Ajp12ConnectionHandler"/>
<Parameter name="port" value="8007"/>
과 같이 되어 있다. 여기서 8007이 포트 번호이며, 이 값을 변경할 경우 두 파일의 값이 일치해야 한다. 이 외에 server.xml에는 포트 번호를 적는 곳이 하나 더 있다.
<Parameter name="handler"
  value="org.apache.tomcat.service.http.HttpConnectionHandler"/>
<Parameter name="port" value="8080"/>
자세히 보면 첫 줄의 value 부분이 다른 것을 알 수 있을 것이다. 이 포트는 Tomcat이 자체적으로 갖고 있는 HTTP 써버를 위한 것이다. 이 값은 앞에서 정해준 포트 번호는 물론 아파치의 포트 번호와도 달라야 한다.

시험

먼저 아파치를 다시 실행시키고, 아파치 자체의 동작에 아무 문제가 없는가를 확인해야 한다. 아파치가 문제없이 실행된다면 Tomcat을 실행시킬 수 있다. Tomcat을 설치한 곳의 bin 디렉토리에 보면 startup.sh이란 파일이 있는데, 이것이 Tomcat을 실행시키는 파일이다. 그 전에 두 가지 환경 변수를 설정해 주어야 하는데, 하나는 Tomcat이 설치된 곳을 가리키는 TOMCAT_HOME이고, 또 하나는 자바가 설치된 곳을 가리키는 JAVA_HOME이다. Tomcat을 /usr/local/jakarta에서 압축을 풀었다면 그 밑에 생긴 jakarta-tomcat이 TOMCAT_HOME이 된다. JAVA_HOME은 자바 실행 환경이 설치된 디렉토리이며, 실행 파일이 /usr/local/jdk/bin/java라면 /usr/local/jdk가 그 값이 된다.

모든 설정이 끝나고 startup.sh을 실행시켰다면 웹브라우져로 다음 URL을 방문해보라.

  • http://<hostname>/examples/servets/

  • http://<hostname>/examples/jsp/

물론 <hostname>은 알맞은 이름으로 바꿔 주어야 하고, 만일 웹써버를 80번 포트가 아닌 다른 포트에서 실행시켰다면 포트 번호도 명시해 주어야 한다. Tomcat에서 자체적으로 제공하는 HTTP 써버를 이용하여 테스트해보려면 8080번 포트로 접속해보면 된다. 여러 예제들을 실행해 볼 수 있는 화면이 나오고, 각 예제들이 문제없이 실행된다면 Tomcat이 제대로 동작하고 있는 것이다.

가상 호스트 설정

현 버젼의 Tomcat은 가상 호스트 기능을 제공하지 않는다. 아파치의 가상 호스트 기능을 이용해서 aa.webdox.co.kr과 bb.webdox.co.kr을 쓰고 있다고 해도 Tomcat은 http://aa.webdox.co.kr/hello.jsp와 http://bb.webdox.co.kr/hello.jsp를 모두 같은 파일로 간주한다. 이를 극복하는 방법은 각 가상 호스트마다 별개의 Tomcat을 실행하는 것이다. 그런 다음 아파치에서 가상 호스트에 따라 다른 Tomcat으로 접속하게 하면 마치 Tomcat이 가상 호스트를 지원하는 것과 같은 효과를 가져올 수 있다. 물론 이 방법은 가상 호스트 수 만큼의 process가 필요하므로 그 수가 너무 많다면 문제가 되겠지만 호스팅 업체가 아니라면 그렇게 많은 수의 가상 호스트가 필요할 일은 없으므로 대부분의 경우 무난할 것이다. 그리고 Tomcat 개발자들도 하나의 Tomcat process에서 여러 가상 호스트를 지원하는 것을 고려하고 있으므로 조만간 이 기능이 Tomcat에 포함되리라 생각한다.

우선 아파치에서 가상 호스트 기능을 구현하기 위해서는 가상 호스트의 수만큼 Tomcat을 인스톨해야 한다. 예를 들어, aa.webdox.co.kr과 bb.webdox.co.krd의 두 가상 호스트를 위해 /usr/local/tomcats 디렉토리 아래에 두 개의 Tomcat을 압축 해제하고 디렉토리 이름 충돌을 막기 위해 tomcat_aa, tomcat_bb식으로 이름을 바꾼다. 이제, aa.webdox.co.kr을 위해서는 /usr/local/tomcats/tomcat_aa를, bb.webdox.co.kr을 위해서는 /usr/local/tomcats/tomcat_bb를 사용하도록 하고 하나씩 설정해 보자.

각각의 Tomcat에는 conf 디렉토리 밑에 tomcat.conf 파일이 있다. 개별 호스트 마다 tomcat.conf를 설정할 필요가 없고 오직 하나만 설정하면 된다. 여기서는 tomcat_aa/conf/tomcat.conf 를 설정하기로 하자. 잊지말아야 할 것은 설정하기로 결정한 하나의 tomcat.conf 파일을 꼭 아파치 써버의 httpd.conf 파일에서 불러들이는 것이다. 다음처럼 한다.

Include /usr/local/tomcats/tomcat_aa/conf/tomcat.conf

이제 tomcat_aa/conf/tomcat.conf에 가상 호스트 환경을 다음처럼 설정해 주어야 한다.

#############################################################################
#                   Apache-Tomcat 가상 호스트 설정 파일
#############################################################################

LoadModule jserv_module libexec/mod_jserv.so

<IfModule mod_jserv.c>
ApJServManual on
ApJServDefaultProtocol ajpv12
ApJServSecretKey DISABLED
ApJServMountCopy on
ApJServLogLevel notice

### Change if you run tomcat on a different host
#ApJServDefaultHost localhost
#ApJServDefaultPort 8007


### Virual Hosts
NameVirtualHost 211.53.212.40

<VirtualHost 211.53.212.40>
ServerName aa.webdox.co.kr
DocumentRoot /home/httpd/aa/html

ApJServDefaultPort 8007
ApJServMount default ajpv12://localhost:8007/root
ApJServMount /servlet ajpv12://localhost:8007/servlet
AddType text/jsp .jsp
AddHandler jserv-servlet .jsp
</VirtualHost>

<VirtualHost 211.53.212.40>
ServerName bb.webdox.co.kr
DocumentRoot /home/httpd/bb/html

ApJServDefaultPort 8008
ApJServMount default ajpv12://localhost:8008/root
ApJServMount /servlet ajpv12://localhost:8008/servlet
AddType text/jsp .jsp
AddHandler jserv-servlet .jsp
</VirtualHost>

</IfModule>
가상 호스트 설정이 httpd.conf가 아니라 여기에 포함되어야 한다. 위에 적은 것은 예로 든 것이므로 각 가상 호스트에 필요한 내용들을 httpd.conf에서처럼 적어주면 된다. 단, 각 가상 호스트 설정의 마지막 다섯 줄은 JSP 파일과 써블릿을 서로 다른 Tomcat으로 보내기 위한 것이므로 JSP를 사용하는 가상 호스트에는 반드시 필요하다. 위에서 예로 든 두 경우에서 포트 번호가 다름에 주목하기 바란다. 이제 Tomcat을 8007번 포트와 8008번 포트를 쓰도록 하면 된다.

두 Tomcat을 실행시키려면 server.xml을 수정해야 한다. tomcat_aa/conf/server.xml과 tomcat_bb/conf/server.xml의 포트 번호를 위의 tomcat.conf 에서 정해준 값과 일치시켜야 한다. tomcat_aa/conf/server.xml 을 살펴보면 다음과 같은 부분이 있다.

<Connector className="org.apache.tomcat.service.SimpleTcpConnector">
<Parameter name="handler"
           value="org.apache.tomcat.service.http.HttpConnectionHandler"/>
<Parameter name="port" value="8080"/>
</Connector>

<Connector className="org.apache.tomcat.service.SimpleTcpConnector">
<Parameter name="handler"
           value="org.apache.tomcat.service.connector.Ajp12ConnectionHandler"/>
<Parameter name="port" value="8007"/>
</Connector>
앞의 것은 Tomcat이 자체적으로 갖고 있는 웹써버의 포트번호인데, 아파치를 쓰고 있으므로 굳이 다른 웹써버를 또 띄울 이유가 없다. 그러므로 앞의 네 줄은 모두 삭제하기 바란다. 뒤의 네 줄이 아파치와 Tomcat이 통신하는 포트인데 이 값을 tomcat.conf에서 정해준 값과 같은 8007로 적어주면 된다. tomcat_bb/conf/server.xml에는 다음과 같이 8008번으로 적어준다.
<Connector className="org.apache.tomcat.service.SimpleTcpConnector">
<Parameter name="handler"
           value="org.apache.tomcat.service.connector.Ajp12ConnectionHandler"/>
<Parameter name="port" value="8008"/>
</Connector>

다음으로 수정할 것은 JSP 파일에 대한 요청이 들어왔을 때 이를 어떤 디렉토리에서 찾을 것인가를 지정해주는 부분이다. 포트번호를 적어준 아래에 보면 <Context> 태그가 있는데, 이 태그가 Tomcat으로 들어오는 요청과 실제 디렉토리를 대응시켜주는 구실을 한다. 설치 후 수정한 것이 없다면 example과 test를 정의하고 있을텐데, 이 두 줄을 삭제하고 다음과 같이 하나의 <Context>만을 남겨 놓으면 된다.

<Context path="" docBase="webapps/ROOT" debug="0" reloadable="true">
</Context>
tomcat_bb/conf/server.xml도 마찬가지이다.

위의 방법은 DocumentRoot 이하의 어느 곳에서도 JSP를 사용할 수 있게 한다. 말하자면 전체가 하나의 웹 애플리케이션으로 동작하는 셈이다. 이를 위해, 마지막으로 webapps/ROOT가 실제 DocumentRoot를 가리키도록 해야 한다. 즉, 각 Tomcat의 TOMCAT_HOME 아래에 있는 webapps/ROOT를 삭제하고, 대신 DocumentRoot를 가리키는 심볼릭 링크로 대체한다. 본 예에서는 aa.webdox.co.kr의 DocumentRoot 값이 /home/httpd/aa/html이므로, 다음처럼

ln -s /home/httpd/aa/html /usr/local/tomcats/tomcat_aa/webapps/ROOT
심볼릭 링크를 만든다. 이렇게 해 두면 Tomcat 실행시에 DocumentRoot 이하를 검색하여 CLASSPATH를 추가하는 등의 초기화 작업을 하게 된다. 만일 JSP파일 등에서 불러 쓰고 싶은 class가 있다면 .class 파일로 만들어서 DocumentRoot 밑에 WEB-INF/classes라는 디렉토리에 넣어 두면 된다. tomcat_bb의 경우도 마찬가지다

특정 디렉토리 이하에서만 쓰도록 하고 싶다면 보다 나은 해결책이 있다. 위의 예에서 path="" 부분에 그 값을 명시하면 된다. 예를 들어 http://aa.webdox.co.kr/java/ 이하에만 JSP나 servlet을 넣고 싶다면 다음과 같이 한다.

<Context path="/java" docBase="webapps/java" debug="0" reloadable="true">
</Context>
물론, webapps/java은 실제 파일들이 존재하는 /home/httpd/aa/html/java으로의 심볼릭 링크이다. docBase는 다른 원하는 디렉토리로 대체해도 무방하다. 그런 다음 /home/httpd/aa/html/java 밑에 마찬가지로 WEB-INF/classes 디렉토리를 만들고 거기에 필요한 .class 파일들을 넣으면 된다.

모든 설정이 끝났으면 아파치를 다시 실행하고, 각각의 가상 호스트마다 Tomcat을 따로이 실행시킨다. 여기서는 다음처럼 하면 된다.

# /usr/local/tomcats/tomcat_aa/bin/tomcat.sh start
# /usr/local/tomcats/tomcat_bb/bin/tomcat.sh start
이미 실행중인 Tomcat이 있다면 그걸 먼저 종료하는 것을 잊지 말자. 이제 두 가상 호스트로 접속해서 실행 여부를 확인하면 된다.

한글 코드 문제와 해결방법

Tomcat에서 한글을 바로 사용하기 위해서는 모든 JSP 페이지와 써블릿에서 문자셋을 EUC_KR로 지정해야 한다. 써블릿에서는 HttpServletResponse 클래스의 setContentType() 메쏘드에 인자로 "text/html; charset=EUC_KR"를 넘겨주면 되고 JSP에서는 페이지 상단의 <%@ page> 태그안에 다음처럼 하면 된다.

<%@ page contentType="text/html; charset=EUC_KR" %>

그런데, Tomcat은 한글 처리에 있어서 한 가지 문제점이 있다. GET이나 POST 를 통해 이동되는 값이 Cp1252로 변환된다는 점이다. 따라서, request.getParameter() 메쏘드를 사용할 때 꼭 EUC_KR로 다시 변환해 주어야 한다. 다음처럼 코딩하면 된다.

<%@ page contentType="text/html; charset=EUC_KR" %>

...

<%
    String userId = new String(request.getParameter("id").getBytes("Cp1252"),
                               "EUC_KR");

...

사용의 편의를 위해 코드 변환을 해 주는 클래스를 하나 만들면 좋겠다.

request.getParameter() 메쏘드를 사용하여 GET 혹은 POST로 넘어오는 값을 EUC_KR로 변환하는 것은 적당히 클래스만 만들어 놓으면 번거롭지 않으나, 문제는 <jsp:setProperty>를 사용하는 데 있다. Beans를 사용하면 <jsp:setProperty>를 통해 form의 각 필드의 이름과 beans의 setXXX() 메쏘드의 이름을 참조하여 form의 필드 값과 set 이후가 같은 이름의 setXXX() 메쏘드를 사용하여 자동적으로 beans의 필드 값을 설정할 수 있다. (Beans의 개념과 <jsp:setProperty> 구문에 대한 설명은 JSP에서 Beans 사용하기를 참고하면 된다) 그런데, 이렇게 자동적으로 beans의 필드가 설정될 때 역시 Cp1252로 인코딩되기 때문에, beans의 필드 값을 <jsp:setProperty>로 자동 설정한 후에 꼭 다시 모든 필드를 EUC_KR로 변환해야 한다. 이해를 돕기 위해 예를 들어 보겠다.




JSP 문서 

<jsp:useBean id="user" class="User" scope="page"/>
<jsp:setProperty name="user" property="*"/>
<% user.toKorean(); %>

User Bean (User.java)

import java.io.*;
import CharacterSet;

public class User {
    private String id;
    private String password;

    public void setId(String str) {
	id = str;
    }

    public void setPassword(String str) {
	password = str;
    }

    public String getId() {
	return id;
    }

    public String getPassword() {
	return password;
    }

    public void toKorean() {
	id = CharacterSet.toKorean(id);
    }
}

CharacterSet 클래스 (CharacterSet.java)

import java.lang.*;
import java.io.*;

public class CharacterSet {
    public static String toKorean(String str) {
        try {
            return new String(str.getBytes("Cp1252"), "EUC_KR");
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }
}

CharacterSet 클래스는 코드 변환을 쉽도록 만든 것이고, User.java에서 이 클래스를 사용하고 있다. User bean에 form에서 입력받은 아이디와 비밀번호를 자동으로 설정하고 나서 User bean의 메쏘드는 toKorean()을 사용하여 EUC_KR로 변환하는 것을 볼 수 있다.

한글 코드 문제는 form에서 전달받은 값을 beans에 자동 설정할 때만 생기는 것으로서, 직접 beans에 값을 설정할 때는 문제가 없다.


[원글링크] : https://www.linux.co.kr/home2/board/subbs/board.php?bo_table=lecture&wr_id=448


이 글을 트위터로 보내기 이 글을 페이스북으로 보내기 이 글을 미투데이로 보내기

 
(주) 수퍼유저