Django 를 많이 사용하면서 많은 서버를 세팅했는데, 한 번도 내 블로그에 정리해 본적이 없는 것 같다. 인터넷에서 많은 정보를 얻어왔는데, 이번에는 나도 다른 사람들에게 도움이 될 수 있도록 이글을 남긴다. 내 경우 사수없이 혼자서 공부해서 세팅한 경우가 많기 때문에 많은 내용들이 공식적인 내용이 아니라 좀 많이 야매이다. 이 점을 좀 고려해서 아래글을 읽기 바란다. 



 일반적으로 개발할 때는 Django 을 테스트 모드로 설정해 자체적인 서버로 동작한다. 지금은 테스트 모드로 동작하는 서버도 멀티프로세스로 동작하는 것 같은데 초장기에는 싱글 프로세스라서 매우 느렸다. (그런데 이게 싱글프로세스 였는지, Eclipse + Pydev 가 멀티 프로세스를 지원하지 않은 것인지 잘 기억이 나지 않는다. ) 그리고 뭣 모르고 그 상태로 상용서비스에 올리기도 했다. 물론 그 서버는 내부 관리 사이트여서 죽어도 크게 문제가 되지 않긴 했다. 


 그리고 나중에 서버에서는 꽤 복잡하게 동작한다는 것을 이해했다. 일반적으로 서비스, daemon 이런 것이 돌아 갈 때는 죽지 않게 하기 위해 실제 코드가 돌아가는 부분은 따로 process 를 생성해서 동작한다. 그래서 그 process 는 죽더라도 메인 process 가 죽지 않아서 계속 돌아갈 수 있도록 한다. 그리고 그 process 도 CPU core 나 하이퍼쓰레드 지원등을 고려해서 여러개 생성한다. 또 main Process 자체가 죽을 수 있으니 서비스로 등록해서 죽지 않도록 하기도 한다. 


우선 리눅스를 다룬적 없다는 가정하여 몇가지 기본 명령어에 대해 설명하겠다. 


1. 퍼미션 유저 그룹

서버의 경우 퍼미션과 유저, 그룹에 대해 민감한 편이다. 서비스가 설치된 폴더는 일반적으로 최소의 퍼미션을 유지하고 유저, 그룹도 최대한 권한이 없어야 한다. 해당 서비스가 돌아갈 때도 따로 유저, 그룹을 설정한다. 일반적으로 Ubuntu 에서는 www-data 를 유저로 www-data 를 그룹으로 설정한다. 


2. ps 명령어

프로세스 검색은 ps 를 통해 확인 한다. 나의 경우 습관적으로 옵션을 aux 까지 붙여 ps -aux 를 하는 편이다. a 옵션은 다른 사용자 프로세스 까지 보여주는 것인데 프로세스를 다른 사용자로 돌리는 경우가 많으므로 필수이다. u는 프로세스 별 유저와 시간을 보여준다. x  옵션은 현재 로그인 한 세션에서 생성된 것 뿐만 아니라 모든 프로세스를 보여준다. 


모든 OS의 콘솔에서 파이프를 이용해 어떤 명령어의 결과를 다른 명령어의 argument 로 이용할 수 있다. 이러한 방식으로 입력을 받는 대표적인 프로그램이 grep 라는 프로그램이다. 

ps aux | grep nginx 

라고 하면 ps aux 의 결과를 입력으로 사용해서 grep 는 ps aux 의 결과 중 nginx 라는 글자가 발견된 라인만 출력하다. 다만 여기서 grep 라는 명령어가 동작하면서 이 것도 다시 ps aux 에 나오게 된다. 그래서 nginx 라는 프로세스가 안돌고 있어도

hanmil 11575 0.0 0.0 15508 1080 pts/1 S+ 23:15 0:00 grep --color=auto nginx

이런식으로 grep 프로세스가 nginx 라는 argument 가 들어간 부분도 보여질 수 있다.


