9 сентября 2026 года в блоге Percona вышла заметка Juan Arruti: как включить TLS на трафике между нодами Percona XtraDB Cluster, не останавливая весь кластер. Это не новый пакет и не CVE. Это процедура для живого PXC, у которого шифрование репликации выключено, а аудит, compliance или сегмент сети вдруг потребовали его включить.
С PXC 8.0 переменная pxc-encrypt-cluster-traffic по умолчанию включена. Она закрывает SSL на group communication, State Snapshot Transfer (SST) и Incremental State Transfer (IST). На практике кластеры без TLS встречаются часто: ставили давно, дефолт тогда был другой, или кто-то выключил «чтобы завелось».
Переменная не динамическая. Нода с шифрованием слушает ssl://, соседи без него остаются на tcp://. Если просто включить флаг на одной ноде и перезапустить её, в логе Galera будет Failed to establish connection: wrong version number. Это обычная реакция OpenSSL, когда клиент шлёт TLS, а сервер ждёт открытый TCP.
Откуда это известно и что говорит документация
Первоисточник: пост Percona от 9 сентября 2026. Автор разбирает обходной путь, который появляется с PXC 8.0.28 и есть во всех PXC 8.4. Он опирается на опцию провайдера Galera socket.dynamic.
Документация PXC 8.4 по шифрованию трафика по-прежнему описывает штатный сценарий иначе: pxc-encrypt-cluster-traffic нельзя поменять на работающем кластере, смена требует остановить кластер, поправить конфиг и поднять ноды заново. В индексе wsrep_provider_options для 8.4 опции socket.dynamic нет. Имеет смысл не спорить с докой «на глаз», а идти по шагам из блога и сверять логи ssl:// / tcp://.
Что это меняет на VPS с WordPress
Типичный WordPress на одном VPS с nginx, PHP-FPM и одной MariaDB эту процедуру не запускает. PXC это не «просто MySQL» и не MariaDB Galera из репозитория Debian. Это кластер Percona Server на базе Galera, обычно три ноды. Если в переменных нет wsrep_* и pxc_encrypt_cluster_traffic, дальше можно не читать: новость про чужой контур.
Если база сайта реально сидит на PXC, TLS между нодами и HTTPS сайта это разные слои. Сертификат Let’s Encrypt на nginx сайт не шифрует порт 4567. Аудит, который просит «закрыть репликацию», смотрит на межнодовый трафик: SST, IST и write-set. Клиентский TLS (WordPress → MySQL) тоже отдельно: его документация PXC описывает через те же ssl-ca / ssl-cert / ssl-key, но пост Arruti про inter-node, не про wp-config.php.
На практике это означает: пока нода в rolling restart, кворум держат остальные. Если PHP ходит в конкретный хост из DB_HOST, рестарт этой ноды даст обрыв SQL на время подъёма. Если перед кластером балансировщик с живыми бэкендами, запрос уйдёт на соседнюю ноду. Kubernetes и «просто уйдите в облако» здесь ни при чём.
Что делает socket.dynamic
Опция позволяет ноде говорить с соседями и по TLS, и открытым TCP. Сначала попытка зашифрованного соединения. Если сосед отвечает не TLS, нода повторяет уже без шифрования и входит в кластер. Без socket.dynamic на первой же ошибке wrong version number она так и не присоединится.
В runtime это не переключается. Чтобы включить опцию, ноду всё равно нужно перезапустить. Даунтайм всего кластера при этом не обязателен: схема рассчитана на rolling restart трёх нод, и таких проходов будет два. Percona прямо пишет: полностью перевести кластер на TLS без двух проходов не получится.
Сертификаты и my.cnf до первого рестарта
На всех нодах одни и те же ключ и сертификат. Неважно, сгенерировал их MySQL сам или выпустили вы. Percona советует держать файлы вне datadir: joiner перед полным SST вычищает каталог данных, выживают только файлы по шаблону [sst] cpat. По умолчанию туда попадают *.pem. Файл .crt или .key, лежащий в datadir, будет удалён.
Документация 8.4 для того же сюжета предлагает каталог /etc/mysql/certs и те же имена: ca.pem, server-cert.pem, server-key.pem. В блоге каркас my.cnf такой:
[mysqld] pxc-encrypt-cluster-traffic=ON wsrep_provider_options="socket.dynamic=YES" ssl-ca=/etc/mysql/certs/ca.pem ssl-cert=/etc/mysql/certs/server-cert.pem ssl-key=/etc/mysql/certs/server-key.pem [sst] encrypt=4 ssl-ca=/etc/mysql/certs/ca.pem ssl-cert=/etc/mysql/certs/server-cert.pem ssl-key=/etc/mysql/certs/server-key.pem
pxc-encrypt-cluster-traffic=ON включает TLS для group communication, IST и SST. socket.dynamic=YES нужен на время раскатки, чтобы нода умела оба протокола. Секция [sst] с encrypt=4 в блоге названа страховкой: флаг сам по себе требует SST на encrypt=4, а явная секция помогает донору и joiner, пока правка ещё не применена на всех нодах.
Побочный эффект, который легко пропустить: скрипт SST перечитывает my.cnf на каждой передаче. Как только в файле появились [sst] encrypt=4 и ssl-*, доноры начинают шифровать SST, даже если mysqld на них ещё не перезапускали. Конфиг лучше разложить на все ноды до первого рестарта, а не «по ходу». Перед правкой: копия my.cnf.
Два прохода rolling restart
Типовая схема в посте: три ноды.
Первый проход: TLS есть, plaintext ещё можно
Ноды 1 и 2 перезапускают по одной с конфигом выше. После каждой ждать, пока нода снова в кластере и в состоянии Synced. Перезапущенная нода пробует TLS и откатывается на plaintext.
Что настройки дошли до провайдера, в блоге проверяют так. wsrep_provider_options это длинная строка пар, из неё вытаскивают нужные ключи:
SELECT REGEXP_SUBSTR(@@wsrep_provider_options,'socket\\.dynamic = [^;]+') AS socket_dynamic, REGEXP_SUBSTR(@@wsrep_provider_options,'socket\\.ssl = [^;]+') AS socket_ssl, REGEXP_SUBSTR(@@wsrep_provider_options,'socket\\.ssl_ca = [^;]+') AS socket_ssl_ca, REGEXP_SUBSTR(@@wsrep_provider_options,'socket\\.ssl_cert = [^;]+') AS socket_ssl_cert, REGEXP_SUBSTR(@@wsrep_provider_options,'socket\\.ssl_key = [^;]+') AS socket_ssl_key\G
Ожидаемый кадр из разбора: socket.dynamic=YES, socket.ssl=YES, пути к pem совпадают с конфигом. socket.ssl и сертификаты провайдер получает от MySQL, потому что pxc-encrypt-cluster-traffic уже ON. Это ещё не значит, что репликация зашифрована. В промежуточном состоянии трафик может идти открытым текстом.
В статье это ловят tcpdump на ноде 1, порт 4567, пакеты с ноды 2. На ноде 2 создают учебную таблицу. DDL в PXC уходит statement’ом, и в дампе виден create table test.table_test:
tcpdump -i any -nn -A -s 0 "tcp port 4567 and host node2" -c 2000 | grep -a table_test
На проде такую таблицу на боевой базе лучше не плодить. Достаточно смотреть лог Galera: после первого прохода соединения ещё могут быть tcp://. Учебный CREATE TABLE оставлен как в источнике, не как обязательный шаг.
Второй проход: только TLS
Ноду 3 поднимают с socket.dynamic=NO. Ей динамический режим не нужен: две другие уже умеют и TLS, и plaintext. В my.cnf на этом шаге:
[mysqld] wsrep_provider_options="socket.dynamic=NO"
После рестарта в логе должны появиться соединения ssl://, не tcp://. Затем то же на нодах 1 и 2: убрать socket.dynamic, перезапустить по одной. Когда все три говорят только TLS, тот же tcpdump на 4567 уже не находит DROP TABLE test.table_test: трафик зашифрован.
Снять TLS, если понадобится, можно тем же механизмом и тоже двумя rolling restart. Сначала вернуть socket.dynamic=YES на нодах 1 и 2, оставив pxc-encrypt-cluster-traffic=ON. Затем ноду 3 поднять с pxc-encrypt-cluster-traffic=OFF. Потом ноды 1 и 2 тоже выключить шифрование и убрать socket.dynamic. Секцию [sst] с encrypt и ssl-* чистят в конце, не в начале.
Что проверить руками
Сначала убедиться, что это PXC, а не одиночный mysqld или MariaDB. Команды ниже типовые, без выдуманных пакетов Ubuntu. Пользователь с правом чтения переменных, не обязательно root на всю машину.
mysql --version mysql -e "SHOW VARIABLES LIKE 'pxc_encrypt_cluster_traffic'; SHOW VARIABLES LIKE 'wsrep_on'; SHOW STATUS LIKE 'wsrep_cluster_size'; SHOW STATUS LIKE 'wsrep_local_state_comment';"
Если pxc_encrypt_cluster_traffic нет в списке, вы не на PXC. Не копируйте wsrep_provider_options в MariaDB «на всякий случай». Версии 8.0.28 и 8.4 в посте относятся к Percona XtraDB Cluster, не к пакету mariadb-server из Debian.
После каждого рестарта ноды: тот же SHOW STATUS, плюс запрос с REGEXP_SUBSTR из блока выше. Пока socket.dynamic=YES, наличие socket.ssl=YES ещё не равно «соседи говорят только TLS».
Рестарт ноды кластера это не nginx -t и не reload. Две ноды сразу не трогать. Копия конфига до правки. Не предлагаю mysql_upgrade с потолка: к включению TLS он не относится.
Где обычно ломается
- Разные сертификаты на нодах. Документация 8.4 об этом пишет отдельно: тогда нода просто не вступит.
- Сертификаты оставили в datadir, потом случился SST. Joiner получил чистый каталог без
.crt/.key. - Включили
pxc-encrypt-cluster-trafficна одной ноде безsocket.dynamicи без подготовки соседей. Получилиwrong version numberи узел вне кластера. - Поправили только
[mysqld], забыли[sst]. Скрипт SST читает файл сразу, donor и joiner могут разъехаться поencrypt=4. - Перепутали HTTPS сайта и TLS Galera. certbot на 443 порт 4567 не закрывает.
- Перепутали MariaDB на том же VPS и PXC. Ветки, пакеты и дефолты другие.
- Рестарт всех трёх нод «чтобы наверняка». Кворум и сайт поедут вместе.
Не выключать AppArmor и файрвол «чтобы Galera завелась». Если 4567 и соседние порты репликации не ходят между нодами, сначала сеть, не шифрование. chmod 777 на каталог сертификатов тоже не нужен: в документации 8.4 для /etc/mysql/certs достаточно владельца mysql:mysql.
Если у вас один MySQL или MariaDB рядом с WordPress, эта новость про чужой контур. Если PXC уже стоит и TLS между нодами выключен, имеет смысл идти по схеме Percona, а не останавливать три ноды разом. Смотреть версию: обходной путь заявлен с 8.0.28 и во всей 8.4. Документация по-прежнему описывает полную остановку кластера как штатный способ сменить pxc-encrypt-cluster-traffic. Блог как раз про то, как этого избежать двумя rolling restart.