Rocky Linux - Web Server(HTTP) + Apache tomcat 연결

    이전 포스팅에서는 아파치 톰캣(Apache tomcat)만 설치를 했다면 이번에는 웹 서버 아파치(HTTP)를 연동하여 이용하는 방법을 알아보도록 하겠습니다.

     

    연동 방식은 mod_jk / mod_proxy / mod_prox_ajp 3가지 모듈 방식이 있다고 합니다.

    여기서는 아파치(HTTP)에서 가장 많이 사용하는 mod_jk 이용하여 연동하도록 하겠습니다.


    STEP01 → 아파치 톰캣(Apache Tomcat) 설치

    URL : https://foxydog.tistory.com/79

    필수로 먼저 설치 후에 진행해주시기 바랍니다.

     

     

    STEP02 → 아파치 웹(HTTP) 설치

    [root@localhost ~]# dnf install gcc gcc-c++ httpd-devel

    ※ mod_jk를 설치하기 위해서는 필수 패키지 gcc gcc-c++ 설치되어 있어야 합니다. 록키 OS 설치 시 개발 툴을 선택했다면 기본적으로 패키지 설치가 되어 있습니다. 또한 httpd-devel(개발 버전)으로 설치 진행해주시기 바랍니다.

     

     

    STEP03 → Tomcat Connectors (mod_jk) 다운로드 및 설치

    ※ 패키지로 설치하는 하는 게 아닌 소스(Source)를 직접 다운로드하여 컴파일을 해야 합니다.

     

    3-1 소스 다운

    공식 홈페이지(다운) URL : http://tomcat.apache.org/download-connectors.cgi

    Wget을 이용하여 서버에 다운(인터넷이 불가한 환경은 파일 받은 후 서버에 직접 SFTP 업로드)

    [root@localhost ~]# wget https://mirror.navercorp.com/apache/tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.48-src.tar.gz

    ※ 미러 사이트는 인터넷 접속 환경에 따라 달라질 수 있으므로 꼭 사이트 링크 주소를 확인하시기 바랍니다.

     

    [root@localhost ~]# ll | grep tomcat  (다운 파일 확인)
    -rw-r--r--  1 root root 3665280  7월  3  2020 tomcat-connectors-1.2.48-src.tar.gz

     

    3-2 압축 해제 및 경로 이동

    [root@localhost ~]# tar zxvf tomcat-connectors-1.2.48-src.tar.gz  (압축 해제)

    [root@localhost ~]# cd tomcat-connectors-1.2.48-src/native  (경로 이동)

     

    3-3 컴파일 설치(순서대로)

    [root@localhost native]# ./configure --with-apxs=/usr/bin/apxs

    ※ --with-apxs=/usr/bin/apxs Apache 확장 기능 설치를 도와주는 유틸리티 경로, httpd-devel 패키지를 설치할 경우는 기본적으로 해당 경로(/usr/bin/apxs)에 있습니다. 소스로 설치했다면 해당 파일이 있는 경로를 잡아주면 됩니다.

    [root@localhost native]# make

    [root@localhost native]# make install  (최종)

    ※ 해당 경로(/usr/lib64/httpd/modules/)에도 파일이 생기지만 패키지로 설치한 경로에도 파일이 생성이 됩니다.

    [root@localhost native]# ls -al /etc/httpd/modules/mod_jk.so
    -rwxr-xr-x 1 root root 1985888  8월 23 04:58 /etc/httpd/modules/mod_jk.so  (파일 생성 확인)

     

     

    STEP04 → 아파치(httpd.conf) 설정

    공식 홈페이지 연동 매뉴얼 URL : https://tomcat.apache.org/connectors-doc/webserver_howto/apache.html

    ※ Apache 하위 버전의 경우는 httpd.conf 대체로 파일 하나에 모든 설정을 넣었지만 최신 패키지로 설치할 경우 기능별. conf 파일로 분리하여 인클루드(Include conf.modules.d/*.conf, IncludeOptional conf.d/*.conf) 형태로 불러옵니다. 설정에 익숙해지시면 본인이 원하는 방식대로 설정하시면 됩니다. 설명을 위해 정석대로 진행하겠습니다.

     

    4-1 mod_jk.so 모듈 적용

    [root@localhost ~]# vi /etc/httpd/conf.modules.d/00-base.conf

     

    LoadModule jk_module modules/mod_jk.so  (하단 추가 후 저장)

     

    4-2 가상호스트 설정

    ※ httpd.conf 에 설정을 해도 되지만, 여러 개의 호스트를 설정해야 한다면 구분하기 위해 별도의 파일을 새로 생성하여 관리를 하는 게 좋습니다.

    [root@localhost ~]# vi /etc/httpd/conf.modules.d/httpd-vhost.conf  (파일 새로 생성)

     

    <VirtualHost *:80>
     ServerName localhost

     DocumentRoot "/opt/tomcat/webapps/ROOT"

     <Directory "/opt/tomcat/webapps/ROOT">
              AllowOverride None
              Require all granted
     </Directory>

     DirectoryIndex index.html index.jsp

      JkMount /*.jsp tomcat
      JkMount /*.json tomcat
      JkMount /*.xml tomcat
      JkMount /*.do tomcat
    </VirtualHost>

    □ 추가 설명

    ServerName - 내부 PC에서만 접근할 경우는 127.0.0.1(localhost) 등록하지만 실서버 외부에서 접근할 경우는 서버의 IP 또는 도메인(예: eztest.com)으로 등록하시면 됩니다.

    DocumentRoot - 처음 접근했을 때 가장 먼저 불러오는 문서 경로, 톰캣설치/webapps/ROOT 와 동일하게 맞출 필요가 있습니다.

    Directory - 디렉토리 접근 방식, 아파치 2.4.X 버전 이상은 모든 접근 허용 시 Require all granted 이용

    DirectoryIndex - 처음 접근 했을 때 불러오는 기본 문서 설정, 톰캣의 경우는 기본 문서가 index.jsp를 불러오므로 추가 필요

    JKMount - /(ROOT)의 톰캣에서 가장 많이 쓰이는 jsp/json/xml/do 요청이 들어오면 tomcat(workers.properties 정의)이 그 해당 요청을 톰캣에게 보내는 역할을 합니다. 여기서 연동한다는 의미로 가장 중요한 옵션입니다. /*. jsp에 대한 모든 URL을 톰캣에 보내므로 DocumentRoot와 같은 맥락으로 Apache와 Tomcat의 ROOT 경로를 동일하게 맞추는 이유입니다.

     

    4-3 mod_jk 구성 파일 설정

    아래는 간단한 구성 예제입니다. 필요에 따라 구성이 달라질 수 있습니다. 문서에 있는 지시문을 참고해주시기 바랍니다.

    [root@localhost ~]# vi /etc/httpd/conf.modules.d/mod_jk.conf  (파일 새로 생성)

     

    <IfModule mod_jk.c>
     JkWorkersFile conf/workers.properties
     JkShmFile run/mod_jk.shm
     JkLogFile logs/mod_jk.log
     JkLogLevel info
     JkLogStampFormat "[%y-%m-%d %H:%M:%S.%Q] "
    </IfModule>

    □ 추가 설명

    JkWorkersFile - workers정의 설정 경로, /etc/httpd/conf/workers.properties 형태로 절대 경로로 입력 가능

    JkShmFile - 공유 메모리 파일 위치, Selinux 보안을 사용할 경우는 무조건 run 경로로 설정 필요

    JkLogFile - 로그 생성 경로, 일정 버전 이상일 경우는 로테이션 가능(예시)

    ⊙ "|/usr/bin/rotatelogs /etc/httpd/logs/mod_jk.log 86400"

    JkLogLevel - 로그 레벨 설정

    info(기본값)  가장 기본적인 활동 기록

    error  오류 보고서를 포함한 활동 기록

    debug  가장 높은 레벨로 모든 활동 정보 기록

    JkLogStampFormat - 로그 파일에 있는 날짜/시간 형식 구성

     

    4-4 workers 파일 설정

    ※ mod_jk.conf 파일에서 추가한 JkWorkersFile(workers.properties) 파일 위치에 맞게 설정

    [root@localhost ~]# vi /etc/httpd/conf/workers.properties  (파일 새로 생성)

     

    worker.list=tomcat
    worker.tomcat.port=8009
    worker.tomcat.host=localhost
    worker.tomcat.type=ajp13
    worker.tomcat.lbfactor=1

    □ 추가 설명

    worker.list - worker(톰캣)의 인스턴스 리스트입니다. 이름은 임의로 지정하되, [worker.이름.속성=값]의 형태를 사용해야 합니다.

    worker.list.tomcat.port - Apahce와 Tomcat이 통신하기 위한 포트입니다. 톰캣의(server.xml) 기본 설정 포트를 따라가는 부분으로 변경 가능합니다.

    worker.list.tomcat.host - WEB/WAS가 같은 서버에 설치가 되어 있다면 일반적으로는 내부 통신이므로 127.0.0.1 [localhost]로 설정하지만 분리가 되어 있다면 호스트를 찾을 수 있게 서버의 IP 또는 도메인 주소를 입력

    worker.list.tomcat.type - Apahce와 Tomcat이 통신하기 위한 Protocol(프로토콜) ajp13을 이용

    worker.list.tomcat.lbfactor - 일종의 로드밸런싱 같은 개념으로 1개일 때는 크게 의미가 없으나 2개 이상의 톰캣을 설치하여 운영할 경우 숫자의 비율로 작업을 처리한다는 의미입니다.

    □ 추가 예시(Tomcat 2개 이상 설치하여 운영할 경우)

    worker.list=tomcat1,tomcat2

     

    worker.tomcat1.port=8009
    worker.tomcat1.host=localhost
    worker.tomcat1.type=ajp13
    worker.tomcat1.lbfactor=1

     

    worker.tomcat2.port=8011  (2번째 톰캣-server.xml 설정에서 동일하게 포트 변경)
    worker.tomcat2.host=localhost
    worker.tomcat2.type=ajp13
    worker.tomcat2.lbfactor=2

     

    4-5 아파치(httpd.conf) 실행 권한 변경

    ※ 필자는 톰캣(tomcat) 설치 경로의 유저, 그룹 권한이 tomcat으로 되어 있으므로 아파치(httpd) 실행 시 해당 경로에 접근하기 위해서는 실행 권한을 동일하게 맞춰야 합니다. 최근 보안 정책으로 ROOT로 실행하는 것을 권고하지 않음

    [root@localhost ~]# ls -al /opt | grep tomcat  (설치 경로 유저, 그룹 권한 확인)
    drwxr-xr-x   9 tomcat tomcat 4096  8월 17 02:39 tomcat

     

    [root@localhost ~]# vi /etc/httpd/conf/httpd.conf  (유저, 그룹 권한 변경)

    User tomcat  (apache → tocmat)

    Group tomcat  (apache → tocmat)

     

     

    STEP05 → 아파치 톰캣(server.xml) 설정

    [root@localhost ~]# vi /opt/tomcat/conf/server.xml

     

    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector protocol="AJP/1.3"
        address="::1"
        port="8009"

        secretRequired="false"  (추가 등록)
        redirectPort="8443" />

    □ 추가 설명

    공식 문서 참고 URL : https://tomcat.apache.org/tomcat-10.0-doc/config/ajp.html

    ※ AJP프로토콜을 사용하게 되면 HTTP를 통해 Tomcat의 내부 데이터 구조를 직접적으로 조회 및 조작할 수 있으므로 Apache Tomcat 9 버전 이상부터는 추가 보안 고려 사항이 추가됩니다. 옵션 중 address, secret, secretRequired 및 allowedRequestAttributesPattern 등을 설정을 해야 정상적으로 연동이 가능합니다.

     

    secretRequired - 설정하지 않으면 기본값이 true 되어 있습니다. 즉, 기본적으로 보안(SSL) 응답 요청을 하기 때문에 address, secret 설정이 없다면 HTTP ▷ Tomcat 웹 연결 시 넘어가지 못하고 무한 로딩 상태가 됩니다. 저는 테스트를 위해 또는 기본 내부 네트워크(신뢰할 수 있는 네트워크) 환경이라면 "false" 옵션을 무조건 줘야 합니다.

     

    address - IP 주소가 두 개 이상인 서버의 경우 이 속성은 지정된 포트에서 수신 대기하는 데 사용할 주소를 지정. 기본적으로 커넥터는 루프백 주소에서 수신 대기합니다. 별다른 시스템 속성을 사용하지 않을 경우 기본 커넥터로 address="0.0.0.0"으로 구성하며 IPv4/IPv6 주소 모두에서 수신 대기합니다. 저의 경우는 최신 톰캣 10 버전으로 설치를 했으며 기본적으로 address="::1" IPv6로 값이 들어가 있는데 저 값이 IPv4의 127.0.0.1(Localhost)과 로컬 통신과 같은 의미로 수정할 필요는 없습니다.

     

    secret - 기본값이 NULL 상태로 secretRequired가 명시적으로 구성되지 않는 한 값으로 지정되어야 처리가 됩니다. 값으로 구성된 경우는 세팅 시 Apache와 Tomcat 같은 보안 키가 일치해야 하며 그렇지 않으면 secretRequired 설정에 관계없이 요청이 거부가 됩니다.

     

    ◎ 사용 예시

    [root@localhost ~]# vi /etc/httpd/conf/workers.properties  (worker 설정)

     

    worker.list=tomcat
    worker.tomcat.port=8009
    worker.tomcat.host=localhost
    worker.tomcat.type=ajp13
    worker.tomcat.lbfactor=1
    worker.tomcat.secret=eztest1234  (값을 추가)

    [root@localhost ~]# vi /opt/tomcat/conf/server.xml  (tomcat 설정)

     

        <!-- Define an AJP 1.3 Connector on port 8009 -->
        <Connector protocol="AJP/1.3"
                   address="::1"
                   port="8009"
                   secret="eztest1234"  (worker 설정 값과 동일하게 추가)
                   redirectPort="8443" />

    [root@localhost ~]# systemctl restart httpd  (httpd 재시작)

    [root@localhost ~]# systemctl restart tomcat  (tomcat 재시작)

     

     

    STEP06 → 방화벽 허용

    ※ 80 포트를 통해 접속 톰캣 접속을 해야 하므로 Firewall 방화벽에 추가 허용하도록 하겠습니다.

    [root@localhost ~]# firewall-cmd --zone=public --permanent --add-port=80/tcp  (추가)

    success

    [root@localhost ~]# firewall-cmd --reload  (실시간 적용)

    success

    [root@localhost ~]# firewall-cmd --list-all | grep ports  (추가 확인)
      ports: 8080/tcp 80/tcp

     

     

    STEP07 → 최종 적용을 위한 서비스 재시작

    [root@localhost ~]# systemctl restart httpd  (아파치 재시작)

    [root@localhost ~]# systemctl restart tomcat  (톰캣 재시작)

     

    ※ Tomcat의 경우는 별도의 Service를 등록하여 사용한 명령어로 일반적으로는 톰캣 설치 경로의 중지 시작 스크립트를 이용

    [root@localhost ~]# /opt/tomcat/bin/shutdown.sh

    [root@localhost ~]# /opt/tomcat/bin/startup.sh

     

    [root@localhost ~]# ps -ef |grep httpd  (아파치 프로세스 구동 확인)

    [root@localhost ~]# ps -ef |grep java  (톰캣 프로세스 구동 확인)

     

     

    STEP08 → 웹 접속 확인 및 로그 확인

    본인 PC 브라우저 URL 입력 http://서버IP

    ▶ :8080 포트 없이 톰캣 기본 페이지가 접속이 된다면 80 포트를 통해 정상적으로 연동이 된다는 것을 확인할 수 있습니다.

    실시간 로그(연동 확인)

    [root@localhost ~]# tail -f /etc/httpd/logs/access_log  (아파치 로그)

    192.168.150.1 - - [25/Aug/2021:02:06:23 -0400] "GET / HTTP/1.1" 200 11143 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36 Edg/92.0.902.78"

     

    [root@localhost ~]# tail -f /opt/tomcat/logs/localhost_access_log.2021-08-25.txt  (톰캣 로그)

    192.168.150.1 - - [25/Aug/2021:02:06:24 -0400] "GET /index.jsp HTTP/1.1" 200 11143


    ★ 트러블 슈팅(Trouble Shooting)

    ① You don't have permission to access this resource. 에러 메시지

    ▷ 원인 : 에러 메시지에도 바로 답이 나와있지만, 해당 파일 시스템에 접근할 권한이 없어 발생하는 문제

    [root@localhost ~]# tail -f /etc/httpd/logs/error_log  (실시간 에러 메시지의 예)

    [Mon Aug 30 21:03:09.658491 2021] [core:error] [pid 3972:tid 140639995893504] (13)Permission denied: [client 192.168.150.1:61815] AH00035: access to / denied (filesystem path '/opt/tomcat/webapps/ROOT') because search permissions are missing on a component of the path

    ▶ 확인 : 아래와 같이 해당 경로 디렉토리 접근 권한이나 소유자 권한 설정에 문제가 없는지 확인

    [root@localhost ~]# ll /opt/tomcat/webapps/ | grep ROOT
    drwxr-x--- (디렉토리 권한)  3 tomcat tomcat (소유자 권한) 4096  8월 17 02:39 ROOT

     

     

    ② The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later. 무한 로딩, 최종 에러 메시지

    ▷ 원인 : Httpd와 Tomcat 연동 실패로 인한 에러, ajp_service 넘기기 위한 통신이 실패했을 경우

    [root@localhost ~]# tail -f /etc/httpd/logs/mod_jk.log  (실시간 에러 메시지의 예)

    [21-08-30 21:47:35.736] [4458:140126009071360] [error] ajp_send_request::jk_ajp_common.c (1724): (tomcat)

    connecting to backend failed. Tomcat is probably not started or is listening on the wrong port (errno=111)

    [root@localhost ~]# tail -f /opt/tomcat/logs/catalina.out  (실시간 에러 메시지의 예)

    ※ Tomcat 카탈리나 로그에서도 마지막 시작 전, 에러 로그를 확인할 수 있습니다.

    30-Aug-2021 21:47:37.662 심각 [main] org.apache.catalina.util.LifecycleBase.handleSubClassException 구성요소 [Connector[AJP/1.3-8009]]을(를) 시작하지 못했습니다.
            org.apache.catalina.LifecycleException: 프로토콜 핸들러 시작 실패

     

    Caused by: java.lang.IllegalArgumentException: AJP 연결자는 secretRequired="true"로 구성되었으나 보안 속성이 널 또 는 ""입니다. 이 조합은 유효하지 않습니다.

    ▶ 확인 : 위에서도 언급했지만 Apache Tomcat 9 버전 이상부터는 보안 고려 사항으로 옵션 중 address, secret,

    secretRequired 필수로 사용을 해야 합니다. 설정하지 않으면 기본적으로 연결을 거부합니다. 설정 방법은 STEP05을 참고하시면 됩니다.

     

    에러 발견 시 추가 예정


    마치며

    기본적인 세팅 방식으로 연결을 진행해보았습니다. 개발 솔루션마다 세팅 및 튜닝 작업이 천차만별이므로 개발자의 경우는 다양한 옵션에 대한 이해도가 필요합니다. 필자도 기존에는 따라 하기만 하다가 직접 세팅을 하여 연동을 해보니 다양한 에러를 접하면서 트러블 슈팅 과정 중에서 많은 공부가 되었습니다. 아직 설명이 부족한 부분은 문서를 참고하여 추가 준비하도록 하겠습니다.

    Designed by JB FACTORY