728x90

개념 정리 — 왜 상황이 복잡한가?
- macOS는 리눅스처럼 Docker가 네이티브로 동작하지 않습니다. 대신 Colima(Lima)나 Docker Desktop이 VM을 띄우고 그 안에서 Docker가 돌아갑니다. 그 결과 네트워크가 최소 2계층(호스트 ↔ VM ↔ 컨테이너)으로 구성되어 IP/포트/헤더 관련 동작이 달라집니다.
- 기본 모드: user-mode NAT — Colima는 기본적으로 VM 내부에서 NAT를 사용해 외부와 통신합니다. VM 내부에
docker0(예: 172.17.x.x)와 Lima NAT 네트워크(예: 192.168.5.0/24)가 존재합니다. - 브리지(bridged) 모드: VM을 호스트 LAN에 연결해 VM이 LAN IP를 받게 하는 모드입니다. 하지만 macOS에서는 특히 Wi-Fi 인터페이스에서 L2 브리지 제한(여러 MAC 전달 불가, 프롬스큐어스/스푸핑 제한 등)으로 정상 동작하지 않는 경우가 많습니다.
- gvproxy / 포트포워딩: Colima는 gvproxy 같은 프록시/포워딩 계층을 사용합니다. 여기서도 소스 IP가 변형될 수 있습니다.
- 결론: macOS 개발환경에서 컨테이너가 보는
$remote_addr에 실제 클라이언트 IP가 그대로 남지 않는 건 구조적 한계에서 기인합니다.
Colima 네트워크 모드별 구조(도식)
- 기본 NAT (일반적)
Client(네트워크) → Mac Host → (port-forward) → Colima VM (eth0: 192.168.5.1) → docker0 (172.17.0.1) → Container - 브리지(성공 시)
Client → LAN Router → Mac Host └─ Colima VM (eth0: 192.168.0.XXX) → docker0 → Container - host 네트워크(리눅스만 유효)
Container ↔ Host 네트워크 (동일 네트워크 스택)
실무적 문제: nginx 로그에 VM/도커 IP가 찍히는 원인
curl http://localhost:8080처럼 접속하면 호스트 → VM → 컨테이너로 패킷이 전달되고, 이 과정에서 NAT/프록시가 발생해 컨테이너에서 보는 소스 IP는 VM 또는 docker gateway가 됩니다.- 또한 포트포워딩 레이어(gvproxy 등)가 중간에서 연결을 맺어주며 원본 IP 헤더(
X-Forwarded-For)를 자동으로 추가하지 않으면 컨테이너는 원 IP를 알 수 없습니다.
300x250
가능한 해결책(우선순위 및 권장)
권장 A — 리버스 프록시(호스트 또는 별도 컨테이너) + nginx realip 사용 (현실적·안정적)
- 장점: 가장 간단하고 안전. macOS의 제한과 무관.
- 구성: 호스트(또는 Traefik)에서 요청을 받아
X-Forwarded-For를 추가 → backend nginx에서ngx_http_realip_module로 복원. - nginx 예시 (backend nginx)
# /etc/nginx/conf.d/realip.conf set_real_ip_from 127.0.0.1; # 호스트 리버스프록시가 localhost에서 오는 경우 set_real_ip_from 192.168.5.0/24; # Colima NAT IP 범위(필요 시 추가) real_ip_header X-Forwarded-For; real_ip_recursive on; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; - 검증 방법: 호스트에서
curl -H "X-Forwarded-For: 1.2.3.4" http://localhost:8080후 nginx 로그에$remote_addr가1.2.3.4로 표시되는지 확인.
권장 B — Traefik(또는 nginx-proxy) 같은 리버스 프록시를 Docker 레벨에서 사용
- Traefik은 Docker 레이블로 자동 라우팅 및 X-Forwarded 헤더 관리 제공. 로깅/인증/ACME 등도 통합 가능.
대체 C — bridged 모드로 VM을 LAN에 직접 붙이는 방법 (성공하면 원 IP 보존 가능)
- 제약: macOS에서 Wi-Fi 인터페이스는 대부분 실패. 유선 인터페이스(USB-Ethernet, Thunderbolt-ethernet)에서 성공 확률이 높음.
- 절차 (주의: 기존 인스턴스 삭제 필요)
colima stop colima delete # 확인: network 인터페이스 이름 (유선 예: en5) networksetup -listallhardwareports # bridged 모드로 다시 시작 (예시) colima start --network-mode bridged --network-interface en5 - 검증:
colima ssh→ip a로 eth0가 LAN DHCP로 받은 IP(예: 192.168.0.34)인지 확인. - 만약 eth0가 192.168.5.1 같은 내부 NAT IP면 bridged 실패 / fallback.
참고 D — 컨테이너 IP를 고정하는 방법(호스트 LAN IP와는 별개)
- docker network create + --subnet + --ip로 컨테이너 IP 고정 가능(컨테이너 내부 브리지 IP 고정).
docker network create --subnet 172.18.0.0/16 mynet docker run --net mynet --ip 172.18.0.10 -d nginx - 주의: 이 IP는 VM 내부 네트워크 상의 고정 IP이며, 호스트 네트워크(물리 LAN)와는 별개입니다.
비실용 E — --network host
- macOS에서는 효과 없음(호스트가 VM이기 때문에 컨테이너가 macOS network stack을 직접 쓰지 못함). 리눅스 전용.
Colima/Lima 내부에서 IP를 수동(임시)으로 설정하는 방법 — 실제 명령과 한계
- VM 내부에서 임시 IP 지정 (부팅 후 사라짐)
colima ssh sudo ip addr add 192.168.5.10/24 dev eth0 sudo ip route add default via 192.168.5.2 - 한계: 이 IP는 Lima NAT 대역(192.168.5.0/24) 안에서만 의미가 있습니다. 다른 LAN 장치가 보는 IP가 바뀌지 않음.
- 영구 설정(권장하지 않음, 고급): Lima VM의 설정(
~/.colima/_lima/default/lima.yaml)을 직접 수정하거나 cloud-init 스크립트로 네트워크를 설정 가능하나 macOS vmnet + Colima 매니저가 이를 덮어쓸 수 있어 복잡하고 위험합니다.
네트워크 디버깅 절차(단계별 명령)
- Colima/VM 상태 확인
colima status
colima ls
- VM 접속 후 인터페이스/라우팅 확인
colima ssh
# 내부에서
ip a
ip route
cat /etc/resolv.conf
- 외부 연결 테스트
ping -c 4 8.8.8.8 # 네트워크 연결(라우팅)
ping -c 4 google.com # DNS 동작 확인
- 포워딩/프록시가 실제로 IP를 변형하는지 확인 (tcpdump)
# Colima VM에서 (또는 컨테이너 내부에 tcpdump 설치 후)
sudo tcpdump -n -i any port 80
# 또는 패킷의 src/dst를 추적
sudo tcpdump -n -i eth0 host <클라이언트 IP>
- nginx 로그 포맷에 http_x_forwarded_for 추가
log_format combined_ext '$remote_addr [$time_local] "$request" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log combined_ext;
- 호스트에서 curl 테스트 (헤더 주입)
curl -v http://localhost:8080 -H "X-Forwarded-For: 203.0.113.7"
# nginx access.log에서 X-Forwarded-For 확인
브리지 모드 시도 시 체크리스트(특히 Wi-Fi 환경)
networksetup -listallhardwareports로 인터페이스 이름 확인 (en0, en1, en5 등).- 유선 랜 사용 권장(USB-C/Thunderbolt 어댑터 등).
- 기존 colima 인스턴스 삭제 필요 (
colima delete). colima start --network-mode bridged --network-interface <device>실행(권한 요구될 수 있음).colima ssh→ip a로 eth0가 LAN DHCP IP를 받았는지 확인.- Wi-Fi이면 브리지 실패 가능성 높음 → fallback NAT (eth0: 192.168.5.1) 확인.
보안 관점: 반드시 점검해야 할 항목 (체크리스트)
- 서비스 노출 범위 점검:
docker run -p 0.0.0.0:80:80처럼 0.0.0.0 바인딩하면 LAN 전체에서 접근 가능 — 개발용이라도 주의. 가능하면127.0.0.1:8080:80처럼 localhost 바인딩 권장. - 리버스프록시 신뢰 범위 설정:
set_real_ip_from에는 신뢰할 수 있는 프록시/호스트 IP(또는 서브넷)만 추가 — 임의의 클라이언트가X-Forwarded-For를 스푸핑할 수 있으므로 주의. - 포트 접근 제어: macOS 방화벽, 회사 네트워크 방화벽, 라우터 ACL 등에서 불필요한 포트가 열리지 않도록 검토.
- 로그 무결성: access 로그에 X-Forwarded-For 등을 기록할 때 소스 검증 로직을 두어 스푸핑 시도 탐지(예: 내부 IP가 아닌 외부에서 직접 들어온 X-Forwarded-For) 구현.
- ARP 충돌 방지: VM/수동 IP를 LAN에 강제 할당할 때 LAN 상에서 동적 DHCP와 충돌하지 않도록 사전 확인.
- 백업: colima delete 전 컨테이너/볼륨/이미지 백업 (
docker save,docker run --rm -v vol:/data ... tar czf) 권장.
실전 예제 시나리오(3가지) — 단계별 명령 & 기대 결과
예제 A — (안정적) 호스트 nginx → 컨테이너 nginx 로그에 실제 IP 남기기
- macOS에 nginx 설치(또는 Docker로 호스트 프록시 실행)
- 호스트 nginx proxy_pass →
http://localhost:8080(컨테이너) - 호스트 nginx가
proxy_set_header X-Forwarded-For $remote_addr;추가 - 컨테이너 nginx에서 위
realip설정 적용
→ 결과: nginx 로그에 클라이언트 실제 IP가 남음.
예제 B — Traefik을 사용해 Docker 레벨에서 처리 (추천: Docker Compose)
# docker-compose.yml (요약)
services:
traefik:
image: traefik:v2.10
ports:
- "80:80"
- "8080:8080"
command:
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
web:
image: nginx
labels:
- "traefik.http.routers.web.rule=Host(`example.local`)"
→ 결과: Traefik이 X-Forwarded-For를 관리해 백엔드에서 realip로 복원 가능.
예제 C — bridged 시도 (유선 환경)
colima stop
colima delete
# 네트워크 인터페이스 확인
networksetup -listallhardwareports
# en5가 유선이면
colima start --network-mode bridged --network-interface en5
colima ssh
ip a # eth0가 192.168.0.x 인지 확인
→ 결과: eth0가 LAN IP를 받으면, 외부에서 VM IP로 직접 접근 가능하고 실제 클라이언트 IP가 보존될 가능성 존재.
권장 최종 아키텍처(개발/테스트용)
- 개발용(간편/안정): Colima 기본 NAT + 호스트(또는 Traefik) 리버스프록시 → backend 컨테이너. nginx realip로 원 IP 복원.
- 고급(네트워크 실 IP 필요, 유선 환경): bridged 모드 + VM이 LAN IP 획득 → 필요시 VM/컨테이너 내부에서 추가 설정.
- 권장하지 않음: Wi-Fi에서 브리지 시도(불안정), 직접 Lima 네트워크 깊게 건드려서 영구 변화 시도(운영 리스크).
빠른 요약
- macOS에서 Docker → VM → Container 구조 때문에 원 IP 손실이 일반적입니다.
- 현실적으로는 리버스 프록시 + nginx realip 또는 Traefik 사용이 가장 안정적입니다.
- bridged는 유선에서만 제대로 동작하는 경우가 많으며, 기존 인스턴스 삭제 후 재시작해야 적용됩니다.
- 보안: X-Forwarded-For 신뢰 범위 관리, 포트 바인딩 최소화, ARP 충돌 주의.
728x90
그리드형(광고전용)
댓글