Перейти к содержимому

Обратный прокси

Обратный прокси перед slimTDS позволяет отдавать скрипт пикселя и клик-эндпоинт с собственного домена вашего лендинга, а не с хоста slimTDS. Это делает все запросы first-party, обходит ограничения cross-origin для cookie и убирает хостнейм slimTDS из вкладки сети в браузере.

Два типичных сценария:

  • Пиксель как first-party — ваш SEO-лендинг работает на lander.example.com. Вы проксируете /p.js и /p/event через его nginx, чтобы пиксель срабатывал в рамках собственного origin лендинга. Cookie vu посетителя устанавливается под доменом лендинга, обеспечивая стабильную идентичность между визитами.
  • Клик-эндпоинт как first-party — вы хотите, чтобы /<slug> (горячий путь редиректа) появлялся под доменом лендинга до того, как посетитель будет перенаправлен на оффер.

Оба случая требуют корректно проброшенного реального IP клиента в slimTDS, иначе гео-таргетинг, обнаружение ботов и фингерпринтинг деградируют.


App\Shared\RealIp определяет IP посетителя, проходя по этим заголовкам по порядку:

ПриоритетЗаголовокТипичный источник
1X-Slim-IPЗарезервирован — задаётся кастомным доверенным слоем перед slimTDS
2X-Real-IPnginx ngx_http_realip_module / ручной proxy_set_header
3CF-Connecting-IPПрямое подключение через Cloudflare
4True-Client-IPАльтернатива Cloudflare Enterprise
5X-Forwarded-ForПервый IP в цепочке через запятую
6REMOTE_ADDRПоследний вариант — TCP-пир (сам прокси, а не клиент)

Если вы не пробрасываете ни один из заголовков 1–5, slimTDS видит IP прокси в REMOTE_ADDR, и каждый посетитель выглядит так, будто пришёл с вашего прокси-сервера. Гео-фильтры, ASN-правила ботов и серверный отпечаток молча перестают работать.

Рекомендуется: задавать X-Real-IP $remote_addr (nginx) или эквивалентную директиву Apache на каждой проксируемой локации.

Подделка заголовков на уровне приложения не блокируется

Заголовок раздела «Подделка заголовков на уровне приложения не блокируется»

App\Shared\RealIp проходит заголовки выше безусловно — он не проверяет, пришёл ли запрос от доверенного прокси. Любой, кто может достучаться до порта slimTDS напрямую, вправе предъявить подделанный X-Real-IP и выбрать, какой IP попадёт в лог. Считайте определение IP атрибуцией для аналитики по принципу best-effort, а не границей безопасности.

Ключ TRUSTED_PROXIES в .env.example этого не меняет — его не читает ни один компонент. Оставьте его пустым.

Что действительно защищает цепочку:

  • Не выставляйте порт приложения в интернет. Дотянуться до него должен только ваш прокси — привяжите порт к loopback, оставьте его внутри Docker-сети или закройте фаерволом. Это и есть настоящая мера защиты.
  • В режимах cf_* config/frankenphp/Caddyfile.cf задаёт trusted_proxies static … с захардкоженным списком диапазонов Cloudflare и client_ip_headers CF-Connecting-IP, поэтому Caddy принимает этот заголовок только от Cloudflare. Список статический — если Cloudflare изменит диапазоны, обновлять придётся вручную.

Опционально: заголовки атрибуции лендинга

Заголовок раздела «Опционально: заголовки атрибуции лендинга»

Когда slimTDS обрабатывает клик, ClickHandler читает два опциональных заголовка, чтобы записать, с какого лендинга пришёл посетитель:

ЗаголовокНазначение
X-Lander-HostПолный хостнейм лендинга, например lander.example.com
X-Lander-PathИсходный путь запроса + query, например /play/betsson/?utm_source=google

