[Tomcat] (수정) Java File IO Permission Problem / 톰캣 자바 파일 입출력 권한 문제

JSP 혹은 서블릿을 이용해 웹 서버를 개발할 때 파일 입출력 관련 프로그래밍을 해야하는 경우가 있다. 이 때, 출력 파일의 권한을 수정할 때, 수정되지 않는 경우가 있다. 이번 게시글에 작성할

dev-whoan.xyz

위 링크를 통해 확인 부탁드립니다.


톰캣 8.5 버전 이상부터 톰캣 컨텍스트 애플리케이션에서 파일 쓰기 작업을 할 때 정상적으로 안되는 경우가 있다.

톰캣 버전이 올라가면서 시스템 보안을 위한 정책이 추가된건데,  기본적으로 톰캣이 포함된 webapps와 logs 파일에 읽고 쓰기를 지원하고, 다른 경로는 설정을 통해 읽고 쓰기가 가능하게끔 해야한다.

이러한 방법에는 다음과 같은 두 가지 방법을 생각할 수 있다.

1. 톰캣유저 자체의 권한 상승

2. 톰캣 서비스 수정을 통한 IO 경로 추가

1번의 경우 보안상 이유로 패치된것 이기 때문에 추천하지 않고, 따라서 2번을 추천하다.


$ cd /etc/systemd/system/multi-user.target.wants
$ vi /tomcat9.service
     # 여기부터 tomcat9.service File

...

#Security
#제일 하단에 다음과 같이 추가
ReadWritePaths=IO작업을 수행할 경로

ReadWritePaths 옵션을 보면 알겠지만, 톰캣이 파일 IO작업을 할 수 있도록 허용하는 경로를 추가하는 것이다.

[Linux] Apache2 Installation, and Configuration / 아파치2 설치 및 설정

[Linux] Tomcat 9.0 Installation & Configuration / 톰캣 9.0 설치 및 설정

 

[Linux] Tomcat 9.0 Installation & Configuration / 톰캣 9.0 설치 및 설정

https://blog.dev-whoan.xyz/2 위 링크를 통해 Apache2 설치를 마쳤고, 톰캣 연동을 원하거나, 톰캣만 설치하여 웹서버를 운용하고 싶을 때 도움되는 글이다. 톰캣은 아파치재단에서 만든 웹 애플리케이션

blog.dev-whoan.xyz

위 두 게시글에서 아파치 및 톰캣 설치를 알아봤고, 이제는 두개를 연동하고자 한다.

많은 접속자가 발생할 경우 톰캣만으로는 성능이 떨어질 수 있기 때문에 연동을 추천한다.


Tomcat 복제, Tomcat01 생성

기존 톰캣을 곧바로 연동해도 되지만, 이럴 경우 설정이 실패하거나 '톰캣'만으로 서버를 돌려야 할 때 문제가 된다. 그래서 설치한 Tomcat의 사본 Tomcat01을 만들어 Tomcat01을 아파치에 연동한다.

이를 위해 기존에 깔린 tomcat을 그대로 복사하면 된다.

$ cp /etc/default/tomcat9 /etc/default/tomcat01

$ vi /etc/default/tomcat01
    # /etc/default/tomcat01
JAVA_OPTS="-Dlog.nameattach=01  -Djava.awt.headless=true  -Xmx512m -X:+UseconcMarkSweepGC  -Djava.security.egd=file:/dev/./urandom"

cp /etc/init.d/tomcat9 /etc/init.d/tomcat01
    # /etc/init.d/tomcat01
...
set -e
NAME=tomcat01
DESC="Tomcat 01 servlet engine"


$ systemctl daemon-reload
$ cp -a /var/lib/tomcat9 /var/lib/tomcat01
$ cp -a /usr/share/tomcat9 /var/lib/tomcat01

