홈서버(미니PC)로 실서비스 운영하기
운영중인 블로그의 인프라설계 / 네트워크 설계에 대해서 정리해보겠습니다.
1. 시작 배경
미니PC를 홈서버처럼 사용해서 개인 프로젝트를 운영하려고 했다.
운영하려는 서비스는 다음과 같다.
- React 프론트엔드 서버
- Node.js API 서버
- PostgreSQL 데이터베이스
- NAS 또는 기타 내부 서비스
- 추후 여러 프로젝트 추가 운영
처음에는 단순하게 각각의 포트를 외부에 열면 된다고 생각할 수 있다.
예를 들면 다음과 같은 방식이다.
React : 3000
Node API : 8080
PostgreSQL : 5432
NAS : 5000
하지만 이 방식은 실서비스 구조로 보기에는 좋지 않다.
특히 데이터베이스 포트까지 외부에 노출하면 보안상 위험하고, 프로젝트가 늘어날수록 포트 관리도 복잡해진다.
2. 요구사항 정리
이번 홈서버 구성에서 필요한 조건은 다음과 같다.
- 외부에서 도메인으로 접속할 수 있어야 한다.
- HTTPS가 적용되어야 한다.
- 여러 프로젝트를 도메인 기반으로 운영할 수 있어야 한다.
- 내부 서비스 포트는 외부에 최대한 노출하지 않아야 한다.
- 데이터베이스는 외부에서 직접 접근하지 못하게 해야 한다.
즉, 핵심 목표는 다음과 같다.
여러 개의 내부 서비스를 도메인 기반으로 안전하게 외부에 노출하는 것
3. 전체 구조 요약
전체 흐름은 다음과 같다.
사용자
↓
도메인 DNS
↓
공인 IP
↓
공유기 포트포워딩
↓
Nginx Proxy Manager
↓
내부 서비스
조금 더 자세히 보면 다음과 같은 구조다.
[인터넷 사용자]
↓
[DNS]
blog.minseok.life
api.minseok.life
nas.minseok.life
↓
[공인 IP]
↓
[공유기 포트포워딩]
80 → Nginx Proxy Manager
443 → Nginx Proxy Manager
↓
[Nginx Proxy Manager]
↓
[내부 서비스]
React : 3000
Node API : 8080
PostgreSQL : 5432
NAS : 5000
여기서 중요한 점은 외부 사용자는 3000, 8080, 5432, 5000 같은 내부 포트로 직접 접근하지 않는다는 것이다.
외부 사용자는 오직 도메인으로만 접근한다.
4. 왜 Nginx Proxy Manager를 사용하는가?
Nginx Proxy Manager는 쉽게 말하면 외부 요청을 내부 서비스로 연결해주는 중간 관리자 역할을 한다.
예를 들어 사용자가 다음 주소로 접속한다고 가정한다.
https://blog.minseok.life
이 요청은 먼저 공유기를 지나 Nginx Proxy Manager로 들어온다.
Nginx Proxy Manager는 요청된 도메인을 확인한다.
blog.minseok.life 요청이네?
그러면 내부의 192.168.55.83:3000으로 보내야겠다.
이런 식으로 도메인에 따라 내부 서비스로 요청을 전달한다.
5. 도메인 라우팅 예시
Nginx Proxy Manager에서는 도메인별로 목적지를 지정할 수 있다.
예시는 다음과 같다.
blog.minseok.life → 192.168.55.83:3000
api.minseok.life → 192.168.55.85:8080
nas.minseok.life → 192.168.55.101:5000
이렇게 설정하면 외부에서는 모두 HTTPS 도메인으로 접근하지만, 내부에서는 각각 다른 서버나 포트로 연결된다.
6. 공유기 포트포워딩 설정
공유기에서는 모든 내부 서비스 포트를 열 필요가 없다.
외부에 열어야 하는 포트는 기본적으로 다음 두 개다.
80 → HTTP
443 → HTTPS
즉, 공유기에서는 다음과 같이 설정한다.
외부 80 → Nginx Proxy Manager 서버의 80
외부 443 → Nginx Proxy Manager 서버의 443
React의 3000번 포트, Node API의 8080번 포트, PostgreSQL의 5432번 포트, NAS의 5000번 포트는 외부에 직접 열지 않는다.
7. PostgreSQL은 왜 외부에 열면 안 되는가?
PostgreSQL은 데이터베이스다.
데이터베이스에는 사용자 정보, 게시글, 설정값, 인증 정보 등 중요한 데이터가 저장된다.
따라서 PostgreSQL 포트인 5432를 외부에 직접 노출하는 것은 좋지 않다.
좋은 구조는 다음과 같다.
외부 사용자
↓
Nginx Proxy Manager
↓
Node API 서버
↓
PostgreSQL
즉, 사용자는 데이터베이스에 직접 접근하지 않는다.
반드시 API 서버를 통해서만 데이터에 접근하게 해야 한다.
8. Proxmox, VMware, Docker 중 무엇을 선택할까?
홈서버를 구성할 때 선택할 수 있는 방식은 여러 가지가 있다.
대표적으로 다음 세 가지가 있다.
| 방식 | 장점 | 단점 |
|---|---|---|
| Docker 단독 | 가볍고 배포가 빠름 | 서버 전체 관리와 격리 구조가 약할 수 있음 |
| VMware | 익숙하고 안정적 | 홈서버 기준으로는 무거울 수 있음 |
| Proxmox | VM과 LXC 컨테이너를 함께 관리 가능 | 초기 학습 비용이 있음 |
이번 구조에서는 Proxmox + Docker 조합이 가장 적합하다.
9. 추천 구성 방식
추천하는 구조는 다음과 같다.
[미니PC]
↓
[Proxmox]
├── VM 또는 LXC 1: Nginx Proxy Manager
├── VM 또는 LXC 2: Docker 서비스 서버
│ ├── React
│ ├── Node API
│ └── PostgreSQL
└── VM 또는 LXC 3: NAS 또는 기타 서비스
이렇게 구성하면 역할을 나누기 쉽다.
Nginx Proxy Manager는 외부 요청을 받는 입구 역할을 하고, Docker 서버는 실제 애플리케이션을 실행하는 역할을 한다.
10. 네트워크 요청 흐름
사용자가 블로그에 접속하는 흐름을 예로 들면 다음과 같다.
1. 사용자가 브라우저에서 https://blog.minseok.life 접속
2. DNS가 blog.minseok.life의 공인 IP를 찾아줌
3. 요청이 집 공유기로 들어옴
4. 공유기는 443 요청을 Nginx Proxy Manager로 전달
5. Nginx Proxy Manager가 도메인을 확인
6. blog.minseok.life에 매핑된 내부 서버로 요청 전달
7. React 서비스가 응답
8. 응답이 다시 사용자 브라우저로 전달
그림으로 보면 다음과 같다.
사용자 브라우저
↓
blog.minseok.life
↓
DNS
↓
공인 IP
↓
공유기
↓
Nginx Proxy Manager
↓
React 서버
11. HTTPS 적용 방식
HTTPS는 Nginx Proxy Manager에서 처리한다.
Nginx Proxy Manager는 Let's Encrypt 인증서를 쉽게 발급받을 수 있도록 도와준다.
흐름은 다음과 같다.
사용자 → HTTPS 요청 → Nginx Proxy Manager → 내부 서비스
이때 외부 사용자와 Nginx Proxy Manager 사이에는 HTTPS가 적용된다.
내부 서비스는 HTTP로 통신할 수도 있다.
외부 구간: HTTPS
내부 구간: HTTP
예시:
https://blog.minseok.life
↓
Nginx Proxy Manager
↓
http://192.168.55.83:3000
12. 이 구조의 장점
1. 포트를 최소한으로 노출할 수 있다
외부에 공개되는 포트는 80, 443 정도로 제한된다.
내부 서비스 포트는 외부에서 직접 접근할 수 없다.
2. 여러 프로젝트를 운영하기 쉽다
서비스가 늘어나도 도메인만 추가하면 된다.
예를 들어 다음과 같이 확장할 수 있다.
blog.minseok.life → 블로그
api.minseok.life → API 서버
nas.minseok.life → NAS
3. HTTPS 적용이 쉽다
각 서비스마다 직접 SSL 인증서를 설정하지 않아도 된다.
Nginx Proxy Manager에서 도메인별로 SSL 인증서를 관리하면 된다.
4. 내부 구조를 숨길 수 있다
외부 사용자는 내부 IP나 내부 포트를 알 필요가 없다.
사용자는 오직 도메인만 알고 접근한다.
13. 주의할 점
1. 데이터베이스 포트는 외부에 열지 않는다
PostgreSQL의 5432 포트는 외부에 노출하지 않는 것이 좋다.
나쁜 예:
외부 → PostgreSQL:5432 직접 접근
좋은 예:
외부 → API 서버 → PostgreSQL
2. SSH 포트도 주의해야 한다
SSH를 외부에 열어야 한다면 기본 포트인 22를 그대로 쓰기보다는 포트를 변경하고, 비밀번호 로그인 대신 SSH Key 방식을 사용하는 것이 좋다.
3. 서버 관리 도구는 외부 노출을 최소화한다
Proxmox, Nginx Proxy Manager 같은 서버 관리 도구는 외부에 그대로 노출하지 않는 것이 좋다.
가능하면 내부망에서만 접근하거나 VPN, Cloudflare Zero Trust 같은 방식을 고려하는 것이 안전하다.
4. React 개발 서버는 실서비스용으로 적합하지 않을 수 있다
React의 3000 포트는 보통 개발 서버에서 사용된다.
실서비스에서는 React를 빌드한 뒤 정적 파일로 배포하는 방식이 더 적합하다.
예를 들면 다음과 같다.
React build
↓
Nginx 정적 파일 서빙
또는 Docker 컨테이너 안에서 빌드 결과물을 서빙하도록 구성할 수도 있다.
14. 최종 정리
이번 홈서버 구조의 핵심은 다음과 같다.
모든 외부 요청은 Nginx Proxy Manager를 거친다.
그리고 외부에 공개하는 포트는 최소화한다.
외부 공개:
80
443
외부 비공개:
3000
8080
5432
5000
서비스별 연결은 도메인으로 구분한다.
blog.minseok.life → React
api.minseok.life → Node API
nas.minseok.life → NAS
이 구조를 사용하면 홈서버에서도 비교적 안전하고 깔끔하게 여러 프로젝트를 운영할 수 있다.
15. 한 줄 요약
포트는 숨기고, 도메인으로 서비스하자.
