집 서버 보안 설정 – Cloudflare로 IP 숨기고 공격 막기

집 NAS에 블로그를 열면 도메인만 조회해도 집 IP가 나오고, 같이 열려 있는 NAS 로그인 화면까지 공격 대상이 됩니다. 실제로 제 NAS는 2년 동안 IP 1만 7천여 개를 자동 차단했습니다(공격 기록). 무료 Cloudflare로 집 IP 숨기기, 관리 화면 국가 제한, xmlrpc 차단, 실제 방문자 IP 복원까지 적용한 순서를 정리했습니다.

한눈에 보기

  1. SSL 모드를 “전체(엄격)”로 바꾼 뒤 DNS 레코드를 전부 프록시(주황 구름)로 → 집 IP가 사라짐
  2. Bot Fight Mode와 AI 봇 차단은 끔 → Jetpack 연결과 AI 검색 노출 유지
  3. 블로그 외 하위 도메인(NAS 관리 화면 등)은 한국에서만 접속되게 규칙 1개
  4. xmlrpc.php는 Jetpack(ASN 2635)만 허용하는 규칙 1개
  5. NAS의 nginx와 워드프레스가 실제 방문자 IP를 보도록 복원 → 자동 차단이 계속 제 역할을 함
Cloudflare를 앞에 둔 홈 서버 구성도: 방문자, Cloudflare, 공유기, NAS, 도커 컨테이너
Cloudflare가 집 서버 앞에서 방패 역할을 합니다.

1. Cloudflare 프록시로 집 IP 숨기기

도메인 네임서버가 Cloudflare에 있어도, 레코드가 “DNS 전용(회색 구름)”이면 집 IP가 그대로 보입니다. 프록시(주황 구름)를 켜야 방문자에게 Cloudflare 주소만 보입니다. 순서가 중요합니다.

  1. SSL/TLS → 개요에서 암호화 모드를 전체(엄격) / Full (strict)로 먼저 바꿉니다.
  2. DNS → 레코드에서 루트(@), www, 와일드카드(*), 그 밖의 하위 도메인 레코드를 모두 프록시됨으로 바꿉니다.
  3. 터미널에서 dig +short 도메인을 쳐서 104.x / 172.6x 같은 Cloudflare 주소만 나오는지 확인합니다.

1번을 건너뛰고 “유연(Flexible)” 모드로 두면, Cloudflare는 서버에 http로 접속하고 워드프레스는 다시 https로 보내는 일이 반복돼 무한 리다이렉트가 납니다. “전체(엄격)”는 서버에 공인 인증서가 있어야 하는데, 저는 ZeroSSL 와일드카드 인증서를 이미 쓰고 있어서 바로 됐습니다.

레코드 하나라도 회색 구름으로 남으면 그 주소로 집 IP를 알아낼 수 있습니다. 메일·VPN처럼 프록시를 못 거는 서비스용 레코드가 있다면 그 이름도 따로 점검해야 합니다.

2. 봇 설정 두 가지는 끄기

  • Bot Fight Mode: 켜면 워드프레스닷컴 서버의 요청까지 막혀 Jetpack 연결이 끊길 수 있습니다.
  • AI 봇 차단: 켜면 ChatGPT·Perplexity 같은 AI 검색에 글이 나오지 않습니다. 검색 노출을 원하면 끄고, 학습만 막고 싶다면 robots.txt로 학습용 봇만 따로 막습니다.

끈 뒤에 구글봇, 빙봇, 네이버 Yeti, 다음, ChatGPT 검색봇, Claude 검색봇, PerplexityBot 이름으로 접속해 보니 모두 정상(200)으로 들어왔습니다.

3. NAS 관리 화면은 한국에서만

