Reverzní proxy a Nette router

Rndoom04
Člen | 78
+
0
-

Ahoj,
dokázal by mi někdo poradit? Zatím je to 1:0 pro mou neznalost a nevím kde už dělám chybu.

  1. Hlavní doména domainA.tld má modul /w. Takže kdybych načetl domainA.tld/w/identifikator, tak to funguje dobře.
  2. K tomu se generuje identifikator.domainA.tld, který se podívá do routy a upřednostní tento zápis.
  3. K dispozici ale může být i zcela jiná doména – domainB.tld, která má jediný cíl a to načíst modul W.

Nastavil jsem proxy takto:

SSLProxyEngine On
SSLProxyVerify none
SSLProxyCheckPeerCN Off
SSLProxyCheckPeerName Off
ProxyPreserveHost Off
ProxyPass / https://www.domainA.cz/
ProxyPassReverse / https://www.domainA.cz/

RequestHeader set X-Forwarded-Host "www.domainB.cz"
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"

RequestHeader set Host "www.domainA.cz"

To funguje relativně dobře, ale problém je, že se mi to redirectne na zápis se subdoménou: identifikator.domainA.tld. V případě, že filterOut upravím, tak dochází k nekonečné smyčce přesměrování. Takže to false v té podmínce je teď pro to, aby to fungovalo nějak, ale určitě to není cílem. Cílem je, že www.domainB.tld načte modul /w/identifikator. Propojené to mám databází.

<?php

declare(strict_types=1);

namespace App\Core;

use Nette\Application\Routers\RouteList;
use Nette\Database\Explorer;

final class RouterFactory {

    public function __construct(private Explorer $db,) { ; }

    public function createRouter(): RouteList {
        $router = new RouteList;

        /* ===== 1. Dynamické domény a subdomény pro W ===== */
        $router[] = $w = new RouteList('W');

        $w->addRoute('//<host>/[<presenter>][/<action>]', [
            'presenter' => 'Home',
            'action' => 'default',
            '' => [
                'filterOut' => function (array $params) {
                    if (!isset($params['url'])) {
                        return null;
                    }

                    $url = $params['url'];
                    $row = $this->db->fetch('SELECT vlastni_domena FROM websites WHERE url = ?', $url);

                    if (false && $row && $row->vlastni_domena) {
// Úmyslně false, aby to zatím nějak fungovalo, ale jinak tady je způsoben ten nekonečný redirect
                        $params['host'] = $row->vlastni_domena;
                    } else {
                        $currentHost = $_SERVER['HTTP_X_FORWARDED_HOST']
                            ?? $_SERVER['HTTP_HOST']
                            ?? 'domainA.local';
                        $currentHost = trim(explode(',', $currentHost)[0]);
                        $currentHost = explode(':', $currentHost)[0];

                        $baseDomain = str_ends_with($currentHost, '.cz') ? 'domainA.cz' : 'domainA.local';
                        $params['host'] = $url . '.' . $baseDomain;
                    }

                    unset($params['url']);
                    return $params;
                },
                'filterIn' => function (array $params) {
                    $forwardedHost = isset($_SERVER['HTTP_X_FORWARDED_HOST'])
                        ? trim(explode(',', $_SERVER['HTTP_X_FORWARDED_HOST'])[0])
                        : null;

                    // Pokud X-Forwarded-Host je hlavní doména, tato routa se netýká
                    $mainDomains = [
                        'domainA.local',
                        'domainA.cz',
                        'www.domainA.cz',
                        '192.168.100.204',
                    ];

                    if ($forwardedHost && in_array($forwardedHost, $mainDomains, true)) {
                        return null;
                    }

                    // Přepíšeme host skutečnou doménou klienta
                    if ($forwardedHost) {
                        $params['host'] = $forwardedHost;
                    }

                    $hostWithPort = $params['host'] ?? '';
                    if ($hostWithPort === '')
                        return null;

                    $host = explode(':', $hostWithPort)[0];

                    if (in_array($host, $mainDomains, true)) {
                        return null;
                    }

                    // A) Kontrola vlastní domény
                    $row = $this->db->fetch(
                        'SELECT url FROM websites WHERE vlastni_domena = ? AND zverejneno = 1 AND platne_do > NOW()',
                        $host,
                    );

                    if ($row) {
                        $params['url'] = $row->url;
                        return $params;
                    }

                    // B) Kontrola subdomény
                    foreach (['domainA.local', 'domainA.cz'] as $main) {
                        if (str_ends_with($host, '.' . $main)) {
                            $slug = substr($host, 0, -strlen('.' . $main));
                            $row = $this->db->fetch(
                                'SELECT url FROM websites WHERE url = ? AND platne_do > NOW()',
                                $slug,
                            );
                            if ($row) {
                                $params['url'] = $row->url;
                                return $params;
                            }
                        }
                    }

                    // C) Neznámá doména – redirect na hlavní web
                    $currentHost = $forwardedHost ?? ($_SERVER['HTTP_HOST'] ?? '');
                    $isLocal = str_contains($currentHost, '.local') || str_contains($currentHost, '192.168.');
                    $targetMain = $isLocal ? $currentHost : 'domainA.cz';

                    if ($host === '192.168.100.204' || $host === $targetMain || $host === "www.$targetMain") {
                        return null;
                    }

                    header("Location: https://$targetMain/domena-nenapojena", true, 302);
                    exit;
                },
            ],
        ]);

        /* ===== 2. Výchozí doména (Administrace, Cron, atd.) ===== */
        $router[] = $admin = new RouteList('Admin');
        $admin->addRoute('admin/<presenter>/<action>[/<id>]', 'Home:default');

        $router[] = $cron = new RouteList('Cron');
        $cron->addRoute('cron/<presenter>/<action>', 'Home:default');

        $router[] = $app = new RouteList('App');
        $app->addRoute('app/plan/dekujeme/<orderVS>', 'Plan:dekujeme');
        $app->addRoute('app/<presenter>[/<action>][/<id>]', 'Home:default');

        $router[] = $webhook = new RouteList('Webhook');
        $webhook->addRoute('webhook/<presenter>/<action>[/<id>]', 'Home:default');

        $router[] = $error = new RouteList('Error');
        $error->addRoute('error/<presenter>/<action>', 'Error4xx:default');

        $router[] = $front = new RouteList('Front');
        $front->addRoute('sitemap.xml', 'Sitemap:default');
        $front->addRoute('stahnout[/<cloudJob>]', 'Stahnout:default');
        $front->addRoute('<presenter>/<action>[/<id>]', 'Home:default');

        return $router;
    }
}

Budu moc rád za popostrčení, AI neporadilo – kromě přepsání práv k souborům na serveru nebo nějakých dalších nesmyslů. Ale nemyslím si, že bych chtěl nějak moc. :) Předem děkuji. :)

Editoval Rndoom04 (Dnes 5:03)