Web Application Server/Apache Tomcat

○ Apache Tomcat 가이드 - 설정파일 분석하기

심심한 낙지 2020. 7. 7. 06:54

POOPOO: 배변 일기 앱

SMALL

 

이 포스팅은 CentOS 7 / Tomcat 8.0.22 버전에서 진행되었습니다.


목차


server.xml

 

1.1 Listener

리스너는 일반적으로 Apache Tomcat이 시작하거나 중지하는 것과 같이, 라이프 사이클 안에서의 이벤트를 정의합니다.

리스너를 선언하는 방법은 아래와 같습니다.

<Listener className="리스너 클래스(패키지경로)" 속성="값" />

 

이어서 리스너의 종류별로 지원하는 속성에 대해 말씀드리겠습니다.

 

APR Lifecycle Listener - org.apache.catalina.core.AprLifecycleListener

이 리스너는 APR/native 라이브러리가 존재하는재 확인한 후, 존재한다면 라이브러리를 로딩해주는 역할을 합니다.

추가적으로 제공하는 옵션은 아래와 같습니다.

No 제목 내용
1 SSLEngine

사용할 SSLEngine의 이름입니다. off: SSL을 사용하지 않습니다 on. : SSL을 사용하지만 특정 엔진은 사용 하지 않습니다 .

기본값은 on 입니다.  SSLEnabled속성을 사용하여 APR / 네이티브 커넥터에서 활성화해야하는 기본 SSL 엔진을 초기화 합니다.

지원되는 SSL 하드웨어 엔진 및 제조업체에 대한 자세한 내용  공식 OpenSSL 웹 사이트 를 참조하십시오.

2 SSLRandomSeed SSLEngine의 PRNG를 시드하는 데 사용되는 엔트로피 소스입니다.

기본값은 builtin입니다.
개발 환경에서는 /dev/urandom 파일을 수정해서 시작시간을 더 빠르게 개선할 수 있습니다.
3 FIPSMode

on - FIPSMode가 설정되어있지 않은 경우 OpenSSL을 FIPSMode로 설정
enter - 강제로 OpenSSL을 FIPSMode로 설정
require - 이미 OpenSSL에 FIPSMode가 설정되어있는경우 에러

사용하기 위해서는 직접 빌드해야하는 FIPSMode를 지원하는 OpenSSL 라이브러리를 사용해야합니다.
SSLEngine 옵션도 사용가능해야합니다.
기본값은 off입니다.

4 useAprConnector 이 속성은 커넥터 구현의 자동 선택을 제어합니다.

프로토콜을 HTTP/1.1로 지정하거나 AJP/1.3 속성이있는 경우 true 입니다.
APR/native 커넥터가 사용되지만이 속성이 false 인 경우 NIO 커넥터가 사용됩니다.
5 useOpenSSL
이 속성은 OpenSSL JSSE 구현의 자동 선택을 제어합니다.

기본값은 true이며, 기본 라이브러리를 사용할 수 있고, NIO 또는 NIO2 커넥터가 사용되는 경우 OpenSSL을 사용합니다.

 

 

Global Resources Lifecycle Listener - org.apache.catalina.mbeans.GlobalResourcesLifecycleListener

이 리스너는 server.xml 파일 안에 있는 Global JNDI Resource를 초기화합니다.

이 리스너 없이는 Global Resource를 이용할 수 없습니다.

 

 

JNI Library Loading Listener - org.apache.catalina.core.JniLifecycleListener

웹 애플리케이션 로더가 컨텍스트 클래스 로더인 경우  메모리 누수가 발생한다면, 자바 런타임 환경은 싱글톤을 로드하기 위한 컨텍스트 클래스 로더를 사용하는데, 그 해결방안을 제공해주는 리스너입니다.

No 제목 내용
1 appContextProtection 웹 애플리케이션에서 sun.awt.AppContext.getAppContext() 호출로 인한 메모리 누수가 발생하지 않도록 보호를 활성화합니다. 

