오라클 클라우드 프리티어의 제한된 메모리 환경에서 워드프레스를 안정적으로 운영하기 위한 보안 및 관리 방안을 다룹니다. 독립 서버에서 워드프레스 블로그를 운영할 때 발생하는 보안 위협에 대응하기 위한 웹 방화벽의 필요성과 메모리(RAM) 부족을 해결하기 위한 웹서버와 DB서버의 분리 사례를 보여줍니다.
서버의 실제 물리 메모리 점유율을 정확히 파악하기 위해 RSS 대신 PSS 지표를 활용하는 모니터링 쉘 스크립트를 소개합니다. 이는 아파치나 PHP-FPM처럼 공유 메모리를 사용하는 프로세스의 사용량을 정밀하게 측정하여, 저사양 가상 서버에서도 효율적인 자원 관리와 안정적인 서비스 유지를 가능하게 합니다.
오라클 클라우드의 프리티어에서 상시 무료로 제공하는 1 Cpu / 1 GB RAM 스펙의 가상서버(VM)에 워드프레스를 설치해 블로그를 운영하고 있다면 메모리 사용량에 민감할 수 밖에 없다. 게다가 워드프레스와 함께 MySQL이나 MariaDB를 설치했다면 그 가상서버는 수시로 다운될 가능성이 매우 높다.
그나마 필자의 블로그(blogger.pe.kr)는 프리티어 가상서버(VM) 두 대에 웹(워드프레스)와 DB(MariaDB)를 분리하여 설치했기 때문에 안정적으로 운영이 가능한 것이다.
네이버나 티스토리 같은 포털의 블로그 플랫폼이 아닌 독립서버에서 운영되는 블로그(blogger.pe.kr)의 구성이 궁금하다면 다음 포스트를 참고하기 바란다. 최근에 새로 구성한 이미지 캐시서버까지 포함된 구성이다.
블로그 독립의 위험성
필자의 블로그(blogger.pe.kr)는 과거 번영(?)을 누렸었다. 구글 애드센스의 일 방문자 수가 3000을 넘겨 한동안 구글 애드센스의 수익으로 용돈을 제법 챙기기도 했었다.
하지만 포털의 블로그 플랫폼(티스토리, 네이버블로그 등)에서 독립서버로 블로그를 이전하게 되면 검색엔진에 등록된 2차 도메인(blogger.pe.kr)과 포스트의 경로를 그대로 유지하더라도 블로그 플랫폼에서 기본으로 제공해주는 SEO 설정을 독립서버에서는 수동으로 설정해야 하는데 이를 미처 인지하지 못해 SEO 설정을 누락하여 검색순위가 급락했다.
게다가 독립서버에서는 악성봇이나 해킹 시도 차단 등 모든 보안 조치를 직접 해주어야 한다. 이런 저런 보안 조치를 위해 직접 보안설정을 하면서 검색봇이 차단되기도 하고 서비스가 중단되기도 해서 SEO는 더 나빠졌다.
결과 현재는 일 방문자 150을 넘기지 못하는 수준으로 쪼그라 들었지만 그 와중에도 악성 봇과 해킹 시도는 오히려 더 늘어만 갔다.
자체 웹 방화벽의 필요성
SSH 접속과 워드프레스 관리자 페이지 로그인을 시도하는 Brute Force 공격은 물론 웹서버의 취약점을 스캔하는 파일 스캔, SQL 인젝션 공격, XSS 공격 등 웹 해킹 시도와 목적은 알기 어렵지만 무단으로 글을 퍼가거나 읽어가는 크롤러와 봇의 방문은 가히 상상을 초월할 정도다.
네이버나 티스토리에서 블로그를 운영한다면 전혀 신경쓰지 않아도 되는 것들이지만 독립서버에서 블로그를 운영한다면 이런 공격을 모두 직접 차단해야 한다.
사실 취약점만 존재하지 않는다면 이런 공격들을 그대로 몸빵~해도 된다. 오라클 클라우드의 무료 트래픽이 충분히 커버 가능한 용량이기 때문이다. 그리고 2년 이상 그냥 몸빵하며 버텼다. 하지만 DoS 공격으로 인해 서버가 다운된 후 재발을 방지하고 또 언제 새로운 취약점이 발견될지 알 수 없기에 클라우드 플레어와 크라우드섹을 적용하기도 했으나 이런 저런 만족스럽지 않은 부분이 보여 결국 iptable + ipset + fail2ban을 조합한 웹방화벽을 구성하여 해킹 시도를 방어하고 있다.
클라우드 플레어나 크라우드섹으로 돌아갈 일은 없을 듯 하다.
문제는 앞에서도 언급했듯 과연 작은 용량의 프리티어 가상서버가 충분히 버틸 수 있는가 하는 것이다. 하루 1만 정도의 방문자수는 CPU 1개의 웹서버도 충분히 감당할 수 있다. 하지만 1 G Byte의 램은 이야기가 달라진다. 기본적으로 부족한 수치다. 게다가 추가로 설치된 ipset과 fail2ban 그리고 방문자가 늘면서 추가로 실행될 apache2 웹서버와 php-fpm 프로세스가 램을 얼마나 잠식하느냐가 서버의 안정성을 흔들 수 있기 때문이다.
그나마 웹서버와 DB서버를 분리했기에 문제가 없을 것으로 예상하고 있지만 직접 눈으로 apach2, php-fpm, fail2ban-server 프로세스의 실제 물리 메모리 사용량을 확인해야 했다.
워드프레스와 웹 방화벽의 메모리 사용량 모니터링 하기
다음과 같이 제미나이의 도움을 받아 물리 메모리 사용량을 모니터링하는 쉘 스크립트를 작성했다.
#!/bin/bash
# 특정 프로세스 이름의 PSS 총합(KB)과 프로세스 개수를 구하는 함수
get_pss_kb() {
local proc_name=$1
local total_pss=0
local count=0
# pgrep으로 해당 프로세스의 모든 PID 추출
for pid in $(pgrep -f "$proc_name"); do
# smaps_rollup 파일이 존재하는지 확인 (커널 4.14+)
if [ -f "/proc/$pid/smaps_rollup" ]; then
pss=$(awk '/^Pss:/ {print $2}' "/proc/$pid/smaps_rollup" 2>/dev/null)
total_pss=$((total_pss + ${pss:-0}))
count=$((count + 1))
# 구형 커널 대비 fallback (smaps 사용)
elif [ -f "/proc/$pid/smaps" ]; then
pss=$(awk '/^Pss:/ {sum += $2} END {print sum}' "/proc/$pid/smaps" 2>/dev/null)
total_pss=$((total_pss + ${pss:-0}))
count=$((count + 1))
fi
done
# PSS 합산 값과 프로세스 개수를 공백으로 구분하여 출력
echo "$total_pss $count"
}
while true; do
echo "==== $(date) ===="
# 1. 시스템 전체 메모리 정보 추출 (단위: KB)
# free 명령어의 두 번째 줄(Mem:)에서 전체(Total)와 사용 중(Used) 메모리를 가져옴
read sys_total_kb sys_used_kb <<< $(free -k | awk '/^Mem:/ {print $2, $3}')
# MB 단위로 변환
sys_total_mb=$(echo "scale=2; $sys_total_kb / 1024" | bc)
sys_used_mb=$(echo "scale=2; $sys_used_kb / 1024" | bc)
# 2. 개별 서비스 프로세스 메모리 정보 추출
read php_pss php_count <<< $(get_pss_kb 'php-fpm')
read apache_pss apache_count <<< $(get_pss_kb 'apache2')
read f2b_pss f2b_count <<< $(get_pss_kb 'fail2ban-server')
# MB 단위로 변환
php_mb=$(echo "scale=2; $php_pss / 1024" | bc)
apache_mb=$(echo "scale=2; $apache_pss / 1024" | bc)
f2b_mb=$(echo "scale=2; $f2b_pss / 1024" | bc)
# 모니터링 대상 서비스 총합 계산
total_target_pss=$((php_pss + apache_pss + f2b_pss))
total_target_mb=$(echo "scale=2; $total_target_pss / 1024" | bc)
total_target_count=$((php_count + apache_count + f2b_count))
# 결과 출력
echo "[시스템 전체 메모리]"
echo "전체 물리 메모리 : ${sys_total_mb} MB"
echo "사용 중인 메모리 : ${sys_used_mb} MB"
echo ""
echo "[주요 서비스 메모리 (PSS)]"
echo "php-fpm : ${php_mb} MB (프로세스: ${php_count}개)"
echo "apache2 : ${apache_mb} MB (프로세스: ${apache_count}개)"
echo "fail2ban : ${f2b_mb} MB (프로세스: ${f2b_count}개)"
echo "--------------------------------------------------------"
echo "모니터링 대상 합계: ${total_target_mb} MB (총 프로세스: ${total_target_count}개)"
echo "========================================================"
sleep 5
done
이 스크립트에서 핵심은 RSS 대신 PSS 항목의 값을 수집해 분석한다는 점이다.
RSS와 PSS의 차이
RSS(Resident Set Size)는 프로세스가 디스크로 스왑되지 않고 실제 물리 메모리(RAM)에 직접 올라와 차지하고 있는 공간의 크기를 뜻하기 때문에 언뜻 RSS의 값을 확인하면 될 것 같지만 Apach2 나 php-fpm 프로세스처럼 마스터 프로세스가 여러개의 자식 프로세스를 포크(fork)하는 경우 여러 프로세스가 공유하는 메모리(shared memory)가 발생한다.
만약 Apache2 프로세스 5개가 각각 10M의 독립된 메모리와 10M의 공유메모리를 함께 사용하는 상황이라면 RSS는 5개의 프로세스가 각각 20M의 메모리를 사용하고 있다고 응답한다. 즉 20M *5 로 계산하여 100M를 사용하는 것으로 계산되는 것이다. 하지만 실제로 5개의 Apache2 프로세스는 5개의 10M 램과 공유 메모리 10M를 사용하여 60M의 램만 사용하는 것이다.
반면 PSS(Proportional Set Size)는 RSS와 동일하게 실제 물리 메모리(RAM)에 상주하고 있는 값을 돌려주지만 5개의 프로세스가 50M의 공유메모리를 사용하고 있다면 5등분한 10M만 각각의 프로세스가 사용하고 있는 것으로 분할하여 응답한다는 점이 다르다.
즉 Apache2나 php-fpm 프로세스와 같이 자식 프로세스를 포크(fork)하는 경우 합산한 실제 물리메모리의 사용량을 정확하게 계산하고 싶다면 RSS가 아닌 PSS를 사용하는 것이 바람직하다.
스크립트 실행 결과

답글 남기기