[CentOS 7] step5. 서비스 설정 2014-09-02

1. Database

> MySQL 또는 MariaDB, MongoDB 기반 서비스를 설정한다.

>>> MySQL or MariaDB
## root 암호 등록
mysqladmin -u root password "[PASSWORD]"
## 개발 디비 생성
mysql -u root -p [PASSWORD]
create database {생성할 디비명} collate 'utf8_general_ci';
## 개발 디비 사용자 생성
create user '[ID]'@'localhost' identified by '[PASSWORD]';
grant all privileges on {생성할 디비명}.* to '[ID]'@'localhost';
flush privileges;
## 개발 디비 외부접근 사용자 생성
create user '[ID]'@'{접속할IP}' identified by '[PASSWORD]';
grant all privileges on {생성할 디비명}.* to '[ID]'@'{접속할IP}';
flush privileges;
>>>>>> description
– 개발에 사용할 디비 생성시 꼭 사용자를 따로 생성하여 권한을 부여
>>> MongoDB
## 관리자 계정 생성
mongo
use {사용할디비명}
db.createUser( { "user" : "[ID]","pwd": "[PASSWORD]", roles: [ "readWrite", "dbAdmin" ]})
show users
exit
## 인증 후 디비접속이 가능하도록 설정
vi /etc/mongod.conf
service mongod restart
## 개발 디비 생성
use {생성할 디비명}
## 개발 디비 사용자 생성
db.createUser( { "user" : "[ID]","pwd": "[PASSWORD]", roles: [ "readWrite" ]})
## 사용자 로그인
db.auth({"user" : "[ID]","pwd": "[PASSWORD]"});
## 사용자 비번 변경
db.changeUserPassword("[ID]", "[PASSWORD]")
## /etc/mongod.conf
auth=true
httpinterface=true
>>>>>> description
– 기본설치시 로그인 과정없이 디비에 접속됨
– 개발에 사용할 디비 생성시 꼭 사용자를 따로 생성하여 권한을 부여

2. Cache

> Redis, Memcached 기반 서비스를 설정한다.

>>> REDIS
vi /etc/redis.conf
## REDIS를 데몬으로 실행
daemonize yes
## REDIS를 PASSWORD인증 후 실행
requirepass {PASSWORD}
>>>>>> description
– REDIS는 지속성이 보장됨.(database로 활용이 가능)
– RDB, AOF의 두가지 형태의 데이터베이스로 활용 가능
– 데이터베이스로 활용시 REPLICATION 구성이 가능
>>> MEMCACHED
vi /etc/sysconfig/memcached
OPTIONS="-l {접속허용IP}"
>>>>>> description
– 인증기능 및 지속성을 제공하지 않음
– IP로 접속을 제한할 수 있음

3. World Wide Web

> JSP(Java server page) 또는 PHP(Personal Hypertext Preprocessor) 기반으로 웹서비스를 설정한다.

>>> JSP : Apache + Tomcat
## 연동설정 : mod_jk 설치
#### -- connector 다운로드
cd /usr/local/src
wget http://server.opendocs.co.kr/tomcat-connectors-1.2.40-src.tar.gz
#### -- 컴파일 & 설치
tar -xvf tomcat-connectors-1.2.40-src.tar.gz
cd tomcat-connectors-1.2.40-src/native
./configure -with-apxs=/usr/bin/apxs
make
make install
#### -- 공통 설정
vi /etc/httpd/conf.modules.d/00-base.conf
vi /etc/httpd/conf/httpd.conf
vi /etc/httpd/conf.d/mod_jk.conf
vi /etc/httpd/conf/workers.properties
#### -- 프로젝트 폴더 생성
mkdir /var/www/{PROJECT_NAME}-api
#### -- manager 복사
cp -R /usr/local/apache-tomcat-8.0.21/webapps/manager /var/www/{PROJECT_NAME}-api
#### -- apache 호스트 설정(conf.d 폴더의 전체 파일은 자동 인클루드됨)
vi /etc/httpd/conf.d/{PROJECT_NAME}.conf
#### -- tomcat 호스트 설정
vi /usr/local/apache-tomcat-8.0.21/conf/server.xml
vi /usr/local/apache-tomcat-8.0.21/conf/Catalina/localhost/ROOT.xml
#### -- manager 설정
vi /usr/local/apache-tomcat-8.0.21/conf/tomcat-users.xml
## 공통 : /etc/httpd/conf.modules.d/00-base.conf
LoadModule jk_module modules/mod_jk.so
## 공통 : /etc/httpd/conf/httpd.conf
DirectoryIndex index.jsp
## 공통 : /etc/httpd/conf.d/mod_jk.conf
<IfModule jk_module>
     JkWorkersFile /etc/httpd/conf/workers.properties
     JkShmFile /var/log/httpd/mod_jk.shm
     JkLogFile /var/log/httpd/mod_jk.log
     JkLogLevel info
     JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"
