Якщо ваш сайт на WordPress «має SSL», але браузер все одно викидає попередження, ви не самі. Замочок бреше — ну, не зовсім. Він виконує те, для чого створений: сигналізує, коли будь-який ресурс на сторінці, завантаженій по HTTPS, отримується через HTTP.
Ось тут команди панікують, ставлять ще три плагіни й випадково роблять гірше. Не робіть так. Змішаний вміст — це проблема системи: база даних, теми, плагіни, CDN, проксі, кеші та заголовки — всі мають голос. Виправляють це звуженням джерел, внесенням змін у правильному шарі та запобіганням рецидиву.
Що таке змішаний вміст насправді (і чому браузери звертають на це увагу)
Змішаний вміст виникає, коли сторінка, завантажена по HTTPS, підвантажує будь-який підресурс по простому HTTP. Підресурси включають зображення, CSS, JavaScript, шрифти, iframe, відео, XHR/fetch виклики і навіть фонувані зображення, які вказані в CSS.
Браузери трактують це як зниження рівня безпеки. TLS захищає верхньорівневий документ, але якщо ви завантажуєте скрипт по HTTP, атакуючий у мережі може його підмінити. Вашу «безпечну» сторінку можна перетворити на кіоск для збору облікових даних.
Активний проти пасивного змішаного вмісту
- Активний змішаний вміст (скрипти, iframe, XHR) може виконувати код або змінювати поведінку сторінки. Браузери зазвичай блокують його за замовчуванням.
- Пасивний змішаний вміст (зображення, аудіо, відео) зазвичай не може прямо виконувати код. Браузери можуть дозволити його, але попереджають. «Може дозволити» — не стратегія.
Чому «я встановив SSL» недостатньо
Термінування SSL означає лише, що край може говорити HTTPS. WordPress все ще може:
- Зберігати абсолютні HTTP URL у базі даних.
- Генерувати HTTP-посилання, якщо думає, що працює по HTTP (невідповідність через зворотні проксі).
- Підвантажувати сторонні ресурси по HTTP (старі теми, вставки від постачальників, вбудований контент).
- Надсилати редиректи непослідовно (деякі шляхи 301 на HTTPS, інші — ні).
- Кешувати старий HTML, що містить HTTP URL (кеш сторінок, кеш CDN).
Ще одне: попередження браузера не завжди пов’язані з очевидним http://. Вони можуть виникати через протокольно-результативні URL (//example.com), CSS url(), inline-скрипти та жорстко закодовані кінцеві точки плагінів. Змішаний вміст — це полювання за трофеєм, тільки трофей ховається у вашому футер-віджеті.
Цікаві факти та трохи історії
- «Змішаний вміст» існував до сучасних браузерів. Ранні HTTPS-сайти часто вбудовували HTTP-зображення, щоб економити CPU — TLS колись вимагав багато ресурсів.
- «HTTPS як сигнал ранжування» від Google (2014) перетворив замочок із гарної опції на KPI в масштабі організації.
- Let’s Encrypt (публічний запуск 2015) зробив сертифікати безкоштовними та автоматизованими, що прискорило прийняття HTTPS — і виявило десятиліття HTTP-хардкодингу.
- HTTP/2 (стандартизований 2015) фактично став HTTPS-only у провідних браузерах, підштовхнувши сайти до переходу заради продуктивності.
- Chrome почав маркувати HTTP-сторінки як «Не захищено» (2018), особливо при формах, що змусило навіть охоче не переходити бізнеси прибирати змішаний вміст під час переходу на HTTPS.
- HSTS може «зафіксувати» домен на HTTPS. Чудово для безпеки, але жорстко, якщо у вас лишилися піддомени або сторонні ресурси лише по HTTP.
- Протокольно-результативні URL (
//) колись були трюком для міграції. Сьогодні вони здебільшого плутають і їх варто припинити на сучасних HTTPS-проектах. - WordPress зберігає URL у багатьох місцях. Не лише в постах: опції, віджети, дані конструктора сторінок, серіалізовані масиви і іноді theme mods.
- Деякі CDN повторно вводять змішаний вміст. Ви можете термінувати TLS на CDN, але при цьому CDN все одно отримуватиме ресурси з origin по HTTP або непослідовно переписувати HTML.
Швидка діагностика: як швидко знайти винуватця
Це порядок триажу, який я використовую, коли хтось пише «замочок зламався» за п’ять хвилин до запуску.
1) Відтворіть проблему на одній сторінці та подивіться консоль браузера
Виберіть одну проблемну сторінку, відкрийте DevTools → Console та Network. Помилки про змішаний вміст зазвичай містять точний URL, що спричиняє проблему.
Рішення: Якщо ресурс на вашому домені — виправляйте WordPress/конфіг/базу даних. Якщо сторонній — вирішіть, замінити, проксувати чи видалити.
2) Підтвердьте, який URL вважає вашим сам WordPress
Якщо siteurl/home вказані як HTTP, WordPress із задоволенням друкуватиме HTTP-посилання завжди.
Рішення: Якщо є невідповідність — виправте в БД або через WP-CLI, потім очистіть кеші.
3) Перевірте TLS і поведінку редиректів на рівні краю
Переконайтеся, що HTTP посилає редирект на HTTPS послідовно, і чи ваш зворотний проксі встановлює правильні заголовки.
Рішення: Якщо WordPress за load balancer/CDN, забезпечте, щоб він бачив еквіваленти HTTPS=on (зазвичай X-Forwarded-Proto: https).
4) Пошукайте жорстко прописані http:// у відрендереному HTML
Не гадати — підвантажте сторінку і зробіть grep. Якщо http:// з’являється — у вас проблема перепису/бази/теми.
Рішення: Якщо це в HTML з постів/опцій — зробіть безпечну пошуково-заміну. Якщо у коді теми/плагіна — виправте код або перевизначте.
5) Якщо проблема «іноді», підозрюйте кеші або умовний рендеринг
Кеш сторінок, object cache, CDN і кеши конструктора можуть зберігати старі URL. Також: вивід для залогінених користувачів може відрізнятися від анонімного.
Рішення: Очищайте правильні шари кешу і перевіряйте свіжий запит, що оминає кеш.
Звідки береться змішаний вміст у WordPress (реальні режими відмов)
Абсолютні URL у базі даних
Контент WordPress — це звалище URL. Пости й сторінки зберігають абсолютні посилання. Так само віджети. Так само плагіни-конструктори. Найгірше: деякі плагіни зберігають дані як серіалізовані PHP-масиви, тож наївна пошуково-замінна операція ламає довжини рядків і псує дані.
Сучасний WP-CLI обробляє це правильно. Більшість плагінів для «пошук і заміна» також роблять це вірно, але запускати їх у продакшні без бекапу — спосіб додати собі сивого волосся.
Хардкодинг у темі або плагіні
Типові шаблони:
- Підключені скрипти/стилі з жорстко прописаним
http://. - Google Fonts або аналітика, вставлені зі старого гайда.
- Inline CSS з
background-image: url(http://...). - Старі соціальні віджети й трекінгові пікселі.
Невідповідність у зворотному проксі / CDN: WordPress думає, що це HTTP
Якщо TLS термінується на load balancer (AWS ALB, NGINX proxy, CDN), бекенд може отримувати простий HTTP. Якщо ви не передасте правильні заголовки і не налаштуєте WordPress довіряти їм, він згенерує HTTP-URL для ресурсів.
Саме тут ви бачите петлі: HTTP→HTTPS редиректи відбуваються на проксі, але WordPress все одно редиректить назад або генерує змішані схеми в canonical-посиланнях.
CDN або кеш, що віддає застарілий HTML
Ви виправили БД, але CDN все ще віддає старий HTML з HTTP-URL. Або плагін кешування сторінок має статичний HTML-файл з минулого тижня. Або object cache містить застарілі опції.
Сторонній контент: те, що ви не можете виправити звідси
Якщо сторонній скрипт доступний тільки по HTTP — це мертва залежність. Замініть його. Якщо замінити неможливо, іноді можна проксувати його через свій домен по HTTPS, але тоді ви берете на себе відповідальність за безпеку та кешування. Не робіть цього легковажно.
Жарт №1: Змішаний вміст — це як пристібатися ременем без закриття дверцят машини: технічно ви старалися, практично — ні.
Практичні завдання з командами: виявити, вирішити, виправити
Ці завдання передбачають, що ви можете SSH на хост або контейнер, де працює WordPress. Якщо не можете — більшість перевірок доступні з вашого ноутбука, але в реальності виправлення часто потребує доступу на сервер.
Правило: Кожне завдання закінчується рішенням. Якщо ви не вирішуєте — ви просто збираєте логи для скрапбука.
Завдання 1: Перевірте відрендерений HTML на очевидні HTTP-ресурси
cr0x@server:~$ curl -sS https://example.com/ | grep -Eo 'http://[^"]+' | head
http://example.com/wp-content/uploads/2022/10/hero.jpg
http://fonts.googleapis.com/css?family=Open+Sans:400,700
Що це означає: HTML сторінки містить абсолютні HTTP URL.
Рішення: Якщо це ваш домен (example.com) — виправляйте БД/тему. Якщо сторонній (fonts.googleapis.com) — оновіть вставку на HTTPS або замініть/видаліть.
Завдання 2: Використайте браузерний рівень із заголовками, щоб підтвердити редиректи
cr0x@server:~$ curl -I http://example.com/
HTTP/1.1 301 Moved Permanently
Location: https://example.com/
Server: nginx
Що це означає: HTTP редиректить на HTTPS на рівні краю.
Рішення: Добре. Якщо ви не отримуєте 301/308 на HTTPS — виправте політику редиректів у вебсервері/CDN першочергово. Виправляти змішаний вміст марно, якщо користувачі все ще потрапляють на HTTP.
Завдання 3: Підтвердіть canonical-URL, який виводить WordPress
cr0x@server:~$ curl -sS https://example.com/ | grep -iE 'rel="canonical"|og:url' | head -n 5
<link rel="canonical" href="http://example.com/" />
<meta property="og:url" content="http://example.com/" />
Що це означає: WordPress (або SEO-плагін) вважає, що URL сайту — HTTP.
Рішення: Виправте home і siteurl в опціях WP і перевірте заголовки зворотного проксі.
Завдання 4: Перевірте налаштування URL у WordPress через WP-CLI
cr0x@server:~$ cd /var/www/html
cr0x@server:~$ wp option get home
http://example.com
cr0x@server:~$ wp option get siteurl
http://example.com
Що це означає: Базові URL вказані як HTTP і це керує генерацією внутрішніх посилань.
Рішення: Оновіть обидва на HTTPS (наступне завдання), потім очистіть кеші.
Завдання 5: Безпечно оновіть home і siteurl
cr0x@server:~$ wp option update home 'https://example.com'
Success: Updated 'home' option.
cr0x@server:~$ wp option update siteurl 'https://example.com'
Success: Updated 'siteurl' option.
Що це означає: WordPress тепер за замовчуванням генеруватиме HTTPS-URL.
Рішення: Повторно протестуйте сторінку. Якщо вміст все ще містить HTTP — необхідна пошуково-замінна операція в постах/опціях.
Завдання 6: Знайдіть HTTP-URL по всій базі даних (спочатку dry-run)
cr0x@server:~$ wp search-replace 'http://example.com' 'https://example.com' --all-tables --dry-run
+----------------------+--------------+--------------+------+
| Table | Column | Replacements | Type |
+----------------------+--------------+--------------+------+
| wp_posts | post_content | 128 | SQL |
| wp_postmeta | meta_value | 42 | PHP |
| wp_options | option_value | 19 | PHP |
+----------------------+--------------+--------------+------+
Success: Made 189 replacements.
Що це означає: Знайдено 189 випадків HTTP-URL, включно з серіалізованими даними (позначено PHP).
Рішення: Якщо кількість замін виглядає розумною — запустіть ту ж команду без --dry-run. Якщо лічильник несподівано величезний — зупиніться і зробіть бекап БД перш ніж продовжити.
Завдання 7: Виконайте пошук/заміну в БД насправді
cr0x@server:~$ wp search-replace 'http://example.com' 'https://example.com' --all-tables
+----------------------+--------------+--------------+------+
| Table | Column | Replacements | Type |
+----------------------+--------------+--------------+------+
| wp_posts | post_content | 128 | SQL |
| wp_postmeta | meta_value | 42 | PHP |
| wp_options | option_value | 19 | PHP |
+----------------------+--------------+--------------+------+
Success: Made 189 replacements.
Що це означає: Тепер вміст бази даних посилається на HTTPS для вашого домену.
Рішення: Очистіть шари кешу; потім знову запустіть Завдання 1. Якщо сторонній HTTP залишається — вирішіть його індивідуально.
Завдання 8: Знайдіть жорстко прописані HTTP у коді теми/плагінів
cr0x@server:~$ grep -RIn --exclude-dir=node_modules --exclude-dir=.git "http://" wp-content/themes wp-content/plugins | head
wp-content/themes/acme/header.php:44: <script src="http://cdn.vendor.example/widget.js"></script>
wp-content/plugins/old-analytics/old-analytics.php:12:$src = 'http://stats.vendor.example/pixel.js';
Що це означає: У коді є жорстко прописані HTTP. Пошуково-замінна операція в БД це не зачепить.
Рішення: Оновіть на HTTPS або видаліть залежність. Якщо у постачальника нема HTTPS — замініть постачальника. Не ігноруйте попередження.
Завдання 9: Підтвердіть, що бачить бекенд (перевірка зворотного проксі)
cr0x@server:~$ wp eval 'var_dump($_SERVER["HTTPS"] ?? null, $_SERVER["HTTP_X_FORWARDED_PROTO"] ?? null);'
NULL
string(4) "http"
Що це означає: WordPress думає, що працює по HTTP за проксі (forwarded proto — http).
Рішення: Налаштуйте проксі так, щоб він встановлював X-Forwarded-Proto: https для TLS-запитів, і налаштуйте WordPress довіряти цьому заголовку (часто через wp-config.php або конфіг сервера). Без цього змішаний вміст може повернутися навіть після очищення БД.
Завдання 10: Перевірте заголовки відповіді на наявність підказок про безпеку та схему
cr0x@server:~$ curl -sSI https://example.com/ | grep -iE 'strict-transport-security|content-security-policy|location|x-forwarded-proto'
Strict-Transport-Security: max-age=0
Що це означає: HSTS вимкнено (max-age=0). Прямо не пов’язано зі змішаним вмістом, але впливає на те, наскільки агресивно браузери залишаються на HTTPS.
Рішення: Не вмикайте довгий HSTS, поки змішаний вміст не зникне і ви не впевнені, що кожен піддомен підтримує HTTPS.
Завдання 11: Перевірте конфіг NGINX на предмет заголовків проксі (якщо ви його використовуєте)
cr0x@server:~$ sudo nginx -T 2>/dev/null | grep -n "X-Forwarded-Proto" | head
128: proxy_set_header X-Forwarded-Proto $scheme;
Що це означає: NGINX передаватиме схему, яку отримав. Якщо NGINX термінує TLS, $scheme має бути https.
Рішення: Якщо TLS термінується деінде (CDN/ELB), NGINX може бачити HTTP і передавати http. У такому випадку явно встановіть значення на основі вхідних forwarded-заголовків або термінуйте TLS на NGINX.
Завдання 12: Знайдіть змішаний вміст у CSS (фонові зображення підступні)
cr0x@server:~$ grep -RIn "url(http://" wp-content | head
wp-content/themes/acme/assets/css/main.css:233:background-image: url(http://example.com/wp-content/uploads/2021/03/bg.png);
Що це означає: Статичні ресурси посилаються на HTTP всередині CSS. Браузери будуть це помічати.
Рішення: Виправте CSS (використайте відносні шляхи або HTTPS) і перебудуйте/мінімізуйте за потреби. Потім очистіть кеші/CDN.
Завдання 13: Перевірте, що завантаження (uploads) віддаються по HTTPS і не редиректять дивно
cr0x@server:~$ curl -I https://example.com/wp-content/uploads/2022/10/hero.jpg
HTTP/2 200
content-type: image/jpeg
cache-control: public, max-age=31536000
Що це означає: Завантаження доступні через HTTPS безпосередньо.
Рішення: Якщо ви бачите редиректи на HTTP або інший хост — виправте правила перезапису, конфіг origin у CDN або налаштування плагіна offload.
Завдання 14: Перевірте, чи увімкнені в WordPress налаштування «force SSL» та схема для адмінки
cr0x@server:~$ wp config get FORCE_SSL_ADMIN --type=constant
true
Що це означає: Адмінка примусово через SSL. Добре, але це не гарантує коректності фронтенду.
Рішення: Залишайте це увімкненим, але не плутайте з виправленням змішаного вмісту. Фронтенд-ресурси і контент все ще потребують очищення.
Завдання 15: Перевірте, що на сторінці після виправлень не лишилося HTTP
cr0x@server:~$ curl -sS https://example.com/ | grep -Eo 'http://[^"]+' | wc -l
0
Що це означає: HTML цієї сторінки більше не містить очевидних HTTP-URL.
Рішення: Якщо браузер все ще попереджає — ймовірно, джерело знаходиться в runtime-запитах (JS, сторонні виклики) або в іншому шаблоні сторінки. Використайте DevTools Network, щоб вирахувати його.
Завдання 16: Якщо у вас є CDN, переконайтеся, що він не переписує і не кешує старий контент
cr0x@server:~$ curl -sSI https://example.com/ | grep -iE 'cf-cache-status|x-cache|age|via'
Age: 8421
Via: 1.1 varnish
Що це означає: Ви потрапляєте на кеш-лінію зі старим контентом. Там може бути ще старі HTTP-посилання.
Рішення: Очищайте кеш для уражених шляхів або інвалідуйте все, якщо змінили URL по всьому сайту. Потім тестуйте з Cache-Control: no-cache або обходячи кеш через query-string (залежно від політик CDN).
Три корпоративні міні-історії (як це псується)
Міні-історія 1: Інцидент через хибне припущення
Компанія A перемістила маркетинговий сайт WordPress за новий балансувальник навантаження. TLS термінувався на LB; трафік до origin ішов по HTTP у приватній мережі. Усі кивали і казали: «Все добре, внутрішній трафік довірений.» Вони були напівправі — найгірший вид правоти.
Вебкоманда перевірила, що https:// завантажується і побачила замочок на головній. День запуску. Раптом платний трафік почав потрапляти на лендинги, які в деяких браузерах показували «Не захищено». Конверсія впала. Маркетинг звинуватив нову тему. Тема звинуватила CDN. SRE на виклику звинуватив гравітацію.
Корінь був простий: WordPress вважав, що запити — HTTP, бо заголовок forwarded proto був неправильний. LB відправляв X-Forwarded-Proto: http через неправильно налаштоване правило слухача. Головна сторінка випадково була закешована з правильними HTTPS-лінками з попереднього шляху запиту, але кілька лендингів відрендерилися свіжо і згенерували HTTP-ресурси.
Виправлення: поправити поведінку LB щодо заголовків, додати логику бекенду довіряти заголовку лише від відомих IP проксі, очистити кеш, потім виконати пошуково-замінну операцію в базі для очищення старого контенту. «TLS на краю означає, що додаток знає про HTTPS» — помилкове припущення. Додаток не читає думки.
Міні-історія 2: Оптимізація, що відплатилась бумерангом
Компанія B хотіла швидші сторінки. Хтось увімкнув «HTML rewrite» на CDN, щоб мінімізувати та «нормалізувати» контент. Здавалося нешкідливо. Ще тиждень показники Lighthouse покращувалися.
Потім оновлення плагіна додало протокольно-результативні URL для підключення скрипта: //vendor.example/script.js. Логіка перепису CDN вирішила «допомогти» й переписала деякі протокольно-результативні URL у http://, коли запит до origin був по HTTP (бо з’єднання CDN→origin використовувало HTTP для швидкодії — так, справді).
Результат: браузери почали блокувати активний змішаний вміст, але тільки для користувачів, що потрапляли на кешовані сторінки, оброблені тим шляхом перепису. DevTools показував скрипт з HTTP, але пошук по базі WordPress його не знаходив. Команда витратила години на пошуково-замінні операції в контенті, який ніколи не був джерелом.
Виправлення не було у відкаті плагіна. Це було вимкнення фічі HTML-rewrite на CDN (або налаштування її так, щоб зберігати схему), переведення CDN→origin на HTTPS та закріплення критичних сторонніх ресурсів як явних HTTPS. Оптимізація, що відплатилася класично — інтернет завжди збирає свій борг з відсотками.
Міні-історія 3: Нудна, але правильна практика, що врятувала день
Компанія C мала прісний рукбук для «міграцій URL», який ніхто не любив. Він вимагав: бекап БД, WP-CLI dry-run пошуково-заміну, перевірку через curl/grep, очищення кешу, а потім тест канаркового сторінки у staging і production.
Під час ребрендингу вони перейшли на новий домен і ввімкнули HTTPS усюди. Змішаний вміст мав би з’явитися — були роки вбудованих зображень, inline HTML-блоків і конструктор сторінок, що зберігав JSON-об’єкти в postmeta.
Але рукбук змусив їх пройти неприємні кроки: серіалізовано-безпечну заміну WP-CLI, сканування на http:// у директоріях тем/плагінів і перевірку, яка підвантажувала топ-20 шаблонів і шукала HTTP. Також вимагався purge CDN після змін, а не до.
День запуску пройшов непомітно. Ніхто не хвалив рукбук. Саме так ви розумієте, що він спрацював. Нудна практика не лише виправила змішаний вміст; вона запобігла появі випадкового попередження браузера у важливий момент.
Поширені помилки: симптом → корінь → виправлення
- Симптом: На головній стоїть замочок, але деякі сторінки показують «Не захищено»
- Корінь: Закешована головна vs некешовані шаблони; змішаний вміст в окремих блоках конструктора або postmeta.
- Виправлення: Використайте DevTools на проблемній сторінці, потім запустіть WP-CLI search-replace по всіх таблицях і проскануйте теми/плагіни на жорстко прописаний HTTP.
- Симптом: У консолі браузера «blocked active mixed content» для JS-файлу
- Корінь: Жорстко прописане
http://підключення скрипта в темі, плагіні або інжекційному тег-менеджері. - Виправлення: Видаліть або оновіть вставку на HTTPS; якщо сторонній не підтримує HTTPS — замініть постачальника. Не проксуйте довільний JS, якщо не готові взяти на себе відповідальність.
- Симптом: Адмінка WordPress через HTTPS, але фронтенд видає HTTP-ресурси
- Корінь:
FORCE_SSL_ADMINвстановлено, алеhome/siteurlще HTTP; або невідповідність заголовків зворотного проксі. - Виправлення: Оновіть
homeіsiteurlна HTTPS; переконайтеся, щоX-Forwarded-Protoправильний; очистіть кеші. - Симптом: Змішаний вміст з’являється лише для деяких користувачів чи регіонів
- Корінь: CDN edge кешує застарілий HTML; регіональні POP мають різні стани кешу; A/B тестинг інжектує HTTP URL.
- Виправлення: Очищайте кеш CDN; перевірте ключі кешування; аудитуйте системи інжекції; перетестуйте з декількох регіонів з однаковими заголовками.
- Симптом: Після «виправлення» через плагін шаблон ламається або контент зникає
- Корінь: Наївна пошуково-замінна операція пошкодила серіалізовані дані або JSON-блоби конструктора.
- Виправлення: Відновіть бекап; використайте WP-CLI
search-replace, що обробляє серіалізацію; перезапустіть обережно з dry-run спочатку. - Симптом: Зображення завантажуються, але браузер все одно попереджає про змішаний вміст
- Корінь: Існує iframe, скрипт, шрифт або XHR, що ще по HTTP. Зображення — лише типічний підозрюваний, але не єдиний.
- Виправлення: Перевірте DevTools Network, відфільтрувавши «blocked» або «mixed content»; проскануйте HTML і CSS на
http://. - Симптом: Ввімкнув HSTS і тепер частини сайту ламаються
- Корінь: Деякі підресурси (піддомени, сторонні контенти) все ще вимагають HTTP; HSTS змушує HTTPS і жорстко виявляє прогалини.
- Виправлення: Відкочуйте HSTS (короткий max-age), виправте всі залежності, потім поступово знову вмикайте. Не додавайте у preload, поки не впевнені.
- Симптом: WooCommerce checkout падає або iframe платіжної системи не завантажується
- Корінь: Ресурси платіжного провайдера запитуються по HTTP або callback-ендпоїнти неправильно промарковані за схемою через проксі.
- Виправлення: Переконайтеся, що URL провайдера HTTPS; перевірте заголовки проксі; валідуйте сторінку оформлення замовлення в DevTools і налаштування провайдера.
Контрольні списки / покроковий план (зробити один раз — правильно)
Чекліст A: Односайтовий WordPress, TLS термінується на вебсервері
- Переконайтеся, що HTTP → HTTPS редирект працює для
/і декількох внутрішніх шляхів (категорія, пост, ресурс). - Переконайтеся, що сертифікат дійсний і ланцюжок коректний (перевірка в браузері + curl заголовки).
- Встановіть
homeіsiteurlна HTTPS через WP-CLI. - Запустіть WP-CLI
search-replace(dry-run, потім реальний) для вашого домену. - Зробіть grep по директоріях тем/плагінів на
http://; виправте жорстко прописані ресурси. - Очистіть плагін кешування сторінок і перегенеруйте мінімізовані ресурси.
- Підвантажте топ-шаблони і знайдіть
http://у відрендереному HTML. - Перевірте в DevTools: немає змішаного вмісту в Console; немає блокованих запитів у Network.
Чекліст B: WordPress за зворотним проксі / балансувальником / CDN
- Підтвердіть, що edge редиректить HTTP → HTTPS послідовно.
- Підтвердіть, що edge надсилає правильні forwarded-заголовки (
X-Forwarded-Proto: httpsколи клієнт використовує HTTPS). - Налаштуйте бекенд вебсервер і/або WordPress довіряти заголовкам проксі лише від відомих IP-адрес проксі.
- Встановіть
homeіsiteurlна HTTPS. - Запустіть серіалізовано-безпечну заміну в БД.
- Очистіть кеші CDN після змін контенту (не перед).
- Переконайтеся, що origin не генерує HTTP у canonical/meta для некешованих сторінок.
- Тільки потім подумайте про вмикання HSTS з коротким max-age, потім поступово збільшуйте.
Чекліст C: Сценарій міграції (зміна домену або схеми)
- Зробіть бекап БД і uploads. Немає бекапу — ніяких змін. Це не догма, це виживання.
- Програйте зміну в staging із копією продакшен-даних.
- Запустіть WP-CLI dry-run search-replace; перегляньте кількість замін по таблицях/стовпцях.
- Виконайте реальну заміну; перевірте топ-сторінки і критичні потоки (логін, checkout, форми).
- Переведіть DNS / конфіг краю; перевірте редиректи і canonical-теги.
- Очищайте кеші і «прогрівайте» CDN маленьким краулом важливих сторінок.
- Моніторте логи помилок і клієнтські console-помилки через RUM, якщо доступно.
Профілактика: не допустити повернення змішаного вмісту
Встановіть правильні інваріанти
- Усе по HTTPS (включно з uploads, API викликами, шрифтами, аналітикою, вбудованими елементами).
- Один канонічний хост (www vs apex — оберіть один і редиректьте інший).
- Одна канонічна схема (HTTPS завжди).
Використовуйте Content Security Policy (CSP) як запобіжник, а не пластир
CSP допоможе ловити регресії, повідомляючи про блокування змішаного вмісту або заборонених джерел. Але CSP не виправить зламані URL у базі даних. Він лише робить помилку голоснішою й більш детермінованою.
Якщо впроваджуєте CSP — починайте з report-only режиму, дивіться, що ламається, потім підтягуйте політику. Ставте це як процес управління змінами, а не як однорядкове рішення.
HSTS: потужно, але небезпечно при недбалості
HSTS каже браузерам: «Завжди використовуйте HTTPS для цього домену». Це добре. Також це означає, що будь-яка залишкова HTTP-залежність стає жорсткою помилкою. Впроваджуйте поетапно: короткий max-age, перевірка, потім збільшення. Уникайте preload, поки все не чисто і стабільно.
Операційний вислів
Надія — не стратегія.
— Джеймс Кемерон
Жарт №2: Браузерний замочок — це ваш аудит безпеки, тільки він працює у вихідні і ніколи не погоджується на пончики.
Питання та відповіді
Чому я все ще бачу змішаний вміст після зміни WordPress Address і Site Address?
Тому що ці налаштування змінюють те, що WordPress генеруватиме надалі, але не те, що вже збережено. Старі пости, віджети, дані конструктора і опції теми можуть містити абсолютні HTTP URL. Виконайте серіалізовано-безпечну пошуково-замінну операцію і проскануйте теми/плагіни на жорстко прописані URL.
Чи можна «виправити змішаний вміст» плагіном, що примушує HTTPS?
Іноді він ховає симптоми переписом виводу. Рідко це вирішує корінь проблеми. Використовуйте його лише як тимчасову міру, поки чистите базу та код. Інакше ви випустите постійний хаґ, що зламається під час кешування, мініфікації чи оновлення плагінів.
Який найбезпечніший спосіб замінити HTTP на HTTPS у базі даних?
WP-CLI wp search-replace з dry-run спочатку. Він коректно обробляє серіалізовані дані. Завжди робіть бекап БД перед реальним запуском, особливо на сайтах із конструкторами сторінок.
Чому змішаний вміст видно лише в Chrome, а не в Firefox (або навпаки)?
Браузери відрізняються в тому, що блокують, а що лише попереджають, відрізняються в кешуванні й у звітності DevTools. Не сперечайтеся з браузером; використайте DevTools Network/Console, щоб ідентифікувати точний URL і виправити його в джерелі.
Я за Cloudflare (або іншим CDN). Чому WordPress думає, що це HTTP?
Бо з’єднання до origin може бути HTTP, і forwarded-заголовки можуть не встановлюватися або не довірятися. Переконайтеся, що CDN надсилає X-Forwarded-Proto: https і налаштуйте origin/WordPress так, щоб він трактував запит як HTTPS у відповідних випадках.
Чи можна лишити «пасивний» змішаний вміст, наприклад зображення?
Ні. Це привчає користувачів ігнорувати сигнали безпеки і може витікати метадані поведінки користувача через запити. До того ж браузери дедалі жорсткіше ставляться до правил. Виправте зараз, поки це лише попередження, а не зламана сторінка.
Чи виправить HSTS проблему змішаного вмісту?
Ні. HSTS змушує браузер використовувати HTTPS для навігації по вашому домену. Він не перезапише сторонні URL і не виправить HTTP-посилання, вбудовані в HTML, CSS чи скрипти. HSTS може зробити помилки помітнішими — це корисно після очищення сайту.
Чому WooCommerce показує змішаний вміст саме на сторінці оформлення замовлення?
Сторінка оформлення зазвичай містить скрипти платіжних провайдерів, iframe і API-виклики. Один HTTP-ендпоїнт достатній, щоб викликати попередження або блокування. Перевірте DevTools на предмет сторонніх URL і переконайтеся в коректності проксі-заголовків і налаштувань site URL.
Як зрозуміти, що я виправив це всюди, а не лише на одній сторінці?
Тестуйте репрезентативні шаблони: головну, пост блогу, категорію, пошук, логін, кошик/checkout і кілька лендингів з конструктором. Програмно підвантажте і зробіть grep на http:// у HTML, і використайте DevTools, щоб зловити runtime-запити.
Наступні кроки, які можна відправити сьогодні
- Виберіть одну проблемну сторінку і ідентифікуйте точний HTTP-ресурс у DevTools.
- Перевірте, що
homeіsiteurlвказані як HTTPS; виправте, якщо ні. - Запустіть WP-CLI
search-replace(dry-run, потім реальний) для вашого домену. - Проскануйте код тем/плагінів і CSS на жорстко прописані
http://і приберіть їх. - Очищайте всі шари кешу (кеш сторінок + CDN) після змін.
- Тільки після того, як сайт чистий, поступово вмикайте HSTS, щоб уникнути повернення проблеми.
Якщо ви виконуєте ці кроки в порядку, змішаний вміст перестане бути примхою браузера і перетвориться на послідовне інженерне прибирання. Саме тим він завжди і був.