가족과 사진을 공유하느라 NAS 관리 화면을 완전히 닫을 수는 없어서, 블로그를 뺀 나머지 하위 도메인은 한국에서만 열리게 했습니다. 해외에서 들어오는 자동 공격 대부분이 여기서 걸러집니다.

  1. Security(보안) → Security rules(보안 규칙) (화면에 따라 WAF → Custom rules)
  2. Create rule → Custom rules, 이름은 알아보기 쉽게
  3. Edit expression을 누르고 아래 표현식 붙여넣기 (example.com 자리에 내 도메인)
  4. 동작은 Block, 마지막에 Deploy (Save as Draft는 적용 안 됨)
(http.host ne "example.com" and http.host ne "www.example.com" and ip.src.country ne "KR")

블로그(루트와 www)는 규칙에서 빠져 있어서 구글봇처럼 해외에서 오는 크롤러는 그대로 들어옵니다. 적용 후 해외 7개국(캐나다·네덜란드·스페인·이탈리아·스웨덴·인도네시아·이란) 지점에서 접속해 보니 관리 화면은 모두 403으로 막혔고, 블로그는 모두 200으로 열렸습니다. 해외여행 갈 때는 이 규칙 스위치를 잠시 끄면 됩니다.

4. xmlrpc.php는 Jetpack만 허용

서버 로그를 보니 워드프레스의 xmlrpc.php로 약 20초에 한 번꼴로 로그인 시도가 들어오고 있었습니다. 2단계 인증이 켜져 있어 뚫리지는 않지만 서버 자원을 계속 씁니다. 다만 Jetpack은 이 주소로 워드프레스닷컴과 통신하기 때문에 통째로 막으면 안 됩니다. Jetpack 공식 안내대로 Automattic의 네트워크(ASN 2635)만 통과시켰습니다.

(http.request.uri.path eq "/xmlrpc.php" and ip.src.asnum ne 2635)

ASN 항목을 쓸 수 없는 경우에는 Jetpack이 공개한 IP 대역으로 대신 적을 수 있습니다.

(http.request.uri.path eq "/xmlrpc.php" and not ip.src in {192.0.64.0/18 122.248.245.244 54.217.201.243 54.232.116.4 195.234.108.0/22})
xmlrpc.php에 접속하자 Cloudflare가 띄운 "Sorry, you have been blocked" 차단 화면
일반 회선에서 xmlrpc.php를 열면 Cloudflare 차단 화면이 뜹니다.

적용 후 Jetpack의 연결 진단(워드프레스닷컴 → 사이트 접속 테스트 포함)은 모두 통과했습니다. (Jetpack IP 허용 목록 안내)

5. 실제 방문자 IP 되살리기

프록시를 켜면 서버에는 모든 방문자가 Cloudflare 서버 IP로 보입니다. 이걸 그대로 두면 두 가지가 꼬입니다.

  • NAS의 자동 차단이 공격자 대신 Cloudflare IP를 차단하면, 같은 경로로 들어오는 나와 가족까지 잠깁니다.
  • 워드프레스의 댓글, 스팸 차단, 로그인 보호가 진짜 방문자를 구분하지 못합니다.

NAS(nginx)에서 복원하기

DSM의 nginx 설정을 열어 보면 이미 이런 줄이 들어 있습니다. “X-Forwarded-For에서 실제 IP를 꺼내되, 믿을 수 있는 프록시 목록은 이 폴더에서 읽겠다”는 뜻입니다.

