---
type: tutorial
title: nginx로 프록시 게이트 설정하기
summary: 사이트 키에서 게이트를 활성화하고, nginx 리버스 프록시를 끝에서 끝까지 배선하고, 실제 방문자 하나를 막기 전에 미리보기 모드에서 지켜봅니다.
---

이 튜토리얼이 끝나면 게이트는 nginx 뒤의 사이트 앞에서 돌고 있을 것입니다. 통과되지 않은 방문자는 게임으로 보내지고, 풀린 게임은 쿠키를 설정하며, 이후 요청은 곧장 통과합니다. 당신은 먼저 그 전체를 **미리보기 모드**에서 지켜볼 테니, 배선을 확인하기 전까지는 아무것도 막히지 않습니다. 여기서는 nginx를 씁니다. [Traefik, Caddy, Authelia 레시피](/docs/proxy-page-gate/reverse-proxy-recipes)는 같은 형태를 따릅니다.

<Callout type="tip">
프록시를 건드리기 전에 1단계를 하세요. 미리보기 모드는 게이트를 감시 전용으로 돌립니다. 대시보드는 게이트가 무엇을 *했을지* 기록하지만, 요청은 여전히 모두 통과하므로, 배선 실수가 누군가를 밖에 가두는 일은 결코 없습니다.
</Callout>

## 1. 미리보기 모드를 켭니다

대시보드에서 팀을 열고 **미리보기 모드**를 켭니다. 켜진 동안, 게이트 인가자는 챌린지 대 통과 결정을 [통계 페이지](/docs/proxy-page-gate/statistics)에 기록하지만 결코 막지 않습니다. 마지막에 끄게 됩니다.

## 2. 사이트 키에서 게이트를 활성화합니다

사이트 키를 열고 **프록시 게이트** 페이지로 갑니다. **상태 → 활성화**를 켠 뒤 설정합니다:

- **통과 TTL**: 한 번의 풀이가 방문자를 얼마나 오래 통과시키는지(기본값 30분). 짧을수록 재확인이 많아지지만 쿠키가 도난당했을 때의 창은 작아집니다.
- **실패 모드**: 프록시가 Caputchin의 인가자에 닿을 수 없을 때 무엇을 하는지. **실패 시 닫힘**(fail closed)은 막습니다(로그인 포털에 더 안전). **실패 시 열림**(fail open)은 요청을 통과시킵니다(공개 사이트의 다운타임을 피함).

이 페이지는 당신의 사이트 키가 이미 채워진, 복사해 바로 쓸 nginx 스니펫도 보여 줍니다.

## 3. 게이트를 거는 오리진을 허용합니다

챌린지는 오직 **허용된 오리진**으로만 되돌아 리디렉션합니다. 위젯이 쓰는 것과 같은 오리진 허용 목록입니다. 당신이 게이트를 거는 오리진, 예컨대 `https://auth.example.com`이 포함되도록 하세요. 아직 없다면 사이트 키의 Cap 구성에서 그것을 설정합니다.

## 4. 인가자와 챌린지 리디렉션을 배선합니다

두 개의 `location` 블록: 내부 **인가자** 서브요청과, 프록시가 `401`에서 뛰어가는 **챌린지** 리디렉션입니다. `YOUR_SITE_KEY`를 당신의 공개 키로 바꾸세요.

```nginx
# Gate the protected paths.
location / {
  auth_request /_cpt_authz;             # 204 = allow, 401 = challenge
  error_page 401 = @cpt_challenge;
  # ...proxy_pass to your app...
}

location = /_cpt_authz {
  internal;
  proxy_pass https://verify.caputchin.com/v1/gate/authz?site=YOUR_SITE_KEY;
  proxy_pass_request_body off;
  proxy_set_header Content-Length "";
  proxy_set_header Cookie $http_cookie;  # forward the cpt_gate cookie
}

location @cpt_challenge {
  return 302 https://verify.caputchin.com/v1/gate/challenge?site=YOUR_SITE_KEY&return=$scheme://$host$request_uri;
}
```

진입 경로(포털 HTML과 로그인 POST)에 게이트를 거세요. 인가자 서브요청, 헬스 체크, 아래의 콜백에는 게이트를 걸지 **마세요**.

## 5. 쿠키를 설정하는 콜백을 더합니다

챌린지 페이지는 끝에 당신 오리진의 `/__cpt/callback`으로 작은 `POST`를 자동 제출하며, **본문**에 `cpt_gate`(패스)와 `to`(방문자를 어디로 보낼지)를 담습니다. 아주 작은 핸들러가 쿠키를 설정하고 리디렉션합니다. 각 쿠키 속성이 왜 중요한지를 포함한 전체 계약은 [리버스 프록시 레시피](/docs/proxy-page-gate/reverse-proxy-recipes#the-callback)에 있습니다. 최소한:

```js
app.post("/__cpt/callback", express.urlencoded({ extended: false }), (req, res) => {
  const pass = String(req.body.cpt_gate || "");
  const to = String(req.body.to || "/");
  const target = new URL(to, `https://${req.headers.host}`);
  if (target.host !== req.headers.host) return res.status(400).end(); // same-origin only
  res.setHeader(
    "Set-Cookie",
    `cpt_gate=${pass}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=1800`
  );
  res.redirect(303, target.pathname + target.search);
});
```

## 6. 미리보기에서 지켜봅니다

게이트된 URL을 불러옵니다. 미리보기가 켜져 있으므로 당신은 곧장 통과하지만, [통계 페이지](/docs/proxy-page-gate/statistics)는 `challenge_served`를 기록하고(당신에게 쿠키가 없었으므로), 당신이 풀고 콜백이 돌면 `pass_issued`를 기록합니다. 새로고침하면 `passthrough`가 오르는 것을 봐야 합니다. 챌린지가 결코 나타나지 않으면 인가자 블록이 맞지 않는 것이고, 콜백이 400을 내면 `to` 오리진을 확인하세요.

## 7. 라이브로 갑니다

숫자가 옳아 보이면 **미리보기 모드**를 끕니다. 게이트는 이제 강제합니다. 통과되지 않은 방문자는 게임으로 보내지고, 푼 방문자는 그의 패스가 만료될 때까지 돌아다닙니다.

## 다음으로 갈 곳

- [리버스 프록시 레시피](/docs/proxy-page-gate/reverse-proxy-recipes): Traefik, Caddy, 그리고 Authelia 전체 안내.
- [프록시 게이트 통계](/docs/proxy-page-gate/statistics): 라이브가 되면 각 숫자가 무엇을 뜻하는지.
- [개요](/docs/proxy-page-gate/overview): 개념과 게이트가 일부러 하지 않는 것.