이 보호기능을 사용하면, Java head-less mode 를 사용하지 않는 한, 그래픽 환경에 대한 요구사항이 트리거됩니다. 

기본값은 false 이며, Java 8 이상에서 수정된 기능이기 때문에, Java 8 이상에서 실행하는 경우 보호기능이 비활성화됩니다.
2 AWTThreadProtection 웹 애플리케이션에서 java.awt.Toolkit.getDefaultToolkit() 호출로 인한 메모리 누수가 발생하지 않도록 보호를 활성화합니다. 

AWT 스레드가 실행되기때문에, 기본값은 false 입니다. 

이 기능은, Java 9 이상에서 누수가 수정되었으므로 Java 9 이상에서 실행하는 경우, 보호기능이 비활성화됩니다.
3 classesToInitialize 리스너의 시작과 함께 클래스의 이름을 로딩해줍니다. 
이를 통해 요청 처리중에 로드된 클래스로더 누출을 유발하는 것으로 알려진 클래스를 사전에 로드할 수 있습니다. 

기본값은 empty 이지만, 특정 JRE 클래스가 다른 메모리 누수 보호기능에 의해서 추가될 수 있습니다.
4 driverManagerProtection java.sql.DriverManager를 처음 사용하면 현재의 클래스 로더에서 JDBC 드라이버가 로드 및 트리거됩니다.

대부분의 경우, 웹 애플리케이션의 메모리 누수 방지 기능으로 이를 처리할 수 있지만, 여기서 로드를 트리거하면 부작용이 줄어듭니다.
기본값은 true입니다.
5 forkJoinCommonPoolProtection ForkJoinPool.commonPool()을 사용해서 생성된 스레드가 메모리 누수가 되지 않도록 보호합니다.

java.util.concurrent.ForkJoinPool.common.threadFactory 시스템 속성을 설정하여 보호를 활성화할 수도 있습니다.

기본값은 true 입니다.
이 기능은 Java 8 에서만 이용 가능합니다.
Java 9 부터는 메모리 누수가 이미 수정되었습니다.
Java 8 이전 버전에는 common pool이 존재하지 않습니다.
6 gcDaemonProtection 웹 애플리케이션에서 sun.misc.GC.requestLatency(long)의 호출로 인한 메모리 누수가 발생하지 않도록 보호합니다.

RMI를 사용하면 이 메소드에 대한 호출이 트리거 될 수 있습니다.
이 보호 기능을 활성화하면 "GC Daemon" 이라는 스레드가 생성됩니다.
보호기능은 리플렉션을 사용하여 내부 Sun 클래스에 접근하며, Sun 이외의 JVM에서 시작시 오류가 발생할 수 있습니다.
기본값은 true입니다.
Java 9 이상에서 누수가 수정되었기 때문에, Java 9 이상에서는 비활성화됩니다.
7 ldapPoolProtection com.sun.jndi.ldap.LdapPoolManager 시작된 PoolCleaner 스레드가 메모리 누수를 발생시키지 않도록 보호를 활성화합니다.

LdapPoolManager 시스템 등록정보인 com.sun.jndi.idap.connect.pool.timeout 값이 0보다 큰 값으로 설정된 경우, 스레드를 처음 사용할 때 비로소 시작됩니다.

이 보호기능이 없으면, 웹 애플리케이션이 이 클래스를 사용하넌 경우, 스레드의 컨텍스트 클래스 로더가 스레드 컨텍스트 클래스 로더로 설정되어 PoolCleaner 스레드가 구성되고, 다시 로드할 때, 메모리 누수가 발생합니다.

참고 : 기본 누출은 Java 7 업데이트 51 이상 및 Java 8 이상에서 수정되었습니다. Java 8 이상에서 실행중인 경우이 보호 기능이 비활성화됩니다.
8 securityLoginConfigurationProtection 웹 애플리케이션에서 javax.security.auth.login.Configuration 클래스를 사용하는 경우에 메모리 누수가 발생하지 않도록 보호합니다.

