---
type: how-to
title: وصفات الوكيل العكسي وعقد ردّ النداء
summary: صِل بوّابة الوكيل على Traefik أو Caddy، واستضِف ردّ النداء الذي يحوّل تصريحًا محلولًا إلى كوكي، وأغلِق Authelia ببوّابة دون أن تمسّها.
---

كل وكيل عكسي يحتاج القطعتين نفسيهما: فحص **مُخوِّل** يسأل Caputchin إن كان طلب يحمل تصريحًا صالحًا، و**ردّ نداء** على أصلك يحوّل تصريحًا محلولًا إلى كوكي `cpt_gate`. [شرح nginx](/docs/proxy-page-gate/set-up) يبيّن الشكل من طرف إلى طرف؛ وهذه الصفحة تعطي الوكلاء الآخرين، وعقد ردّ النداء بالضبط، ومثال Authelia كاملًا. استبدِل `YOUR_SITE_KEY` بمفتاحك العامّ في كل موضع.

نقاط الوصول هي نفسها في كل مكان:

- **المُخوِّل**: `GET https://verify.caputchin.com/v1/gate/authz?site=YOUR_SITE_KEY`، مع تمرير ترويسة `Cookie` الخاصّة بالزائر. `204` تعني اسمح، و`401` تعني تحدٍّ.
- **التحدّي**: أعِد توجيه المتصفّح إلى `https://verify.caputchin.com/v1/gate/challenge?site=YOUR_SITE_KEY&return=<الرابط الأصلي>`.

## Traefik

استخدِم وسيطة `forwardAuth` للمُخوِّل. يمرّر Traefik ترويسة `Cookie` الواردة افتراضيًّا. عند `401` من الوسيطة، أعِد توجيه المتصفّح إلى التحدّي (وسيطة صفحة خطأ موجّهة إلى مسار صغير يُصدِر `302`، أو عالِج `401` عند حافّتك).

```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

استخدِم `forward_auth` للمُخوِّل و`handle_errors` لتحويل `401` إلى إعادة توجيه. هذه نقطة بداية؛ اضبط صياغة التوجيهات لإصدار Caddy عندك.

```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
}
```

## ردّ النداء

تنتهي صفحة التحدّي المُستضافة بإرسال ذاتي لنموذج `POST` إلى `https://<أصلك>/__cpt/callback` بحقلين في **الجسم**: `cpt_gate` (التصريح) و`to` (إلى أين يُرسَل الزائر). أضِف هذا المسار الواحد إلى أصلك (أو ككتلة location مخصّصة على الوكيل). يجب أن:

1. يقرأ `cpt_gate` و`to` من **جسم** POST، لا من الرابط أبدًا (تصريح في رابط يتسرّب إلى السجلّات والمُحيلين).
2. يؤكّد أن `to` على أصلك أنت، ويرفض ما عداه، كي لا يُحوَّل ردّ النداء إلى إعادة توجيه مفتوحة.
3. يضبط الكوكي بالسمات أدناه.
4. يعيد التوجيه (`303`) إلى `to`.

```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);
});
```

سمات الكوكي هي نموذج الأمان كلّه. ولأن التصريح غير مربوط بجهاز، فإن `HttpOnly` (يحجب سرقة السكربت)، و`Secure` (HTTPS فقط)، و`SameSite=Lax`، و`Max-Age` قصير (طابِقه مع مدّة السماح TTL) هي ما يحميه. وأيضًا: لا تسجّل قيمة `cpt_gate` في سجلّات وصولك، وأبقِ `Referrer-Policy: no-referrer` على ردّ النداء كي لا يركب التصريح أبدًا في ترويسة مُحيل.

## مثال محلول: Authelia

بوّابة تسجيل الدخول في Authelia تطبيق أحادي الصفحة مُصرَّف بلا مكان لإدراج الأداة وبلا خطّاف إضافة، فالبوّابة هي طريقة حمايته. Authelia تجلس أصلًا خلف وكيل عكسي (هكذا يعمل ForwardAuth الخاصّ بها)، وذلك الوكيل هو موضع البوّابة. وAuthelia نفسها تُترَك دون أي تعديل بتاتًا.

ضَع البوّابة على vhost البوّابة (مثلًا `auth.example.com`):

- **أغلِق ببوّابة** HTML البوّابة ونقطة وصول تسجيل الدخول بالعامل الأول (`/api/firstfactor`).
- **استثنِ** نقطة وصول verify الخاصّة بـ ForwardAuth في Authelia (`/api/verify`)، التي يناديها الوكيل لكل طلب upstream محمي. إغلاقها ببوّابة سيكسر كل تطبيق محمي خلف Authelia.
- **استثنِ** فحوص السلامة والأصول الساكنة التي تحتاجها صفحة التحدّي نفسها.
- **أضِف** مسار `/__cpt/callback` كما أعلاه.

تُبقي البوّابة البوتات بعيدة عن البوّابة؛ ويظلّ Regulation المدمج في Authelia (حدّ المحاولات والحظر) يسقّف محاولات بيانات الاعتماد لمن يمرّ، فتتراكم الطبقتان. تحمي البوّابة البوّابة التفاعلية فقط (واجهة تسجيل الدخول والموافقة)؛ ولا تُغلق، ولا ينبغي أن تُغلق، نقاط وصول الرموز غير التفاعلية.

## انظر أيضًا

- [أعدّ بوّابة الوكيل](/docs/proxy-page-gate/set-up): شرح nginx والطرح بوضع المعاينة أولًا.
- [نظرة عامة](/docs/proxy-page-gate/overview): الفكرة وكوكي السماح.
- [الإحصاءات](/docs/proxy-page-gate/statistics): أكّد التوصيل بمراقبة التحدّي مقابل المرور المباشر.