어쩌든 ps aux | grep nginx     하면 nginx 라는 프로세스가 있는지 확인할 수 있다.

이 동작은 프로세스가 동작하는지 확인 뿐만아니라 pid 를 확인 해서 프로세스를 강제로 종료 할 때도 많이 사용된다.


=============

hanmil@ubuntu:~$ ps aux |grep nginx

root      1164  0.0  0.0 125112  1448 ?        Ss   21:56   0:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;

www-data  1165  0.0  0.1 125436  3140 ?        S    21:56   0:00 nginx: worker process

hanmil   11616  0.0  0.0  15508  1092 pts/1    S+   23:23   0:00 grep --color=auto nginx

=============


붉은 색으로 표시한 부분이 pid(process id) 이다. 이 id 를 가지고 프로세스를 강제로 죽일 수 있다.

이를 테면  kill -9 1165     이렇게 할 수 있다.  그런데 이 상황에서는 로그인 한 유저는 hanmil 이고 프로세스 1165는  www-data 라는 유저의 프로세스이기 때문에 해당 프로세스를 죽일 수 없다. 이 때는 sudo 를 이용해서 잠시 root 권한을 가져야 한다. 

그래서  sudo kill -9 1165   이렇게 해야한다.



3. pid 파일

uwsgi 를 설정할 때, pid 을 설정하게 된다. pid 는 프로세스 정보가 담긴 파일이다. 그래서 가끔 pid 파일을 생성하는 데몬을 돌리다가 강제로 죽이면 pid 

파일은 그대로 남아 있는 경우가 있다. 정상적인 종료일 경우 프로그램이 종료되면서 pid 파일을 스스로 삭제해야 하나 강제로 죽이면 이러지 못한다. 그런데 이 상태로 다시 uwsgi 를 실행하면 pid 파일이 남아 있어 프로그램이 중복 실행하는 줄 알고 실행이 안되는 경우가 있다. 이 때는 그냥 pid 파일을 삭제하고 uwsgi 를 실행하면 된다. 



4. apt-get

리눅스에는 구글플레이나 앱스토어 처럼 여러 프로그램을 모아둔 리눅스 프로그램 서버가 있다. 보통 repository 라고 부른다. 이 리포지토리에 저장된 프로그램을 관리하는 명령어가 ubuntu 에서는 apt-get 이고 centos 에서는 yum 이다. 

리포지토리는 기본 저장소가 있고 이 저장소의 여러 mirror 들이 있어 보통 같은 국가에 있는 저장소를 이용한다. 리포지토리 URL들이 저장되는 곳은 /etc/apt/sources.list 이다. 그리고 기본저장소는 안전성을 위해 리눅스 배포판이 처음 만들어 질 때의 버전의 프로그램이 있기 마련이다. 그래서 최신 버전의 프로그램을 받기 위해 기본 저장소가 아닌 저장소를 추가 하기도 한다. 이런 저장소를 PPA(Personal Package Archive) 저장소라고 한다. 

 CentOS 의 경우 이런 PPA 저장소 중에 자주 사용하는 것이 epel, remi 이고 Ubuntu 도 있는데 아직 사용해 본적은  없어서 잘 모르겠다........

 경우에 따라서는 바이너리 프로그램을 바로 설치하기도 하는데 윈도우즈에서 파일 확장자가 .exe 이 듯이 CentOS 계열은 확장자가 .rpm 이고 .deb 파일이다. 


어째든 Ubuntu 에서는 여러 프로그램(nginx, mysql 같은 것들)  apt-get 으로 인터넷으로 바이너리를 다운받아 설치할 수 있다. 

설치를 위해서는  sudo apt-get install 패키지명 ,  삭제를 위해서는 sudo apt-get uninstall 패키지명  이다. 




5. netstat 

프로그램이 잘 돌아가면서 port 를 열고 기다리는지 확인 하는 용도로 사용된다. 

나의 경우 netstat -apt  같이 사용한다. 