이 클래스의 첫 번째 접근은 컨텍스트 클래스 로더에 대한 정적 참조를 유지하는 initializer를 트리거합니다.

보호기능은 시스템 클래스 로더와 함께 클래스를 로드하여 정적 초기화 프로그램이 웹 애플리케이션에 의해 트리거되지 않도록 합니다.
기본값은 true입니다.

Java 8 이상에서 누수가 수정되었기 때문에, Java 8 이상에서는 보호 기능이 비활성화됩니다.
9 securityPolicyProtection 

javax.security.auth.Policy의 더이상 사용되지 않는 클래스를 사용하더라도 메모리 누수가 발생되지 않도록 보호합니다.


이 클래스의 첫 번째 접근은 컨텍스트 클래스 로더에 대한 정적 참조를 유지하는 정적 초기화 프로그램을 트리거합니다.
보호기능은 이 클래스로부터 getPolicy()를 호출하여 웹 애플리케이션으로부터 트리거를 막아줍니다.
기본값은 true입니다.

누출은 Java 7 업데이트 51 이상 및 Java 8 이상에서 수정되었습니다.
따라서, Java 8 이상에서 실행중인 경우 보호기능이 비활성화됩니다.
10 tokenPollerProtection sun.security.pkcs11.SunPKCS11.initToken() 메소드에 의해 초기화된 토큰 폴러 스레드가 메모리 누수를 일으키지 않도록 보호합니다.

스레드는 Java Cryptography Architecture 초기화의 일부로 다양한 조건에 따라 시작됩니다.

보호기능이 없으면, 웹 배포중에 세션 ID 생성을 위한 MessageDigest가 초기화 될 때, 누수가 발생할 수 있습니다.

결과적으로 스레드에는 스레드 컨텍스트 클래스 로더로 Webapp 클래스 로더가 있습니다. 

보호를 사용하면 Tomcat 시작 중에 JCA가 초기에 초기화됩니다.
기본값은 true입니다.

Java 9 이상에서 누수가 수정되었기 때문에, Java 9 이상에서 실행하는 경우에는 비활성화됩니다.
11 urlCacheProtection java.net.URLConnections를 사용하여 JAR 파일에서 자원을 읽을 때 JAR 파일이 잠기지 않도록 보호합니다.

이 보호 기능을 활성화하면 java.net.URLConnections 를 통해 얻은 모든 리소스에 대해 기본적으로 캐싱이 비활성화됩니다.
필요에 따라 사례별로 캐싱을 다시 활성화 할 수 있습니다.
기본값은 true입니다.
12 xmlParsingProtection 웹 응용 프로그램 내에서 XML 파일을 구문 분석해도 메모리 누수가 발생하지 않도록 보호를 활성화합니다.

메모리 프로파일러는 이러한 누수와 관련된 GC 루트를 표시하지 않을 수 있으므로 특히 진단하기가 어렵습니다.

기본값은 true입니다. Java 9 이상에서 누수가 수정되었으므로 Java 9 이상에서 실행하는 경우이 보호 기능이 비활성화됩니다.

 

 

Security Lifecycle Listener - org.apache.catalina.security.SecurityListener

Tomcat 이 시작할때 보안을 체크하고, 시작 실패시 보호해주는 역할을 하는 리스너입니다.

기본적으로는 비활성화 되어 있습니다. 활성화를 하기 위해서는 server.xml 파일에서 주석을 풀어주어야 합니다.

Tomcat 8.5.30 이전 버전의 경우 운영 체제가 umask를 지원하면 $CATALINA_HOME/bin/catalina.sh 에서 umask를 얻는 행도 주석 처리를 제거해야합니다. 

Tomcat 8.5.30 이상의 경우 umask가 Tomcat으로 자동 전달됩니다.