real_ip_header            X-Forwarded-For;
real_ip_recursive         on;
set_real_ip_from          127.0.0.1;
include     /var/tmp/nginx/trusted_proxy/*.conf;

그런데 DSM 6.2에는 이 목록을 채우는 화면이 없어서 폴더가 비어 있었습니다. 여기에 Cloudflare IP 대역과 NAS 자신의 주소를 적은 파일을 넣으면, 블로그·NAS 관리 화면·사진 서비스가 모두 실제 IP를 봅니다.

# /var/tmp/nginx/trusted_proxy/cloudflare.conf (일부)
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 104.16.0.0/13;
# ... https://www.cloudflare.com/ips/ 의 IPv4·IPv6 대역 전부
# + NAS 자신의 내부 IP (DSM 리버스 프록시를 거치는 경우)

/var/tmp는 재부팅 등으로 비워질 수 있어서, 파일이 없거나 내용이 다르면 다시 쓰고 nginx 설정을 검사한 뒤 다시 읽는 스크립트를 만들어 DSM 작업 스케줄러(root, 10분마다)에 걸었습니다. 설정 검사가 실패하면 파일을 지우고 원래대로 돌아갑니다.

워드프레스에서 한 번 더

nginx 설정이 잠깐 빠지는 경우에 대비해, 워드프레스에도 “요청이 Cloudflare IP에서 왔을 때만 CF-Connecting-IP 헤더를 실제 IP로 쓰는” 작은 mu-plugin을 넣었습니다. Cloudflare가 아닌 곳에서 온 요청은 헤더를 무시하므로 IP를 속일 수 없습니다.

확인은 간단했습니다. 적용 전에는 워드프레스가 본 제 IP가 Cloudflare 주소(162.159.x.x)였고, 적용 후에는 실제 공인 IP로 바뀌었습니다.

nginx 신뢰 프록시 스크립트(realip.sh)와 워드프레스용 mu-plugin은 GitHub(dsm6-wordpress-homeserver)에 올려 두었습니다. NAS 주소 한 줄만 바꾸면 다른 DSM 6.2에서도 쓸 수 있고, refresh 명령으로 Cloudflare의 최신 IP 대역을 받아 올 수 있습니다.

6. 함께 챙기면 좋은 것

  • NAS 관리자 계정은 admin 같은 기본 이름을 쓰지 않고, 2단계 인증을 켭니다.
  • NAS 자동 차단은 몇 번 실패하면 막을지(저는 3번)와 차단 기간을 정해 둡니다.
  • Cloudflare를 거치지 않고 집 IP로 직접 들어오는 접속도 막아야 완성입니다. 방화벽에서 80·443을 Cloudflare 대역만 허용하거나, Cloudflare Tunnel로 포트포워딩 자체를 없애는 방법이 있습니다. 예전 DNS 기록에 집 IP가 남아 있을 수 있어서, 마무리로 공인 IP를 바꿔 주면 더 좋습니다.
  • 밖에서 NAS를 관리해야 한다면 SSH 포트를 열지 말고 Tailscale 같은 VPN으로만 들어가는 게 안전합니다.
  • 마지막 안전장치는 외부 백업입니다. 보안 설정이 뚫렸을 때 되돌릴 방법은 백업뿐입니다.

자주 묻는 질문

Cloudflare 무료 요금제로 충분한가요?

개인 블로그라면 충분합니다. 프록시, 인증서, 사용자 지정 보안 규칙(국가·경로·ASN 조건)까지 이 글의 내용은 모두 무료 요금제에서 적용했습니다.

국가 제한을 걸면 검색엔진이 못 들어오지 않나요?

블로그 주소(루트와 www)는 규칙에서 빼서 해외 크롤러도 그대로 들어옵니다. 막히는 건 블로그가 아닌 하위 도메인뿐입니다.

xmlrpc.php를 아예 꺼도 되나요?

Jetpack을 쓰지 않으면 꺼도 됩니다. Jetpack을 쓴다면 Automattic(ASN 2635)만 허용하는 방식이 안전합니다.

Cloudflare를 켠 뒤 NAS 자동 차단은 그대로 써도 되나요?

실제 IP 복원(5번)을 하지 않으면 위험합니다. Cloudflare IP가 차단되면 그 경로로 들어오는 모든 사람이 막힙니다.

전체 구성은 집 NAS 블로그 운영기, PHP 8.3 전환은 이 글에 정리했습니다.

최종 확인: 2026-10-25

lavient 아바타

글쓴이

lavient

소소한 일상과 관심 있는 분야를 기록하는 공간입니다. 직접 써 보고, 가 보고, 겪어 본 이야기를 솔직하게 남깁니다.

댓글 남기기