Bali, Indonesia
Insights

Situs Malah Menampilkan Sertifikat Domain Lain? Cek SNI dan VirtualHost Default

November 4, 2026
0:00
Pengunjung membuka situs kamu lalu browser menolak dengan peringatan seperti NET::ERR_CERT_COMMON_NAME_INVALID. Saat detail sertifikatnya dibuka, nama yang tertera ternyata domain lain yang kebetulan ada di server yang sama. Banyak orang langsung curiga sertifikatnya tertukar atau dicuri. Hampir selalu penyebabnya lebih sederhana: server tidak menemukan konfigurasi HTTPS yang cocok untuk nama domain kamu, jadi ia menjawab dengan konfigurasi default untuk IP dan port itu. Di meja support, keluhan ini sering datang dari pemilik situs yang baru menambah domain, baru pindah server, atau baru memasang SSL. Pola pemeriksaannya hampir selalu sama, jadi kita bahas urutannya dari gejala sampai akar masalah.
Satu IP biasanya dipakai bersama oleh banyak domain. Untuk HTTP biasa ini tidak masalah, karena browser mengirim header Host dan server tinggal memilih situs yang sesuai. Di HTTPS urutannya berbeda. Sertifikat harus dikirim saat TLS handshake, yaitu proses negosiasi enkripsi yang terjadi sebelum request HTTP mana pun dikirim. Header Host belum ada di tahap itu. SNI (Server Name Indication) mengisi celah ini. SNI adalah ekstensi TLS yang membuat klien menyebutkan nama domain tujuannya di pesan pertama handshake. Server membaca nama itu lalu memilih sertifikat dari VirtualHost (Apache) atau server block (Nginx) yang cocok. Kalau tidak ada yang cocok, server tidak menolak koneksi. Ia memakai konfigurasi default untuk kombinasi IP:port tersebut. Di Apache, default-nya adalah VirtualHost pertama yang terbaca untuk alamat itu. Di Nginx, default-nya server block yang ditandai default_server pada listen, atau server block pertama kalau tidak ada yang ditandai. Sertifikat milik vhost default itulah yang akhirnya sampai ke pengunjung kamu. Jadi pertanyaan diagnosanya bukan "kenapa sertifikatnya tertukar", tapi "kenapa nama domain ini tidak cocok dengan vhost HTTPS mana pun di IP dan port yang dituju".
Sebelum membongkar konfigurasi, pastikan koneksi pengunjung memang sampai ke server yang kamu kira. Ada beberapa pengecoh yang gejalanya mirip. Pertama, DNS. Kalau record A domain masih mengarah ke server lama atau server lain, sertifikat yang muncul berasal dari mesin yang salah. Bandingkan hasil dig +short contoh.com A dengan IP server yang seharusnya, dan lakukan juga untuk www. Kedua, IPv6. Pengecoh ini sering terlewat. Domain bisa punya record AAAA yang mengarah ke IPv6 server, sementara vhost HTTPS hanya dikonfigurasi untuk IPv4. Pengunjung dengan koneksi IPv6 akan mendarat di vhost default, sementara kamu yang mengetes dari jaringan IPv4 melihat semuanya normal. Cek dengan dig +short contoh.com AAAA. Ketiga, proxy atau CDN. Kalau domain lewat layanan reverse proxy, sertifikat yang dilihat browser berasal dari edge layanan itu, bukan dari server kamu. Masalahnya ada di pengaturan layanan tersebut. Kalau IP-nya benar dan tidak ada proxy di depan, kita lanjut ke server.
Tes paling jujur adalah berbicara langsung ke IP server dengan openssl s_client, sekali dengan menyebutkan nama domain lewat SNI dan sekali tanpa SNI. Cara ini melewati cache browser dan DNS lokal.
BASH
# Dengan SNI: minta sertifikat untuk contoh.com langsung ke IP server
openssl s_client -connect 203.0.113.10:443 -servername contoh.com </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates -ext subjectAltName

# Tanpa SNI: lihat sertifikat vhost default untuk IP:port ini
openssl s_client -connect 203.0.113.10:443 -noservername </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer

# Untuk IPv6, tulis alamat di dalam kurung siku
openssl s_client -connect '[2001:db8::10]:443' -servername contoh.com </dev/null 2>/dev/null \
  | openssl x509 -noout -subject
Ganti IP dan domain dengan milikmu. Bagian -ext subjectAltName menampilkan daftar nama yang benar-benar dicakup sertifikat. Bagian ini yang dicek browser, bukan hanya subject. Opsi -noservername dan -ext butuh OpenSSL 1.1.1 ke atas. Di versi lebih lama, hapus -ext dan lihat SAN lewat -text. Cara membaca hasilnya:
  • Dengan SNI, sertifikatnya benar: server sudah oke. Masalahnya ada di jalur pengunjung, misalnya DNS, IPv6, proxy, atau klien yang tidak mengirim SNI.
  • Dengan SNI, sertifikatnya sama dengan hasil tanpa SNI: server jatuh ke vhost default. Tidak ada vhost HTTPS di IP:port itu yang mengenali nama domain kamu.
  • Dengan SNI, sertifikatnya milik domain kamu tapi www tidak ada di SAN: ini masalah cakupan sertifikat, bukan pemilihan vhost.