a 옵션은 all 을 의미하고 포트를 사용하는 process_id,  t 는 tcp 소켓을 의미한다.


이렇게 할 경우 대기하고 있는 포트들이 보인다. 간혹  0.0.0.0:80  이나 ::80   또는 127.0.0.1:80  이런식으로 표시된다. 127.0.0.1 인 경우 외부에 들어나지 않고 내부에서만 접속 가능한 port 라는 의미이다. 따라서 외부에서 접속해야 하는 경우 절대 127.0.0.1 로 보이면 안된다. 


6. telnet 

예전에 PC 통신 이라는게 있었는데, 이런 서비스들은 telnet 기반의 서비스이다. 이런 telnet 은 윈 포트가 잘 접속되는지 확인 하는 용도로 많이 사용한다.  서버가 리눅스인 경우가 많지만 개발자의 PC는 윈도우즈인 경우가 많다보니 telnet 를 윈도우즈 리눅스에서 같이 사용될 수 있는 telnet 이 사용된다. 윈도우즈의 경우 제어판에 들어가 윈도우즈 기능을 추가해야 할 수도 있다. (이 부분은 인터넷 검색을 하도록...)

telnet 도메인이나ip  포트번호

보통

========

C:\programs\pros\conemu>telnet 1.1.1.1 80

연결 대상 1.1.1.1...호스트에 연결할 수 없습니다. 포트 80: 연결하지 못했습니다.


C:\programs\pros\conemu>

==========

이런 식으로 이용된다. 이 경우 1.1.1.1 이라는 서버의 80 포트로 연결이 안된다는 의미이다. 만일 해당 서버에서 netstat -apt 했을 때 127.0.0.1 이 아니고 그냥 80포트가 열려 있다고 한다면 해당 리눅스 서버에서 방화벽이 오픈되지 않았거나 하나 서버를 사용하는 호스팅에서 제공하는 방화벽이 열리지 않았을 수도 있다. 이런식으로 연결 상태를 확인 하기 위해 telnet 을 많이 이용한다. 





다음에는 실질적인 실질적으로 서버 세팅을 하도록 하겠다. 

  요즘 리눅스 서버를 계속 세팅하고 있었다. 나도 리눅스에 참 익숙하지 않았는데 어느 덧 서버 세팅을 내가 나서서 하고 있게 되었다. 그런데 세팅하다보면 참 검색을 많이하게 된다. 그러면서 또 배우게 되는데 어째든 이렇게 배운 것들에 대해 정리 해 볼까한다. 


 우선 리눅스 쪽을 한 번 정리하고 나서 CentOS에만 적용되는 것을 또 한 번 정리 해 볼까 한다. 리눅스 라고 했지만 대부분 서버를 관리하거나 세팅할 때 사용되는 명령어가 대부분이다. 



일부 설정의 경우 root 권한이나 sudo 를 이용해서 설정해야 한다. 


== nameserver 설정 ==

* nameserver 란 도메인을 IP 로 변경해주는 서버이다. 이런 서버는 자체적으로 구성하기도 하고 인터넷 provider의  nameserver를 사용하기도 하고 구글 DNS 같은 공개형 네임서버도 있다. 간혹 이 서비스가 설정되지 않아 DNS를 통해 접속시 에러가 발생하기도 한다. CentOS를 설치하고 yum을 사용하려고 할 때 안되는 원인중에 하나이다. 아래와 같이 설정할 수 잇다. 8.8.8.8 과 8.8.4.4 는 구글에서 제공하는 nameserver 이다. 

* /etc/resolv.conf 파일 수정

* nameserver 8.8.8.8

  nameserver 8.8.4.4


== hostname과 ip 를 연결하는 파일

* DNS Server 를 설정한다고 해도 이 파일의 우선파일가 높음

vim /etc/hosts 파일을 수정한다.

127.0.0.1   tt.co.kr

tt.co.kr 을 접속하면 127.0.0.1(다시 말해 자기자신)에 접속하게 된다. 


