1Panel로 배포한 Discourse에서 모든 사용자 IP가 Cloudflare로 표시되고 실제 브라우저 IP가 아닌 문제를 해결하는 방법

VPS에 1Panel을 설치하고, Discourse를 컨테이너로 배포한 뒤, OpenResty(컨테이너 배포)로 리버스 프록시를 설정했습니다. 도메인은 Cloudflare에 호스팅되어 있으며, CDN(오렌지 클라우드)이 활성화되어 있습니다. 아래는 사용자 IP가 Cloudflare에서 온 것으로 표시되는 문제가 아니라, 실제 사용자 브라우저 IP로 표시되도록 해결하는 방법입니다.

1. 1Panel에서 정기 작업을 생성하여 매주 최신 Cloudflare IP 목록을 다운로드하고 OpenResty 설정 디렉터리에 저장합니다.

  1. 1Panel 왼쪽 메뉴바에서 **“정기 작업”**을 클릭합니다.

  2. 오른쪽 상단의 **“정기 작업 생성”**을 클릭합니다.

  3. 아래 매개변수에 따라 입력합니다(복사해서 붙여넣기 가능):

  • 작업 유형: Shell 스크립트 선택.

  • 작업 이름: 예: Cloudflare IP 세그먼트 자동 업데이트.

  • 실행 주기: 매주를 권장합니다(예: 매주 토요일 오전 03:00).

  • 스크립트 내용: 아래 전체 코드를 그대로 복사하여 붙여넣으십시오(주의: 코드의 맨 위쪽 컨테이너 이름과 설정 디렉터리 경로를 먼저 수정해야 합니다):

#!/bin/bash
# 설정 영역
CONTAINER_NAME="1Panel에서 openresty 컨테이너 이름"
# 지정된 웹사이트 proxy 디렉터리로 수정
CONF_DIR="/opt/1panel/www/sites/www.당신의도메인.club/proxy"

echo "[$(date)] Cloudflare 공식 사이트에서 최신 IP 세그먼트 가져오기 시작..."
TEMP_DIR=$(mktemp -d)

# IP 목록을 가져와 Nginx가 인식하는 형식으로 변환
curl -fsS https://www.cloudflare.com/ips-v4 | sed 's/.*/set_real_ip_from &;/' > $TEMP_DIR/cf-ips-v4.conf
curl -fsS https://www.cloudflare.com/ips-v6 | sed 's/.*/set_real_ip_from &;/' > $TEMP_DIR/cf-ips-v6.conf

# 파일 확인 및 이동
if [[ -s $TEMP_DIR/cf-ips-v4.conf ]] && [[ -s $TEMP_DIR/cf-ips-v6.conf ]]; then
    mv $TEMP_DIR/cf-ips-v4.conf $CONF_DIR/
    mv $TEMP_DIR/cf-ips-v6.conf $CONF_DIR/
    echo "[$(date)] 설정 파일이 $CONF_DIR에 성공적으로 업데이트되었습니다."
else
    echo "[$(date)] 오류: Cloudflare IP 가져오기 실패!"
    rm -rf $TEMP_DIR
    exit 1
fi
rm -rf $TEMP_DIR

# Nginx 테스트 및 재로드
echo "[$(date)] Nginx 설정 테스트 중..."
if docker exec $CONTAINER_NAME nginx -t; then
    docker exec $CONTAINER_NAME nginx -s reload
    echo "[$(date)] 성공! OpenResty 설정 재로드 완료."
else
    echo "[$(date)] 실패! Nginx 설정 테스트를 통과하지 못했습니다."
    exit 1
fi

작업이 생성된 후에는 토요일을 기다릴 필요가 없습니다. 바로 테스트할 수 있습니다: “정기 작업” 목록에서 방금 생성한 작업을 찾습니다.

오른쪽의 “보고서” 버튼을 클릭합니다. 팝업된 로그 창을 확인합니다. 마지막 몇 줄에 성공! OpenResty 설정 재로드 완료라고 표시되면 1Panel 내부에서 전체 프로세스가 완벽하게 작동하고 있음을 의미합니다!

2. OpenResty에 realip 설정 추가

호스트 머신의 /opt/1panel/www/sites/www.당신의도메인/proxy/ 디렉터리에 새 파일을 생성합니다(파일명은 임의이며, .conf로 끝나면 됩니다. 메인 설정의 include *.conf에 의해 자동으로 로드됩니다): realip.conf

# 컨테이너 내 경로 사용
include /www/sites/www.당신의도메인/proxy/cf-ips-v4.conf;
include /www/sites/www.당신의도메인/proxy/cf-ips-v6.conf;

real_ip_header CF-Connecting-IP;
real_ip_recursive on;

3. OpenResty 재로드

docker exec 1Panel에서 openresty 컨테이너 이름 nginx -t
docker exec 1Panel에서 openresty 컨테이너 이름 nginx -s reload

4. OpenResty가 실제 IP를 가져오는지 확인

OpenResty의 access 로그를 확인합니다:

tail -f /opt/1panel/www/sites/www.당신의도메인/log/access.log

설정이 올바르게 되어 있다면, 로그의 첫 번째 IP가 Cloudflare의 173.245.x.x 등의 세그먼트가 아니라 실제 공개 IP로 변경되어야 합니다.

5. Discourse 측 설정

app.yml을 편집하고, run: 코드 블록 내에 다음 내용을 추가합니다:

  #docker로 discourse를 배포한 후, 다음 세 단계를 추가하여 포럼 사용자의 실제 IP가 전달되도록 보장해야 합니다
  - file:
      path: /etc/nginx/conf.d/outlets/server/set-real-ip-from-docker.conf
      chmod: 644
      contents: |
        set_real_ip_from 172.16.0.0/12;
        set_real_ip_from 127.0.0.1;
  
  - file:
      path: /etc/nginx/conf.d/outlets/server/real-ip-header.conf
      chmod: 644
      contents: |
        real_ip_header x-forwarded-for;
  
  - file:
      path: /etc/nginx/conf.d/outlets/server/real-ip-recursive.conf
      chmod: 644
      contents: |
        real_ip_recursive on;

이렇게 하면 Discourse 내장 Nginx는 다음을 수행합니다:

  1. Docker 네트워크 세그먼트(172.16.0.0/12)를 신뢰합니다.
  2. x-forwarded-for에서 실제 IP를 읽습니다.
  3. 다중 프록시를 재귀적으로 분석합니다.

6. 참고 사항

Discourse의 app.yml에 - "templates/cloudflare.template.yml"를 추가하는 것은 Discourse가 Cloudflare에 직접 노출될 때만 유효합니다. 중간에 OpenResty 리버스 프록시를 추가했기 때문에, Discourse 컨테이너가 보는 출처 IP는 실제로 Docker 게이트웨이(예: 172.17.0.1 또는 172.18.0.1)입니다. 따라서 해당 템플릿의 set_real_ip_from <CloudflareIP>는 매칭되지 않습니다.

따라서 Discourse의 app.yml에 - "templates/cloudflare.template.yml"를 추가할 필요가 없습니다.


2026-07-03 업데이트

2개의 좋아요

참고

처리 터미널 사용자 실제 IP의 “신뢰 체인” - 문서 / 셀프 호스팅 - Discourse Meta

주제 게시물을 업데이트했습니다.