Bali, Indonesia
Insights

Mengira wp-cron Rusak, Padahal Loopback Gagal karena Sertifikat SSL Kedaluwarsa

October 25, 2026
0:00
Post terjadwal muncul dengan status Missed schedule, lalu Site Health bilang situs gagal melakukan loopback request. Kesimpulan yang paling cepat muncul biasanya: wp-cron rusak. Setelah itu orang reinstall plugin, memasang plugin pemicu cron tambahan, atau langsung menyalahkan hosting. Padahal wp-cron sendiri jarang benar-benar rusak. Yang lebih sering gagal adalah jalur request dari server ke dirinya sendiri, dan sertifikat SSL yang kedaluwarsa atau chain yang tidak lengkap termasuk penyebab yang gampang terlewat.
WP-Cron bukan cron sistem. Ia tidak jalan sendiri di background. Setiap ada kunjungan ke halaman, WordPress mengecek apakah ada event yang sudah jatuh tempo, misalnya publish post terjadwal, cek update, atau tugas plugin. Kalau ada, WordPress mengirim request HTTP ke wp-cron.php di URL situs itu sendiri. Request dari server ke dirinya sendiri inilah yang disebut loopback request. Request itu melewati jalur yang sama dengan pengunjung biasa. Nama domain di-resolve lewat DNS, koneksi dibuka ke port 443 kalau situs pakai HTTPS, terjadi TLS handshake, lalu baru PHP mengeksekusi wp-cron.php. Tes loopback di Site Health memakai jalur yang mirip. Jadi kalau salah satu langkah itu gagal, event tidak pernah dieksekusi. Penyebabnya bisa DNS yang mengarah ke IP yang salah, firewall yang memblokir IP server sendiri, basic auth, plugin keamanan, atau TLS. Masalahnya, spawn cron dikirim secara non-blocking dengan timeout pendek. Pengunjung tidak melihat error apa pun, dan sering tidak ada jejak di log aplikasi. Dari luar kelihatannya cron diam saja, makanya cepat dicap rusak. Di support, keluhan seperti ini biasanya datang sebagai post tidak terbit, bukan sebagai masalah SSL. Akibatnya pengecekan pertama sering salah arah.
Ada satu detail yang perlu jujur disampaikan. Di WordPress core, request spawn cron dan tes loopback Site Health biasanya memakai nilai dari filter https_local_ssl_verify untuk menentukan apakah sertifikat diverifikasi, dan nilai default-nya false. Artinya, di instalasi standar tanpa modifikasi, sertifikat kedaluwarsa sering tidak menghentikan wp-cron. Cek sendiri di versi yang kamu pakai, karena detail seperti ini bisa berubah. Sertifikat baru jadi penyebab ketika ada sesuatu di jalur loopback yang memverifikasinya. Kasus yang umum:
  • Ada plugin, mu-plugin, atau kode di tema yang mengembalikan true pada filter https_local_ssl_verify. Ini cukup sering dipasang sebagai bagian dari hardening.
  • Domain mengarah ke reverse proxy, CDN, atau load balancer yang memvalidasi sertifikat origin sebelum meneruskan request. Loopback dari server ikut lewat sana, sehingga ikut ditolak.
  • Plugin lain, misalnya plugin backup atau page builder, memanggil REST API situs sendiri dengan verifikasi aktif. Hasilnya, gejalanya mirip tapi sumbernya berbeda.
Cara tercepat memilah semua ini adalah membaca detail error di Site Health, bukan hanya judulnya. Kalau isinya menyebut cURL error 60 dengan keterangan soal sertifikat, arahnya jelas ke TLS. Kalau isinya timeout, 401, atau 403, kemungkinan besar penyebabnya bukan SSL. Arahkan pengecekan ke firewall, DNS, atau proteksi akses.
Ada dua masalah sertifikat yang sering tertukar. Kedaluwarsa berarti tanggal notAfter sudah lewat. Chain tidak lengkap berarti server hanya mengirim sertifikat leaf (sertifikat milik domain) tanpa sertifikat intermediate dari CA. Akibatnya klien tidak bisa menyambungkan leaf itu ke root yang dipercaya. Chain tidak lengkap sering membingungkan karena sebagian browser bisa melengkapi intermediate sendiri. Di browser gembok terlihat normal, tapi curl dan PHP di server gagal. Karena itu tes harus dijalankan lewat SSH dari server itu sendiri, bukan dari laptop. Jalur DNS, proxy, dan perilaku kliennya berbeda.
BASH
# 1) Lewat jalur yang sama dengan loopback (DNS domain apa adanya)
curl -sv -o /dev/null https://example.com/wp-cron.php 2>&1 | grep -Ei 'expire|issuer|SSL certificate|HTTP/'