Они пробрасываются nginx лендинга через proxy_set_header X-Lander-Host $host и proxy_set_header X-Lander-Path $request_uri. Без них оба поля в логе клика будут null. Они актуальны только когда клик-эндпоинт проксируется через собственный веб-сервер лендинга — пропустите их для отдельно стоящих прокси только под пиксель.

Когда /p.js и /p/event отдаются под доменом лендинга (например, lander.example.com/p.js), cookie посетителя vu устанавливается под этим доменом. Клики, маршрутизируемые напрямую на slimtds.example.com/<slug>, устанавливают cookie под доменом slimTDS. Эти два домена не будут разделять одну cookie, поэтому идентичность посетителя опирается на FingerprintJS CE ID для повторного связывания сессий между доменами.


Проксируйте /p.js и /p/event через веб-сервер лендинга. Дополнительная настройка CORS не нужна — slimTDS уже возвращает заголовок Origin запроса обратно в Access-Control-Allow-Origin и обрабатывает OPTIONS-preflight на /p/event.

# В блоке server для вашего лендинга
location = /p.js {
proxy_pass https://slimtds.example.com/p.js;
proxy_set_header Host slimtds.example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location = /p/event {
proxy_pass https://slimtds.example.com/p/event;
proxy_set_header Host slimtds.example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# В блоке VirtualHost для вашего лендинга
# Требуется: mod_proxy, mod_proxy_http, mod_remoteip
ProxyPass /p.js https://slimtds.example.com/p.js
ProxyPassReverse /p.js https://slimtds.example.com/p.js
ProxyPass /p/event https://slimtds.example.com/p/event
ProxyPassReverse /p/event https://slimtds.example.com/p/event
# Проброс реального IP клиента в X-Real-IP
RequestHeader set X-Real-IP "%{REMOTE_ADDR}s"
# Альтернатива: использовать mod_remoteip для проброса через X-Forwarded-For
# RemoteIPHeader X-Forwarded-For

Проксируйте slug горячего пути напрямую, чтобы редирект выглядел исходящим с домена лендинга. Замените /<slug> на конкретный slug кампании или используйте префикс пути, который вы маршрутизируете в slimTDS.

# В блоке server для вашего лендинга
location /go/ {
# Срезает префикс /go/ и пробрасывает в slimTDS.
# Например, /go/aBcDeF → https://slimtds.example.com/aBcDeF
rewrite ^/go/(.*)$ /$1 break;
proxy_pass https://slimtds.example.com;
proxy_set_header Host slimtds.example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Опционально: проброс атрибуции лендинга
proxy_set_header X-Lander-Host $host;
proxy_set_header X-Lander-Path $request_uri;
}

Чтобы проксировать один slug без префикса:

location = /aBcDeF {
proxy_pass https://slimtds.example.com/aBcDeF;
proxy_set_header Host slimtds.example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Lander-Host $host;
proxy_set_header X-Lander-Path $request_uri;
}
# В блоке VirtualHost для вашего лендинга
# Требуется: mod_proxy, mod_proxy_http, mod_rewrite, mod_headers
# Проксирование /go/<slug> → slimTDS /<slug>
RewriteEngine On
RewriteRule ^/go/(.+)$ https://slimtds.example.com/$1 [P,L]
ProxyPassReverse /go/ https://slimtds.example.com/
# Проброс реального IP клиента
RequestHeader set X-Real-IP "%{REMOTE_ADDR}s"
# Опционально: атрибуция лендинга
RequestHeader set X-Lander-Host "%{HTTP_HOST}s"
RequestHeader set X-Lander-Path "%{REQUEST_URI}s"

Чтобы проксировать один slug:

ProxyPass /aBcDeF https://slimtds.example.com/aBcDeF
ProxyPassReverse /aBcDeF https://slimtds.example.com/aBcDeF
RequestHeader set X-Real-IP "%{REMOTE_ADDR}s"
RequestHeader set X-Lander-Host "%{HTTP_HOST}s"
RequestHeader set X-Lander-Path "%{REQUEST_URI}s"