</ifModule>
## 공통 : /etc/httpd/conf/workers.properties
worker.list={PROJECT_NAME_1}, {PROJECT_NAME_2},...
#### 포트번호는 server.xml 파일의 AJP/1.3 프로토콜 컨넥터와 일치 시킴
worker.{PROJECT_NAME_1}.port=8009
worker.{PROJECT_NAME_1}.host={localhost or 외부서버IP}
worker.{PROJECT_NAME_1}.type=ajp13
worker.{PROJECT_NAME_1}.lbfactor=20
worker.{PROJECT_NAME_2}...
## 프로젝트별 : /etc/httpd/conf.d/{PROJECT_NAME}.conf
#### {PROJECT_NAME}-api
<VirtualHost *:80>
     DocumentRoot /var/www/{PROJECT_NAME}-api
     ServerName api.{PROJECT_DOMAIN}
     JkMount /* {PROJECT_NAME_1}
     ErrorLog logs/error_log_{PROJECT_NAME}-api
     CustomLog logs/access_log_{PROJECT_NAME}-api common
     <Directory "/var/www/{PROJECT_NAME}-api">
          AllowOverride All
          Order Allow,Deny
          Allow From All
     </Directory>
</VirtualHost>
## /usr/local/apache-tomcat-8.0.21/conf/server.xml
<Engine name="Catalina">
   <Host name="api.{PROJECT_DOMAIN}"  appBase="/var/www/{PROJECT_NAME}-api" unpackWARs="true" autoDeploy="true">
      <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
            prefix="access_log_{PROJECT_NAME}-api." suffix=".txt"
            pattern="%h %l %u %t &quot;%r&quot; %s %b" />
   </Host>
</Engine>
## /usr/local/apache-tomcat-8.0.21/conf/Catalina/{localhost or 외부서버IP}/ROOT.xml
<?xml version='1.0' encoding='utf-8'?>
<!-- default virtual host\ROOT -->
<Context path="/" docBase="" reloadable="true">
</Context>
## /usr/local/apache-tomcat-8.0.21/conf/tomcat-users.xml
<tomcat-users>
   <role rolename="manager-script"/>
   <role rolename="manager-gui"/>
   <role rolename="manager-jmx"/>
   <role rolename="manager-status"/>
   <user username="manager" password="xxxxxxxxx" roles="manager-script,manager-gui,manager-jmx,manager-status"/>
</tomcat-users>
>>>>>> description
– 연동이 필요한 이유
==> Tomcat은 서블릿 컨테이너의 역할만 하고 Apache는 웹서버의 역할을 하여 기능을 분리
==> Apache에서 제공하는 편리한 기능을 사용할 수 있음
==> 부하 분산의 효과를 가질 수 있음(mod_jk의 Load Balancing과 FailOver기능을 사용)
– 연동에는 세가지 방법이 있다
==> mod_jk : 가장 많이 사용하므로 자료가 많고 유연한 설정이 가능 하나 톰캣에서만 사용이 가능함
==> mod_proxy or mod_proxy_ajp : 별도 설치가 필요없어 설치 및 설정이 간편하고 특정 WAS에 의존적이지 않음
– TOMCAT에서 제공하는 관리기능을 활용하면 배포, 상태 확인 등을 편리하게 할 수 있다. ({MANAGER_DOMAIN} 연결)
>>> PHP : Apache + PHP
#### -- 아파치 설정
vi /etc/httpd/conf.d/{PROJECT_NAME}.conf
#### -- PHP 설정
vi /etc/php.ini
## /etc/httpd/conf.d/{PROJECT_NAME}.conf
<VirtualHost *:80>
     DocumentRoot /var/www/{PROJECT_NAME}
     ServerName {HOSTNAME}
     ErrorLog logs/error_log_{PROJECT_NAME}
     CustomLog logs/access_log_{PROJECT_NAME} common
     <Directory "/var/www/{PROJECT_NAME}">
          AllowOverride All
          Order allow,deny
          Allow from all
     </Directory>
</VirtualHost>
## /etc/php.ini
#### <? 에 php 없이 설정 : 개발편의성
short_open_tag = On
#### timezone 설정
date.timezone = Asia/Seoul
>>>>>> description
– 프로젝트의 필요성에 따라 apache에서 제공하는 많은 모듈들을 적절히 활용할 수 있음
>>> NodeJS : Apache + NodeJS
## 시작 / 종료 / 재시작 스크립트 작성
vi /etc/init.d/{PROJECT_NAME}
## 실행권한 변경
chmod 755 /etc/init.d/{PROJECT_NAME}
## 시작시 자동실행
chkconfig --add {PROJECT_NAME}
chkconfig --level 234 {PROJECT_NAME} on
## 서비스 시작
service {PROJECT_NAME} start
## /etc/init.d/{PROJECT_NAME}
#!/bin/bash
# description: {PROJECT_NAME} Start Stop Restart
# processname: {PROJECT_NAME}
# chkconfig: 234 20 80 

case $1 in
start)
# 시작
forever start -a -l forever.log -o out.log -e err.log /var/www/{PROJECT_NAME}/app.js
;;
stop)
# 종료
forever stop /var/www/{PROJECT_NAME}/app.js
;;
restart)
# 재시작
forever stop /var/www/{PROJECT_NAME}/app.js
forever start -a -l forever.log -o out.log -e err.log /var/www/{PROJECT_NAME}/app.js
;;
esac
exit 0
>>>>>> description
– nodejs의 경우 오류 발생시 프로세스가 바로 죽게됨
– forever 모듈을 사용하여 운영함

[CentOS 7] step4. 보안 설정 2014-09-01

1. 방화벽 설정

> 방화벽 역할을 하는 장비가 없다면 리눅스 iptables을 활용하여 구축해야한다.

>>> 설치
yum -y install iptables
chkconfig iptables on
service iptables start
>>>>>> description
– iptables : 프로토콜의 상태 추적, 패킷 애플리케이션 계층검사, 속도 제한, 필터링 정책을 명시하기 위한 매커니즘을 제공한다.
– 기본적으로 설치되어 있으나 그렇지 않다면 위와 같이 설치한다.
>>> 설정확인
iptables -L -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
 104K   21M ACCEPT     all  --  any    any     anywhere             anywhere            state RELATED,ESTABLISHED
    0     0 ACCEPT     icmp --  any    any     anywhere             anywhere
 8799  530K ACCEPT     all  --  lo     any     anywhere             anywhere
    1    52 ACCEPT     tcp  --  any    any     anywhere             anywhere            state NEW tcp dpt:ssh
...
 2018  204K REJECT     all  --  any    any     anywhere             anywhere            reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 REJECT     all  --  any    any     anywhere             anywhere            reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT 114K packets, 20M bytes)
 pkts bytes target     prot opt in     out     source               destination

>>>>>> description
> Chain(체인) : 패킷을 구분
— INPUT : 호스트를 향한 모든 패킷
— OUTPUT : 호스트에서 발생하는 모든 패킷
— FORWARD : 라우트로 사용되는 호스트를 통과하는 패킷
> Match(매치) : 패킷의 조건
–source (-s) : 출발지 IP주소나 네트워크와의 매칭
–destination (-d) : 목적지 ip주소나 네트워크와의 매칭
–protocol (-p) : 특정 프로토콜과의 매칭
–in-interface (i) : 입력 인테페이스
–out-interface (-o) : 출력 인터페이스
–state : 연결 상태와의 매칭
–string : 애플리케이션 계층 데이터 바이트 순서와의 매칭
–comment : 커널 메모리 내의 규칙과 연계되는 최대 256바이트 주석
–syn (-y) : SYN 패킷을 허용하지 않는다.
–fragment (-f) : 두 번째 이후의 조각에 대해서 규칙을 명시한다.
–table (-t) : 처리될 테이블
–jump (-j) : 규칙에 맞는 패킷을 어떻게 처리할 것인가를 명시한다.
–match (-m) : 특정 모듈과의 매치
> Target(타겟) : 패킷을 처리하는 방식
— ACCEPT : 패킷을 받아들임
— DROP : 패킷을 버림(전송되지 않은 것으로 처리)
— REJECT : 패킷을 버리고 적절한 응답제공
— LOG : 패킷을 syslog에 기록
— RETURN : 호출 체인 내에서 패킷처리 계속
> Connection Tracking(연결 추적) : 연결 상태에 따른 패킷 제어
— NEW : 새로운 연결을 요청하는 패킷
— ESTABLISHED : 기존 연결의 일부패킷
— RELATED : 기존 연결에 속하지만 새로운 연결을 요청하는 패킷
— INVALID : 어떤 연결에도 속하지 않는 패킷
>>> 설정
iptables {옵션} {설정값}
>>>>>> description
-A (–append) : 새로운 규칙을 추가
-D (–delete) : 규칙을 삭제
-C (–check) : 패킷을 테스트
-R (–replace) : 새로운 규칙으로 교체
-I (–insert) : 새로운 규칙을 삽입
-L (–list) : 규칙을 출력
-F (–flush) : chain으로부터 규칙을 모두 삭제
-Z (–zero) : 모든 chain의 패킷과 바이트 카운터 값을 0으로 만듬
-N (–new) : 새로운 chain을 만듬
-X (–delete-chain) : chain을 삭제
-P (–policy) : 기본정책을 변경
>>> 설정예제
# CentOS 7 미만
iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
service iptables restart
# CentOS 7 이상
firewall-cmd --zone=public --permanent --add-port=80/tcp
firewall-cmd --reload
>>>>>> description
– CentOS 7 이상부터 iptables 가 firewall-cmd로 대체 되었다
– 기존과 동일하게 사용하기 위해서는 firewall을 제거 하고 iptables-services를 설치

2. SSH 보안설정

> 서버 접속에 대한 보안룰을 적용한다.

## 루트 로그인 방지를 위한 일반관리계정 추가
useradd -G wheel admin
passwd admin
## 일반관리계정에 root 계정 권한 부여
chmod 600 /etc/sudoers
vi /etc/sudoers
## SSH 접속 제한설정
vi /etc/ssh/sshd_config
# /etc/sudoers : 다음내용 주석해제
%wheel        ALL=(ALL)       NOPASSWD: ALL
# /etc/ssh/sshd_config
## 접속포트 변경 : 22번이 아닌 다른포트
Port {포트번호}
## 인증없이 서버로 접속하는 rhost를 금지
IgnoreRhosts yes
## root로 직접로그인 금지
PermitRootLogin no
## wheel 그룹만 로그인가능
AllowGroups wheel
### 특정 계정 또는 그룹에 대해서 접속을 허용 또는 거부
AllowGroups {그룹}
AllowUser {계정}
DenyGroups {그룹}
DenyUser {계정}
## 서비스 재시작
service sshd restart
## 서비스 재시작 : CentOS 7 이상
systemctl restart sshd.service
>>>>>> description
– root로 직접로그인 하지 못하도록하여 비정상적인 접근시 복잡도를 증가시킴
– 시스템 운영의 중요한 부분은 wheel그룹만 가능토록함

3. 퍼미션 설정

> 보안에 문제가 될 수 있는 명령어는 root계정 또는 wheel그룹에게만 권한을 부여한다.

## 컴파일러 퍼미션 변경
chmod 100 /usr/bin/gcc /usr/bin/g++
chattr +i /usr/bin/gcc /usr/bin/g++
## su명령은 wheel그룹만 가능
chown root.wheel /bin/su
chmod 4750 /bin/su
chattr +i /bin/su
## 기타 명령 퍼미션 변경
chmod 750 /usr/sbin/useradd
chmod 750 /usr/bin/top
chmod 750 /sbin/fdisk
chmod 750 /sbin/mkfs*
chmod 750 /sbin/fsck*
>>>>>> description
– 퍼미션 변경으로 기본적인 보안이 가능

4. SELInux(Security-Enhanced Linux) 설정

> 보안정책이 적용되면 다음과 같은 문제점이 발생하는데 사용하지 않도록 설정(setenforce 0)한다기 보다 정책에 맞추어 설정하여 운영할 수 있도록 한다.

## [ERROR 1] apache 실행시 에러가 발생한다.
Starting httpd: (13)Permission denied: make_sock: could not bind to address [::]:88
(13)Permission denied: make_sock: could not bind to address 0.0.0.0:88
no listening sockets available, shutting down
Unable to open logs
                                                           [FAILED]
## [ERROR 1 - 해결]
### 88번 포트는 SELinux 정책에서는 기본적으로 허용하지 않는포트이다.
yum -y install policycoreutils-python
semanage port -a -t http_port_t -p tcp 88
>>>>>> description
– SELinux에서 기본적으로 허용하는 포트는 다음 8개포트 이다.
==> 80, 81, 443, 488, 8008, 8009, 8443, 9000

[CentOS 7] step3-3. 웹서버 설치 2014-08-12

1. 기존 설치된 패키지 제거

> OS에 포함되어 있거나 기존에 쓰던 서버를 활용하는 것이라면 버전 호환성을 위해 제거 후 다시 설치

yum -y remove \
       httpd \
       nginx \
       java*jdk-devel \
       php 
>>>>>> description
– 설치여부 및 버전 확인 : yum list installed httpd* nginx* php* java*jdk-devel

2. APACHE OR NGINX

>>> 설치
## apache
yum -y install --enablerepo=remi,remi-php56 \
       httpd httpd-devel
## nginx
yum -y install --enablerepo=remi,remi-php56 \
       nginx nginx-devel
>>>>>> description
– remi repository를 사용
>>> 시스템 시작시 자동실행설정
## apache
systemctl enable httpd
## nginx
systemctl enable nginx
>>>>>> description
– 서비스는 설정파일 수정 후 시작함. (step5. 서비스 설정)

3. JDK & TOMCAT

>>> jdk 설치 가능여부 확인
yum list --enablerepo=remi java*jdk-devel
>>>>>> description
– 설치가능여부를 확인하고 필요한 버전의 패키지(1.7 or 1.8)를 설치
>>> jdk 설치
yum -y install --enablerepo=remi \
       java-1.8.0-openjdk-devel.x86_64
>>>>>> description
– 의존성 있는 기타 패키지가 함께 설치됨
>>> jdk 설치 확인
java -version
>>>>>> description
– 버전정보가 확인된다면 정상설치된 것임
>>> tomcat7 설치 : yum 설치시 apache-common-collections 버전 충돌로 설치 되지 않는다. 직접 다운받아 설치하도록 한다.
## yum 설치 : 현재기준[2014-09-14] 의존성 에러발생
yum -y install --nogpgcheck \
       tomcat7 tomcat7-admin-webapps tomcat7-webapps
## 다운로드
cd /usr/local/src
wget http://server.opendocs.co.kr/apache-tomcat-8.0.21.tar.gz
## 압축해제
tar xvf apache-tomcat-8.0.21.tar.gz
## 폴더이동
mv apache-tomcat-8.0.21 ../
## 시작 / 종료 / 재시작 스크립트 작성
vi /etc/init.d/tomcat
## 실행권한 변경
chmod 755 /etc/init.d/tomcat
## 시작시 자동실행
chkconfig --add tomcat
chkconfig --level 234 tomcat on
## 서비스 시작
service tomcat start
## /etc/init.d/tomcat
#!/bin/bash
# description: Tomcat Start Stop Restart
# processname: tomcat
# chkconfig: 234 20 80 

# 환경변수 등록
JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk
export JAVA_HOME
PATH=$JAVA_HOME/bin:$PATH
export PATH
CATALINA_HOME=/usr/local/apache-tomcat-8.0.21

case $1 in
start)
# 시작
sh $CATALINA_HOME/bin/startup.sh
;;
stop)
# 종료
sh $CATALINA_HOME/bin/shutdown.sh
;;
restart)
# 재시작
sh $CATALINA_HOME/bin/shutdown.sh
sh $CATALINA_HOME/bin/startup.sh
;;
esac
exit 0
>>>>>> description
– 단순압축 해제만으로 설치가능
– 운영을 위하여 시작/종료/재시작의 스크립트를 작성

4. PHP

>>> 설치
yum -y install --enablerepo=remi,remi-php56 \
       php php-devel php-pear
>>>>>> description
– remi repository를 사용
– PEAR : 재사용할 수 있는 PHP 컴포넌트를 관리해주는 시스템
– PECL : PHP 확장라이브러리 설치 및 업그레이드 기능을 제공하며 PEAR와 함께 설치됨
>>> 확장라이브러리 설치
yum -y install --enablerepo=remi,remi-php56 \
       php-gd php-mbstring php-mhash \
       php-mcrypt php-bcmath \
       php-mysql php-mysqli
>>>>>> description
– remi repository를 사용
– PHP로 각종 라이브러리를 사용할 수 있도록 설치
>>> PECL을 통한 확장라이브러리 설치 및 충돌해결
## 충돌해결
pecl upgrade igbinary
pecl upgrade memcached redis
## 설치
yum -y install --enablerepo=remi,remi-php56 \
       php-pecl-memcached php-pecl-redis \
       php-pecl-zendopcache php-pecl-xdebug
## 설치시 충돌발생
PHP Warning: PHP Startup: igbinary: Unable to initialize module
PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/redis.so' - /usr/lib64/php/modules/redis.so: undefined symbol: igbinary_unserialize in Unknown on line 0
PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/memcached.so' - /usr/lib64/php/modules/memcached.so: undefined symbol: igbinary_unserialize in Unknown on line 0
>>>>>> description
충돌내용
– 설치된 php컴파일 버전과 라이브러리의 컴파일 버전이 일치하지않음
– PECL로 라이브러리의 컴파일버전을 업그레이드 해야함
>>> yum으로 제공되지 않는 확장라이브러리 설치
## mongoDB 라이브러리 설치
pecl install mongo
vi /etc/php.d/mongo.ini
extension=mongo.so
## svn 라이브러리 설치
pecl install svn
vi /etc/php.d/svn.ini
extension=svn.so
>>>>>> description
– redis, memcached등은 자동으로 ini에 추가되나 mongo, svn의 경우 수동으로 추가해주어야 함
– 다음명령으로 PECL 설치내역 및 버전 확인
pecl list

5. NodeJS

>>> 설치
# 패키지 설치
yum -y install --enablerepo=remi npm nodejs
# 패키지 관리자 업데이트
npm -g update
>>>>>> description
– remi repository를 사용
– NPM(Node Package Manager) : nodejs와 함께 자동 설치됨
>>> 서비스 운영을 위한 패키지 설치
npm -g install supervisor forever
>>>>>> description
– ‘-g’ : 글로벌 옵션을 주어 설치
– supervisor : js 파일 수정시 자동으로 재시작 해줌
– forever : 예외 발생시 데몬이 죽어도 자동으로 재시작(무한 또는 횟수 지정) 해줌
※ 상세 활용법은 별도 문서 작성 [forever], [supervisor]