# 2) Paksa langsung ke web server lokal, lewati DNS dan proxy
curl -sv -o /dev/null --resolve example.com:443:127.0.0.1 https://example.com/wp-cron.php 2>&1 | grep -Ei 'expire|issuer|SSL certificate|HTTP/'
Ganti example.com dengan domainnya. Kalau web server tidak listen di 127.0.0.1, pakai IP server. Perbandingan dua hasil ini cukup informatif. Kalau tes pertama gagal tapi tes kedua lolos, masalahnya ada di lapisan depan, misalnya proxy atau CDN. Kalau keduanya gagal dengan pesan yang sama, masalahnya di sertifikat yang dipasang di server. Pesan dengan pola certificate has expired mengarah ke sertifikat kedaluwarsa. Pesan unable to get local issuer certificate biasanya berarti chain tidak lengkap. Teks persisnya bisa berbeda tergantung TLS backend yang dipakai curl. Untuk melihat isi sertifikat dan jumlah sertifikat yang dikirim server, pakai openssl s_client. Parameter -servername penting karena server dengan banyak domain memilih sertifikat berdasarkan SNI. Tanpa parameter itu, yang muncul bisa sertifikat default.
BASH
# Subject, issuer, dan tanggal berlaku sertifikat yang dikirim server
echo | openssl s_client -connect 127.0.0.1:443 -servername example.com 2>/dev/null | openssl x509 -noout -subject -issuer -dates

# Hitung jumlah sertifikat yang dikirim (leaf + intermediate)
echo | openssl s_client -connect 127.0.0.1:443 -servername example.com -showcerts 2>/dev/null | grep -c 'BEGIN CERTIFICATE'
Kalau notAfter sudah lewat, ada dua kemungkinan. Pertama, renewal memang gagal. Kedua, renewal sebenarnya berhasil tapi web server belum di-reload, sehingga masih menyajikan sertifikat lama. Kemungkinan kedua cukup sering terjadi. Bandingkan dengan tanggal di file sertifikat yang baru. Kalau hitungan sertifikat hanya 1, server cuma mengirim leaf. Konfigurasinya perlu diarahkan ke file full chain atau bundle intermediate. Nama dan lokasi file itu tergantung control panel dan ACME client yang dipakai.
Sertifikat TLS publik sekarang berumur lebih pendek. Ballot SC081v3 di CA/Browser Forum menetapkan batas masa berlaku 200 hari mulai 15 Maret 2026, 100 hari mulai 15 Maret 2027, dan 47 hari mulai 15 Maret 2029. Sebelumnya batasnya 398 hari. DigiCert, misalnya, sudah membatasi sertifikat yang terbit mulai 24 Februari 2026 maksimal 199 hari, sehari di bawah batas forum. Dampak praktisnya sederhana: renewal makin sering terjadi, dan setiap renewal punya peluang gagal. Validasi domain bisa gagal karena redirect atau record CAA. Sertifikat baru bisa terpasang tanpa intermediate. Service bisa lupa di-reload. Dulu kegagalan seperti ini mungkin baru terasa setahun sekali. Sekarang jedanya jauh lebih pendek, dan gejala pertamanya kadang bukan peringatan di browser, melainkan cron yang diam. Kalau masa berlaku masih dicatat manual, alasan kenapa cara itu makin tidak terkejar dibahas di artikel soal tracking renewal manual. Untuk renewal yang gagal setelah pindah ke ACME client, cek juga kegagalan CAA saat beralih dari SSL manual.
Perbaiki sertifikatnya dulu, jangan disembunyikan. Memaksa curl -k atau mematikan verifikasi lewat kode memang membuat error hilang dari Site Health. Tapi pengunjung, API eksternal, dan monitoring tetap melihat sertifikat yang bermasalah, dan kamu kehilangan sinyal paling awalnya. Cek log renewal di AutoSSL atau ACME client, pastikan konfigurasi web server menunjuk ke file full chain, lalu reload service. Setelah itu, ulangi dua tes di atas sampai keduanya bersih. Setelah sertifikat beres, kurangi ketergantungan cron pada loopback. Set DISABLE_WP_CRON ke true di wp-config.php, lalu jalankan event lewat cron sistem dengan WP-CLI. Cara ini menjalankan PHP langsung tanpa request HTTP, sehingga tidak bergantung pada DNS, proxy, atau TLS. Jadwalnya juga tidak lagi bergantung pada ada atau tidaknya pengunjung.
BASH
# Cari kode yang memaksa verifikasi SSL pada loopback
grep -rn 'https_local_ssl_verify' wp-content/

# Tes spawn wp-cron dan lihat event yang menunggu
wp cron test
wp cron event list --fields=hook,next_run_relative

# Contoh baris crontab setelah DISABLE_WP_CRON aktif (interval hanya contoh)
# */5 * * * * cd /path/ke/wordpress && wp cron event run --due-now --quiet
Perlu dicatat, wp cron test akan melaporkan bahwa WP-Cron dinonaktifkan setelah DISABLE_WP_CRON aktif. Itu normal. Untuk monitoring, opsi -checkend pada openssl x509 bisa dipakai di cron untuk memberi peringatan kalau sertifikat akan habis dalam jangka waktu tertentu. Contohnya -checkend 1209600 untuk 14 hari. Jalankan cek ini dari server, bukan hanya dari layanan monitoring luar, supaya chain yang tidak lengkap juga ikut tertangkap. Jadi, kalau post terjadwal terlewat dan loopback gagal, baca dulu pesan error lengkapnya di Site Health. Lalu jalankan curl dari server sendiri dengan dan tanpa --resolve. Dua langkah itu biasanya cukup untuk memastikan apakah masalahnya di sertifikat, chain, atau lapisan lain. Pindah ke cron sistem membuat jadwal lebih andal, tapi bukan pengganti renewal yang sehat. Dengan masa berlaku yang terus memendek, renewal dan pengecekan chain sebaiknya diperlakukan sebagai proses rutin, bukan kejadian tahunan.