Nginx Proxy Manager 완벽 가이드: 리버스 프록시로 홈서버 깔끔하게 정리하기
“jellyfin.mydomain.com, nextcloud.mydomain.com, pihole.mydomain.com…”
홈서버에 서비스가 늘어날수록 관리가 복잡해집니다. 각 서비스마다 다른 포트 번호를 기억해야 하고, 포트포워딩 규칙도 서비스 개수만큼 늘어납니다. HTTPS를 적용하려면 서비스마다 인증서를 따로 관리해야 할 것 같고…
이 모든 문제를 한 방에 해결하는 것이 바로 리버스 프록시입니다. 그리고 홈서버 환경에서 리버스 프록시를 가장 쉽게 구축할 수 있는 도구가 **Nginx Proxy Manager(NPM)**입니다.
오늘 이 글을 따라하고 나면:
- 모든 서비스를
서비스명.mydomain.com형태로 접속할 수 있게 됩니다 - 포트 번호를 외울 필요가 없어집니다
- HTTPS가 원클릭으로 적용됩니다
- 특정 서비스에 비밀번호 보호를 걸 수 있습니다
1. 리버스 프록시란?
프록시의 기본 개념
**프록시(Proxy)**는 “대리인”이라는 뜻입니다. 클라이언트와 서버 사이에서 요청을 대신 전달해주는 중간자 역할을 합니다.
프록시에는 두 종류가 있습니다:
포워드 프록시 (Forward Proxy)
- 클라이언트 측에서 동작
- 사용자의 요청을 대신 전달
- 예: 회사에서 인터넷 접속 시 거치는 프록시, VPN
리버스 프록시 (Reverse Proxy)
- 서버 측에서 동작
- 외부 요청을 받아서 내부 서버로 전달
- 예: 오늘 배울 Nginx Proxy Manager
┌─────────────────────────────────────────────────────────────┐│ 프록시의 두 가지 종류 │├─────────────────────────────────────────────────────────────┤│ ││ [포워드 프록시] ││ ││ 사용자 ──→ 프록시 ──→ 인터넷 ││ (클라이언트 측) ││ "나 대신 요청해줘" ││ ││ ───────────────────────────────────────────────────────── ││ ││ [리버스 프록시] ││ ││ 인터넷 ──→ 프록시 ──→ 서버들 ││ (서버 측) ││ "요청을 적절한 서버로 전달해줄게" ││ │└─────────────────────────────────────────────────────────────┘리버스 프록시가 필요한 이유
홈서버에 여러 서비스가 있다고 가정해봅시다:
- Jellyfin: 8096 포트
- Nextcloud: 8080 포트
- Pi-hole: 80 포트
- Vaultwarden: 8222 포트
- Home Assistant: 8123 포트
리버스 프록시 없이 운영하면:
포트포워딩 규칙 5개 필요 │ ┌─────────────────┼─────────────────┐ │ │ │ ▼ ▼ ▼ :8096 → Jellyfin :8080 → Nextcloud :80 → Pi-hole :8222 → Vaultwarden :8123 → Home Assistant
접속 방법: - http://mydomain.com:8096 (Jellyfin) - http://mydomain.com:8080 (Nextcloud) - http://mydomain.com:8222 (Vaultwarden) - ...
문제점: - 포트 번호를 다 외워야 함 - 포트포워딩 규칙이 서비스마다 필요 - HTTPS 적용이 서비스마다 따로 - 일부 포트는 ISP가 차단할 수 있음리버스 프록시를 사용하면:
포트포워딩 규칙 2개만 필요 (80, 443) │ ▼ ┌─────────────────┐ │ Nginx Proxy │ │ Manager │ │ (리버스 프록시) │ └────────┬────────┘ │ ┌───────────────────┼───────────────────┐ │ │ │ ▼ ▼ ▼ jellyfin. nextcloud. pihole. mydomain.com mydomain.com mydomain.com │ │ │ ▼ ▼ ▼ localhost:8096 localhost:8080 localhost:80
접속 방법: - https://jellyfin.mydomain.com - https://nextcloud.mydomain.com - https://pihole.mydomain.com - ...
장점: - 포트 번호 외울 필요 없음 - 포트포워딩은 80, 443 두 개만 - SSL 인증서 한 곳에서 통합 관리 - 접근 제어(ACL)를 프록시에서 처리리버스 프록시의 핵심 기능
1) 요청 라우팅
- 도메인/경로에 따라 적절한 백엔드 서버로 요청 전달
jellyfin.mydomain.com→ Jellyfin 컨테이너nextcloud.mydomain.com→ Nextcloud 컨테이너
2) SSL/TLS 종단 (SSL Termination)
- 클라이언트와의 HTTPS 암호화를 프록시가 처리
- 내부 서비스는 HTTP로 통신해도 됨 (설정 간소화)
3) 로드 밸런싱
- 여러 서버에 요청을 분산 (홈서버에서는 잘 안 씀)
4) 캐싱
- 자주 요청되는 콘텐츠를 캐싱하여 속도 향상
5) 보안 계층
- 백엔드 서버를 외부에 직접 노출하지 않음
- 추가 인증 계층 적용 가능
2. Nginx Proxy Manager 소개
NPM이란?
**Nginx Proxy Manager(NPM)**는 Nginx를 웹 GUI로 쉽게 관리할 수 있게 만든 도구입니다.
Nginx는 원래 설정 파일을 직접 편집해야 하는 전문가용 도구입니다. NPM은 이 복잡한 설정을 웹 인터페이스에서 클릭 몇 번으로 할 수 있게 만들었습니다.
핵심 기능
- 웹 기반 GUI: 브라우저에서 모든 설정 가능
- Let’s Encrypt 통합: SSL 인증서 자동 발급 및 갱신
- 프록시 호스트 관리: 서브도메인별 라우팅 설정
- 접근 제어: IP 차단, 비밀번호 보호
- 스트림 프록시: TCP/UDP 포워딩 (SSH, 게임 서버 등)
- 리다이렉션: URL 리다이렉트 설정
NPM vs 다른 리버스 프록시
| 특성 | NPM | Traefik | Caddy | 순정 Nginx |
|---|---|---|---|---|
| 설정 방식 | Web GUI | Docker Labels/YAML | Caddyfile | nginx.conf |
| 학습 곡선 | 매우 낮음 | 중간 | 낮음 | 높음 |
| Let’s Encrypt | 원클릭 | 자동 | 자동 | 수동/Certbot |
| Docker 통합 | 수동 설정 | 자동 감지 | 수동 설정 | 수동 설정 |
| 리소스 사용 | 중간 | 낮음 | 낮음 | 낮음 |
| 홈서버 추천 | 입문자 | 중급자 | 중급자 | 전문가 |
결론: 홈서버 입문자에게는 NPM이 가장 쉽습니다. 나중에 더 세밀한 제어가 필요해지면 Traefik이나 Caddy로 마이그레이션할 수 있습니다.
3. 사전 준비사항
NPM을 설정하기 전에 다음이 준비되어 있어야 합니다:
체크리스트
[ ] 도메인 보유 (필수) - 무료: DuckDNS (xxx.duckdns.org) - 유료: 가비아, Namecheap 등에서 구매
[ ] DNS 설정 완료 - A 레코드: mydomain.com → 공인 IP - CNAME 또는 A 레코드: *.mydomain.com → 공인 IP (와일드카드)
[ ] 포트포워딩 설정 - 80 포트 → NPM이 설치된 서버 - 443 포트 → NPM이 설치된 서버
[ ] Docker 설치 완료DNS 설정 예시
DuckDNS 사용 시:
DuckDNS는 서브도메인을 직접 지원하지 않습니다.
하지만 myhome.duckdns.org를 A 레코드로 등록하면 NPM에서 호스트명으로 사용할 수 있습니다.
커스텀 도메인 사용 시 (Cloudflare 예시):
DNS Records for mydomain.com:
Type Name Content Proxy─────────────────────────────────────────────────────A @ 121.134.56.78 OffA * 121.134.56.78 Off (와일드카드: 모든 서브도메인을 같은 IP로)
또는 개별 설정:A jellyfin 121.134.56.78 OffA nextcloud 121.134.56.78 OffA pihole 121.134.56.78 Off중요: Cloudflare를 사용할 경우, 처음 설정할 때는 프록시(주황색 구름)를 꺼두세요. NPM의 Let’s Encrypt 인증서 발급이 실패할 수 있습니다. 설정이 완료된 후에 프록시를 켜도 됩니다.
4. Nginx Proxy Manager 설치
Docker Compose로 설치
services: npm: container_name: nginx-proxy-manager image: jc21/nginx-proxy-manager:latest restart: unless-stopped ports: - "80:80" # HTTP - "443:443" # HTTPS - "81:81" # 관리자 웹 UI volumes: - /srv/npm/data:/data - /srv/npm/letsencrypt:/etc/letsencrypt environment: - TZ=Asia/Seoul# 디렉토리 생성 및 실행mkdir -p /srv/npm/{data,letsencrypt}docker compose up -d초기 로그인
- 브라우저에서
http://서버IP:81접속 - 기본 계정으로 로그인:
- Email:
admin@example.com - Password:
changeme
- Email:
- 즉시 이메일과 비밀번호 변경 (보안상 필수)
관리 UI 포트 보안
81 포트는 관리자 페이지입니다. 외부에서 접근할 필요가 없다면 포트를 로컬로 제한하세요:
ports: - "80:80" - "443:443" - "127.0.0.1:81:81" # 로컬에서만 접근 가능또는 나중에 NPM 자체를 통해 npm.mydomain.com으로 접근하도록 설정할 수 있습니다.
5. 프록시 호스트 설정하기
이제 실제로 서비스를 연결해봅시다.
예시로 Jellyfin을 jellyfin.mydomain.com으로 접속할 수 있게 설정합니다.
Step 1: 프록시 호스트 추가
- NPM 대시보드 → Hosts → Proxy Hosts
- Add Proxy Host 클릭
Step 2: Details 탭 설정
Domain Names:┌─────────────────────────────────────────────┐│ jellyfin.mydomain.com │└─────────────────────────────────────────────┘
Scheme: http (내부 서비스가 HTTP일 경우)
Forward Hostname / IP:┌─────────────────────────────────────────────┐│ 192.168.0.10 (또는 컨테이너 이름: jellyfin) │└─────────────────────────────────────────────┘
Forward Port:┌─────────────────────────────────────────────┐│ 8096 │└─────────────────────────────────────────────┘
옵션:[x] Cache Assets # 정적 파일 캐싱[x] Block Common Exploits # 일반적인 공격 차단[ ] Websockets Support # WebSocket 사용 시 체크 (Jellyfin은 필요)Websockets Support: 실시간 통신이 필요한 서비스는 반드시 체크
- Jellyfin: 필요 (실시간 재생 상태)
- Nextcloud: 필요 (실시간 알림)
- Home Assistant: 필요
- Vaultwarden: 필요
Step 3: SSL 탭 설정 (중요)
SSL Certificate:┌─────────────────────────────────────────────┐│ Request a new SSL Certificate │└─────────────────────────────────────────────┘
옵션:[x] Force SSL # HTTP → HTTPS 자동 리다이렉트[x] HTTP/2 Support # 속도 향상[ ] HSTS Enabled # 보안 강화 (주의: 신중히 사용)[ ] HSTS Subdomains
Email Address for Let's Encrypt:┌─────────────────────────────────────────────┐│ your-email@example.com │└─────────────────────────────────────────────┘
[x] I Agree to the Let's Encrypt Terms of ServiceSave 클릭하면 자동으로:
- Let’s Encrypt에서 SSL 인증서 발급
- Nginx 설정 생성
- 인증서 자동 갱신 스케줄 등록 (만료 전 자동 갱신)
Step 4: 접속 테스트
브라우저에서 https://jellyfin.mydomain.com 접속
- 자물쇠 아이콘 확인 (HTTPS 적용됨)
- Jellyfin 페이지가 정상적으로 표시되는지 확인
6. 주요 서비스별 설정 가이드
Jellyfin / Plex
Forward Hostname: jellyfin (또는 IP)Forward Port: 8096 (Jellyfin) / 32400 (Plex)
[x] Websockets Support ← 반드시 체크![x] Block Common ExploitsNextcloud
Nextcloud는 추가 설정이 필요합니다.
NPM 설정:
Forward Hostname: nextcloud (또는 IP)Forward Port: 80 (또는 커스텀 포트)
[x] Websockets Support[x] Block Common ExploitsCustom Nginx Configuration (Advanced 탭):
proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 10G; # 대용량 파일 업로드 허용proxy_connect_timeout 600;proxy_send_timeout 600;proxy_read_timeout 600;Nextcloud config.php 수정 필요:
'trusted_proxies' => ['172.16.0.0/12', '192.168.0.0/16'], # Docker 네트워크'overwriteprotocol' => 'https',Home Assistant
Forward Hostname: homeassistant (또는 IP)Forward Port: 8123
[x] Websockets Support ← 필수!Home Assistant configuration.yaml 추가:
http: use_x_forwarded_for: true trusted_proxies: - 172.16.0.0/12 - 192.168.0.0/16Vaultwarden
Forward Hostname: vaultwarden (또는 IP)Forward Port: 80
[x] Websockets Support[x] Force SSL ← 반드시! (비밀번호 관리자)Pi-hole Admin
Forward Hostname: pihole (또는 IP)Forward Port: 80
[ ] Websockets Support (불필요)주의: Pi-hole 자체가 80 포트를 사용하면 NPM과 충돌합니다. Pi-hole을 다른 포트(예: 8053)로 변경하거나, 다른 서버에 설치하세요.
Portainer
Forward Hostname: portainer (또는 IP)Forward Port: 9000
[x] Websockets Support7. 접근 제어 설정 (Access Lists)
NPM의 강력한 기능 중 하나는 **접근 제어 목록(ACL)**입니다. 특정 서비스에 추가 보안 계층을 적용할 수 있습니다.
Access List 생성
-
NPM 대시보드 → Access Lists → Add Access List
-
Details 탭:
Name: Internal OnlyAuthorization: (비워두면 IP 제한만)Pass Auth to Host: Off- Access 탭 (IP 기반 제어):
Satisfy: All
Allow:┌─────────────────────────────────────────────┐│ 192.168.0.0/24 # 내부 네트워크 허용 ││ 10.0.0.0/8 # Tailscale 네트워크 │└─────────────────────────────────────────────┘
Deny:┌─────────────────────────────────────────────┐│ all # 나머지는 모두 차단 │└─────────────────────────────────────────────┘- Save
비밀번호 보호 추가
민감한 서비스에 기본 인증(Basic Auth)을 추가할 수 있습니다.
-
Access Lists → Add Access List
-
Details 탭:
Name: Password Protected- Authorization 탭:
Username: adminPassword: secure-password-here- Save
Access List 적용
- Proxy Hosts → 해당 호스트 Edit
- Details 탭 → Access List 드롭다운에서 생성한 ACL 선택
- Save
사용 시나리오
┌─────────────────────────────────────────────────────────────┐│ 접근 제어 활용 예시 │├─────────────────────────────────────────────────────────────┤│ ││ [서비스] [접근 제어] ││ ───────────────────────────────────────────────────────── ││ Jellyfin 공개 (가족/친구 사용) ││ Nextcloud 공개 (개인 클라우드) ││ Pi-hole Admin 내부만 + 비밀번호 ││ Portainer 내부만 + 비밀번호 ││ NPM 관리 페이지 내부만 ││ Home Assistant 공개 (HA 자체 인증 있음) ││ │└─────────────────────────────────────────────────────────────┘8. 고급 설정
Custom Locations
하나의 도메인에서 경로별로 다른 서비스로 연결할 수 있습니다.
예: mydomain.com/jellyfin → Jellyfin
mydomain.com/nextcloud → Nextcloud
- Proxy Host → Edit → Custom Locations 탭
- Add Location
Location: /jellyfinScheme: httpForward Hostname: 192.168.0.10Forward Port: 8096주의: 모든 서비스가 경로 기반 프록시를 지원하는 것은 아닙니다. 대부분의 경우 서브도메인 방식이 더 안정적입니다.
스트림 프록시 (TCP/UDP)
HTTP가 아닌 TCP/UDP 서비스도 프록시할 수 있습니다.
- Hosts → Streams → Add Stream
예: SSH 접속을 2222 포트로:
Incoming Port: 2222Forward Host: 192.168.0.10Forward Port: 22TCP Forwarding: OnUDP Forwarding: Off예: 게임 서버:
Incoming Port: 25565 (Minecraft)Forward Host: 192.168.0.10Forward Port: 25565TCP Forwarding: On리다이렉션 호스트
특정 도메인을 다른 URL로 리다이렉트할 수 있습니다.
- Hosts → Redirection Hosts → Add Redirection Host
Domain Names: www.mydomain.comScheme: httpsDomain Name: mydomain.comPreserve Path: On이렇게 하면 www.mydomain.com/path가 mydomain.com/path로 리다이렉트됩니다.
404 Host
등록되지 않은 서브도메인 접속 시 표시할 페이지를 설정할 수 있습니다.
- Hosts → 404 Hosts → Add 404 Host
9. Docker 네트워크 통합
NPM과 다른 서비스들이 Docker에서 실행 중이라면, 같은 네트워크에 연결하는 것이 좋습니다.
공용 Docker 네트워크 생성
docker network create proxy-networkDocker Compose 수정
NPM docker-compose.yml:
services: npm: container_name: nginx-proxy-manager image: jc21/nginx-proxy-manager:latest restart: unless-stopped ports: - "80:80" - "443:443" - "81:81" volumes: - /srv/npm/data:/data - /srv/npm/letsencrypt:/etc/letsencrypt networks: - proxy-network
networks: proxy-network: external: true다른 서비스 (예: Jellyfin) docker-compose.yml:
services: jellyfin: container_name: jellyfin image: jellyfin/jellyfin # ... 기타 설정 ... networks: - proxy-network - default # 내부 네트워크도 유지하려면
networks: proxy-network: external: true장점
같은 Docker 네트워크에 있으면:
- IP 대신 컨테이너 이름으로 연결 가능 (
jellyfin:8096) - IP가 바뀌어도 설정 변경 불필요
- 내부 통신이 더 빠름
NPM에서 Forward Hostname을 jellyfin으로 설정하면 됩니다.
10. 문제 해결
SSL 인증서 발급 실패
증상: “Error: Validation Failed” 또는 인증서 발급 안 됨
해결책:
-
DNS 확인: 도메인이 올바른 IP를 가리키는지 확인
Terminal window nslookup jellyfin.mydomain.com -
포트 확인: 80, 443 포트가 열려있는지 확인
Terminal window # 외부에서 테스트 (https://www.yougetsignal.com/tools/open-ports/) -
Cloudflare 프록시: Cloudflare를 사용한다면 프록시(주황색 구름)를 잠시 끄기
-
방화벽: 서버 방화벽에서 80, 443 허용 확인
Terminal window sudo ufw allow 80/tcpsudo ufw allow 443/tcp
502 Bad Gateway
증상: 프록시 설정 후 502 에러
해결책:
-
백엔드 서비스 확인: 타겟 서비스가 실행 중인지 확인
Terminal window docker ps | grep jellyfincurl http://192.168.0.10:8096 # 직접 접속 테스트 -
Forward Hostname 확인: IP 또는 컨테이너 이름이 정확한지 확인
-
네트워크 확인: Docker 네트워크가 연결되어 있는지 확인
Terminal window docker network inspect proxy-network -
포트 확인: Forward Port가 정확한지 확인
WebSocket 연결 실패
증상: 실시간 기능이 동작하지 않음 (알림, 재생 상태 등)
해결책:
- Websockets Support 체크: Proxy Host 설정에서 활성화
- 서비스 재시작: NPM과 해당 서비스 재시작
Terminal window docker restart nginx-proxy-managerdocker restart jellyfin
무한 리다이렉트
증상: ERR_TOO_MANY_REDIRECTS
해결책:
- Force SSL 설정 확인: 이미 HTTPS인 서비스에 Force SSL을 켜면 문제 발생 가능
- 백엔드 서비스 설정: 서비스 자체에서 HTTPS를 강제하는지 확인
11. 보안 권장사항
반드시 해야 할 것
[x] NPM 관리자 비밀번호 변경[x] 관리 페이지(81번 포트) 외부 노출 차단[x] 모든 서비스에 Force SSL 적용[x] Block Common Exploits 활성화[x] 민감한 서비스에 Access List 적용추가 보안 조치
1) NPM 관리 페이지를 NPM을 통해 접근:
npm.mydomain.com→localhost:81프록시 설정- Access List로 내부 IP만 허용
2) Fail2ban 연동: NPM 로그를 Fail2ban으로 모니터링하여 무차별 대입 공격 차단
3) 정기적인 업데이트:
docker compose pulldocker compose up -d12. 최종 구성 예시
모든 설정을 마친 후의 구조입니다:
┌─────────────────────────────────────────────────────────────┐│ 완성된 홈서버 구조 │├─────────────────────────────────────────────────────────────┤│ ││ 인터넷 ││ │ ││ ▼ ││ 공유기 (포트포워딩: 80, 443 → NPM) ││ │ ││ ▼ ││ ┌─────────────────────────────────────────────────────┐ ││ │ Nginx Proxy Manager │ ││ │ │ ││ │ jellyfin.mydomain.com ──→ jellyfin:8096 │ ││ │ nextcloud.mydomain.com ──→ nextcloud:80 │ ││ │ pihole.mydomain.com ──→ pihole:80 (ACL: 내부만) │ ││ │ vault.mydomain.com ──→ vaultwarden:80 │ ││ │ ha.mydomain.com ──→ homeassistant:8123 │ ││ │ portainer.mydomain.com ──→ portainer:9000 (ACL) │ ││ │ │ ││ │ SSL: Let's Encrypt 와일드카드 또는 개별 인증서 │ ││ └─────────────────────────────────────────────────────┘ ││ ││ 모든 서비스가 HTTPS로 보호됨 ││ 민감한 서비스는 추가 인증 적용 ││ │└─────────────────────────────────────────────────────────────┘13. 다음 단계
NPM으로 리버스 프록시를 구축했다면, 홈서버의 기초 인프라가 완성된 것입니다.
다음 포스팅 **“Tailscale: 0원으로 구축하는 메시 VPN”**에서는 포트포워딩 없이도 어디서든 안전하게 홈서버에 접속하는 방법을 다룹니다.
또한 이후 포스팅에서는:
- Cloudflare Tunnel: CGNAT 환경에서도 안전한 외부 접속
- Authentik: 모든 서비스에 통합 인증(SSO) 적용
이런 고급 주제들도 다룰 예정입니다.