Kasus kedua adalah inti artikel ini.
Di Apache, apachectl -S menampilkan bagaimana Apache memetakan setiap IP:port ke VirtualHost, termasuk mana yang jadi default. Di Debian/Ubuntu perintahnya biasanya apache2ctl, di keluarga RHEL bisa httpd -S. Di Nginx, nginx -T mencetak seluruh konfigurasi yang sedang dimuat, dan kamu cukup memfilter baris yang relevan.
BASH
# Apache: tampilkan pemetaan vhost untuk port 443
apachectl -S 2>&1 | grep -A5 ':443'

# Nginx: tampilkan listen, server_name, dan sertifikat beserta nomor barisnya
nginx -T 2>/dev/null | grep -nE 'listen .*443|server_name|ssl_certificate '
Keduanya hanya membaca konfigurasi dan aman dijalankan. Contoh format output Apache kira-kira seperti ini:
TEXT
*:443                  is a NameVirtualHost
         default server domainlain.com (/etc/apache2/sites-enabled/domainlain-ssl.conf:2)
         port 443 namevhost domainlain.com (/etc/apache2/sites-enabled/domainlain-ssl.conf:2)
         port 443 namevhost toko.com (/etc/apache2/sites-enabled/toko-ssl.conf:2)
Baris default server adalah vhost yang sertifikatnya muncul di browser pengunjung. Setelah itu, cari domain kamu di daftar namevhost. Biasanya ada beberapa kemungkinan. Domain sama sekali tidak muncul di blok port 443. Vhost-nya hanya ada untuk port 80. Kondisi ini umum terjadi kalau SSL dipasang manual tanpa membuat vhost HTTPS-nya, atau kalau penerbitan sertifikat otomatis gagal sehingga vhost SSL tidak pernah dibuat. Untuk kasus AutoSSL, bahasannya ada di Kenapa AutoSSL Gagal Diperbarui Padahal Domain Sudah Mengarah ke Server. Domain ada, tapi www tidak. Apache hanya mencocokkan nama yang tertulis di ServerName atau ServerAlias. Di Nginx, nama harus tercantum di server_name. Kalau www.contoh.com tidak tercantum, request ke www jatuh ke default. Domain ada, tapi di blok alamat yang berbeda. Kasus ini paling membingungkan. Apache dan Nginx sama-sama memilih kelompok vhost berdasarkan alamat dulu, baru mencocokkan nama di dalam kelompok itu. Kalau ada vhost yang ditulis <VirtualHost 203.0.113.10:443> dan vhost kamu ditulis <VirtualHost *:443>, request ke IP tersebut akan dicocokkan di kelompok yang IP-nya spesifik. Vhost kamu tidak pernah dipertimbangkan, padahal namanya benar. Di output apachectl -S, keduanya muncul sebagai blok terpisah. Di Nginx, prinsipnya sama antara listen 203.0.113.10:443 dan listen 443. Konfigurasi sudah benar di file, tapi belum dimuat. Kalau nginx -T atau apachectl -S tidak menunjukkan perubahan terbaru, berarti service belum di-reload, atau file vhost berada di direktori yang tidak di-include. Di server dengan control panel seperti cPanel, file vhost biasanya dibuat otomatis dan bisa ditimpa saat rebuild. Perbaiki lewat panel atau tool resminya, bukan dengan mengedit file hasil generate. Kalau web server-nya LiteSpeed, ia biasanya membaca konfigurasi Apache yang dibuat panel, jadi apachectl -S tetap berguna untuk melihat pemetaannya. Detailnya tergantung setup, jadi cek dokumentasi panel yang kamu pakai.
Setelah menambah vhost HTTPS, melengkapi ServerAlias atau server_name, atau menyamakan format alamat listen, selalu tes sintaks sebelum reload: apachectl configtest untuk Apache dan nginx -t untuk Nginx. Config yang rusak bisa membuat web server gagal start dan semua situs di mesin itu ikut down, jadi langkah ini jangan dilewati. Setelah reload, ulangi tes openssl s_client dengan SNI untuk domain utama dan www, lewat IPv4 dan IPv6 kalau ada record AAAA. Subject dan SAN harus mencakup nama yang kamu uji. Baru setelah itu cek dari browser, sebaiknya di jendela private agar tidak terpengaruh cache. Ada satu hal yang sering terlupakan. Selama vhost default berisi sertifikat domain sungguhan, setiap kesalahan konfigurasi di domain lain akan memamerkan nama domain itu ke pengunjung yang salah alamat. Sebagian admin memilih membuat vhost default netral dengan sertifikat self-signed. Di Nginx 1.19.4 ke atas, ada juga opsi ssl_reject_handshake on di server block default untuk menolak handshake tanpa nama yang cocok. Trade-off-nya, pengunjung tetap melihat error, hanya saja tidak ada domain lain yang ikut terbawa. Mana yang cocok tergantung kebijakan server kamu. Kalau mau dirangkum jadi kebiasaan: begitu ada laporan sertifikat domain lain, cek dulu IP di DNS (termasuk AAAA), lalu tanya langsung ke IP server dengan openssl s_client -servername. Kalau hasilnya sama dengan tes tanpa SNI, buka apachectl -S atau nginx -T, cari baris default, dan periksa kenapa domainmu tidak masuk ke kelompok alamat yang sama. Hampir semua kasus selesai di salah satu langkah itu.