PonsLink를 운영하면서 가장 자주 받는 질문은 단순하다. "이 서비스, 실제로 어떻게 붙어 있어요?" 마케팅 문구로는 "요청-우선 세션 데스크"라고 말하지만, 그 문장 뒤에는 nginx 한 줄, Node 컨테이너 한 개, Postgres 두 개의 DB, Redis, coturn, SFU, R2, 결제 공급자 네 곳이 동시에 움직인다. 이 글은 2026-08-07 기준 `ssh ponslink`에서 실측한 desk.ponslink.com의 배포 구조를 정리한다.
한 줄로 보면
브라우저 → nginx(TLS 443) → (정적 SPA | `/api`·`/auth` | `/socket.io`) → ponslink-api(Node 24, :6650) → Postgres / Redis / coturn / SFU / R2 / 외부 API.
프론트엔드는 React SPA다. nginx는 `/home/declan/ponslink-frontend-dist`를 루트로 두고, 앱 라우트(`/public-desk`, `/room`, `/lounge`, `/login` 등)는 `app-shell.html`로 떨어뜨린다. `/assets/`는 1년 캐시, `sw.js`는 no-cache다. 비즈니스 트래픽은 전부 같은 호스트의 upstream `127.0.0.1:6650`으로 프록시된다.
API 컨테이너가 들고 있는 것
실측 env 기준 API는 다음을 동시에 붙잡는다.
– **DB**: `DATABASE_URL=…/ponslink` (세션·미디어·웹훅 도메인). 같은 Postgres 인스턴스에 `ponswarp` DB(계정·결제·클라우드 공유)가 나란히 있다.
– **Redis**: Socket.IO 어댑터 + 레이트리밋.
– **TURN**: `turn.ponslink.com:3478` udp/tcp, `:5349` tcp. HMAC 자격증명 TTL 600초.
– **SFU**: `wss://ponslink.com/sfu/ws`, RTC 포트 40000–40100.
– **스토리지**: Cloudflare R2 presigned URL, 객체 TTL 180분, 정리 스케줄러 가동.
– **결제**: `PAYMENT_PROVIDER=polar`. PayPal sandbox, LemonSqueezy/Stripe 웹훅 호환 유지.
– **미디어/AI**: Azure Translator·Speech, Deepgram, Google OAuth/Calendar/Translate, Giphy, OpenRouter.
모듈 경계는 소스 기준으로 `auth / billing / signaling / turn / providers / store / webhooks / security`로 나뉜다. `routes.ts`에는 260개 넘는 REST 라우트가 등록돼 있고, 실시간은 Socket.IO 브로커(`signaling/broker.ts` + `redisAdapter.ts` + `replayStore.ts`)가 맡는다.
왜 이렇게 쪼갰는가
초기에 "방만 만들면 된다"고 생각했다. 틀렸다. 요청 수집, 결제 게이트, 세션 미디어, 기록 보관은 실패 모드가 다르다. 그래서:
1. **엣지(nginx)** 는 TLS·정적·WebSocket upgrade만 담당한다.
2. **API** 는 비즈니스 상태와 시그널링을 한 프로세스에서 처리하되, 미디어 중계는 SFU/TURN으로 넘긴다.
3. **파일 바이트** 는 API를 경유하지 않는다. R2 presigned URL로 클라이언트가 직접 PUT/GET 한다.
4. **결제 상태** 는 공급자 웹훅 + 이벤트 원장 + 멱등성 키로만 확정한다.
이 분리는 "데모는 되는데 운영이 흔들리는" 지점을 줄이기 위한 선택이었다. 다음 글에서는 그 상태를 담는 데이터 모델(ERD)을 풀어쓴다.
실측 체크리스트
– `cat /etc/nginx/sites-enabled/desk.ponslink.com`
– `docker inspect docker-ponslink-api-1`
– `docker exec docker-postgres-1 psql -U ponswarp -d ponslink -c '\dt'`
– `docker exec docker-postgres-1 psql -U ponswarp -d ponswarp -c '\dt'`
– `systemctl status` / `docker ps` — nginx, docker-ponslink-api-1, postgres, redis, coturn
댓글