WP Manifestindependent plugin directory
manifest / performance / robin-proxy-bridge

Robin Proxy Bridge

WordPress-мост: разворачивает исходящие запросы Robin Image Optimizer на собственный обратный прокси через pre_http_request, не изменяя код плагина

by boris0024 · github.com/boris0024/robin-proxy-bridge · website

0stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/boris0024/robin-proxy-bridge/archive/refs/heads/main.zip

Плагин WordPress, который разворачивает исходящие запросы Robin Image Optimizer на ваш собственный обратный прокси.

Нужен в одной ситуации: плагин установлен, настроен и работает, но его API (dashboard.robinoptimizer.com) недоступно с вашего сервера. Картинки не жмутся, WebP не создаётся, а в логах плагина висят неудачные запросы.

Обычные пути решения плохие: форкать чужой плагин больно на каждом обновлении, менять оптимизатор дорого, если библиотека уже обработана наполовину. Этот мост не трогает код Robin вообще.

Как это работает

WordPress пропускает все исходящие HTTP-запросы через свой HTTP API, а тот даёт фильтр pre_http_request, который срабатывает до отправки. Плагин ловит запрос, подменяет адрес и выполняет его сам.

Три точки перехвата:

  1. pre_http_request - запрос к API оптимизатора разворачивается на прокси.
  2. http_response - в теле ответа переписываются ссылки на скачивание результата. Бесплатный тариф Robin отдаёт JSON со ссылкой на готовый файл, и без подмены плагин пошёл бы за ним напрямую, снова в недоступный хост.
  3. http_api_curl - точечно отключает проверку сертификата, если прокси работает на самоподписанном (по умолчанию проверка включена).

Приём универсальный. Замените хост через фильтр rpb_target_host, и тот же мост будет работать для любого плагина, который ходит в недоступный сервис через WP HTTP API:

add_filter( 'rpb_target_host', function () {
    return 'api.example-service.com';
} );

Почему не WP_PROXY_HOST

В WordPress есть встроенная поддержка прокси через константы в wp-config.php. Она не подходит по трём причинам:

  • через прокси пойдут все запросы WordPress: обновления ядра, тем, других плагинов, а WP_PROXY_BYPASS_HOSTS это список исключений, а не белый список;
  • нужен полноценный прямой прокси (squid, 3proxy), то есть отдельный демон, который придётся закрывать от посторонних;
  • здесь используется обратный прокси на nginx, который умеет ходить ровно к одному хосту и прячется за секретным путём.

Установка

1. Прокси на сервере, с которого API доступно

Возьмите nginx/robin-proxy.conf, замените плейсхолдеры и подключите:

cp nginx/robin-proxy.conf /etc/nginx/sites-available/robin-proxy
# сгенерируйте свой секретный путь:
echo "rp_$(openssl rand -hex 16)"
# впишите его, IP вашего сайта в allow и пути к сертификатам
ln -s /etc/nginx/sites-available/robin-proxy /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx

Строку limit_req_zone нужно положить в nginx.conf, в блок http:

limit_req_zone $binary_remote_addr zone=robin_proxy_limit:1m rate=10r/s;

2. Плагин на сайте

Скопируйте папку в wp-content/plugins/robin-proxy-bridge, активируйте, откройте Настройки → Robin Proxy Bridge:

  • включите прокси;
  • впишите полный адрес вместе с секретным путём: https://proxy.example.com:8443/rp_ваш_секрет;
  • оставьте проверку сертификата включённой, если у прокси нормальный сертификат;
  • нажмите «Проверить прокси».

Ответ с любым кодом кроме 404 означает, что туннель работает. Код 404 обычно значит, что секретный путь в настройках не совпадает с location в nginx.

Обновление с версии 1.0.0

В 1.0.0 проверка TLS-сертификата была отключена жёстко, в 1.1.0 она стала настройкой и включена по умолчанию.

Если ваш прокси работает на самоподписанном сертификате, сразу после обновления запросы начнут падать:

cURL error 60: SSL certificate problem: self-signed certificate

Лечится одним из двух способов:

  • выпустить нормальный сертификат Let's Encrypt на домен прокси (правильный путь);
  • снять галку «Проверять сертификат» в настройках плагина.

Безопасность

Прочитайте, прежде чем поднимать это в продакшене.

  • Закрывайте прокси по IP. allow <IP сайта>; deny all; в конфиге это главный рубеж. Открытый порт находят сканеры: на боевом сервере за сутки набегает больше сотни посторонних запросов.
  • Секретный путь это секрет. Он попадает в настройки WordPress, в бэкапы базы и, что неприятнее, в логи самого Robin Image Optimizer открытым текстом, потому что тот пишет полный URL скачивания. Кто получил доступ к логам сайта, получил доступ к прокси.
  • Не выключайте проверку сертификата без нужды. Через прокси идут файлы, а на платном тарифе ещё и ключ лицензии в заголовке Authorization. Лучше выпустить Let's Encrypt на домен, чем жить с самоподписанным сертификатом.
  • Ротируйте секретный путь, если он мог утечь: поменяйте location в nginx и адрес в настройках плагина.

Проверено на

Компонент Версия
WordPress 6.7.5
Robin Image Optimizer 2.0.5
PHP 8.3.31
nginx 1.22.1 и 1.31.1

Версия 1.1.0 проверена на боевой связке с реальным прокси: перехват запроса к API отдаёт HTTP 200 через прокси, ссылка на скачивание в ответе переписывается корректно, запросы к посторонним хостам (api.wordpress.org) остаются нетронутыми, а с включённой проверкой самоподписанного сертификата запрос ожидаемо падает с cURL error 60.

Результат на двух боевых сайтах: 7 684 изображения сконвертированы в WebP, 1 309.7 МБ оригиналов против 443.2 МБ WebP, то есть минус 66% веса картинок.

Что этот плагин не делает

Он не отдаёт WebP посетителям. Отдачей занимается сам Robin Image Optimizer: по умолчанию он подставляет теги <picture> в HTML через выходной буфер PHP. Режим отдачи средствами сервера у Robin реализован только для Apache через .htaccess, на nginx он в настройках недоступен. Этот мост решает другую задачу: доставить запрос до API, чтобы WebP вообще создался.

Лицензия

GPL-2.0-or-later, как и сам WordPress. См. LICENSE.

Проект не связан с разработчиками Robin Image Optimizer и не аффилирован с ними. Robin Image Optimizer распространяется по своей лицензии, его код в этот репозиторий не входит.