$ cd /var/lib/tomcat01
$ rm /var/lib/tomcat01/conf
$ mkdir conf
$ cp -a /etc/tomcat8/* /var/lib/tomcat01/conf/

$ rm /var/lib/tomcat01/work
$ mkdir work

$ vi /var/lib/tomcat01/conf/server.xml
    # /var/lib/tomcat01/conf/server.xml

<?xml version='1.0' encoding='utf-8'?>
<Server port="포트1" shutdown="SHUTDOWN">
        <Listener className="org.apache.catalina.startup.VersionLoggerListener" /> 
        <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
        <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
        <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

        <Service name="Catalina">
                <Connector port="포트2" protocol="AJP/1.3" redirectPort="443"
                        URIEncoding="UTF-8"
                        maxThreads="1024"
                        maxPostSize="-1"
                />

                <Engine name="Catalina" defaultHost="localhost">
                        <Host name="도메인"  appBase="웹앱 디렉토리"
                                unpackWARs="true" autoDeploy="false"
                                xmlValidation="false" xmlNamespaceAware="false">
                        </Host>
                </Engine>

        </Service>
</Server>

$ /etc/init.d/tomcat01 restart

이 때, 위에 포트1과 포트2로 나뉘어져 있는걸 볼 수 있는데, 다음과 같은 규칙을 가지면 좋다.

포트1=800X   |  포트2=801X

이후 tomcat01이 정상적으로 동작하는지 보면 된다.


Apache2 설정

Tomcat01이 정상적으로 동작한다면 Apache2의 설정을 진행하면 된다.

$ vi /etc/apache2/envvars
    # /etc/apache2/envvars
export APACHE_RUN_USER=tomcat9     #혹은 자신이 설치한 tomcat (복제본 아님)
export APACHE_RUN_GROUP=tomcat9    #혹은 자신이 설치한 tomcat (복제본 아님)

$ vi /etc/apache2/conf-enabled/other-vhosts-acces-log.conf
    # /etc/apache2/conf-enabled/other-vhosts-acces-log.conf
# CustomLog ~     # 주석 처리

$ cd /etc/apache2/sites-available
$ vi 본인이 JSP로 연결할 사이트.conf
    # vi 본인이 JSP로 연결할 사이트.conf
<VirtualHost *:80>
...
    JkMountCopy On
    JkMount /* 워커이름
...
</VirtualHost>

$ apt-get install libapache2-mod-jk
$ vi /etc/apache2/mods-available/jk.conf
    # /etc/apache2/mods-available/jk.conf
JkLogLevel Error
    # 아래 내용 주석 처리
#    <Location /jk-status>
#        # Inside Location we can omit the URL in JkMount
#        JkMount jk-status
#        Order deny,allow
#        Deny from all
#        Allow from 127.0.0.1
#    </Location>
#    <Location /jk-manager>
        # Inside Location we can omit the URL in JkMount
#        JkMount jk-manager
#        Order deny,allow
#        Deny from all
#        Allow from 127.0.0.1
#    </Location>

$ vi /etc/libapache2-mod-jk/workers.properties
worker.list=워커이름

worker.톰캣복사본이름=port=포트2
worker.톰캣복사본이름.host=도메인주소 #특별하지 않으면 localhost를 사용하자
worker.톰캣복사본이름.type=ajp13   # HTTP로 설정할 경우 오류가 발생한다.
worker.톰캣복사본이름.lbfactor=1

worker.워커이름.type=lb
worker.워커이름.balance_workers=톰캣복사본이름

톰캣2에서 환경변수 설정을 통해 아파치 실행 유저를 톰캣 유저로 설정하는건 안해도 되지만, 나는 JSP서버만 이용할것이기 때문에 tomcat9유저로 통일했다.

JSP 서버를 실행하기 위해서는 mod-jk를 사용해야하는데, mod-jk는 아파치 프로토콜을 사용하여 Tomcat 서블릿 컨테이너를 연결하는 모듈이다.

따라서 내가 연결할 사이트에 JkMount를 설정해줘야한다.

mod-jk를 설정하고, 워커 (loadbalancer)를 설정해줘야 하는데, 이는 내 서버의 아이피 주소로 들어오는 연결을 톰캣으로 보내기 위함이다.

따라서 워커가 갖는 host과 port는 tomcat01(톰캣복사본) server.xml에서 설정한 포트와 hostname이 된다.

type의 경우도 server.xml에서 설정한 protocol이 되는데, 아파치와 톰캣은 AJP를 이용해 통신하므로 ajp13으로 해준다. (이 때문에 tomcat복사본의 server.xml의 protocol도 AJP 1.3이다.)

로드 밸런싱(워커 설정)이 끝났으면 아파치 톰캣 재시작으로 확인하면 된다.

$ systemctl stop apache2
$ systemctl stop tomcat8
$ systemctl stop tomcat01
$ systemctl start tomcat01
$ systemctl start apache2

주의할 점은 tomcat9(기존 톰캣)와 tomcat01이 동시에 실행되면 충돌이 일어나기 때문에 항상 기존 tomcat은 프로세스를 종료하도록 하자.

[Linux] Apache2 Installation, and Configuration / 아파치2 설치 및 설정

위 링크를 통해 Apache2 설치를 마쳤고, 톰캣 연동을 원하거나, 톰캣만 설치하여 웹서버를 운용하고 싶을 때 도움되는 글이다.

톰캣은 아파치재단에서 만든 웹 애플리케이션 서버로 JSP, 자바 서블릿이 실행될 수 있는 환경을 제공한다.

Javascript 서버를 구동하는데 Nodejs가 필요한것 처럼 Java 서버를 구동하려면 Tomcat이 필요하다.


Tomcat 9.0 Installation

$ apt-get install openjdk-8-jre-headless
$ apt-get install openjdk-8-jdk
$ apt-get install tomcat9

위 명령을 실행하여 tomcat9을 설치할 수 있다.

톰캣은 Java를 실행시키는 웹서버로 자바 설치도 필요하다. 만약 제대로 설치가 안된다면

$ apt-get update
$ apt-get -y upgrade

를 통해 시스템을 최신 버전으로 유지하자.

윈도우에서 흔히 사용하는 환경변수를 리눅스에서 설정해줄 수 있지만, 안해도 웹서버 유지에 큰 문제는 되지 않는다.

$ vi /etc/profile
    # /etc/profile
JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 # 혹은 설치한 자바 경로
export JAVA_HOME
PATH=$PATH:$JAVA_HOME/bin
CLASSPATH=$CLASSPATH:$JAVA_HOME/lib

이후 톰캣 설정해야하는데, 웹앱 디렉토리 설정은 본 게시글의 하단에서 설명하겠다.

우선 톰캣의 사용 유저와 그룹을 설정하여 해당 유저와 그룹을 통해 프로세스를 관리할 수 있도록 하고, 메모리를 설정해 주자.

$ vi /etc/default/tomcat9
    # /etc/default/tomcat9
TOMCAT8_USER=root
TOMCAT8_GROUP=tomcat9
JAVA_OPTS="-Djava.awt.headless=true -Xmx1024m  -Djava.security.egd=file:/dev/./urandom"

JAVA_OPTS를 설명하자면,

Djava.awt.headless=true

- 리눅스 환경에서 GUI 클래스를 사용할 수 있게 한다.

Xmx1024m

- 최대 JVM이 1024Mb를 가질 수 있다. (Xms는 최소)

Djava.security.egd

- 자바 응용 프로그램은 시작시 난수를 이용해 임의의 값(세션 아이디 같은)을 생성하는데, 리눅스 시스템에서는 난수 생성을 위해서 /dev/urandom을 사용한다. 따라서 해당 경로를 설정해주는 것이다.


/etc/tomcat9/server.xml

이후 웹앱에 대한 설정을 해야한다. server.xml파일을 통해 내가 등록할 웹 앱들을 관리할 수 있다. 많은 옵션들이 존재하지만, 별도로 설정하지 않는다면 다음 설정을 따르길 추천한다.

<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
    <Listener className="org.apache.catalina.startup.VersionLoggerListener" /> 
    <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
    <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
    <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

    <Service name="Catalina">
        <Connector port="웹서버포트" protocol="HTTP/1.1"
            connectionTimeout="20000"
            URIEncoding="UTF-8"
            redirectPort="443" />

        <Engine name="Catalina" defaultHost="localhost">
            <Host name="도메인"  appBase="웹앱경로"
                unpackWARs="true" autoDeploy="false"
                xmlValidation="false" xmlNamespaceAware="false">
            </Host>
        </Engine>
    </Service>
</Server>

여러 포트를 이용하고 싶다면, 여러개의 Connector를 생성해주면 된다. 단, 같은 서비스 내에 여러개의 Connector가 존재하면 오류가 생길 수 있으니, 여러 포트를 이용할 경우 서비스를 여러개 생성하는걸 추천한다.

이후

$ systemctl restart tomcat8
$ systemctl restart tomcat9

둘 중 버전이 맞는걸 통해 잘 실행되는지 확인하면 된다.

웹 서버 공부를 시작할 때 아파치를 빼놓을 수 없고, 흔히 아파치는 PHP, JSP등 웹 애플리케이션을 동작하기 위한 기초적인 웹 서버이다.

Nodejs와도 연동할 수 있는 만큼 웹 개발자로 나아가는 사람이라면 설치는 기본적으로 할 줄 알아야 한다.


아파치를 설치하는 방법은 쉽다.

$ apt-get install apache2

apt를 이용해 install 명령을 날려주면 설치 된다.

문제는 설치 이후에 어떻게 해야 내 컴퓨터로 사람들이 접속할 수 있는지, 그리고 내 도메인을 연결할 수 있는지다.

아파치에서는 해당 아이피에 대해 어떤 webapps 디렉토리로 연결될 지 설정해 주어야 한다. 즉 도메인에 대해 웹 디렉토리를 할당하여, 외부 혹은 내부 사용자가 도메인에 접속을 요청 했을 때, 해당 디렉토리의 webapp 내용을 보여줄 수 있어야 한다.

웹 앱 디렉토리 설정을 들어가기 전에, 내가 사용하고있는 아파치 설정은 다음과 같다.

# /etc/apache2/apache2.conf Timeout 60 KeepAlive On MaxKeepAliveRequests 100

# Timeout : 몇초가 지나면 Timeout을 보낼것인가 ( 초 단위 )
# KeepAlive : Connection에 대해 동일한 연결을 재사용 할 것인지 설정한다. KeepAlive가 꺼져있으면 동일한 요청에 대해 여러 접속이 발생하고, 켜져있으면 한 요청으로 처리하게된다. 하지만 메모리 사용량이 증가하므로(Connection을 갖고 있어야 하기 때문에) 사용 환경에 따라 On Off 하면 될 것 같다.
# MaxKeepAliveRequests : 위 KeepAlive를 몇개까지 허용할 것인지
#KeepAliveTimeout : 얼마만큼의 시간동안 위 KeepAlive를 갖고 있을 것인지 ( 초 단위 )


웹 디렉토리를 설정할 때 내가 사용하는 방법은 다음과 같다.
1. /etc/apache2/apach2.conf 파일 수정
2. /etc/apache2/sites-available 내에 파일 추가
추천하는 방법은 2번이다.
1번에서는 아파치의 기본 설정을 하고, 웹 서버 추가는 2번을 통해 sites를 추가하고, 아파치에 등록함으로써 webapp을 동작시키는 것이다.


/etc/apache2/apache2.conf 파일 수정


위 파일을 열고, "Directory /var/www"를 검색하면 다음과 같은 코드가 있다.

<Directory /var/www/> Options FollowSymLinks AllowOverride All Require all granted </Directory>

아파치를 처음 깔았을 때 보이는 페이지를 해당 코드를 통해 웹서버 등록을 해 주고 있는 것이다.
즉 /var/www로 디렉토리를 변경하면 아파치 설치후 localhost에 접속했을 때 나오는 화면을 볼 수 있다.
우리가 웹 서버를 등록하기 위해서는 위 설정을 따라주면 된다.
Directory 태그를 통해 내가 등록하고자 하는 웹앱을 설정해주면 된다.

<Directory 웹앱경로> DirectoryIndex index.html # 기본 페이지 Options FollowSymLinks # 디렉토리 목록에 대한 설정 AllowOverride All # 접근방식 Require all granted # 접근 권한 </Directory>

웹앱경로: 내가 설정하고자 하는 웹앱의 절대경로이다.
DirectoryIndex: 기본 페이지를 설정한다.
- index.html, index.php, index.jsp 등
Options: 접근제어를 설정할 수 있다. 사용자에게 디렉토리 목록을 보여줄지 말지, SSI를 설정할지 말지 등을 설정한다.
- None, ALL, Indexes, Includes, IncludeNOEXEC, FollowSymLinks, ExecCGI, MultiVIews.
AllowOverride: 접근에 대한 인증을 어떻게 허용할 것인지 설정한다. 즉 연결에 대한 인증을 계속 사용할지, 새로운 연결은 새로운 인증을 할지 등을 설정한다.
- All, AuthConfig, FileInfo, Indexes, Limit, Options 등
Require: 접근 권한을 설정할 수 있다. 모든 접근 허용/거부, 특정 아이피 허용/거부 등을 설정한다.
- all granted, all denied, ip ipv4, not ip ipv4, host hostname, not host hostname


/etc/apache2/sites-available 사이트 추가

1번과는 다르게 2번은 가상호스트를 사용하는 방법이다.
따라서 설정 양식이 다른데, 다음과 같다.

<VirtualHost *:80> ServerName 도메인 주소 DocumentRoot 웹앱 경로 ErrorLog 에러로그 경로 </VirtualHost>

우슨 태그가 VirtualHost이고, 포트도 설정해줘야 한다.
<VirtualHost *:80> : 컴퓨터가 갖고있는 아이피(*)의 80포트 접속을 웹앱으로 설정한다.
ServerName : 아이피(*)중 어떤 도메인 주소 연결을 해당 웹앱으로 받을지 설정한다. 외부 아이피를 줘도 되고, (*)에 적은 아이피를 똑같이 적어줘도 된다.
DocumentRoot : 웹앱 경로
ErrorLog : 에러로그 경로
나는 톰캣 서버를 사용하기 때문에 추가적인 다음 옵션을 사용한다
JkMount /* loadballancer
JkMountCopy On
SSL설정도 사용하고 있어서 http 접속을 https로 Redirect 시켜준다.
Redirect permanent / https://~


이로써 아파치의 기본 설정은 모두 끝났다.

내가 설정한 아이피 주소(도메인)으로 내가 등록해놓은 웹앱이 돌아가는것을 확인할 수 있다. SSL의 경우 추가적인 설정이 필요하기 때문에 나중에 게시할 예정이다.
JSP사용자의 경우 마찬가지로 JkMount, loadbalancer 설정 등이 필요하기 때문에 이 글을 통해 html과 같이 기본적인 페이지만 확인할 수 있다. (따로 플러그인을 사용한다면 그에 맞는 설정만 추가적으로 하면 된다는 말)

한가지 확인해야 할 것은 도메인을 사용중이라면, 도메인 제공자 사이트에서(가비아 등) 해당 도메인에 대해 내 웹서버의 아이피를 설정해줘야 한다.


리눅스 커맨드를 통해 어떻게 하면 되는지 정리하겠다.

$ apt-get install apache2 $ vi /etc/apache2/apache2.conf #여기부터 apache2.conf 파일 KeepAlive On MaxKeepAliveRequests 100 KeepAliveTimeout 5 LogLevel error <Location /WEB-INF> SetHandler WEB-INF Order deny,allow Deny from all </Location> #커맨드 $ vi /etc/apache2/conf-enabled/charset.conf #charset.conf AddDefaultCharset UTF-8 # 아파치의 기본 언어셋을 UTF-8로 설정 #커맨드 $ vi /etc/apache2/sites-available $ vi mywebapp.conf #mywebapp.conf <VirtualHost *:80> ServerName localhost DocumentRoot /myweb/webapps/ROOT ErrorLog /myweb/log/error.log </VirtualHost> #커맨드 $ a2ensite mywebapp $ systemctl restart apache2

+ Recent posts