가끔 접속자가 많은 서버를 운영하다 보면 갑자기 웹 접속이 되지 않거나 접속이 너무 느려 아파치 데몬 개수를 확인해 보면 httpd 가 256개나 떠 있는 경우가 있다. 기본적으로 아파치 웹서버의 경우 MaxClients 가 256으로 설정되어 있어 동시에 256개의 데몬이 뜨게 되면 더 이상의 접속을 받아들이지 않고, 기존의 프로세스가 죽을 때까지 대기한 후 접속이 끊기게 되면 그제서야 접속을 받아들이게 된다. 따라서 동시 접속이 많은 경우에는 이전의 웹 접속이 끊길 때까지 대기를 하여야 하므로 접속 속도가 느린 것처럼 느끼게 되는 것이다. 일반적으로 정상적인 접속의 경우에 256개의 프로세스가 모두 뜨는 경우는 그리 많지 않기에 현재의 상태가 비정상적인 접속인지 여부를 판단하여야 한다. 이를 판단할 수 있는 방법은 netstat –na | grep ES 로 ESTABLISHED 된 연결 상태를 확인하여 클라이언트의 IP 가 정상적인 연결인지 여부를 확인하면 된다. 또는 netstat -na|grep ES|awk '{print $5}'|sort 로 클라이언트의 IP만 따로 Sort 하여 확인하여 보도록 한다. 통상적으로 HTTP 1.1 규약에서부터 적용되기 시작한 KeepAlive 기능을 지정하였을 경우 한 클라이언트 IP 에서 동시에 3-5개정도의 http 프로세스를 생성하므로 한 IP 에서 3-5개 정도의 프로세스를 생성하는 것은 정상적인 현상이다. 비정상적인 접속의 경우에는 아래와 같은 이유가 있을 수 있다.
(1) 서비스 거부 공격(DoS) 의 경우
동시에 서비스할 수 있는 프로세스의 한계가 있다는 점을 악용한 서비스 거부 공격일 가능성이 있다. 이미 한번의 실행으로 100개나 200개등 원하는 만큼의 동시 접속을 맺은 후 이 접속을 끊지 않고 유지할 수 있는 공격 코드가 인터넷상에 공개되어 있다. 그러나 이러한 공격의 경우 공격지의 IP 를 속이기가 매우 어려우므로 netstat 으로 확인 후 비정상적인 접속으로 확인시 해당 IP 를 차단하면 된다.
특정 IP의 라우팅을 차단하는 방법은 아래와 같이 route 를 이용한 방법과 iptables (커널 2.4 이상) 를 이용한 방법 이렇게 두 가지가 있다.
예) 공격지 IP 인 211.40.4.6 으로부터의 라우팅을 차단하는 설정
# route add –host 211.40.4.6 reject
# iptables –A INPUT –s 211.40.4.6 –j DROP
실제 적용되었는지 확인하는 방법은 각각 route –n 과 iptables –L –n 이다.
참고로 TCP SYN Flooding 공격의 경우 SYN 패킷만 대량으로 발송할 뿐 ESTABLISHED 상태가 되지 않으므로TCP SYN Flooding 공격과는 무관하다.
(2) include 를 잘못하여 무한 루프가 돌 경우
요즘에는 php 와 mysql 을 연동하여 많이 사용하고 있는데, 프로그래밍 과정에서의 실수로 php 파일에서 같은 php 파일을 include 하는 경우가 있다. 또는 a.php 파일에서 b.php 파일을 include 하고 b.php 파일에서 다시 a.php 파일을 include 하는 경우도 그러한 경우일 것이다. 이러한 경우에는 무한 루프가 돌게 되어 결국은 아파치 데몬이 금새 Maxclients 에서 지정한 개수로 차 버리게 되는데, 어떤 파일에서 무한 루프가 돌고 있는지 찾기가 힘들다.
따라서 임시로 아래와 같이 include 를 하지 못하도록 차단을 하는 방법이 있다.
# iptables –A INPUT -p tcp -i lo -s xxx.xxx.xxx.xxx --sport 1024:65535 -j DROP
이는 같이 서버내에서 include 시에는 lo (Lookback Interface) 를 통해 sport 가 1024 이후의 high port 를 이용하여 통신한다는 특성을 이용한 것이다. 그러나 이 설정을 하였을 경우 로컬 서버에서 클라이언트 포트를 전혀 사용할 수 없게 되므로 다른 서비스에도 장애가 되기 때문에 임시로만 사용하기 바란다.
또는 ps aux | grep http 로 보이는 프로세스에서 ls –la /proc/pid/ 로 각각의 http 프로세스가 어떤 파일을 참조하고 있는지 일일이 추적하는 방법도 있다.
(예:cwd -> /home/user1/public_html/infinite_loop/)
정상적인 접속의 경우에는 아래와 같이 대처한다.
(1) KeepAlive 옵션 변경
기본값으로 설정되어 있는 KeepAlive On 을 KeepAlive Off 로 변경 후 아파치를 재시작한다. KeepAlive 는 HTTP 1.1 규약에서부터 적용된 것으로 접속 속도에 큰 영향을 준다. KeepAlive 를 Off 로 설정시 다소 접속 속도는 떨어지지만 좀 더 많은 동시 접속을 수용할 수 있다. 따라서 MaxClients 에 도달할 정도로 동시 접속자가 많은 경우에는 KeepAlive 를 Off 로 설정하는 것이 다소 임시 방편이기는 하지만 해결 방법이 될 것이다.
KeepAlive 설정에 대해서는 Hit의 개념과 관련 지어 이해하면 된다. 예를 들어 10개의 이미지 파일을 링크한 HTML 페이지를 로딩시 웹브라우저는 이 HTML 파일을 다운로드하여 클라이언트에서 파싱(parsing) 을 하면서 이미지 파일등이 링크되어 있을 경우 서버에 접속하여 이미지 파일을 요청하는데, KeepAlive 가 On 일 경우에는 한 번 맺은 TCP 연결에 대해 같은 Client IP 에서 접속이 있을 것이라 가정하고 기존의 프로세스가 대기하고 있다가 이후의 접속을 처리하기 때문에 다시 접속을 맺는 절차가 필요 없이 빨리 서비스가 가능하지만, KeepAlive 가 Off 인 경우에는 이미지 파일을 불러올 때마다 매번 세션을 새로 맺고 끊는 과정을 반복하여야 하기 때문에 속도가 느려질 수 밖에 없다. 아파치 홈페이지의 문서에 의하면 많은 이미지 파일이 있는 HTML 문서를 로딩시 KeepAlive 설정에 따라 최고 50%까지 속도 차이가 날 수 있다고 한다. 그렇다고 해서 모든 사이트에서 KeepAlive 를 On 으로 하는 것이 좋은 것이 아니다. 순간적인 동시 접속자는 많지만 한 두 번 검색 후 검색 결과의 링크를 따라 다른 사이트로 빠져 나가는 검색 엔진의 경우에는 KeepAlive 를 Off 로 하는 것이 유리할 것이다. KeepAlive 를 On으로 설정하여 그대로 사용할 경우에는 15초로 설정된 KeepAlive Timeout 을 15초에서 5초 정도로 낮게 설정하는 방법도 있으며 이 값은 자신의 시스템 환경에 맞게 적절히 설정하기 바란다.
(2) 아파치의 MaxClients 조절
기본적으로는 256으로 설정되어 있는 MaxClients 의 한계를 512나 1024 와 같이 적절히 변경한다. 그러나 이 값을 변경하기 위해서는 아파치의 소스를 수정 후 다시 컴파일 하여야 하므로 아파치의 소스 디렉토리에 있는src/include/httpd.h 파일에서 HARD_SERVER_LIMIT 256 로 설정된 값을 512 나 1024로 변경 후 아파치를 재컴파일 하면 된다. 만약 커널 2.2.X 일 경우에는 /usr/src/linux/include/linux/tasks.h 에서 NR_TASKS 와 MAX_TASKS_PER_USER 변수 역시 수정한 후 커널을 재컴파일 해 주어야 하며, 2.4.X 의 경우에는 관련된 커널 제한이 없어졌으므로 아파치만 재컴파일 하면 된다.
그러나 대부분의 사이트에서는 256정도로 설정되어도 충분히 서비스가 가능하므로 무작정 이 값을 크게 늘려 메모리를 낭비할 필요가 없으니 특별한 경우가 아니라면 이 값을 늘리지 않는 것이 좋다.
(3) 추가 아파치 데몬 설정
만약 여러 도메인중 특정 도메인이나 어떠한 사이트내 특정 컨텐츠의 접속이 특별히 많아 같은 서버에 있는 다른 사이트에까지 피해를 주고 있다면 이 부분을 별도로 데몬을 띄워 서비스하는 방법도 있다. 이를테면 한 사이트에서 게시판의 접속이 매우 많다면 기존의 80번 포트외에 8080과 같은 임의의 포트로 작동하는 웹 데몬을 추가로 띄워 이 포트를 통해 접속이 많은 서비스를 담당하게 하는 것이다. 이를 위해서는 기존의 httpd.conf 파일을 httpd8080.conf 와 같이 설정 파일을 복사 후 httpd8080.conf 파일을 아래와 같이 변경하면 된다.
port 80 à port 8080
User nobody à User www
Group nobody à Group www
그리고 /usr/local/apache/bin/httpd –f /usr/local/apache/conf/httpd8080.conf 와 같이 실행하면 8080포트로 작동하는 웹서버 데몬을 추가로 띄우게 되는 것이다. 물론 이때 www 라는 계정은 서버에 생성되어 있어야 하며 Nobody 가 아닌 www 라는 별도의 계정으로 데몬을 작동하는 이유는 한 유저(nobody) 가 생성할 수 있는 프로세스의 한계가 있기 때문이며 커널 2.4.X 에서는 이 제한이 없으므로 Nobody 로 작동해도 관계 없다.
또는 기존의 웹데몬인 httpd 와 파일 이름을 다르게 하여 서로 구별을 쉽게 하기 위해 httpd 대신 httpd8080 등 다른 이름으로 변경하여 실행하여도 좋다.
웹 접속은 http://domain.com:8080/ 으로 하면 되며 이러한 방식으로 8081, 8082, 8083….등의 여러 포트를 띄울 수 있다. 실제로 얼마 전 필자가 운영하는 호스팅 서버에서 특정 사이트의 게시판의 접속이 폭주하여 모든 웹 접속이 느려진 적이 있었는데, 위와 같이 게시판 부분만 따로 떼어 8080 포트로 분리하여 서비스를 하여 문제를 해결한 적도 있다.
(1) 서비스 거부 공격(DoS) 의 경우
동시에 서비스할 수 있는 프로세스의 한계가 있다는 점을 악용한 서비스 거부 공격일 가능성이 있다. 이미 한번의 실행으로 100개나 200개등 원하는 만큼의 동시 접속을 맺은 후 이 접속을 끊지 않고 유지할 수 있는 공격 코드가 인터넷상에 공개되어 있다. 그러나 이러한 공격의 경우 공격지의 IP 를 속이기가 매우 어려우므로 netstat 으로 확인 후 비정상적인 접속으로 확인시 해당 IP 를 차단하면 된다.
특정 IP의 라우팅을 차단하는 방법은 아래와 같이 route 를 이용한 방법과 iptables (커널 2.4 이상) 를 이용한 방법 이렇게 두 가지가 있다.
예) 공격지 IP 인 211.40.4.6 으로부터의 라우팅을 차단하는 설정
# route add –host 211.40.4.6 reject
# iptables –A INPUT –s 211.40.4.6 –j DROP
실제 적용되었는지 확인하는 방법은 각각 route –n 과 iptables –L –n 이다.
참고로 TCP SYN Flooding 공격의 경우 SYN 패킷만 대량으로 발송할 뿐 ESTABLISHED 상태가 되지 않으므로TCP SYN Flooding 공격과는 무관하다.
(2) include 를 잘못하여 무한 루프가 돌 경우
요즘에는 php 와 mysql 을 연동하여 많이 사용하고 있는데, 프로그래밍 과정에서의 실수로 php 파일에서 같은 php 파일을 include 하는 경우가 있다. 또는 a.php 파일에서 b.php 파일을 include 하고 b.php 파일에서 다시 a.php 파일을 include 하는 경우도 그러한 경우일 것이다. 이러한 경우에는 무한 루프가 돌게 되어 결국은 아파치 데몬이 금새 Maxclients 에서 지정한 개수로 차 버리게 되는데, 어떤 파일에서 무한 루프가 돌고 있는지 찾기가 힘들다.
따라서 임시로 아래와 같이 include 를 하지 못하도록 차단을 하는 방법이 있다.
# iptables –A INPUT -p tcp -i lo -s xxx.xxx.xxx.xxx --sport 1024:65535 -j DROP
이는 같이 서버내에서 include 시에는 lo (Lookback Interface) 를 통해 sport 가 1024 이후의 high port 를 이용하여 통신한다는 특성을 이용한 것이다. 그러나 이 설정을 하였을 경우 로컬 서버에서 클라이언트 포트를 전혀 사용할 수 없게 되므로 다른 서비스에도 장애가 되기 때문에 임시로만 사용하기 바란다.
또는 ps aux | grep http 로 보이는 프로세스에서 ls –la /proc/pid/ 로 각각의 http 프로세스가 어떤 파일을 참조하고 있는지 일일이 추적하는 방법도 있다.
(예:cwd -> /home/user1/public_html/infinite_loop/)
정상적인 접속의 경우에는 아래와 같이 대처한다.
(1) KeepAlive 옵션 변경
기본값으로 설정되어 있는 KeepAlive On 을 KeepAlive Off 로 변경 후 아파치를 재시작한다. KeepAlive 는 HTTP 1.1 규약에서부터 적용된 것으로 접속 속도에 큰 영향을 준다. KeepAlive 를 Off 로 설정시 다소 접속 속도는 떨어지지만 좀 더 많은 동시 접속을 수용할 수 있다. 따라서 MaxClients 에 도달할 정도로 동시 접속자가 많은 경우에는 KeepAlive 를 Off 로 설정하는 것이 다소 임시 방편이기는 하지만 해결 방법이 될 것이다.
KeepAlive 설정에 대해서는 Hit의 개념과 관련 지어 이해하면 된다. 예를 들어 10개의 이미지 파일을 링크한 HTML 페이지를 로딩시 웹브라우저는 이 HTML 파일을 다운로드하여 클라이언트에서 파싱(parsing) 을 하면서 이미지 파일등이 링크되어 있을 경우 서버에 접속하여 이미지 파일을 요청하는데, KeepAlive 가 On 일 경우에는 한 번 맺은 TCP 연결에 대해 같은 Client IP 에서 접속이 있을 것이라 가정하고 기존의 프로세스가 대기하고 있다가 이후의 접속을 처리하기 때문에 다시 접속을 맺는 절차가 필요 없이 빨리 서비스가 가능하지만, KeepAlive 가 Off 인 경우에는 이미지 파일을 불러올 때마다 매번 세션을 새로 맺고 끊는 과정을 반복하여야 하기 때문에 속도가 느려질 수 밖에 없다. 아파치 홈페이지의 문서에 의하면 많은 이미지 파일이 있는 HTML 문서를 로딩시 KeepAlive 설정에 따라 최고 50%까지 속도 차이가 날 수 있다고 한다. 그렇다고 해서 모든 사이트에서 KeepAlive 를 On 으로 하는 것이 좋은 것이 아니다. 순간적인 동시 접속자는 많지만 한 두 번 검색 후 검색 결과의 링크를 따라 다른 사이트로 빠져 나가는 검색 엔진의 경우에는 KeepAlive 를 Off 로 하는 것이 유리할 것이다. KeepAlive 를 On으로 설정하여 그대로 사용할 경우에는 15초로 설정된 KeepAlive Timeout 을 15초에서 5초 정도로 낮게 설정하는 방법도 있으며 이 값은 자신의 시스템 환경에 맞게 적절히 설정하기 바란다.
(2) 아파치의 MaxClients 조절
기본적으로는 256으로 설정되어 있는 MaxClients 의 한계를 512나 1024 와 같이 적절히 변경한다. 그러나 이 값을 변경하기 위해서는 아파치의 소스를 수정 후 다시 컴파일 하여야 하므로 아파치의 소스 디렉토리에 있는src/include/httpd.h 파일에서 HARD_SERVER_LIMIT 256 로 설정된 값을 512 나 1024로 변경 후 아파치를 재컴파일 하면 된다. 만약 커널 2.2.X 일 경우에는 /usr/src/linux/include/linux/tasks.h 에서 NR_TASKS 와 MAX_TASKS_PER_USER 변수 역시 수정한 후 커널을 재컴파일 해 주어야 하며, 2.4.X 의 경우에는 관련된 커널 제한이 없어졌으므로 아파치만 재컴파일 하면 된다.
그러나 대부분의 사이트에서는 256정도로 설정되어도 충분히 서비스가 가능하므로 무작정 이 값을 크게 늘려 메모리를 낭비할 필요가 없으니 특별한 경우가 아니라면 이 값을 늘리지 않는 것이 좋다.
(3) 추가 아파치 데몬 설정
만약 여러 도메인중 특정 도메인이나 어떠한 사이트내 특정 컨텐츠의 접속이 특별히 많아 같은 서버에 있는 다른 사이트에까지 피해를 주고 있다면 이 부분을 별도로 데몬을 띄워 서비스하는 방법도 있다. 이를테면 한 사이트에서 게시판의 접속이 매우 많다면 기존의 80번 포트외에 8080과 같은 임의의 포트로 작동하는 웹 데몬을 추가로 띄워 이 포트를 통해 접속이 많은 서비스를 담당하게 하는 것이다. 이를 위해서는 기존의 httpd.conf 파일을 httpd8080.conf 와 같이 설정 파일을 복사 후 httpd8080.conf 파일을 아래와 같이 변경하면 된다.
port 80 à port 8080
User nobody à User www
Group nobody à Group www
그리고 /usr/local/apache/bin/httpd –f /usr/local/apache/conf/httpd8080.conf 와 같이 실행하면 8080포트로 작동하는 웹서버 데몬을 추가로 띄우게 되는 것이다. 물론 이때 www 라는 계정은 서버에 생성되어 있어야 하며 Nobody 가 아닌 www 라는 별도의 계정으로 데몬을 작동하는 이유는 한 유저(nobody) 가 생성할 수 있는 프로세스의 한계가 있기 때문이며 커널 2.4.X 에서는 이 제한이 없으므로 Nobody 로 작동해도 관계 없다.
또는 기존의 웹데몬인 httpd 와 파일 이름을 다르게 하여 서로 구별을 쉽게 하기 위해 httpd 대신 httpd8080 등 다른 이름으로 변경하여 실행하여도 좋다.
웹 접속은 http://domain.com:8080/ 으로 하면 되며 이러한 방식으로 8081, 8082, 8083….등의 여러 포트를 띄울 수 있다. 실제로 얼마 전 필자가 운영하는 호스팅 서버에서 특정 사이트의 게시판의 접속이 폭주하여 모든 웹 접속이 느려진 적이 있었는데, 위와 같이 게시판 부분만 따로 떼어 8080 포트로 분리하여 서비스를 하여 문제를 해결한 적도 있다.