No 제목 내용
1 checkedOsUsers Tomcat 시작을 하기위해서 사용될 수 없는 사용자 목록을 컴마(,)로 구분하여 정의합니다. 기본값은 root 입니다.
2 minimumUmask
Tomcat이 시작되기 전에 구성해야하는 최소의 umask 입니다.
지정하지 않으면 기본값 0007 이 사용됩니다.
이 점검을 사용하지 않으려면 속성을 빈 문자열로 설정하십시오.
Windows 플랫폼에서는 점검이 수행되지 않습니다.

 

 

StoreConfig Lifecycle Listener - org.apache.catalina.storeconfig.StoreConfigLifecycleListener

현재 서버에 관련된 설정을 가지고 있는 server.xml 또는 웹 애플리케이션 설정을 가지고 있는 context.xml 파일의 설정을 저장해두기 위한 StoreConfig MBean을 구성합니다.

No 제목 내용
1 storeConfigClass IStoreConfig를 구현하여 사용할 클래스의 이름입니다.
기본값으로는 org.apache.catalina.storeconfig.StoreConfig가 사용됩니다.
2 storeRegistry
IStoreConfig가 설정값을 저장하는 방법을 정의하고있는 설정파일의 URL입니다.
지정하지 않으면 /org/apache/catalina/storeconfig/server-registry.xml 파일이 사용됩니다.

 

 

ThreadLocal Leak Prevention Listener - org.apache.catalina.core.ThreadLocalLeakPreventionListener

스레드 로컬 관련 메모리 누수를 피하기 위해 컨텍스트가 중지 된 경우, Executor 풀에서 스레드의 갱신을 트리거합니다.

작업을 실행 한 후 풀로 돌아 오면 활성 스레드가 하나씩 갱신됩니다.

갱신은 renewThreadsWhenStoppingContext 속성이 true로 설정된 컨텍스트에 대해서만 발생합니다.

 

 

UserConfig - org.apache.catalina.startup.UserConfig

내용을 입력해 주세요.

UserConfig는 사용자 웹 응용 프로그램의 기능을 제공합니다.

사용자 웹 응용 프로그램은 물결표 문자 ( "~")로 시작하는 요청 URI와, 사용자 이름을 서버의 해당 사용자 홈에있는 디렉토리(일반적으로 public_html)에 매핑합니다.

No 제목 내용
1 directoryName 각 사용자 홈 디렉토리 내에서 검색 할 디렉토리 이름입니다.
기본값은 public_html입니다.
2 userClass 사용자 데이터베이스 클래스의 이름입니다.
현재 두개의 사용자데이터베이스가 있습니다.

Unix 시스템에 쓰이는 org.apache.catalina.startup.PasswdUserDatabase 클래스는  /etc/passwd 파일에서 사용자를 정의합니다.

org.apache.catalina.startup.HomesUserDatabase 클래스는 /etc/passwd 파일을 사용하지 않는 서버에서 사용됩니다.
HomesUserDatabase는 지정된 기본 디렉토리에있는 모든 디렉토리를 배치합니다.

3 homeBase 사용자 홈 디렉토리를 포함하는 기본 디렉토리입니다.
org.apache.catalina.startup.HomesUserDatabase를 사용하는 경우에만 유효합니다.
4 allow 배포가 가능한 사용자를 정규표현식으로 정의합니다.
정의하지 않을 시, 모든 사용자가 배포할 수 있습니다.
5 deny 배포가 거부된 사용자를 정규표현식으로 정의합니다.
정의하지 않을 시, allow 속성 기준으로 제한합니다.

 

 

Version Logging Lifecycle Listener - org.apache.catalina.startup.VersionLoggerListener

JAVA와 운영중인 시스템의 정보를 기록합니다.

이 리스너는 맨 첫번째로 정의되어야 합니다. 즉, 리스너들 중에 제일 상단에 정의해주어야합니다.