== nslookup ==
 * Domain 과 IP 변환을 확인하는 명령어
  * /etc/hosts 에서 변경한 것은 반영하지 않는다. 



== iptable 설정 ==

 * iptable 은 서버자체의 방화벽이자 네트워크 설정 툴이다. 

 * vim /etc/sysconfig/iptables  에서 설정할 수 있고 그냥 명령어를 통해 바로 설정할 수도 있다. 

 * 아래와 같이 설정한다. 

-A INPUT -m state --state NEW -m tcp -p tcp --dport 20 -j ACCEPT

-A INPUT -m state --state NEW -m tcp -p tcp --dport 21 -j ACCEPT

 * 파일로 설정할 경우 /etc/init.d/iptables restart 로 재시작 시켜준다.



== yum ==

 * CentOS(redhat) 에 있는 패키지 설치툴이다. 이 툴의 최대 장점은 command 창에서 텍스트 모드로 설치할 수 있다는 것이다. 인터넷에서 패키지를 자동으로 다운받아 설치 할 수 있다. 

* 패키지 설치 : yum install 패키지명

* 패키지 삭제 : yum remove 패키지명

* 패키지 업데이트 : yum update 패키지명


== rpm ==

 * yum이 되지 않는 네트워크 환경이나 yum 으로 배포되지 않는 패키지의 경우 rpm 을 이용해야 한다. 

 * 설치 :  rpm -ivh 패키지명

 * 업그레이드 또는 설치를 자동으로 : rpm -Uvh 패키지명

 *  설치된 패키지 확인 :  rpm -qa | grep 패키지명 

  - rpm -qa 를 통해 설치된 패키지를 모두 확인할 수 있지만 grep 를 이용해 하나의 패키지를 


== 소유권 ==

 * 서버를 운영하다보면 소유권 문제로 서비스가 잘 동작하지 않는 문제가 많다. 경우에 따라서 로그파일을 남기는데 권한이 없어 문제가 생기는 경우가 많다. 이 때 사용한다.

chown [-R] [user][:group] target1 [target2 ..]

-R : 하위 디렉토리와 파일의 소유권 모두 변경한다. 가장 많이 사용하는 옵션이다. 

 일반적으로 apache의 사용자와 그룹은  apache.apache 이다.

그래서 


chown -R apache.apache  /home/www/homepage

   같은 식으로 이용할 수 있다. 

http://ko.wikipedia.org/wiki/Chown


== 파일, 디렉토리 권한 ==

 * 서버를 운영하다보면 파일 업로드나 스크립트 파일의 실행 때문에 많이 사용하는 명령어 중 하나이다.  단순 sh 파일일지라도 +x 옵션이 없어서 실행하지 못할 수 있다. 아래와 같은 방법으로 사용한다. 

 * chmod [options] mode[,mode] file1 [file2 ...] 

  -R: 재귀적으로 파일들과 디렉터리들의 모드들을 바꾼다.

 * chmod -R 777 /home/www/upload 

http://ko.wikipedia.org/wiki/Chmod





톰캣 설치에 대한 글을 쓴지 1년이 다 되어가는 이 시점에 톰캣 설정에 대한 글을 쓰게 되내요. 찾아보니 톰캣 6.0도 있던데. 그런데  버전이 높다고 해서 다 좋은 것은 아닌 것 같내요. 버전 6.0에 도전해 봤는데, 실패했습니다. servlet에 대한 설정이 안되어서 포기하서 톰캣 5.5에 만족하기로 했습니다.

 어째든 이번에는 servlet을 위한 톰캣 5.5 설정을 해보겠습니다. jsp의 경우 그냥 하면 되는 것 같은데 servlet을 그냥 시도해봤는데 잘 안되고 설정을 변경해야 하는 것 같군요.

 이 글은 그냥 설정에서 끝나지 않고, HelloWorld 까지 만들어 보는데 까지 해보겠습니다.

