---
type: how-to
title: Reverse-Proxy-Rezepte und der Callback-Vertrag
summary: Verdrahte das Proxy-Gate auf Traefik oder Caddy, hoste den Callback, der einen gelösten Pass in das Cookie verwandelt, und sichere Authelia ab, ohne es anzurühren.
---

Jeder Reverse-Proxy braucht dieselben zwei Teile: eine **Autorisierer**-Prüfung, die Caputchin fragt, ob eine Anfrage einen gültigen Pass trägt, und einen **Callback** auf deinem Origin, der einen gelösten Pass in das `cpt_gate`-Cookie verwandelt. Die [nginx-Durchgehung](/docs/proxy-page-gate/set-up) zeigt die Form von Ende zu Ende; diese Seite gibt die anderen Proxys, den genauen Callback-Vertrag, und ein volles Authelia-Beispiel. Ersetze `YOUR_SITE_KEY` durchgehend durch deinen öffentlichen Key.

Die Endpunkte sind überall dieselben:

- **Autorisierer**: `GET https://verify.caputchin.com/v1/gate/authz?site=YOUR_SITE_KEY`, mit weitergeleitetem `Cookie`-Header des Besuchers. `204` heißt erlauben, `401` heißt Challenge.
- **Challenge**: leite den Browser zu `https://verify.caputchin.com/v1/gate/challenge?site=YOUR_SITE_KEY&return=<die ursprüngliche URL>` um.

## Traefik

Nutze eine `forwardAuth`-Middleware für den Autorisierer. Traefik leitet den eingehenden `Cookie`-Header standardmäßig weiter. Bei einem `401` von der Middleware leite den Browser zur Challenge um (eine Error-Page-Middleware, die auf eine kleine Route zeigt, die den `302` ausgibt, oder behandle den `401` an deinem Edge).

```yaml
http:
  middlewares:
    cpt-gate:
      forwardAuth:
        address: "https://verify.caputchin.com/v1/gate/authz?site=YOUR_SITE_KEY"
        # The 401 from forwardAuth is your signal to send the browser to:
        #   https://verify.caputchin.com/v1/gate/challenge?site=YOUR_SITE_KEY&return=<original-url>
  routers:
    portal:
      rule: "Host(`auth.example.com`)"
      middlewares: ["cpt-gate"]
      service: your-app
```

## Caddy

Nutze `forward_auth` für den Autorisierer und `handle_errors`, um den `401` in eine Umleitung zu verwandeln. Das ist ein Ausgangspunkt; pass die Direktiven-Syntax an deine Caddy-Version an.

```caddy
auth.example.com {
  forward_auth https://verify.caputchin.com {
    uri /v1/gate/authz?site=YOUR_SITE_KEY
    copy_headers Cookie
  }
  handle_errors {
    @challenge expression {http.error.status_code} == 401
    redir @challenge https://verify.caputchin.com/v1/gate/challenge?site=YOUR_SITE_KEY&return={scheme}://{host}{uri} 302
  }
  reverse_proxy your-app:8080
}
```

## Der Callback

Die gehostete Challenge-Seite schließt ab, indem sie ein `POST`-Formular an `https://<dein-origin>/__cpt/callback` mit zwei Feldern im **Body** auto-absendet: `cpt_gate` (dem Pass) und `to` (wohin der Besucher geschickt wird). Füge diese eine Route zu deinem Origin hinzu (oder als eigene Location auf dem Proxy). Sie muss:

1. `cpt_gate` und `to` aus dem POST-**Body** lesen, nie der URL (ein Pass in einer URL leckt in Logs und Referrer).
2. Bestätigen, dass `to` auf deinem eigenen Origin liegt, und alles andere ablehnen, sodass der Callback nicht in einen Open Redirect verwandelt werden kann.
3. Das Cookie mit den Attributen unten setzen.
4. (`303`) zu `to` umleiten.

```js
// Any tiny handler on your origin works. Express shown; ~15 lines.
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);
});
```

Die Cookie-Attribute sind das ganze Sicherheitsmodell. Weil der Pass nicht an ein Gerät gebunden ist, sind `HttpOnly` (blockt Skript-Diebstahl), `Secure` (nur HTTPS), `SameSite=Lax`, und eine kurze `Max-Age` (passend zu deiner Freigabe-TTL) das, was ihn schützt. Außerdem: logge den `cpt_gate`-Wert nicht in deinen Access-Logs, und behalte `Referrer-Policy: no-referrer` auf dem Callback, sodass der Pass nie in einem Referrer-Header mitreist.

## Durchgearbeitetes Beispiel: Authelia

Authelias Login-Portal ist eine kompilierte Single-Page-App ohne Platz, das Widget einzubetten, und ohne Plugin-Hook, also ist das Gate der Weg, es zu schützen. Authelia sitzt bereits hinter einem Reverse-Proxy (so funktioniert sein eigenes ForwardAuth), und dieser Proxy ist der Ort für das Gate. Authelia selbst bleibt völlig unverändert.

Setze das Gate auf den vhost des Portals (zum Beispiel `auth.example.com`):

- **Sichere** das Portal-HTML und den First-Factor-Login-Endpunkt (`/api/firstfactor`) ab.
- **Schließe** Authelias eigenen ForwardAuth-verify-Endpunkt (`/api/verify`) aus, den der Proxy bei jeder geschützten Upstream-Anfrage aufruft. Ihn abzusichern würde jede geschützte App hinter Authelia brechen.
- **Schließe** Health-Checks und die statischen Assets aus, die die Challenge-Seite selbst braucht.
- **Füge** die `/__cpt/callback`-Route wie oben hinzu.

Das Gate hält Bots vom Portal fern; Authelias eingebaute Regulation (Retry-Limit und Bann) deckelt weiterhin die Credential-Retries für jeden, der durchkommt, sodass die zwei Schichten sich stapeln. Das Gate schützt nur das interaktive Portal (die Login- und Consent-UI); es sichert die nicht-interaktiven Token-Endpunkte nicht ab, und sollte es auch nicht.

## Siehe auch

- [Das Proxy-Gate einrichten](/docs/proxy-page-gate/set-up): die nginx-Durchgehung und der Vorschaumodus-zuerst-Rollout.
- [Überblick](/docs/proxy-page-gate/overview): das Konzept und das Freigabe-Cookie.
- [Statistik](/docs/proxy-page-gate/statistics): bestätige die Verdrahtung, indem du Challenge gegen Durchgang beobachtest.