No 제목 내용
1 logArgs Tomcat이 시작될 때 Java로 전달 된 명령 행 인수가 기록됩니다.
지정하지 않으면 기본값 인 true가 사용됩니다.
2 logEnv Tomcat이 시작될 때 현재 환경 변수가 기록됩니다.
지정하지 않으면 기본값 인 false가 사용됩니다.
3 logProps 현재 Java 시스템 특성이 기록됩니다. 
지정하지 않으면 기본값 인 false가 사용됩니다.

 

 

1.2 GlobalNamingResources

일반적으로, 보안을 위해서 데이터베이스의 접속 정보를 Tomcat 서버에 저장해두고, 접근권한을 막아버리는 형태로 사용합니다.

프로젝트에 접속정보가 없고, 톰캣 폴더 안에 있기 때문에 보안에 유리합니다.

하지만 요즘에는 Spring Cloud Config 라는 별도의 설정정보를 관리하는 서버를 사용할 수 있도록 제공하고 있기 때문에, 스프링 최신버전이나 스프링 부트를 사용하시는 분들에게는 한번 고려해볼만한 기술인 것 같습니다.

 

데이터베이스 접속정보와 같은 보안에 민감한 정보를 사용하기에 가장 일반적인 방법인 Tomcat 서버측에 관리하는 방법은 아래와 같습니다. name 값으로 리소스 태그를 구분합니다.

driverClassName, url, username, password ... 등의 속성을 통해서 데이터베이스 접속 정보를 정의합니다.

 

[ 파일명 : tomcat/conf/server.xml ]

데이터베이스의 접속 정보를 Resource 태그로 정의합니다. 키 값은 name 값으로 구분합니다.

<GlobalNamingResources>
  <Resource 
    name="jdbc/MyDB" 
    auth="Container"
    type="javax.sql.DataSource" 
    driverClassName="org.postgresql.Driver"
    url="jdbc:postgresql://localhost:5432/postgres"
    username="knowonebyone" 
    password="knowonebyone1234" 
    maxTotal="20" 
    maxIdle="10" 
    maxWaitMillis="-1"/>
</GlobalNamingResources>

 

[ 파일명 : tomcat/conf/context.xml ]

Resource 태그로 정의해둔 리소스를 Context에 링크를 통해 등록해줍니다.

이때 name 값과 global 값을 Resource 태그의 값과 동일하게 입력해줍니다.

<Context>
  <ResourceLink 
    global="jdbc/MyDB" 
    name="jdbc/MyDB" 
    type="javax.sql.DataSource"/>
</Context>

 

[ 파일명 : project/**/web.xml ]

프로젝트에서 Tomcat 서버 컨텍스트의 리소스를 사용하기 위해, 아래와 같이 name 값과 부가정보를 등록해줍니다.

<resource-ref> 
  <description>test</description> 
  <res-ref-name>jdbc/testdb</res-ref-name> 
  <res-type>javax.sql.DataSource</res-type> 
  <res-auth>Container</res-auth> 
</resource-ref>

 

[ 파일명 : project/**/database-context.xml ]

위에서 등록해둔 리소스의 위치를 참조하여 불러온 데이터를 아래와 같이 데이터베이스 연결 파라미터로 사용합니다.

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
	<property name="jndiName">
		<value>java:comp/env/jdbc/MyDB</value>
	</property>
</bean>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="configLocation" value="classpath:mybatis-config.xml" />
  <property name="mapperLocations" value="classpath:mapper/*.xml" />
  <property name="dataSource" ref="dataSource"/>
</bean>

 

위와같이 4개의 파일을 수정하여 JNDI 파라미터를 가지고 데이터베이스에 연결할 수 있습니다.

개발을 하는 경우에는 쓰지 않는 방식이며, 배포를 하는 경우에 해당하는 Tomcat의 설정을 변경하여 사용합니다.

 

 

LIST