우선 servlet을 위한 설정을 해보겠습니다. \conf\web.xml ( 저의 경우 C:\tools\apm\Tomcat 5.5\conf 디렉토리 안에 있내요. 모두 자기 상황에 맞게 디렉토리를 생각하기 바랍니다. )  파일을 수정해야 합니다. 패치된 버전마다 위치가 틀리겠지만 대략 115행에 다음과 같이 주석처리가 되어 있습니다.
==================================
<!--
    <servlet>
        <servlet-name>invoker</servlet-name>
        <servlet-class>
          org.apache.catalina.servlets.InvokerServlet
        </servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>
-->
=================================
여기서 주석처리 기호  <!--  과  --> 를  제거해 줍니다. (제 말을 오해해서 주석된 전체를 지우진 말아주세요.)

대략 366행 쯤에 다음과 같이 주석처리가 되어있습니다.
================================
<!--
    <servlet-mapping>
        <servlet-name>invoker</servlet-name>
        <url-pattern>/servlet/*</url-pattern>
    </servlet-mapping>
-->
==============================
여기서도 주석처리 기호  <!--  과  --> 를  제거해 줍니다.

그러면 설정을 다 되었습니다.

이 다음 이제 HelloWorld 프로그램을 만들어보겠습니다.  \webapps 폴더안에 간단히 Test 라는 폴더를 생성합니다. 이 test라는 폴더명은 자신의 구미에 맞게 써 놓아도 됩니다. 그러나 다음 부터 하는 것은 규정이기 때문에 폴더명을 고치면 안됩니다. 다시 그 안에 WEB-INF 라는 폴더를 생성합니다. 다시 그 안에 classes 이라는 폴더를 생성합니다.
 말이 어렵나요. 결론적으로 이렇게 한다면 \webapps\test\WEB-INF\classes 라는 path가 생성됩니다. 이 안 \webapps\test\WEB-INF 라는 폴더에 \webapps\ROOT\WEB-INF 안에있는  web.xml  파일을 복사해 둡니다.

(대충 눈치 채셨겠지만 내가 원하는 폴더명을 정한 후, 그 안에 일정한 규칙을 갖추어 폴더명을 정합니다. jsp의 경우 이런 복잡한게 필요 없는것 같은데 servlet은 조금 까다롭내요. 약간의 보안을 위해서 이렇게 하는 것 같군요.)




 HelloWorld프로그램의 소스는 examples까지 설치했다면 얻을 수 있습니다. 설치안한 분들을 위해 그 소스를 올립니다.
==========================================
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HelloWorld extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World!</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Hello World!</h1>");
out.println("</body>");
out.println("</html>");
}
}
===========================================
당연히 이 파일을 저장할 때는 HelloWorld.java로 적어야 합니다. 이 파일을 \webapps\test\WEB-INF\classes 안에 둡니다.
그리고 컴파일 합니다. 이 때 환경변수에 classpath가 \Tomcat 5.5\common\lib\servlet-api.jar 설정되어 있어야 합니다. 저의
경우 complile 할 때 옵션에 classpath를 설정하는 방식을 이용했습니다. 그래서
C:\programs\jdk1.5.0_12\bin\javac.exe -classpath "C:\tools\apm\Tomcat 5.5\common\lib\servlet-api.jar" "C:\tools\apm\Tomcat 5.5\webapps\MySample\WEB-INF\classes\HelloServlet.java"
라는 식으로 컴파일 합니다. (굉장히 긴니다. javac.exe가 있는 path 도 설정되어 있지 않기 때문에 이러한 방식을 이용하는데
어차피 acroeditor에서 컴파일하므로 불편한 일은 없습니다. )

이렇게 컴파일하고 나면, 이제 http://localhost:8080/test/servlet/HelloWorld 를 통해

Hello World!


라는 글을 볼수가 있습니다. 물론 tomcat이 작동하고 있어야 가능하겠죠..