<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.2.0">Jekyll</generator><link href="https://www.udienz.web.id/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.udienz.web.id/" rel="alternate" type="text/html" /><updated>2026-11-06T02:50:59+00:00</updated><id>https://www.udienz.web.id/feed.xml</id><title type="html">udienz blog</title><subtitle>A personal blog, talk about life, and other stuff</subtitle><author><name>Mahyuddin Susanto</name></author><entry><title type="html">Penyadapan Presiden Bukan Hal Baru: Menelusuri Jejaknya dari Watergate hingga Istana</title><link href="https://www.udienz.web.id/2026/11/06/sejarah-penyadapan-kepala-negara" rel="alternate" type="text/html" title="Penyadapan Presiden Bukan Hal Baru: Menelusuri Jejaknya dari Watergate hingga Istana" /><published>2026-11-06T00:00:03+00:00</published><updated>2026-11-06T00:00:03+00:00</updated><id>https://www.udienz.web.id/2026/11/06/sejarah-penyadapan-kepala-negara</id><content type="html" xml:base="https://www.udienz.web.id/2026/11/06/sejarah-penyadapan-kepala-negara">&lt;p&gt;Pada 3 November 2026, Bareskrim Polri menetapkan mantan Kapolri Jenderal Listyo Sigit Prabowo dan dua perwira tinggi, Irjen Ahrie Sonta dan Irjen Eko Hadi Santoso, sebagai tersangka penyadapan ilegal. Menurut Kabareskrim Komjen Asep Safrudin, sasarannya adalah “Presiden RI, pejabat negara, tokoh politik, media, tokoh ormas, LSM” (&lt;a href=&quot;https://nasional.kompas.com/read/2026/11/03/20133141/polri-tetapkan-jenderal-listyo-sigit-sebagai-tersangka-penyadapan-ilegal&quot;&gt;Kompas, 3 November 2026&lt;/a&gt;). Sehari kemudian Mensesneg Prasetyo Hadi menyebut perbuatan itu “mengarah ke perbuatan makar” (&lt;a href=&quot;https://nasional.kompas.com/read/2026/11/04/12423931/istana-penyadapan-listyo-sigit-terhadap-presiden-prabowo-masuk-kategori&quot;&gt;Kompas, 4 November 2026&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Penyadapan kepala negara sudah berkali-kali terjadi. Presiden Indonesia sendiri pernah menjadi sasaran pada 2009, waktu itu oleh intelijen Australia, dan Perdana Menteri Yunani disadap lewat sistem penyadapan sah operator seluler pada 2004. Kanselir Jerman dan Presiden Brasil menjadi sasaran NSA yang terungkap pada 2013, dan nomor Presiden Prancis masuk daftar calon sasaran spyware Pegasus pada 2021. Di Amerika Serikat, skandal penyadapan paling terkenal dalam sejarah menjatuhkan seorang presiden. Tulisan ini menjajarkan kasus-kasus itu dengan kasus 2026 untuk melihat apa yang berulang dan apa yang berbeda.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/sejarah-penyadapan-kepala-negara.webp&quot; alt=&quot;Garis waktu skandal penyadapan kepala negara dari Moorer-Radford 1971 dan Watergate 1972 sampai kasus 2026 yang menyasar Presiden Prabowo&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Poin Penting&lt;/strong&gt;&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;Kasus 2026 berbeda dari kasus SBY, Merkel, dan Macron karena pelakunya diduga orang dalam negeri sendiri yang memegang akses sah ke sistem penyadapan, bukan dinas intelijen negara lain.&lt;/li&gt;
    &lt;li&gt;Penyadapan kepala negara oleh negara sekutu atau mitra lazimnya berakhir tanpa pengadilan. Kasus Merkel ditutup jaksa Jerman pada 2015 karena kurang bukti, dan krisis SBY diselesaikan dengan kode etik intelijen pada 2014.&lt;/li&gt;
    &lt;li&gt;Kasus yang terjadi di dalam negeri sendiri bisa dibawa ke pengadilan, seperti Watergate yang berujung pada pengunduran diri Nixon pada 1974. Bisa juga dikubur, seperti kasus Moorer-Radford pada 1971.&lt;/li&gt;
    &lt;li&gt;Status Listyo Sigit dan dua perwira lain masih tersangka. Tuduhan makar baru disebut pejabat pemerintah dan belum diuji di pengadilan.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;delapan-kasus-dalam-satu-tabel&quot;&gt;Delapan kasus dalam satu tabel&lt;/h2&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Kasus&lt;/th&gt;
      &lt;th&gt;Terungkap&lt;/th&gt;
      &lt;th&gt;Sasaran&lt;/th&gt;
      &lt;th&gt;Pelaku yang dituduh&lt;/th&gt;
      &lt;th&gt;Hubungan pelaku dan sasaran&lt;/th&gt;
      &lt;th&gt;Ujungnya&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Moorer-Radford (pencurian dokumen, bukan penyadapan)&lt;/td&gt;
      &lt;td&gt;1971&lt;/td&gt;
      &lt;td&gt;Dewan Keamanan Nasional AS di bawah Nixon&lt;/td&gt;
      &lt;td&gt;Staf militer yang melapor ke Ketua Gabungan Kepala Staf&lt;/td&gt;
      &lt;td&gt;Bawahan dari lembaga sendiri&lt;/td&gt;
      &lt;td&gt;Tak seorang pun dipenjara&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Watergate&lt;/td&gt;
      &lt;td&gt;1972&lt;/td&gt;
      &lt;td&gt;Markas Partai Demokrat&lt;/td&gt;
      &lt;td&gt;Orang-orang suruhan tim kampanye Nixon&lt;/td&gt;
      &lt;td&gt;Kubu presiden terhadap lawan politik&lt;/td&gt;
      &lt;td&gt;Nixon mundur, 1974&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;SBY dan lingkarannya&lt;/td&gt;
      &lt;td&gt;2013 (kejadian 2009)&lt;/td&gt;
      &lt;td&gt;Presiden, Ibu Negara, Wapres, menteri&lt;/td&gt;
      &lt;td&gt;Intelijen sinyal Australia (DSD)&lt;/td&gt;
      &lt;td&gt;Negara tetangga dan mitra&lt;/td&gt;
      &lt;td&gt;Dubes ditarik, kode etik 2014&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Merkel&lt;/td&gt;
      &lt;td&gt;2013&lt;/td&gt;
      &lt;td&gt;Ponsel Kanselir Jerman&lt;/td&gt;
      &lt;td&gt;NSA Amerika Serikat&lt;/td&gt;
      &lt;td&gt;Sekutu NATO&lt;/td&gt;
      &lt;td&gt;Penyidikan ditutup, 2015&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Rousseff&lt;/td&gt;
      &lt;td&gt;2013&lt;/td&gt;
      &lt;td&gt;Komunikasi Presiden Brasil&lt;/td&gt;
      &lt;td&gt;NSA Amerika Serikat&lt;/td&gt;
      &lt;td&gt;Mitra diplomatik&lt;/td&gt;
      &lt;td&gt;Kunjungan kenegaraan ditunda&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Macron&lt;/td&gt;
      &lt;td&gt;2021&lt;/td&gt;
      &lt;td&gt;Nomor ponsel Presiden Prancis&lt;/td&gt;
      &lt;td&gt;Dinas intelijen Maroko (dibantah)&lt;/td&gt;
      &lt;td&gt;Mitra diplomatik&lt;/td&gt;
      &lt;td&gt;Tidak terbukti ada infeksi&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Athens Affair&lt;/td&gt;
      &lt;td&gt;2005 (kejadian 2004)&lt;/td&gt;
      &lt;td&gt;PM Yunani, menteri, sekitar 100 nomor&lt;/td&gt;
      &lt;td&gt;Tidak dipastikan dalam penyidikan resmi&lt;/td&gt;
      &lt;td&gt;Tidak diketahui&lt;/td&gt;
      &lt;td&gt;Vodafone Yunani didenda&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Kasus 2026&lt;/td&gt;
      &lt;td&gt;2026&lt;/td&gt;
      &lt;td&gt;Presiden Prabowo, pejabat, tokoh, media&lt;/td&gt;
      &lt;td&gt;Mantan Kapolri dan dua jenderal polisi (tersangka)&lt;/td&gt;
      &lt;td&gt;Pejabat dalam negeri&lt;/td&gt;
      &lt;td&gt;Proses hukum berjalan&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Kasus yang pelakunya negara lain hampir semuanya selesai lewat jalur politik dan diplomasi, karena pelakunya berada di luar jangkauan hukum negara korban. Kasus yang terjadi di dalam negeri punya pilihan jalur pidana, meski pilihan itu tidak selalu diambil. Bagian-bagian berikut menelusuri kasus-kasus itu satu per satu. Kasus Yunani sengaja ditaruh terakhir sebelum kasus 2026 karena modusnya paling dekat.&lt;/p&gt;

&lt;h2 id=&quot;watergate-dan-moorer-radford-ketika-gedung-putih-jadi-medan-pengintaian&quot;&gt;Watergate dan Moorer-Radford: ketika Gedung Putih jadi medan pengintaian&lt;/h2&gt;

&lt;p&gt;Dini hari 17 Juni 1972, lima orang ditangkap di dalam kantor Komite Nasional Partai Demokrat di kompleks Watergate, Washington. Mereka datang untuk membetulkan alat sadap yang sudah dipasang sebelumnya dan memotret dokumen. Penyelidikan kemudian menelusuri uang dan perintahnya sampai ke tim kampanye pemilihan ulang Presiden Richard Nixon (&lt;a href=&quot;https://www.archives.gov/research/investigations/watergate&quot;&gt;National Archives&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Arah penyadapan Watergate berlawanan dengan kasus-kasus lain di tulisan ini, karena kubu presiden yang menyadap lawan politiknya. Ironinya, bukti yang akhirnya menjatuhkan Nixon justru berasal dari sistem perekam yang ia pasang sendiri di Gedung Putih. Pada 24 Juli 1974, Mahkamah Agung AS dalam perkara &lt;em&gt;United States v. Nixon&lt;/em&gt; memutuskan 8-0 bahwa presiden wajib menyerahkan rekaman itu, karena klaim umum hak istimewa eksekutif tidak bisa mengalahkan kebutuhan akan bukti dalam perkara pidana (&lt;a href=&quot;https://www.oyez.org/cases/1973/73-1766&quot;&gt;Oyez&lt;/a&gt;). Sejumlah rekaman tersebut kini dibuka untuk publik oleh &lt;a href=&quot;https://www.nixonlibrary.gov/white-house-tapes&quot;&gt;Perpustakaan Kepresidenan Nixon&lt;/a&gt;. Nixon mengundurkan diri pada 9 Agustus 1974.&lt;/p&gt;

&lt;p&gt;Kasus yang lebih mirip dengan situasi 2026 dari sisi hubungan pelaku dan sasaran terjadi sekitar setengah tahun sebelum Watergate dan jauh kurang dikenal. Pada Desember 1971, penyelidik Gedung Putih yang memburu sumber bocoran untuk kolumnis Jack Anderson menemukan bahwa Yeoman Charles Radford, juru steno Angkatan Laut yang bertugas di Dewan Keamanan Nasional, selama berbulan-bulan menyalin dokumen rahasia dan meneruskannya ke Ketua Gabungan Kepala Staf, Laksamana Thomas Moorer. Militer AS, dengan kata lain, memata-matai presidennya sendiri (&lt;a href=&quot;https://fas.org/blogs/secrecy/2007/03/a_memorable_leak_case/&quot;&gt;Federation of American Scientists&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Cara kasus ini diselesaikan menunjukkan dilema yang muncul setiap kali pelakunya orang dalam. Pada akhirnya tidak seorang pun dipenjara (&lt;a href=&quot;https://fas.org/blogs/secrecy/2007/03/a_memorable_leak_case/&quot;&gt;Federation of American Scientists&lt;/a&gt;). Rincian lengkapnya baru bisa dipelajari puluhan tahun kemudian, setelah rekaman Gedung Putih dan dokumen terkait dideklasifikasi (&lt;a href=&quot;https://historynewsnetwork.org/article/36240&quot;&gt;History News Network&lt;/a&gt;). Membuka kasus orang dalam berarti mengakui bahwa lingkaran terdekat kekuasaan bisa ditembus, dan pertimbangan semacam itu bisa ikut menentukan apakah sebuah kasus dibawa ke pengadilan.&lt;/p&gt;

&lt;h2 id=&quot;sby-2009-ponsel-presiden-dalam-daftar-intelijen-tetangga&quot;&gt;SBY 2009: ponsel presiden dalam daftar intelijen tetangga&lt;/h2&gt;

&lt;p&gt;Pada 18 November 2013, ABC dan Guardian Australia menerbitkan dokumen dari arsip Edward Snowden yang menunjukkan bahwa Defence Signals Directorate (DSD), badan intelijen sinyal Australia, melacak aktivitas ponsel Presiden Susilo Bambang Yudhoyono selama 15 hari pada Agustus 2009. Daftar sasarannya juga memuat Ibu Negara Ani Yudhoyono, Wakil Presiden Boediono, mantan Wakil Presiden Jusuf Kalla, dan sejumlah menteri (jabatan per 2013; pada Agustus 2009 Kalla masih menjabat wapres). Satu slide berjudul “Indonesian President voice events” berisi catatan data panggilan, yaitu siapa menelepon siapa dan berapa lama, tanpa isi percakapan (&lt;a href=&quot;https://www.abc.net.au/news/2013-11-18/australia-spied-on-indonesian-president,-leaked-papers-reveal/5098860&quot;&gt;ABC, 18 November 2013&lt;/a&gt;; &lt;a href=&quot;https://www.theguardian.com/world/2013/nov/18/australia-tried-to-monitor-indonesian-presidents-phone&quot;&gt;The Guardian, 18 November 2013&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Jakarta bereaksi keras. Indonesia menarik duta besarnya dari Canberra dan menghentikan sementara kerja sama latihan militer, pertukaran intelijen, dan penanganan penyelundupan manusia (&lt;a href=&quot;https://www.aljazeera.com/news/2013/11/21/indonesia-freezes-ties-with-australia&quot;&gt;Al Jazeera, 21 November 2013&lt;/a&gt;). Perdana Menteri Tony Abbott menolak mengomentari urusan intelijen. Krisis baru reda setelah kedua menteri luar negeri, Marty Natalegawa dan Julie Bishop, menandatangani kode etik di Nusa Dua, Bali, pada 28 Agustus 2014. Isinya janji bahwa kedua negara tidak akan memakai sumber daya intelijennya untuk merugikan kepentingan pihak lain (&lt;a href=&quot;https://www.thejakartapost.com/news/2014/08/29/ri-repairs-ties-signs-pact-intelligence-with-australia&quot;&gt;The Jakarta Post, 29 Agustus 2014&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Kasus SBY memperlihatkan pola yang juga muncul di kasus-kasus internasional lain. Pelakunya negara mitra, buktinya datang dari kebocoran, dan tidak ada seorang pun yang diadili. Krisis 2013 itu sendiri diselesaikan dengan dokumen diplomatik.&lt;/p&gt;

&lt;h2 id=&quot;merkel-dan-rousseff-2013-memata-matai-teman-itu-tidak-bisa-diterima&quot;&gt;Merkel dan Rousseff 2013: “memata-matai teman itu tidak bisa diterima”&lt;/h2&gt;

&lt;p&gt;Sebulan sebelum dokumen SBY terbit, majalah Der Spiegel bertanya kepada kantor Kanselir Jerman soal nomor ponsel Angela Merkel yang muncul dalam daftar sasaran NSA. Merkel menelepon Presiden Barack Obama pada 23 Oktober 2013. Gedung Putih menjawab bahwa Amerika Serikat “tidak sedang dan tidak akan” memantau komunikasi Kanselir, jawaban yang tidak menyinggung masa lalu (&lt;a href=&quot;https://www.npr.org/sections/thetwo-way/2013/10/23/240340232/obama-tells-merkel-the-u-s-is-not-wiretapping-her-phone&quot;&gt;NPR, 23 Oktober 2013&lt;/a&gt;). Esoknya di Brussel, Merkel mengucapkan kalimat yang paling sering dikutip dari skandal itu: “Ausspähen unter Freunden, das geht gar nicht”, memata-matai teman itu sama sekali tidak bisa diterima (&lt;a href=&quot;https://www.thelocal.de/20131024/52547&quot;&gt;The Local, 24 Oktober 2013&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Jaksa Agung Federal Jerman membuka penyidikan pada 2014, lalu menutupnya pada 12 Juni 2015 karena tidak menemukan bukti yang bisa bertahan di pengadilan (&lt;a href=&quot;https://www.apr.org/2015-06-12/germany-closes-probe-into-alleged-u-s-hacking-of-merkels-phone&quot;&gt;APR/AP, 12 Juni 2015&lt;/a&gt;). Enam tahun kemudian kasus ini muncul lagi dari arah yang tak terduga. Penyiar publik Denmark DR melaporkan bahwa dinas intelijen pertahanan Denmark membantu NSA menyadap lewat kabel bawah laut Denmark pada 2012 sampai 2014, dengan sasaran antara lain Merkel, Menteri Luar Negeri Frank-Walter Steinmeier, dan tokoh oposisi Peer Steinbrück (&lt;a href=&quot;https://www.aljazeera.com/news/2021/5/31/us-spied-on-merkel-top-eu-officials-through-danish-cables&quot;&gt;Al Jazeera, 31 Mei 2021&lt;/a&gt;). Dalam versi ini, ada dua negara sekutu Jerman yang terlibat.&lt;/p&gt;

&lt;p&gt;Brasil mengalami hal serupa pada tahun yang sama. Setelah muncul laporan bahwa NSA menyadap komunikasi Presiden Dilma Rousseff, ia menunda kunjungan kenegaraan ke Washington yang dijadwalkan 23 Oktober 2013, sebuah penolakan diplomatik yang jarang terjadi terhadap Gedung Putih (&lt;a href=&quot;https://foreignpolicy.com/2013/09/17/brazilian-president-snubs-white-house/&quot;&gt;Foreign Policy, 17 September 2013&lt;/a&gt;).&lt;/p&gt;

&lt;h2 id=&quot;macron-2021-dari-kabel-ke-spyware&quot;&gt;Macron 2021: dari kabel ke spyware&lt;/h2&gt;

&lt;p&gt;Juli 2021, konsorsium media Pegasus Project memberitakan daftar sekitar 50.000 nomor telepon yang diduga dipilih sebagai calon sasaran spyware Pegasus buatan NSO Group dari Israel. Le Monde melaporkan bahwa salah satu nomor Presiden Emmanuel Macron, yang dipakai rutin sejak 2017, masuk daftar yang dipilih dinas intelijen Maroko. Maroko membantah dan menyebut tuduhan itu “tidak berdasar dan palsu”, NSO menyebut laporan itu penuh asumsi keliru, dan Istana Élysée menyatakan bahwa jika benar, fakta itu “sangat serius” (&lt;a href=&quot;https://www.aljazeera.com/news/2021/7/20/frances-macron-among-potential-pegasus-spyware-targets-le-monde&quot;&gt;Al Jazeera, 20 Juli 2021&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Laporan itu hanya menyebut nomor Macron sebagai calon sasaran dan tidak memuat bukti bahwa ponselnya benar-benar terinfeksi. Meski begitu, kasus ini menandai pergeseran teknologi. Pada 1972 penyadap harus masuk ke sebuah gedung. Pada 2009 dan 2013 penyadapan berlangsung di jaringan operator dan kabel. Pada 2021, alatnya cukup sebuah pesan atau tautan yang mendarat di ponsel sasaran.&lt;/p&gt;

&lt;h2 id=&quot;yunani-2004-2005-fitur-penyadapan-sah-yang-dibajak&quot;&gt;Yunani 2004-2005: fitur penyadapan sah yang dibajak&lt;/h2&gt;

&lt;p&gt;Dari sisi modus, kasus yang paling dekat dengan 2026 justru terjadi di Eropa dan tidak berkaitan dengan bocoran Snowden. Menjelang Olimpiade Athena Agustus 2004, seseorang memasang perangkat lunak gelap di sentral telepon Ericsson milik Vodafone Yunani. Perangkat lunak itu menumpang pada fungsi &lt;em&gt;lawful interception&lt;/em&gt;, fitur yang memang disediakan agar aparat bisa menyadap secara sah, lalu menyembunyikan jejaknya dari sistem audit. Sekitar 100 ponsel disadap, termasuk milik Perdana Menteri Kostas Karamanlis dan istrinya, menteri pertahanan, menteri luar negeri, dan menteri kehakiman. Penyadapan itu baru ketahuan pada awal 2005, dan penyidikan resmi saat itu tidak berhasil memastikan pelakunya (&lt;a href=&quot;https://spectrum.ieee.org/the-athens-affair&quot;&gt;IEEE Spectrum, 29 Juni 2007&lt;/a&gt;). Vodafone Yunani kemudian dijatuhi denda.&lt;/p&gt;

&lt;p&gt;Athens Affair, begitu kasus ini dikenal, menunjukkan risiko yang melekat pada setiap sistem penyadapan sah: pintu yang dibuat untuk penegak hukum bisa dipakai oleh siapa pun yang menguasai kuncinya. Bedanya dengan kasus 2026, di Yunani pembajaknya masuk lewat jalur gelap tanpa identitas yang dipastikan secara resmi, sedangkan di Indonesia yang diduga menyalahgunakan sistem adalah pejabat yang memegang akses resminya.&lt;/p&gt;

&lt;h2 id=&quot;kasus-2026-alat-sah-dan-akses-dari-dalam&quot;&gt;Kasus 2026: alat sah dan akses dari dalam&lt;/h2&gt;

&lt;p&gt;Kasus 2026 menggabungkan dua unsur dari kasus-kasus di atas: alat penyadapan modern dan terduga pelaku dari dalam lingkar kekuasaan. Menurut keterangan Bareskrim yang dikutip Kompas, sejumlah nomor ponsel dimasukkan ke &lt;em&gt;Lawful Interception Management System&lt;/em&gt; tanpa verifikasi, lalu disadap padahal tidak ada proses penegakan hukum yang berjalan. Sekitar Oktober 2026 tersangka diduga memerintahkan penghapusan file hasil sadapan dari komputer sistem itu. Petugas yang mengetahuinya membuat laporan polisi pada 30 Oktober 2026, dan penyidik kemudian memeriksa 10 saksi serta 3 ahli dan menyita 11 ponsel, 1 iPad, dan 4 flashdisk (&lt;a href=&quot;https://nasional.kompas.com/read/2026/11/04/12423931/istana-penyadapan-listyo-sigit-terhadap-presiden-prabowo-masuk-kategori&quot;&gt;Kompas, 4 November 2026&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Detik mencatat penyadapan diduga berlangsung sejak 2025 sampai Oktober 2026. Sangkaan awalnya adalah Pasal 258 dan Pasal 332 KUHP nasional (UU 1/2023, berlaku sejak Januari 2026) serta Pasal 32 ayat 1 UU ITE, dengan ancaman maksimal antara 6 dan 10 tahun penjara. Ketiga tersangka ditahan (&lt;a href=&quot;https://news.detik.com/berita/d-8737324/10-hal-tentang-eks-kapolri-jenderal-listyo-sigit-tersangka-penyadapan-presiden&quot;&gt;Detik, 4 November 2026&lt;/a&gt;). Listyo, yang sejak 1 Oktober 2026 menjabat Kepala Staf Kepresidenan (&lt;a href=&quot;https://nasional.kompas.com/read/2026/11/04/12423931/istana-penyadapan-listyo-sigit-terhadap-presiden-prabowo-masuk-kategori&quot;&gt;Kompas, 4 November 2026&lt;/a&gt;), diberhentikan Presiden dari jabatan itu pada 4 November (&lt;a href=&quot;https://news.detik.com/berita/d-8739945/listyo-sigit-dkk-tersangka-sadap-prabowo-jokowi-ajak-semua-hormati-hukum&quot;&gt;Detik, 5 November 2026&lt;/a&gt;).&lt;/p&gt;

&lt;h3 id=&quot;dari-penyadapan-ilegal-ke-dugaan-makar&quot;&gt;Dari penyadapan ilegal ke dugaan makar&lt;/h3&gt;

&lt;p&gt;Pernyataan pejabat pemerintah menggeser perbincangan dari pasal penyadapan ke pasal makar. Menko Kumham Imipas Yusril Ihza Mahendra menyebut ada “indikasi-indikasi yang mengarah kepada tindakan makar” sebagaimana diatur dalam Pasal 191 dan 193 KUHP (&lt;a href=&quot;https://news.detik.com/berita/d-8738406/listyo-sigit-dkk-sadap-prabowo-menko-yusril-indikasi-makar&quot;&gt;Detik, 4 November 2026&lt;/a&gt;). Ia juga menyebut penyidik mendalami kemungkinan adanya keinginan “untuk melumpuhkan” presiden, sambil menegaskan bahwa hal itu “masih dalam proses pendalaman” (&lt;a href=&quot;https://regional.kompas.com/read/2026/11/04/153638978/yusril-ungkap-motif-listyo-sigit-sadap-prabowo-ada-keinginan-melumpuhkan&quot;&gt;Kompas, 4 November 2026&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Rumusan pasalnya menjelaskan kenapa kata “melumpuhkan” penting. Pasal 191 UU 1/2023 mengancam makar yang dilakukan dengan maksud membunuh atau merampas kemerdekaan presiden dan/atau wakil presiden, atau menjadikan mereka tidak mampu menjalankan pemerintahan, dengan pidana mati, penjara seumur hidup, atau penjara paling lama 20 tahun. Pasal 193 mengatur makar untuk menggulingkan pemerintah yang sah (&lt;a href=&quot;https://peraturan.bpk.go.id/Details/234935/uu-no-1-tahun-2023&quot;&gt;UU 1/2023, JDIH BPK&lt;/a&gt;). Penyadapan ilegal sendiri sudah merupakan tindak pidana. Agar bisa dijerat sebagai makar, penyidik perlu membuktikan maksud yang lebih jauh dari sekadar mengumpulkan informasi. Per 6 November 2026, maksud itu belum diuji di pengadilan, media yang dikutip di sini belum memuat tanggapan Listyo Sigit atas sangkaan itu, dan seluruh tersangka berhak atas asas praduga tak bersalah.&lt;/p&gt;

&lt;p&gt;Perbandingan dengan kasus asing memperlihatkan satu perbedaan penting. Merkel, SBY, dan Macron tidak punya jalur pidana yang realistis terhadap NSA, DSD, atau dinas intelijen Maroko, karena pelakunya badan negara lain yang berada di luar jangkauan hukum domestik. Kasus 2026 terjadi sepenuhnya di dalam yurisdiksi Indonesia, dengan sistem, komputer, dan saksi yang bisa diperiksa penyidik. Dalam hal ini, kasus 2026 lebih dekat ke Watergate dan Moorer-Radford daripada ke kasus Merkel.&lt;/p&gt;

&lt;h2 id=&quot;pelakunya-sekutu-mitra-atau-orang-dalam&quot;&gt;Pelakunya sekutu, mitra, atau orang dalam&lt;/h2&gt;

&lt;p&gt;Daftar di atas juga menunjukkan bahwa pelaku penyadapan kepala negara sering kali bukan musuh. Australia adalah tetangga dan mitra keamanan Indonesia. Amerika Serikat adalah sekutu NATO Jerman, dan Denmark adalah anggota NATO sekaligus Uni Eropa. Maroko adalah mitra dekat Prancis di Afrika Utara. Dalam kasus Moorer-Radford, pelakunya bagian dari aparat negara yang dipimpin sang presiden sendiri, dan dalam kasus 2026 terduga pelakunya juga demikian. Sebagian kasus asing ini diketahui publik lewat bocoran, misalnya dokumen Snowden dan daftar Pegasus, sehingga yang tercatat terbuka cenderung operasi yang kebetulan bocor, belum tentu gambaran lengkapnya.&lt;/p&gt;

&lt;p&gt;Ada logika sederhana di balik pola ini. Badan intelijen bertugas mengurangi ketidakpastian bagi pemerintahnya, dan sekutu tetap punya kepentingan yang tidak selalu sama, misalnya soal perdagangan, perundingan iklim, atau posisi di forum internasional. Bagi orang dalam, insentifnya lain: informasi tentang apa yang dipikirkan dan direncanakan atasan adalah modal kekuasaan. Kesempatan juga lebih besar bagi pihak yang dekat. Mitra intelijen berbagi jaringan dan kabel, dan pejabat keamanan dalam negeri memegang kunci sistem penyadapan yang sah.&lt;/p&gt;

&lt;h2 id=&quot;kenapa-terus-berulang&quot;&gt;Kenapa terus berulang&lt;/h2&gt;

&lt;p&gt;Lebih dari lima puluh tahun memisahkan Watergate dari kasus 2026, dan dalam rentang itu ada tiga pola yang terus berulang.&lt;/p&gt;

&lt;p&gt;Pertama, nilai informasinya. Percakapan seorang kepala negara memuat keputusan yang belum diumumkan, sikap dalam perundingan, dan hubungan personal yang tidak tercatat di dokumen resmi. Selama keputusan besar masih dibuat lewat telepon dan pesan singkat, perangkat kepala negara akan tetap menjadi sasaran bernilai tinggi.&lt;/p&gt;

&lt;p&gt;Kedua, biaya teknisnya terus turun. Tim Watergate harus menyusup ke sebuah gedung dan tertangkap basah. DSD cukup mengambil data panggilan dari jaringan. Pegasus hanya butuh nomor telepon. Dalam kasus 2026, menurut penyidik, caranya adalah memasukkan nomor ke sistem yang memang dibangun untuk menyadap.&lt;/p&gt;

&lt;p&gt;Ketiga, akibatnya jarang setimpal, terutama bila pelakunya negara lain. Dari kasus SBY, Merkel, Rousseff, dan Macron, tidak ada satu pun pejabat intelijen yang diadili. Yang terjadi adalah penarikan duta besar, kunjungan yang ditunda, dan penyidikan yang ditutup karena kurang bukti. Hukuman nyata hanya mungkin bila pelakunya berada dalam jangkauan hukum negara sendiri, seperti di Watergate. Itu pun bukan jaminan, seperti terlihat dari kasus Moorer-Radford yang diselesaikan diam-diam.&lt;/p&gt;

&lt;p&gt;Kasus 2026 akan menguji poin ketiga itu di Indonesia. Pertanyaannya adalah apakah pengadilan bisa membuktikan siapa memerintahkan apa, dengan maksud apa, berdasarkan sistem yang sebagian file hasil sadapannya diduga sudah dihapus. Sejarah Watergate menunjukkan bahwa jawabannya sering ditentukan oleh rekaman dan catatan yang tersisa, dan oleh lembaga yang bersedia memintanya dibuka.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;Tulisan ini disusun berdasarkan pemberitaan per 6 November 2026. Kasus ini masih dalam penyidikan; koreksi dan pembaruan akan dicatat di bagian ini. Penulis: Mahyuddin Susanto (&lt;a href=&quot;https://www.udienz.web.id/about/&quot;&gt;tentang penulis&lt;/a&gt;, &lt;a href=&quot;https://www.udienz.web.id/contact.html&quot;&gt;kontak&lt;/a&gt;). Tulisan ini dibantu oleh AI.&lt;/em&gt;&lt;/p&gt;</content><author><name>Mahyuddin Susanto</name></author><category term="Sejarah" /><category term="Keamanan" /><category term="penyadapan" /><category term="sejarah" /><category term="watergate" /><category term="snowden" /><category term="pegasus" /><summary type="html">Pada 3 November 2026, Bareskrim Polri menetapkan mantan Kapolri Jenderal Listyo Sigit Prabowo dan dua perwira tinggi, Irjen Ahrie Sonta dan Irjen Eko Hadi Santoso, sebagai tersangka penyadapan ilegal. Menurut Kabareskrim Komjen Asep Safrudin, sasarannya adalah “Presiden RI, pejabat negara, tokoh politik, media, tokoh ormas, LSM” (Kompas, 3 November 2026). Sehari kemudian Mensesneg Prasetyo Hadi menyebut perbuatan itu “mengarah ke perbuatan makar” (Kompas, 4 November 2026).</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.udienz.web.id/img/sejarah-penyadapan-kepala-negara.webp" /><media:content medium="image" url="https://www.udienz.web.id/img/sejarah-penyadapan-kepala-negara.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Menghidupkan Planet Ubuntu-ID dengan Python 3 dan Cloudflare</title><link href="https://www.udienz.web.id/2026/11/06/menghidupkan-planet-ubuntu-id" rel="alternate" type="text/html" title="Menghidupkan Planet Ubuntu-ID dengan Python 3 dan Cloudflare" /><published>2026-11-06T00:00:00+00:00</published><updated>2026-11-06T00:00:00+00:00</updated><id>https://www.udienz.web.id/2026/11/06/menghidupkan-planet-ubuntu-id</id><content type="html" xml:base="https://www.udienz.web.id/2026/11/06/menghidupkan-planet-ubuntu-id">&lt;p&gt;Planet Ubuntu-ID adalah agregator blog anggota komunitas Ubuntu Indonesia. Saya dulu memelihara repositorinya, &lt;a href=&quot;https://github.com/ubuntu-id/planet&quot;&gt;ubuntu-id/planet&lt;/a&gt;, dan &lt;a href=&quot;https://github.com/ubuntu-id/planet/commit/0f474121dacf05f6382fc52f968119c3769eeaa8&quot;&gt;commit terakhir&lt;/a&gt; di sana bertanggal Februari 2020. Awal November 2026 saya ingin menghidupkannya lagi. Domain &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;planet.ubuntu-id.org&lt;/code&gt; waktu itu sudah tidak resolve di DNS, dan kodenya tidak bisa dijalankan.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Poin Penting&lt;/strong&gt;&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;Planet Venus, mesin lama Planet Ubuntu-ID, berbasis Python 2 dan tidak punya commit baru sejak 2017. Saya menggantinya dengan satu skrip Python 3, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build.py&lt;/code&gt;.&lt;/li&gt;
    &lt;li&gt;Hasilnya situs statis, jadi cukup di Cloudflare tanpa server sendiri. Isinya diperbarui tiap 6 jam lewat Deploy Hook yang dipanggil GitHub Actions.&lt;/li&gt;
    &lt;li&gt;Dari 73 feed lama, 35 yang masih bisa diambil. Satu feed ternyata sudah berisi iklan judi slot.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;kenapa-kode-lama-tidak-bisa-dipakai&quot;&gt;Kenapa kode lama tidak bisa dipakai&lt;/h2&gt;

&lt;p&gt;README lama menyuruh memasang &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python-libxslt1&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python-genshi&lt;/code&gt;, dan sejenisnya, lalu menjalankan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python planet.py&lt;/code&gt;. Semuanya Python 2. Mesinnya, &lt;a href=&quot;https://github.com/rubys/venus&quot;&gt;Planet Venus&lt;/a&gt;, tidak punya commit baru sejak Maret 2017 (&lt;a href=&quot;https://github.com/rubys/venus/commits/dev&quot;&gt;riwayat cabang &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dev&lt;/code&gt;&lt;/a&gt;); cabang &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; berhenti pada Februari 2011. Daripada menghidupkan Python 2 di mesin baru, saya menulis ulang pembangunnya dengan &lt;a href=&quot;https://feedparser.readthedocs.io/&quot;&gt;feedparser&lt;/a&gt; dan &lt;a href=&quot;https://jinja.palletsprojects.com/&quot;&gt;Jinja2&lt;/a&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.ini&lt;/code&gt; tetap dipakai apa adanya, dan template tema Ubuntu hanya berpindah dari format htmltmpl ke Jinja2, jadi tampilannya sama.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build.py&lt;/code&gt; membaca &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.ini&lt;/code&gt;, mengambil semua feed secara paralel, mengambil maksimal 5 entri per feed dan 20 entri untuk halaman utama, lalu menulis &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.html&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rss20.xml&lt;/code&gt;, dan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;opml.xml&lt;/code&gt; ke folder &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;feedparser.parse(url)&lt;/code&gt; (feedparser 6.0.14) macet saat menyambung ke beberapa host blogspot, padahal &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt; dan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;urllib&lt;/code&gt; lancar di mesin yang sama. Jalan keluarnya, unduh feed sendiri dengan timeout eksplisit, lalu serahkan isinya ke &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;feedparser&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;AGENT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;PlanetUbuntuID/2.0 (+https://github.com/ubuntu-id/planet)&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urllib&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;User-Agent&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AGENT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urllib&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urlopen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;feedparser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response_headers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;content-location&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;geturl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Feed yang gagal dilewati dan dicatat di stderr, jadi satu blog yang mati tidak menggagalkan seluruh build.&lt;/p&gt;

&lt;h2 id=&quot;membersihkan-daftar-feed&quot;&gt;Membersihkan daftar feed&lt;/h2&gt;

&lt;p&gt;Pada 6 November 2026 saya mengambil ke-73 feed di &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.ini&lt;/code&gt; satu per satu lewat &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build.py&lt;/code&gt;. Saat pemeriksaan pertama, 38 dari 73 gagal diambil. Satu di antaranya blog saya sendiri, yang domainnya sudah pindah, jadi alamat feed-nya saya ganti dan sekarang berhasil. Itu menyisakan 37 yang gagal. Satu feed lain berhasil diambil tetapi kini berisi iklan judi slot, jadi saya keluarkan dari &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.ini&lt;/code&gt;. Hasil akhirnya, dari 73 feed: 35 berhasil, 37 gagal, 1 dikeluarkan.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Hasil&lt;/th&gt;
      &lt;th&gt;Jumlah feed&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Berhasil diambil&lt;/td&gt;
      &lt;td&gt;35&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Domain tidak resolve (DNS)&lt;/td&gt;
      &lt;td&gt;14&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Bukan feed XML yang valid&lt;/td&gt;
      &lt;td&gt;7&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;HTTP 404, 410, atau 503&lt;/td&gt;
      &lt;td&gt;7&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Timeout&lt;/td&gt;
      &lt;td&gt;6&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Server tidak terjangkau&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Respons tanpa Content-Type atau feed kosong&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Dikeluarkan karena iklan judi slot&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;73&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Feed yang error tidak saya hapus. Ini data komunitas, dan sebagian mungkin hanya timeout sementara. Setiap bagiannya saya komentari lengkap dengan alasannya:&lt;/p&gt;

&lt;div class=&quot;language-ini highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# ERROR (cek 2026-11-06): domain tidak resolve (DNS)
# [http://feeds.fajran.web.id/all/feed.xml]
# name = Fajran Iman Rusadi
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Dari 35 feed yang aktif, hanya 2 yang punya tulisan sejak 2025. Sisanya, 33 feed, terakhir menulis antara 2009 dan 2024, jadi isi Planet Ubuntu-ID saat ini didominasi tulisan lama. Umur feed saya hitung dari tanggal entri terbaru di tiap feed.&lt;/p&gt;

&lt;h2 id=&quot;deploy-ke-cloudflare&quot;&gt;Deploy ke Cloudflare&lt;/h2&gt;

&lt;p&gt;Karena hasilnya statis, saya pakai &lt;a href=&quot;https://developers.cloudflare.com/workers/static-assets/&quot;&gt;static assets di Cloudflare Workers&lt;/a&gt;. Satu file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wrangler.jsonc&lt;/code&gt; cukup untuk menunjuk folder yang diunggah:&lt;/p&gt;

&lt;div class=&quot;language-jsonc highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;planet-ubuntu-id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;compatibility_date&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2026-11-06&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;assets&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;directory&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./public&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Pengaturan build-nya: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pip install -r requirements.txt &amp;amp;&amp;amp; python build.py&lt;/code&gt; sebagai build command, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npx wrangler deploy&lt;/code&gt; sebagai deploy command, dan Python 3.13 lewat file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.python-version&lt;/code&gt; (versi bawaan &lt;a href=&quot;https://developers.cloudflare.com/workers/ci-cd/builds/build-image/&quot;&gt;lingkungan build Workers&lt;/a&gt; bisa diganti dengan cara itu). Nama project hanya boleh huruf kecil, angka, dan tanda hubung, jadi spasi di nama awal saya harus diganti.&lt;/p&gt;

&lt;p&gt;Build pertama gagal dalam 11 detik, saat &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; belum berisi &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build.py&lt;/code&gt;. Setelah &lt;a href=&quot;https://github.com/ubuntu-id/planet/pull/1&quot;&gt;pull request #1&lt;/a&gt; di-merge, build berikutnya lolos.&lt;/p&gt;

&lt;p&gt;Kalau Anda lebih suka menjalankan server sendiri daripada memakai Cloudflare, hasil &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public/&lt;/code&gt; bisa disajikan nginx biasa. Atur TLS-nya dengan &lt;a href=&quot;https://www.udienz.web.id/2026/11/05/ssl-labs-a-plus-nginx-id/&quot;&gt;panduan A+ di SSL Labs untuk nginx&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Situs statis tidak ikut berubah saat blog anggota memposting sesuatu. Karena itu &lt;a href=&quot;https://github.com/ubuntu-id/planet/pull/2&quot;&gt;pull request #2&lt;/a&gt; menambah workflow GitHub Actions yang memanggil Deploy Hook Cloudflare tiap 6 jam. URL hook-nya disimpan sebagai secret repositori, tidak pernah masuk ke kode. &lt;a href=&quot;https://github.com/ubuntu-id/planet/actions/runs/42149231779&quot;&gt;Run manual pertamanya&lt;/a&gt; sukses.&lt;/p&gt;

&lt;h2 id=&quot;pendaftaran-anggota-baru&quot;&gt;Pendaftaran anggota baru&lt;/h2&gt;

&lt;p&gt;Alur lama lewat tiket Launchpad saya ganti dengan pull request yang mengubah &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.ini&lt;/code&gt;. Template PR meminta:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;nama lengkap dan profil Launchpad,&lt;/li&gt;
  &lt;li&gt;alamat feed,&lt;/li&gt;
  &lt;li&gt;pernyataan bahwa pemohon sudah menandatangani Ubuntu Code of Conduct.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pernyataan itu tetap diperiksa manual lewat profil Launchpad sebelum PR di-merge. Selain itu, CI di setiap PR memeriksa sintaks, menjalankan build, dan memastikan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rss20.xml&lt;/code&gt; serta &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;opml.xml&lt;/code&gt; valid.&lt;/p&gt;

&lt;p&gt;Planet Ubuntu-ID sekarang hidup lagi di &lt;a href=&quot;https://planet.ubuntu-id.org/&quot;&gt;planet.ubuntu-id.org&lt;/a&gt;, dan kodenya terbuka di &lt;a href=&quot;https://github.com/ubuntu-id/planet&quot;&gt;GitHub&lt;/a&gt;. Kalau Anda punya blog tentang Ubuntu atau Linux dan sudah menandatangani Ubuntu Code of Conduct, silakan kirim pull request.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;Penulis: Mahyuddin Susanto, penulis blog ini dan mantan pemelihara repositori Planet Ubuntu-ID (&lt;a href=&quot;https://www.udienz.web.id/about/&quot;&gt;tentang penulis&lt;/a&gt;, &lt;a href=&quot;https://www.udienz.web.id/contact.html&quot;&gt;kontak&lt;/a&gt;). Foto sampul oleh &lt;a href=&quot;https://unsplash.com/photos/computer-screen-displaying-network-configuration-RUyWmB5e-00&quot;&gt;Cong Long Vu&lt;/a&gt; di Unsplash. Tulisan ini dibantu oleh AI.&lt;/em&gt;&lt;/p&gt;</content><author><name>Mahyuddin Susanto</name></author><category term="Linux" /><category term="planet" /><category term="ubuntu" /><category term="python" /><category term="cloudflare" /><category term="rss" /><summary type="html">Planet Ubuntu-ID adalah agregator blog anggota komunitas Ubuntu Indonesia. Saya dulu memelihara repositorinya, ubuntu-id/planet, dan commit terakhir di sana bertanggal Februari 2020. Awal November 2026 saya ingin menghidupkannya lagi. Domain planet.ubuntu-id.org waktu itu sudah tidak resolve di DNS, dan kodenya tidak bisa dijalankan.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.udienz.web.id/img/menghidupkan-planet-ubuntu-id.jpg" /><media:content medium="image" url="https://www.udienz.web.id/img/menghidupkan-planet-ubuntu-id.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Cara Mendapat A+ di SSL Labs dengan Apache (Panduan 2026)</title><link href="https://www.udienz.web.id/2026/11/05/ssl-labs-a-plus-apache-id" rel="alternate" type="text/html" title="Cara Mendapat A+ di SSL Labs dengan Apache (Panduan 2026)" /><published>2026-11-05T00:00:00+00:00</published><updated>2026-11-05T00:00:00+00:00</updated><id>https://www.udienz.web.id/2026/11/05/ssl-labs-a-plus-apache-id</id><content type="html" xml:base="https://www.udienz.web.id/2026/11/05/ssl-labs-a-plus-apache-id">&lt;p&gt;Untuk dapat A+ di &lt;a href=&quot;https://www.ssllabs.com/ssltest/&quot;&gt;SSL Labs Server Test&lt;/a&gt; dari Qualys dengan Apache httpd, syaratnya sama dengan web server lain: hanya TLS 1.2 dan TLS 1.3, cipher ECDHE dengan AEAD (GCM atau ChaCha20-Poly1305), sertifikat dikirim bersama chain lengkapnya, header HSTS dengan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age&lt;/code&gt; minimal enam bulan, dan konfigurasi yang sama di semua alamat IP hostname tersebut. Di Apache, ada dua hal yang menentukan berhasil atau tidaknya: header HSTS harus memakai &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header always set&lt;/code&gt;, bukan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header set&lt;/code&gt;, dan virtual host yang punya &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLProtocol&lt;/code&gt; atau &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCipherSuite&lt;/code&gt; sendiri akan diam-diam mengalahkan pengaturan global.&lt;/p&gt;

&lt;p&gt;Tulisan ini memberi konfigurasi yang bisa langsung dipasang di Apache Debian atau Ubuntu, menjelaskan tiap barisnya, dan menunjukkan cara mengecek hasilnya sebelum menjalankan SSL Labs.&lt;/p&gt;

&lt;p&gt;Konfigurasi di bawah sudah diuji di Apache 2.4.69 dengan OpenSSL 3.5.7, memakai layout &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/apache2&lt;/code&gt; bawaan Debian 13 dengan modul, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt;, dan file site dari tulisan ini diaktifkan, lalu dicek dengan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl s_client&lt;/code&gt; dan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read in English:&lt;/strong&gt; &lt;a href=&quot;/2026/11/05/ssl-labs-a-plus-apache&quot;&gt;How to Get an A+ on SSL Labs with Apache httpd&lt;/a&gt;. Pakai nginx? Lihat &lt;a href=&quot;/2026/11/05/ssl-labs-a-plus-nginx-id&quot;&gt;Cara Mendapat A+ di SSL Labs dengan nginx&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/ssl-labs-a-plus-apache-id.png&quot; alt=&quot;Tangga grade SSL Labs untuk Apache: apa yang menahan server di B atau A-, dan syarat A+&quot; /&gt;&lt;/p&gt;

&lt;details class=&quot;toc&quot;&gt;
  &lt;summary&gt;Daftar isi&lt;/summary&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#cara-ssl-labs-memberi-nilai&quot; id=&quot;markdown-toc-cara-ssl-labs-memberi-nilai&quot;&gt;Cara SSL Labs memberi nilai&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#cek-versi-apache-dan-openssl-dulu&quot; id=&quot;markdown-toc-cek-versi-apache-dan-openssl-dulu&quot;&gt;Cek versi Apache dan OpenSSL dulu&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#langkah-1-sertifikat-dan-full-chain&quot; id=&quot;markdown-toc-langkah-1-sertifikat-dan-full-chain&quot;&gt;Langkah 1: Sertifikat dan full chain&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#langkah-2-aktifkan-modul-dan-atur-tls-secara-global&quot; id=&quot;markdown-toc-langkah-2-aktifkan-modul-dan-atur-tls-secara-global&quot;&gt;Langkah 2: Aktifkan modul dan atur TLS secara global&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#langkah-3-virtual-host-hsts-dan-redirect-http&quot; id=&quot;markdown-toc-langkah-3-virtual-host-hsts-dan-redirect-http&quot;&gt;Langkah 3: Virtual host, HSTS, dan redirect HTTP&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#kenapa-harus-header-always-set&quot; id=&quot;markdown-toc-kenapa-harus-header-always-set&quot;&gt;Kenapa harus &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header always set&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#langkah-4-waspadai-virtual-host-yang-menimpa-pengaturan-global&quot; id=&quot;markdown-toc-langkah-4-waspadai-virtual-host-yang-menimpa-pengaturan-global&quot;&gt;Langkah 4: Waspadai virtual host yang menimpa pengaturan global&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#langkah-5-ocsp-stapling-dan-lets-encrypt&quot; id=&quot;markdown-toc-langkah-5-ocsp-stapling-dan-lets-encrypt&quot;&gt;Langkah 5: OCSP stapling dan Let’s Encrypt&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#langkah-6-jebakan-configtest&quot; id=&quot;markdown-toc-langkah-6-jebakan-configtest&quot;&gt;Langkah 6: Jebakan configtest&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#langkah-7-uji-di-lokal-lalu-jalankan-ssl-labs&quot; id=&quot;markdown-toc-langkah-7-uji-di-lokal-lalu-jalankan-ssl-labs&quot;&gt;Langkah 7: Uji di lokal, lalu jalankan SSL Labs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#troubleshooting-arti-pesan-di-laporan-dan-cara-memperbaikinya&quot; id=&quot;markdown-toc-troubleshooting-arti-pesan-di-laporan-dan-cara-memperbaikinya&quot;&gt;Troubleshooting: arti pesan di laporan dan cara memperbaikinya&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#opsional-hsts-preload&quot; id=&quot;markdown-toc-opsional-hsts-preload&quot;&gt;Opsional: HSTS preload&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#konfigurasi-lengkap&quot; id=&quot;markdown-toc-konfigurasi-lengkap&quot;&gt;Konfigurasi lengkap&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#sumber&quot; id=&quot;markdown-toc-sumber&quot;&gt;Sumber&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;/details&gt;

&lt;h2 id=&quot;cara-ssl-labs-memberi-nilai&quot;&gt;Cara SSL Labs memberi nilai&lt;/h2&gt;

&lt;p&gt;SSL Labs menilai dukungan protokol (30%), key exchange (30%), dan kekuatan cipher (40%), lalu memberlakukan batas atas (cap) untuk masalah tertentu. A+ adalah bonus untuk server ber-grade A tanpa warning. Aturan yang berlaku sekarang adalah versi 2009r dari &lt;a href=&quot;https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide&quot;&gt;SSL Server Rating Guide&lt;/a&gt;, tertanggal 16 Mei 2025. Batas-batas yang relevan untuk server Apache pada umumnya:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Masalah&lt;/th&gt;
      &lt;th&gt;Grade maksimal&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;SSLv2, SSLv3 sebagai protokol terbaik, cipher export, bug sekelas Heartbleed&lt;/td&gt;
      &lt;td&gt;F&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Tidak mendukung TLS 1.2&lt;/td&gt;
      &lt;td&gt;C&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;TLS 1.0 atau TLS 1.1 aktif&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Tanpa forward secrecy (tanpa ECDHE/DHE)&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Tanpa cipher AEAD (GCM atau ChaCha20-Poly1305)&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Chain sertifikat tidak lengkap&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Key atau parameter DH di bawah 2048 bit&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Tidak mendukung TLS 1.3&lt;/td&gt;
      &lt;td&gt;A-&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;HSTS tidak ada atau tidak valid&lt;/td&gt;
      &lt;td&gt;A-&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Untuk A+, panduan itu mensyaratkan konfigurasi tanpa warning dan HSTS dengan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age&lt;/code&gt; minimal enam bulan (15768000 detik). Sejak revisi Mei 2025, sekadar dapat A pun butuh TLS 1.3 sekaligus header HSTS yang valid, dan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TLS_FALLBACK_SCSV&lt;/code&gt; tidak dihitung lagi.&lt;/p&gt;

&lt;p&gt;Sertifikat ECDSA P-256 atau RSA 2048 sudah cukup. Nilai key exchange-nya 90 dan tetap dapat A+.&lt;/p&gt;

&lt;h2 id=&quot;cek-versi-apache-dan-openssl-dulu&quot;&gt;Cek versi Apache dan OpenSSL dulu&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apache2 &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt;
apache2ctl &lt;span class=&quot;nt&quot;&gt;-M&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; ssl &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; headers &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; rewrite &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; http2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Versi OpenSSL yang dipakai Apache tercetak di error log saat start, di baris seperti &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Apache/2.4.69 (Debian) OpenSSL/3.5.7 configured -- resuming normal operations&lt;/code&gt;.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Fitur&lt;/th&gt;
      &lt;th&gt;Butuh&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;TLS 1.3 (dan baris &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCipherSuite TLSv1.3 ...&lt;/code&gt;)&lt;/td&gt;
      &lt;td&gt;Apache 2.4.37+ dengan OpenSSL 1.1.1+ (dukungan TLS 1.3 tercatat di 2.4.36, versi yang tidak pernah dirilis)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Intermediate di &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCertificateFile&lt;/code&gt; (tanpa &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCertificateChainFile&lt;/code&gt;)&lt;/td&gt;
      &lt;td&gt;Apache 2.4.8+&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLOpenSSLConfCmd&lt;/code&gt; (dipakai di sini untuk mengatur kurva)&lt;/td&gt;
      &lt;td&gt;Apache 2.4.8+ dengan OpenSSL 1.0.2+&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Protocols h2 http/1.1&lt;/code&gt; (HTTP/2)&lt;/td&gt;
      &lt;td&gt;Apache 2.4.17+&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLProtocol&lt;/code&gt; per virtual host dihormati saat ada SNI&lt;/td&gt;
      &lt;td&gt;Apache 2.4.42+ dengan OpenSSL 1.1.1+&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grup hybrid post-quantum &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X25519MLKEM768&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;OpenSSL 3.5+&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;langkah-1-sertifikat-dan-full-chain&quot;&gt;Langkah 1: Sertifikat dan full chain&lt;/h2&gt;

&lt;p&gt;Dengan Let’s Encrypt dan Certbot, ambil sertifikatnya saja, lalu tulis konfigurasi TLS sendiri:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;certbot certonly &lt;span class=&quot;nt&quot;&gt;--apache&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; example.com &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; www.example.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Certbot 2.0 ke atas membuat key ECDSA secara default.&lt;/p&gt;

&lt;p&gt;Arahkan Apache ke &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fullchain.pem&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;SSLCertificateFile&lt;/span&gt;    /etc/letsencrypt/live/example.com/fullchain.pem
&lt;span class=&quot;nc&quot;&gt;SSLCertificateKeyFile&lt;/span&gt; /etc/letsencrypt/live/example.com/privkey.pem
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sejak Apache 2.4.8, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCertificateFile&lt;/code&gt; boleh berisi sertifikat intermediate setelah sertifikat utama, dan &lt;a href=&quot;https://httpd.apache.org/docs/2.4/mod/mod_ssl.html#sslcertificatefile&quot;&gt;dokumentasi mod_ssl&lt;/a&gt; menyebut &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCertificateChainFile&lt;/code&gt; sudah usang. Kalau &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCertificateFile&lt;/code&gt; diarahkan ke &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cert.pem&lt;/code&gt; dan chain file dibuang, intermediate-nya hilang. Browser sering melengkapinya sendiri, tapi SSL Labs akan menulis “Chain issues: Incomplete” dan membatasi grade di B.&lt;/p&gt;

&lt;p&gt;Kalau memakai installer Certbot (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;certbot --apache&lt;/code&gt; tanpa &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;certonly&lt;/code&gt;), ia menambahkan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Include /etc/letsencrypt/options-ssl-apache.conf&lt;/code&gt; di dalam virtual host. File itu mengatur protokol dan cipher sendiri, dan karena letaknya di virtual host, ia mengalahkan file global dari Langkah 2. Hapus baris include itu, tapi lihat dulu apa lagi yang diatur file tersebut: &lt;a href=&quot;https://github.com/certbot/certbot/blob/main/certbot/src/certbot/_internal/plugins/apache/tls_configs/current-options-ssl-apache.conf&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;options-ssl-apache.conf&lt;/code&gt;&lt;/a&gt; versi sekarang diawali &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLEngine on&lt;/code&gt;. Cek dengan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep -n SSLEngine /etc/letsencrypt/options-ssl-apache.conf&lt;/code&gt; dan, kalau ada, tambahkan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLEngine on&lt;/code&gt; ke virtual host itu sendiri. Tanpa baris itu, Apache melayani HTTP biasa di port 443 tanpa pesan error.&lt;/p&gt;

&lt;h2 id=&quot;langkah-2-aktifkan-modul-dan-atur-tls-secara-global&quot;&gt;Langkah 2: Aktifkan modul dan atur TLS secara global&lt;/h2&gt;

&lt;p&gt;Aktifkan modul yang dipakai di tulisan ini:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;a2enmod ssl headers rewrite http2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a2enmod ssl&lt;/code&gt; sekaligus mengaktifkan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;socache_shmcb&lt;/code&gt; untuk session cache. Di Debian 13, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/apache2/mods-available/ssl.conf&lt;/code&gt; bawaan lalu berisi baris-baris ini (komentar dibuang):&lt;/p&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;SSLSessionCache&lt;/span&gt;     shmcb:${APACHE_RUN_DIR}/ssl_scache(512000)
&lt;span class=&quot;nc&quot;&gt;SSLSessionCacheTimeout&lt;/span&gt;  300
&lt;span class=&quot;nc&quot;&gt;SSLCipherSuite&lt;/span&gt; HIGH:!aNULL
&lt;span class=&quot;nc&quot;&gt;SSLProtocol&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;all&lt;/span&gt; -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
&lt;span class=&quot;nc&quot;&gt;SSLSessionTickets&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;off&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Protokolnya sudah benar. Daftar cipher-nya yang terlalu longgar. Dengan pengaturan bawaan saja, server tes masih menerima suite CBC, key exchange RSA biasa tanpa forward secrecy, dan DHE:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;-cipher &apos;ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA&apos;  -&amp;gt;  Cipher is ECDHE-ECDSA-AES128-SHA
-cipher &apos;AES256-GCM-SHA384&apos;                            -&amp;gt;  Cipher is AES256-GCM-SHA384
-cipher &apos;DHE-RSA-AES256-GCM-SHA384&apos;                    -&amp;gt;  Cipher is DHE-RSA-AES256-GCM-SHA384
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;SSL Labs menandai suite CBC dan RSA biasa dengan label WEAK di daftar cipher-nya, dan TLSRef tidak memasukkan DHE sama sekali. Tidak ada alasan untuk tetap menawarkan semuanya. Rilis lain bisa punya nilai bawaan berbeda, jadi cek punya Anda dengan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep -v &apos;^\s*#&apos; /etc/apache2/mods-available/ssl.conf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Biarkan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl.conf&lt;/code&gt; apa adanya, lalu taruh pengaturan di &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/apache2/conf-available/tls.conf&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Pengaturan TLS untuk semua virtual host HTTPS (konteks server config)&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLProtocol&lt;/span&gt;             -all +TLSv1.2 +TLSv1.3

&lt;span class=&quot;c&quot;&gt;# OpenSSL 3.5+: grup hybrid post-quantum di depan.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Di OpenSSL 3.0-3.4, hapus X25519MLKEM768 dari daftar ini.&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLOpenSSLConfCmd&lt;/span&gt;       Curves X25519MLKEM768:X25519:prime256v1:secp384r1

&lt;span class=&quot;c&quot;&gt;# TLS 1.2: hanya key exchange ECDHE + AEAD. TLS 1.3: tiga suite standar.&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLCipherSuite&lt;/span&gt;          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305
&lt;span class=&quot;nc&quot;&gt;SSLCipherSuite&lt;/span&gt;          TLSv1.3 TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
&lt;span class=&quot;nc&quot;&gt;SSLHonorCipherOrder&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;off&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLSessionTickets&lt;/span&gt;       &lt;span class=&quot;ss&quot;&gt;off&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Aktifkan:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;a2enconf tls
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apache2.conf&lt;/code&gt; di Debian membaca &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mods-enabled/*.conf&lt;/code&gt; lebih dulu dan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;conf-enabled/*.conf&lt;/code&gt; belakangan. Untuk directive-directive ini, nilai global yang datang belakangan menggantikan yang sebelumnya, jadi &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt; menang atas &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl.conf&lt;/code&gt; tanpa perlu mengedit file itu. Di server tes, ketiga suite lemah di atas ditolak begitu &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt; aktif.&lt;/p&gt;

&lt;p&gt;Penjelasan per baris:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLProtocol -all +TLSv1.2 +TLSv1.3&lt;/code&gt;&lt;/strong&gt; mulai dari kosong dan hanya mengizinkan TLS 1.2 dan 1.3. TLS 1.0 atau 1.1 membuat grade mentok di B; tanpa TLS 1.3 mentok di A-.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLOpenSSLConfCmd Curves&lt;/code&gt;&lt;/strong&gt; meneruskan daftar grup key exchange ke OpenSSL. Daftarnya diambil dari &lt;a href=&quot;https://data.tlsref.org/guidelines/6.0.json&quot;&gt;TLSRef guideline 6.0&lt;/a&gt;, penerus Server Side TLS guidelines dari Mozilla, dan sama dengan yang dihasilkan &lt;a href=&quot;https://configurator.tlsref.org/&quot;&gt;TLSRef Configurator&lt;/a&gt; untuk Apache. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X25519MLKEM768&lt;/code&gt; menggabungkan X25519 dengan algoritma post-quantum ML-KEM; klien yang belum mendukungnya turun ke X25519.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCipherSuite&lt;/code&gt; pertama&lt;/strong&gt; hanya berisi suite ECDHE dengan GCM atau ChaCha20-Poly1305: forward secrecy dan AEAD, tidak ada yang lain. Menurut TLSRef, klien tertua yang masih bisa tersambung adalah Firefox 31, Chrome 49, Safari 9, Android 4.4.2, IE 11 di Windows 10, dan Java 8u161.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCipherSuite TLSv1.3 ...&lt;/code&gt;&lt;/strong&gt; mengatur suite TLS 1.3. Ketiganya memang default OpenSSL; baris ini membuatnya eksplisit.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLHonorCipherOrder off&lt;/code&gt;&lt;/strong&gt; membiarkan klien memilih dari daftar. Semua pilihan sudah kuat, dan ponsel tanpa akselerasi AES di hardware akan memilih ChaCha20.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLSessionTickets off&lt;/code&gt;&lt;/strong&gt;. Dokumentasi mod_ssl memperingatkan bahwa ticket yang dipakai tanpa me-restart web server secara berkala (misalnya harian) merusak forward secrecy. Apache tidak merotasi key ticket sendiri, jadi TLSRef mematikannya. Session resumption tetap jalan lewat session cache &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shmcb&lt;/code&gt; dari &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl.conf&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Tanpa parameter DH.&lt;/strong&gt; Daftar cipher tidak berisi suite DHE, jadi parameter DH tidak perlu ditambahkan ke file sertifikat.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;langkah-3-virtual-host-hsts-dan-redirect-http&quot;&gt;Langkah 3: Virtual host, HSTS, dan redirect HTTP&lt;/h2&gt;

&lt;p&gt;Buat &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/apache2/sites-available/example.com.conf&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;VirtualHost&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; *:80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;
&lt;/span&gt;    &lt;span class=&quot;nc&quot;&gt;ServerName&lt;/span&gt; example.com
    &lt;span class=&quot;nc&quot;&gt;ServerAlias&lt;/span&gt; www.example.com

    &lt;span class=&quot;nc&quot;&gt;RewriteEngine&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;On&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;RewriteCond&lt;/span&gt; %{REQUEST_URI} !^/\.well-known/acme-challenge/
    &lt;span class=&quot;nc&quot;&gt;RewriteRule&lt;/span&gt; ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R=308,QSA,L]
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;VirtualHost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;VirtualHost&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; *:443&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;
&lt;/span&gt;    &lt;span class=&quot;nc&quot;&gt;ServerName&lt;/span&gt; example.com
    &lt;span class=&quot;nc&quot;&gt;ServerAlias&lt;/span&gt; www.example.com
    &lt;span class=&quot;nc&quot;&gt;DocumentRoot&lt;/span&gt; /var/www/example.com

    &lt;span class=&quot;nc&quot;&gt;SSLEngine&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;on&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;SSLCertificateFile&lt;/span&gt;    /etc/letsencrypt/live/example.com/fullchain.pem
    &lt;span class=&quot;nc&quot;&gt;SSLCertificateKeyFile&lt;/span&gt; /etc/letsencrypt/live/example.com/privkey.pem

    &lt;span class=&quot;nc&quot;&gt;Protocols&lt;/span&gt; h2 http/1.1

    &lt;span class=&quot;c&quot;&gt;# HSTS: 2 tahun. &quot;always&quot; juga mengirimnya di redirect dan halaman error.&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Header&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;always&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;set&lt;/span&gt; Strict-Transport-Security &quot;max-age=63072000; includeSubDomains&quot;
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;VirtualHost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Lalu aktifkan site-nya dan reload:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;a2ensite example.com
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apache2ctl configtest &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl reload apache2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Baris &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RewriteCond&lt;/code&gt; membiarkan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/.well-known/acme-challenge/&lt;/code&gt; tetap di HTTP biasa, supaya validasi HTTP-01 Let’s Encrypt dijawab langsung di port 80, tanpa bergantung pada redirect dan konfigurasi HTTPS. Redirect-nya 308, sama dengan config TLSRef.&lt;/p&gt;

&lt;h3 id=&quot;kenapa-harus-header-always-set&quot;&gt;Kenapa harus &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header always set&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mod_headers&lt;/code&gt; menyimpan dua daftar header respons. Daftar default (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;onsuccess&lt;/code&gt;) dipakai untuk respons normal; &lt;a href=&quot;https://httpd.apache.org/docs/2.4/mod/mod_headers.html#header&quot;&gt;dokumentasi mod_headers&lt;/a&gt; menyebut bahwa untuk respons non-2xx yang dibuat server sendiri, seperti redirect, hanya daftar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;always&lt;/code&gt; yang dipakai.&lt;/p&gt;

&lt;p&gt;Di server tes, dengan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header set&lt;/code&gt; alih-alih &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header always set&lt;/code&gt; dan baris &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Redirect 302 /old /&lt;/code&gt; di virtual host &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*:443&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;GET /      -&amp;gt;  HTTP/2 200   strict-transport-security: max-age=63072000; includeSubDomains
GET /old   -&amp;gt;  HTTP/2 302   (tanpa header HSTS)
GET /nope  -&amp;gt;  HTTP/2 404   (tanpa header HSTS)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Dengan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header always set&lt;/code&gt;, ketiga respons membawa header itu. Ini paling terasa kalau halaman utama Anda me-redirect, misalnya &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt; ke &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/en/&lt;/code&gt; atau ke halaman login: respons HTTPS pertama yang diterima pengunjung adalah redirect itu, dan tanpa &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;always&lt;/code&gt; ia tidak membawa HSTS.&lt;/p&gt;

&lt;p&gt;Catatan HSTS lainnya:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age=63072000&lt;/code&gt;&lt;/strong&gt; sama dengan dua tahun, nilai dari TLSRef. SSL Labs butuh minimal 15768000 (enam bulan) untuk A+.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;includeSubDomains&lt;/code&gt;&lt;/strong&gt; membuat semua subdomain wajib HTTPS di browser yang pernah menerima header ini. Jangan dipasang sebelum itu benar untuk semua subdomain.&lt;/li&gt;
  &lt;li&gt;Header ini hanya di virtual host &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*:443&lt;/code&gt;. Browser mengabaikan HSTS lewat HTTP biasa, dan &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc6797#section-7.2&quot;&gt;RFC 6797 bagian 7.2&lt;/a&gt; melarang server mengirimnya di sana.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apache tidak punya masalah pewarisan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_header&lt;/code&gt; seperti nginx. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header set Cache-Control ...&lt;/code&gt; di dalam blok &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;Location&amp;gt;&lt;/code&gt; ditambahkan ke header dari virtual host; di server tes, header HSTS tetap ada di respons tersebut.&lt;/p&gt;

&lt;h2 id=&quot;langkah-4-waspadai-virtual-host-yang-menimpa-pengaturan-global&quot;&gt;Langkah 4: Waspadai virtual host yang menimpa pengaturan global&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt; mengatur nilai default untuk seluruh server. Virtual host yang punya &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLProtocol&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCipherSuite&lt;/code&gt; sendiri, atau meng-&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Include&lt;/code&gt; file yang mengaturnya, akan memakai nilai itu. Sejak Apache 2.4.42 dengan OpenSSL 1.1.1 ke atas, &lt;a href=&quot;https://httpd.apache.org/docs/2.4/mod/mod_ssl.html#sslprotocol&quot;&gt;dokumentasi SSLProtocol&lt;/a&gt; menyebut &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLProtocol&lt;/code&gt; milik tiap virtual host name-based dihormati kalau klien mengirim SNI. Sebelum itu, protokol dari virtual host pertama di IP dan port tersebut berlaku untuk semuanya.&lt;/p&gt;

&lt;p&gt;Cari semua tempat yang mengatur opsi TLS:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rn&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; SSLProtocol &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; SSLCipherSuite &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; SSLHonorCipherOrder &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; options-ssl-apache /etc/apache2/
apache2ctl &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Perintah pertama seharusnya hanya menampilkan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mods-available/ssl.conf&lt;/code&gt; dan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt; Anda. Perintah kedua menunjukkan virtual host mana yang menjawab di alamat mana, berguna kalau SSL Labs memberi nilai berbeda untuk IP yang berbeda.&lt;/p&gt;

&lt;h2 id=&quot;langkah-5-ocsp-stapling-dan-lets-encrypt&quot;&gt;Langkah 5: OCSP stapling dan Let’s Encrypt&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLUseStapling&lt;/code&gt; mati secara default di Apache, dan untuk sertifikat Let’s Encrypt sebaiknya tetap begitu. Let’s Encrypt &lt;a href=&quot;https://letsencrypt.org/2024/12/05/ending-ocsp/&quot;&gt;menghentikan dukungan OCSP&lt;/a&gt;: sejak 7 Mei 2025 sertifikatnya tidak lagi memuat URL OCSP, dan responder-nya dimatikan pada 6 Agustus 2025. Tidak ada yang bisa di-staple. (Tulisan saya tahun 2015, &lt;a href=&quot;/2015/04/12/ocsp-stapling-di-nginx&quot;&gt;OCSP Stapling di nginx&lt;/a&gt;, ditulis sebelum perubahan ini.) OCSP stapling juga tidak memengaruhi grade SSL Labs.&lt;/p&gt;

&lt;p&gt;Untuk sertifikat dari CA yang masih menjalankan OCSP, aktifkan di server config (di luar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;VirtualHost&amp;gt;&lt;/code&gt;), misalnya di akhir &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;SSLUseStapling&lt;/span&gt;          &lt;span class=&quot;ss&quot;&gt;on&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLStaplingCache&lt;/span&gt;        &quot;shmcb:${APACHE_RUN_DIR}/ssl_stapling(32768)&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;langkah-6-jebakan-configtest&quot;&gt;Langkah 6: Jebakan configtest&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apache2ctl configtest&lt;/code&gt; hanya mengecek sintaks, bukan apakah OpenSSL menerima nilai yang Anda tulis. Di server tes, nama kurva yang tidak dikenal OpenSSL lolos cek sintaks lalu menghentikan Apache:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ apache2ctl configtest
Syntax OK
$ apache2ctl graceful
# error log:
[ssl:emerg] AH02407: &quot;SSLOpenSSLConfCmd Curves FakeGroup999:X25519:prime256v1:secp384r1&quot; failed for example.test:443
[ssl:emerg] AH02312: Fatal error initialising mod_ssl, exiting.
[:emerg] AH00020: Configuration Failed, exiting
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Graceful reload tidak menyelamatkan Anda di sini. Setelah reload itu, tidak ada satu pun proses Apache yang tersisa, jadi HTTP biasa ikut mati. OpenSSL sebelum 3.5 tidak mengenal &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X25519MLKEM768&lt;/code&gt;, jadi nama itu bisa memicu kegagalan yang sama.&lt;/p&gt;

&lt;p&gt;Karena itu, cek nama grup ke OpenSSL sebelum reload. Di server tes (OpenSSL 3.5.7):&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;openssl list &lt;span class=&quot;nt&quot;&gt;-tls-groups&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;:&apos;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;\n&apos;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-x&lt;/span&gt; X25519MLKEM768
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Kalau tidak ada output, atau &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl&lt;/code&gt; Anda tidak mengenal opsi &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-tls-groups&lt;/code&gt;, hapus &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X25519MLKEM768&lt;/code&gt; dari &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt;. Debian dan Ubuntu membangun Apache dengan OpenSSL sistem, jadi perintah &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl&lt;/code&gt; mengecek library yang sama; untuk build sendiri, bandingkan dengan versi di baris log saat Apache start. Setiap kali mengubah TLS, reload lalu pastikan situs masih menjawab (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl -sI https://example.com/&lt;/code&gt;) sebelum logout.&lt;/p&gt;

&lt;h2 id=&quot;langkah-7-uji-di-lokal-lalu-jalankan-ssl-labs&quot;&gt;Langkah 7: Uji di lokal, lalu jalankan SSL Labs&lt;/h2&gt;

&lt;p&gt;Ganti &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;example.com&lt;/code&gt; dengan host Anda:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# TLS 1.1 harus ditolak. SECLEVEL=0 supaya klien modern mau mencobanya.&lt;/span&gt;
openssl s_client &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; example.com:443 &lt;span class=&quot;nt&quot;&gt;-servername&lt;/span&gt; example.com &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-tls1_1&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-cipher&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;DEFAULT@SECLEVEL=0&apos;&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;alert|Cipher is&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# TLS 1.3 harus jalan. Dengan OpenSSL 3.5+ di kedua sisi, grupnya X25519MLKEM768.&lt;/span&gt;
openssl s_client &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; example.com:443 &lt;span class=&quot;nt&quot;&gt;-servername&lt;/span&gt; example.com &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-tls1_3&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Negotiated TLS1.3 group|Cipher is&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Suite CBC, RSA biasa, dan DHE harus ditolak.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;c &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA&apos;&lt;/span&gt; AES256-GCM-SHA384 DHE-RSA-AES256-GCM-SHA384&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
  &lt;/span&gt;openssl s_client &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; example.com:443 &lt;span class=&quot;nt&quot;&gt;-servername&lt;/span&gt; example.com &lt;span class=&quot;nt&quot;&gt;-tls1_2&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;-cipher&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$c&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;alert|Cipher is&apos;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Full chain: server harus mengirim minimal 2 sertifikat (milik Anda + intermediate).&lt;/span&gt;
openssl s_client &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; example.com:443 &lt;span class=&quot;nt&quot;&gt;-servername&lt;/span&gt; example.com &lt;span class=&quot;nt&quot;&gt;-showcerts&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;/dev/null | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;BEGIN CERTIFICATE&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# HSTS di halaman normal dan halaman error, plus redirect HTTP.&lt;/span&gt;
curl &lt;span class=&quot;nt&quot;&gt;-sI&lt;/span&gt; https://example.com/ | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; strict-transport-security
curl &lt;span class=&quot;nt&quot;&gt;-sI&lt;/span&gt; https://example.com/does-not-exist | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;^HTTP&apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; strict-transport-security
curl &lt;span class=&quot;nt&quot;&gt;-sI&lt;/span&gt; http://example.com/ | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;^HTTP&apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;^location&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Di server tes, hasilnya seperti ini (diringkas):&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tls1_1 :  tlsv1 alert protocol version ... Cipher is (NONE)
tls1_3 :  Negotiated TLS1.3 group: X25519MLKEM768
          New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
CBC    :  ssl/tls alert handshake failure
RSA    :  ssl/tls alert handshake failure
DHE    :  ssl/tls alert handshake failure
404    :  HTTP/2 404 + strict-transport-security: max-age=63072000; includeSubDomains
HTTP   :  HTTP/1.1 308 Permanent Redirect
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Setelah itu buka &lt;a href=&quot;https://www.ssllabs.com/ssltest/&quot;&gt;ssllabs.com/ssltest&lt;/a&gt;, masukkan hostname, dan centang “Do not show the results on the boards” kalau tidak ingin hasilnya tampil di daftar publik. Setelah mengubah konfigurasi, klik “Clear cache” di halaman hasil supaya scan diulang.&lt;/p&gt;

&lt;h2 id=&quot;troubleshooting-arti-pesan-di-laporan-dan-cara-memperbaikinya&quot;&gt;Troubleshooting: arti pesan di laporan dan cara memperbaikinya&lt;/h2&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Yang muncul&lt;/th&gt;
      &lt;th&gt;Penyebab&lt;/th&gt;
      &lt;th&gt;Perbaikan&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade B, “This server supports TLS 1.0 and TLS 1.1”&lt;/td&gt;
      &lt;td&gt;Ada virtual host atau include yang mengatur &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLProtocol&lt;/code&gt; sendiri&lt;/td&gt;
      &lt;td&gt;Jalankan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep&lt;/code&gt; dari Langkah 4; hapus pengaturan itu&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Suite WEAK (CBC, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TLS_RSA_*&lt;/code&gt;) di daftar cipher&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCipherSuite&lt;/code&gt; bawaan distro, atau pengaturan di virtual host&lt;/td&gt;
      &lt;td&gt;Aktifkan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt;; cek dengan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep&lt;/code&gt; dari Langkah 4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade B, “Chain issues: Incomplete”&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCertificateFile&lt;/code&gt; mengarah ke &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cert.pem&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Pakai &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fullchain.pem&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade A-, “This server does not support TLS 1.3”&lt;/td&gt;
      &lt;td&gt;Apache sebelum 2.4.37, OpenSSL sebelum 1.1.1, atau &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLProtocol&lt;/code&gt; tanpa &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+TLSv1.3&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Upgrade; cek kedua versi di baris log saat Apache start&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade A-, HSTS tidak terdeteksi padahal sudah dipasang&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mod_headers&lt;/code&gt; belum aktif, header dipasang di virtual host yang salah, atau &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header set&lt;/code&gt; tanpa &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;always&lt;/code&gt; di halaman yang me-redirect&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a2enmod headers&lt;/code&gt;; pasang &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header always set&lt;/code&gt; di virtual host &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*:443&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Invalid command &apos;Header&apos;&lt;/code&gt; atau &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;RewriteEngine&apos;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Modul belum aktif&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a2enmod headers rewrite&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Apache berhenti setelah reload padahal &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;configtest&lt;/code&gt; bilang Syntax OK (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AH02407&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AH02312&lt;/code&gt;)&lt;/td&gt;
      &lt;td&gt;OpenSSL menolak suatu nilai, sering &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X25519MLKEM768&lt;/code&gt; di OpenSSL sebelum 3.5&lt;/td&gt;
      &lt;td&gt;Hapus grup itu, start Apache lagi; lihat Langkah 6&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;A+ di satu IP, A- di IP lain&lt;/td&gt;
      &lt;td&gt;IPv6 dilayani virtual host atau mesin lain&lt;/td&gt;
      &lt;td&gt;Cek &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apache2ctl -S&lt;/code&gt; dan record AAAA&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade tidak berubah walau Apache sudah diubah&lt;/td&gt;
      &lt;td&gt;Yang diuji CDN, bukan server Anda&lt;/td&gt;
      &lt;td&gt;Lihat di bawah&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Pakai Cloudflare atau CDN lain?&lt;/strong&gt; Kalau proxy aktif, SSL Labs menguji edge CDN, bukan Apache Anda. Grade-nya bergantung pada pengaturan CDN (versi TLS minimum, TLS 1.3, HSTS). Tetap pasang konfigurasi di atas di server origin dan pakai mode “Full (strict)” di Cloudflare supaya koneksi ke server Anda juga diverifikasi.&lt;/p&gt;

&lt;h2 id=&quot;opsional-hsts-preload&quot;&gt;Opsional: HSTS preload&lt;/h2&gt;

&lt;p&gt;HSTS preload memasukkan domain Anda ke daftar yang ditanam di dalam browser. SSL Labs tidak mensyaratkannya untuk A+. &lt;a href=&quot;https://hstspreload.org/&quot;&gt;hstspreload.org&lt;/a&gt; mensyaratkan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age&lt;/code&gt; minimal satu tahun, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;includeSubDomains&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;preload&lt;/code&gt;, HTTPS di semua subdomain, dan redirect HTTP ke HTTPS di host yang sama. Keluar dari daftar itu butuh berbulan-bulan sampai ke pengguna, jadi daftarkan hanya domain yang pasti tetap HTTPS-only di semua subdomain.&lt;/p&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;Header&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;always&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;set&lt;/span&gt; Strict-Transport-Security &quot;max-age=63072000; includeSubDomains; preload&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;konfigurasi-lengkap&quot;&gt;Konfigurasi lengkap&lt;/h2&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# /etc/apache2/conf-available/tls.conf   (a2enconf tls)&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLProtocol&lt;/span&gt;             -all +TLSv1.2 +TLSv1.3
&lt;span class=&quot;nc&quot;&gt;SSLOpenSSLConfCmd&lt;/span&gt;       Curves X25519MLKEM768:X25519:prime256v1:secp384r1
&lt;span class=&quot;nc&quot;&gt;SSLCipherSuite&lt;/span&gt;          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305
&lt;span class=&quot;nc&quot;&gt;SSLCipherSuite&lt;/span&gt;          TLSv1.3 TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
&lt;span class=&quot;nc&quot;&gt;SSLHonorCipherOrder&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;off&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLSessionTickets&lt;/span&gt;       &lt;span class=&quot;ss&quot;&gt;off&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# /etc/apache2/sites-available/example.com.conf   (a2ensite example.com)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;VirtualHost&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; *:80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;
&lt;/span&gt;    &lt;span class=&quot;nc&quot;&gt;ServerName&lt;/span&gt; example.com
    &lt;span class=&quot;nc&quot;&gt;ServerAlias&lt;/span&gt; www.example.com
    &lt;span class=&quot;nc&quot;&gt;RewriteEngine&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;On&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;RewriteCond&lt;/span&gt; %{REQUEST_URI} !^/\.well-known/acme-challenge/
    &lt;span class=&quot;nc&quot;&gt;RewriteRule&lt;/span&gt; ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R=308,QSA,L]
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;VirtualHost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;VirtualHost&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; *:443&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;
&lt;/span&gt;    &lt;span class=&quot;nc&quot;&gt;ServerName&lt;/span&gt; example.com
    &lt;span class=&quot;nc&quot;&gt;ServerAlias&lt;/span&gt; www.example.com
    &lt;span class=&quot;nc&quot;&gt;DocumentRoot&lt;/span&gt; /var/www/example.com
    &lt;span class=&quot;nc&quot;&gt;SSLEngine&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;on&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;SSLCertificateFile&lt;/span&gt;    /etc/letsencrypt/live/example.com/fullchain.pem
    &lt;span class=&quot;nc&quot;&gt;SSLCertificateKeyFile&lt;/span&gt; /etc/letsencrypt/live/example.com/privkey.pem
    &lt;span class=&quot;nc&quot;&gt;Protocols&lt;/span&gt; h2 http/1.1
    &lt;span class=&quot;nc&quot;&gt;Header&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;always&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;set&lt;/span&gt; Strict-Transport-Security &quot;max-age=63072000; includeSubDomains&quot;
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;VirtualHost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Modul: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a2enmod ssl headers rewrite http2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Untuk melayani sertifikat ECDSA dan RSA sekaligus, ulangi pasangan sertifikat di virtual host yang sama; mod_ssl memilih yang cocok untuk tiap klien:&lt;/p&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Pasangan ECDSA, dari Langkah 1&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLCertificateFile&lt;/span&gt;    /etc/letsencrypt/live/example.com/fullchain.pem
&lt;span class=&quot;nc&quot;&gt;SSLCertificateKeyFile&lt;/span&gt; /etc/letsencrypt/live/example.com/privkey.pem
&lt;span class=&quot;c&quot;&gt;# Pasangan RSA&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLCertificateFile&lt;/span&gt;    /etc/letsencrypt/live/example.com-rsa/fullchain.pem
&lt;span class=&quot;nc&quot;&gt;SSLCertificateKeyFile&lt;/span&gt; /etc/letsencrypt/live/example.com-rsa/privkey.pem
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Di server tes, klien TLS 1.2 yang hanya menawarkan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ECDHE-RSA-AES128-GCM-SHA256&lt;/code&gt; menerima sertifikat RSA 2048 bit, sementara klien lain mendapat ECDSA. Dengan Certbot, jalankan sekali lagi dengan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--key-type rsa --cert-name example.com-rsa&lt;/code&gt; untuk mendapat pasangan RSA.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Mahyuddin Susanto adalah sysadmin Linux dan jaringan yang mengelola server sendiri dan menulis soal Apache di blog ini sejak 2007, dimulai dari &lt;a href=&quot;/2007/09/27/apache-server-dengan-module-openssl&quot;&gt;Apache server dengan module OpenSSL&lt;/a&gt;. &lt;a href=&quot;/about&quot;&gt;Tentang penulis&lt;/a&gt; · &lt;a href=&quot;/contact&quot;&gt;Kontak&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;sumber&quot;&gt;Sumber&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Qualys SSL Labs, &lt;a href=&quot;https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide&quot;&gt;SSL Server Rating Guide&lt;/a&gt;, versi 2009r, 16 Mei 2025&lt;/li&gt;
  &lt;li&gt;TLSRef, &lt;a href=&quot;https://data.tlsref.org/guidelines/6.0.json&quot;&gt;Server Side TLS guideline 6.0&lt;/a&gt; dan &lt;a href=&quot;https://configurator.tlsref.org/&quot;&gt;TLS Configurator&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Apache HTTP Server 2.4, &lt;a href=&quot;https://httpd.apache.org/docs/2.4/mod/mod_ssl.html&quot;&gt;mod_ssl&lt;/a&gt; dan &lt;a href=&quot;https://httpd.apache.org/docs/2.4/mod/mod_headers.html&quot;&gt;mod_headers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Let’s Encrypt, &lt;a href=&quot;https://letsencrypt.org/2024/12/05/ending-ocsp/&quot;&gt;Ending OCSP Support in 2025&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hstspreload.org/&quot;&gt;HSTS Preload List Submission&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;IETF, &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc6797&quot;&gt;RFC 6797: HTTP Strict Transport Security&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>Mahyuddin Susanto</name></author><category term="Linux" /><category term="apache" /><category term="tls" /><category term="ssl" /><category term="security" /><category term="hsts" /><summary type="html">Untuk dapat A+ di SSL Labs Server Test dari Qualys dengan Apache httpd, syaratnya sama dengan web server lain: hanya TLS 1.2 dan TLS 1.3, cipher ECDHE dengan AEAD (GCM atau ChaCha20-Poly1305), sertifikat dikirim bersama chain lengkapnya, header HSTS dengan max-age minimal enam bulan, dan konfigurasi yang sama di semua alamat IP hostname tersebut. Di Apache, ada dua hal yang menentukan berhasil atau tidaknya: header HSTS harus memakai Header always set, bukan Header set, dan virtual host yang punya SSLProtocol atau SSLCipherSuite sendiri akan diam-diam mengalahkan pengaturan global.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.udienz.web.id/img/ssl-labs-a-plus-apache-id.png" /><media:content medium="image" url="https://www.udienz.web.id/img/ssl-labs-a-plus-apache-id.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to Get an A+ on SSL Labs with Apache httpd (2026 Guide)</title><link href="https://www.udienz.web.id/2026/11/05/ssl-labs-a-plus-apache" rel="alternate" type="text/html" title="How to Get an A+ on SSL Labs with Apache httpd (2026 Guide)" /><published>2026-11-05T00:00:00+00:00</published><updated>2026-11-05T00:00:00+00:00</updated><id>https://www.udienz.web.id/2026/11/05/ssl-labs-a-plus-apache</id><content type="html" xml:base="https://www.udienz.web.id/2026/11/05/ssl-labs-a-plus-apache">&lt;p&gt;To get an A+ on the &lt;a href=&quot;https://www.ssllabs.com/ssltest/&quot;&gt;Qualys SSL Labs server test&lt;/a&gt; with Apache httpd, you need the same five things as on any web server: TLS 1.2 and TLS 1.3 only, ECDHE key exchange with AEAD ciphers (GCM or ChaCha20-Poly1305), a certificate served with its full chain, an HSTS header with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age&lt;/code&gt; of at least six months, and the same setup on every IP address your hostname resolves to. On Apache, two details decide whether you get there: the HSTS header needs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header always set&lt;/code&gt;, not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header set&lt;/code&gt;, and a virtual host with its own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLProtocol&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCipherSuite&lt;/code&gt; silently overrides your global settings.&lt;/p&gt;

&lt;p&gt;This guide gives you a config you can paste into a Debian or Ubuntu Apache, explains each line, and shows how to check the result before you run SSL Labs.&lt;/p&gt;

&lt;p&gt;The configuration below was tested on Apache 2.4.69 with OpenSSL 3.5.7, using the stock Debian 13 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/apache2&lt;/code&gt; layout with the modules, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt; and site file from this guide enabled, and checked with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl s_client&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Baca dalam Bahasa Indonesia:&lt;/strong&gt; &lt;a href=&quot;/2026/11/05/ssl-labs-a-plus-apache-id&quot;&gt;Cara Mendapat A+ di SSL Labs dengan Apache&lt;/a&gt;. Running nginx? See &lt;a href=&quot;/2026/11/05/ssl-labs-a-plus-nginx&quot;&gt;How to Get an A+ on SSL Labs with nginx&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/ssl-labs-a-plus-apache.png&quot; alt=&quot;SSL Labs grade ladder for Apache: what caps a server at B or A-, and what an A+ needs&quot; /&gt;&lt;/p&gt;

&lt;details class=&quot;toc&quot;&gt;
  &lt;summary&gt;Contents&lt;/summary&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#how-ssl-labs-grades-your-server&quot; id=&quot;markdown-toc-how-ssl-labs-grades-your-server&quot;&gt;How SSL Labs grades your server&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#check-your-apache-and-openssl-versions-first&quot; id=&quot;markdown-toc-check-your-apache-and-openssl-versions-first&quot;&gt;Check your Apache and OpenSSL versions first&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#step-1-get-a-certificate-and-serve-the-full-chain&quot; id=&quot;markdown-toc-step-1-get-a-certificate-and-serve-the-full-chain&quot;&gt;Step 1: Get a certificate and serve the full chain&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#step-2-enable-the-modules-and-set-tls-globally&quot; id=&quot;markdown-toc-step-2-enable-the-modules-and-set-tls-globally&quot;&gt;Step 2: Enable the modules and set TLS globally&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#step-3-the-virtual-hosts-hsts-and-the-http-redirect&quot; id=&quot;markdown-toc-step-3-the-virtual-hosts-hsts-and-the-http-redirect&quot;&gt;Step 3: The virtual hosts, HSTS and the HTTP redirect&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#why-header-always-set-matters&quot; id=&quot;markdown-toc-why-header-always-set-matters&quot;&gt;Why &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header always set&lt;/code&gt; matters&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#step-4-watch-for-virtual-hosts-that-override-the-global-settings&quot; id=&quot;markdown-toc-step-4-watch-for-virtual-hosts-that-override-the-global-settings&quot;&gt;Step 4: Watch for virtual hosts that override the global settings&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#step-5-ocsp-stapling-and-lets-encrypt&quot; id=&quot;markdown-toc-step-5-ocsp-stapling-and-lets-encrypt&quot;&gt;Step 5: OCSP stapling and Let’s Encrypt&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#step-6-the-configtest-trap&quot; id=&quot;markdown-toc-step-6-the-configtest-trap&quot;&gt;Step 6: The configtest trap&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#step-7-test-locally-then-run-ssl-labs&quot; id=&quot;markdown-toc-step-7-test-locally-then-run-ssl-labs&quot;&gt;Step 7: Test locally, then run SSL Labs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#troubleshooting-what-the-report-says-and-how-to-fix-it&quot; id=&quot;markdown-toc-troubleshooting-what-the-report-says-and-how-to-fix-it&quot;&gt;Troubleshooting: what the report says and how to fix it&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#optional-hsts-preload&quot; id=&quot;markdown-toc-optional-hsts-preload&quot;&gt;Optional: HSTS preload&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#the-complete-config&quot; id=&quot;markdown-toc-the-complete-config&quot;&gt;The complete config&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#sources&quot; id=&quot;markdown-toc-sources&quot;&gt;Sources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;/details&gt;

&lt;h2 id=&quot;how-ssl-labs-grades-your-server&quot;&gt;How SSL Labs grades your server&lt;/h2&gt;

&lt;p&gt;SSL Labs scores protocol support (30%), key exchange (30%) and cipher strength (40%), then applies caps for specific problems. The A+ is a bonus on top of an A with no warnings. The current rules are version 2009r of the &lt;a href=&quot;https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide&quot;&gt;SSL Server Rating Guide&lt;/a&gt;, dated 16 May 2025. The caps that matter for a typical Apache server:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Problem&lt;/th&gt;
      &lt;th&gt;Grade limit&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;SSLv2, SSLv3 as the best protocol, export ciphers, Heartbleed-class bugs&lt;/td&gt;
      &lt;td&gt;F&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;TLS 1.2 not supported&lt;/td&gt;
      &lt;td&gt;C&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;TLS 1.0 or TLS 1.1 enabled&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;No forward secrecy (no ECDHE/DHE)&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;No AEAD cipher (GCM or ChaCha20-Poly1305)&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Incomplete certificate chain&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Key or DH parameters under 2048 bits&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;TLS 1.3 not supported&lt;/td&gt;
      &lt;td&gt;A-&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;HSTS missing or invalid&lt;/td&gt;
      &lt;td&gt;A-&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;For the A+, the guide asks for a configuration with no warnings and HSTS with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age&lt;/code&gt; of at least six months (15768000 seconds). Since the May 2025 revision, a plain A needs both TLS 1.3 and a valid HSTS header, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TLS_FALLBACK_SCSV&lt;/code&gt; no longer counts.&lt;/p&gt;

&lt;p&gt;An ECDSA P-256 or RSA 2048 certificate is enough. It scores 90 on key exchange and still gets an A+.&lt;/p&gt;

&lt;h2 id=&quot;check-your-apache-and-openssl-versions-first&quot;&gt;Check your Apache and OpenSSL versions first&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apache2 &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt;
apache2ctl &lt;span class=&quot;nt&quot;&gt;-M&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; ssl &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; headers &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; rewrite &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; http2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The OpenSSL version that Apache uses is printed in the error log at startup, in a line like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Apache/2.4.69 (Debian) OpenSSL/3.5.7 configured -- resuming normal operations&lt;/code&gt;.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Feature&lt;/th&gt;
      &lt;th&gt;Needs&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;TLS 1.3 (and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCipherSuite TLSv1.3 ...&lt;/code&gt; line)&lt;/td&gt;
      &lt;td&gt;Apache 2.4.37+ with OpenSSL 1.1.1+ (TLS 1.3 support is listed under 2.4.36, which was never released)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Intermediates in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCertificateFile&lt;/code&gt; (no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCertificateChainFile&lt;/code&gt;)&lt;/td&gt;
      &lt;td&gt;Apache 2.4.8+&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLOpenSSLConfCmd&lt;/code&gt; (used here to set curves)&lt;/td&gt;
      &lt;td&gt;Apache 2.4.8+ with OpenSSL 1.0.2+&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Protocols h2 http/1.1&lt;/code&gt; (HTTP/2)&lt;/td&gt;
      &lt;td&gt;Apache 2.4.17+&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Per-virtual-host &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLProtocol&lt;/code&gt; honored with SNI&lt;/td&gt;
      &lt;td&gt;Apache 2.4.42+ with OpenSSL 1.1.1+&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Hybrid post-quantum group &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X25519MLKEM768&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;OpenSSL 3.5+&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;step-1-get-a-certificate-and-serve-the-full-chain&quot;&gt;Step 1: Get a certificate and serve the full chain&lt;/h2&gt;

&lt;p&gt;With Let’s Encrypt and Certbot, get the certificate only and write the TLS config yourself:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;certbot certonly &lt;span class=&quot;nt&quot;&gt;--apache&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; example.com &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; www.example.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Certbot 2.0 and newer create an ECDSA key by default.&lt;/p&gt;

&lt;p&gt;Point Apache at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fullchain.pem&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;SSLCertificateFile&lt;/span&gt;    /etc/letsencrypt/live/example.com/fullchain.pem
&lt;span class=&quot;nc&quot;&gt;SSLCertificateKeyFile&lt;/span&gt; /etc/letsencrypt/live/example.com/privkey.pem
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since Apache 2.4.8, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCertificateFile&lt;/code&gt; can hold the intermediate certificates after your own certificate, and the &lt;a href=&quot;https://httpd.apache.org/docs/2.4/mod/mod_ssl.html#sslcertificatefile&quot;&gt;mod_ssl documentation&lt;/a&gt; marks &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCertificateChainFile&lt;/code&gt; as obsolete. If you point &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCertificateFile&lt;/code&gt; at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cert.pem&lt;/code&gt; and drop the chain file, the intermediate is missing. Browsers often fill it in themselves, but SSL Labs reports “Chain issues: Incomplete” and caps the grade at B.&lt;/p&gt;

&lt;p&gt;If you use Certbot’s installer (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;certbot --apache&lt;/code&gt; without &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;certonly&lt;/code&gt;), it adds &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Include /etc/letsencrypt/options-ssl-apache.conf&lt;/code&gt; inside your virtual host. That file sets its own protocols and ciphers, and because it sits in the virtual host, it wins over the global file from Step 2. Remove the include, but first look at what else the file sets: the current &lt;a href=&quot;https://github.com/certbot/certbot/blob/main/certbot/src/certbot/_internal/plugins/apache/tls_configs/current-options-ssl-apache.conf&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;options-ssl-apache.conf&lt;/code&gt;&lt;/a&gt; starts with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLEngine on&lt;/code&gt;. Check with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep -n SSLEngine /etc/letsencrypt/options-ssl-apache.conf&lt;/code&gt; and, if it is there, add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLEngine on&lt;/code&gt; to the virtual host itself. Without it, Apache serves plain HTTP on port 443 and reports no error.&lt;/p&gt;

&lt;h2 id=&quot;step-2-enable-the-modules-and-set-tls-globally&quot;&gt;Step 2: Enable the modules and set TLS globally&lt;/h2&gt;

&lt;p&gt;Enable the modules this guide uses:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;a2enmod ssl headers rewrite http2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a2enmod ssl&lt;/code&gt; also enables &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;socache_shmcb&lt;/code&gt; for the session cache. On Debian 13, the stock &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/apache2/mods-available/ssl.conf&lt;/code&gt; then contains these lines (comments removed):&lt;/p&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;SSLSessionCache&lt;/span&gt;     shmcb:${APACHE_RUN_DIR}/ssl_scache(512000)
&lt;span class=&quot;nc&quot;&gt;SSLSessionCacheTimeout&lt;/span&gt;  300
&lt;span class=&quot;nc&quot;&gt;SSLCipherSuite&lt;/span&gt; HIGH:!aNULL
&lt;span class=&quot;nc&quot;&gt;SSLProtocol&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;all&lt;/span&gt; -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
&lt;span class=&quot;nc&quot;&gt;SSLSessionTickets&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;off&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The protocols are already fine. The cipher list is wider than it needs to be. With only these defaults, the test server accepted CBC suites, plain RSA key exchange without forward secrecy, and DHE:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;-cipher &apos;ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA&apos;  -&amp;gt;  Cipher is ECDHE-ECDSA-AES128-SHA
-cipher &apos;AES256-GCM-SHA384&apos;                            -&amp;gt;  Cipher is AES256-GCM-SHA384
-cipher &apos;DHE-RSA-AES256-GCM-SHA384&apos;                    -&amp;gt;  Cipher is DHE-RSA-AES256-GCM-SHA384
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;SSL Labs marks CBC and plain RSA suites as WEAK in its cipher list, and TLSRef leaves DHE out entirely. There is no reason to keep offering any of them. Other releases may ship different defaults, so check yours with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep -v &apos;^\s*#&apos; /etc/apache2/mods-available/ssl.conf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Leave &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl.conf&lt;/code&gt; as it is and put your settings in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/apache2/conf-available/tls.conf&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# TLS settings for every HTTPS virtual host (server config context)&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLProtocol&lt;/span&gt;             -all +TLSv1.2 +TLSv1.3

&lt;span class=&quot;c&quot;&gt;# OpenSSL 3.5+: hybrid post-quantum group first.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# On OpenSSL 3.0-3.4, remove X25519MLKEM768 from this list.&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLOpenSSLConfCmd&lt;/span&gt;       Curves X25519MLKEM768:X25519:prime256v1:secp384r1

&lt;span class=&quot;c&quot;&gt;# TLS 1.2: ECDHE key exchange + AEAD only. TLS 1.3: the three standard suites.&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLCipherSuite&lt;/span&gt;          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305
&lt;span class=&quot;nc&quot;&gt;SSLCipherSuite&lt;/span&gt;          TLSv1.3 TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
&lt;span class=&quot;nc&quot;&gt;SSLHonorCipherOrder&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;off&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLSessionTickets&lt;/span&gt;       &lt;span class=&quot;ss&quot;&gt;off&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Enable it:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;a2enconf tls
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Debian’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apache2.conf&lt;/code&gt; reads &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mods-enabled/*.conf&lt;/code&gt; first and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;conf-enabled/*.conf&lt;/code&gt; later. For these directives, the later global value replaces the earlier one, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt; wins over &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl.conf&lt;/code&gt; without any edits there. On the test server, the three weak suites above were refused once &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt; was enabled.&lt;/p&gt;

&lt;p&gt;Line by line:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLProtocol -all +TLSv1.2 +TLSv1.3&lt;/code&gt;&lt;/strong&gt; starts from nothing and allows only TLS 1.2 and 1.3. TLS 1.0 or 1.1 would cap you at B; missing TLS 1.3 caps you at A-.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLOpenSSLConfCmd Curves&lt;/code&gt;&lt;/strong&gt; passes the key exchange groups to OpenSSL. The list comes from the &lt;a href=&quot;https://data.tlsref.org/guidelines/6.0.json&quot;&gt;TLSRef guideline 6.0&lt;/a&gt;, the successor of Mozilla’s Server Side TLS guidelines, and matches what the &lt;a href=&quot;https://configurator.tlsref.org/&quot;&gt;TLSRef Configurator&lt;/a&gt; generates for Apache. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X25519MLKEM768&lt;/code&gt; combines X25519 with the ML-KEM post-quantum algorithm; clients without it fall back to X25519.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCipherSuite&lt;/code&gt;&lt;/strong&gt; lists only ECDHE suites with GCM or ChaCha20-Poly1305: forward secrecy and AEAD, nothing else. TLSRef lists the oldest clients this still serves as Firefox 31, Chrome 49, Safari 9, Android 4.4.2, IE 11 on Windows 10 and Java 8u161.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCipherSuite TLSv1.3 ...&lt;/code&gt;&lt;/strong&gt; sets the TLS 1.3 suites. These three are OpenSSL’s defaults anyway; the line makes them explicit.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLHonorCipherOrder off&lt;/code&gt;&lt;/strong&gt; lets the client choose from the list. Every option is strong, and phones without AES hardware pick ChaCha20.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLSessionTickets off&lt;/code&gt;&lt;/strong&gt;. The mod_ssl documentation warns that tickets used “without restarting the web server with an appropriate frequency (e.g. daily)” compromise forward secrecy. Apache does not rotate the ticket key on its own, so TLSRef turns tickets off. Session resumption still works through the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shmcb&lt;/code&gt; session cache from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl.conf&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;No DH parameters.&lt;/strong&gt; The list has no DHE suites, so you do not need to append DH parameters to the certificate file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;step-3-the-virtual-hosts-hsts-and-the-http-redirect&quot;&gt;Step 3: The virtual hosts, HSTS and the HTTP redirect&lt;/h2&gt;

&lt;p&gt;Create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/apache2/sites-available/example.com.conf&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;VirtualHost&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; *:80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;
&lt;/span&gt;    &lt;span class=&quot;nc&quot;&gt;ServerName&lt;/span&gt; example.com
    &lt;span class=&quot;nc&quot;&gt;ServerAlias&lt;/span&gt; www.example.com

    &lt;span class=&quot;nc&quot;&gt;RewriteEngine&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;On&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;RewriteCond&lt;/span&gt; %{REQUEST_URI} !^/\.well-known/acme-challenge/
    &lt;span class=&quot;nc&quot;&gt;RewriteRule&lt;/span&gt; ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R=308,QSA,L]
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;VirtualHost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;VirtualHost&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; *:443&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;
&lt;/span&gt;    &lt;span class=&quot;nc&quot;&gt;ServerName&lt;/span&gt; example.com
    &lt;span class=&quot;nc&quot;&gt;ServerAlias&lt;/span&gt; www.example.com
    &lt;span class=&quot;nc&quot;&gt;DocumentRoot&lt;/span&gt; /var/www/example.com

    &lt;span class=&quot;nc&quot;&gt;SSLEngine&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;on&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;SSLCertificateFile&lt;/span&gt;    /etc/letsencrypt/live/example.com/fullchain.pem
    &lt;span class=&quot;nc&quot;&gt;SSLCertificateKeyFile&lt;/span&gt; /etc/letsencrypt/live/example.com/privkey.pem

    &lt;span class=&quot;nc&quot;&gt;Protocols&lt;/span&gt; h2 http/1.1

    &lt;span class=&quot;c&quot;&gt;# HSTS: 2 years. &quot;always&quot; also sends it on redirects and error pages.&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Header&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;always&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;set&lt;/span&gt; Strict-Transport-Security &quot;max-age=63072000; includeSubDomains&quot;
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;VirtualHost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then enable the site and reload:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;a2ensite example.com
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apache2ctl configtest &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl reload apache2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RewriteCond&lt;/code&gt; line keeps &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/.well-known/acme-challenge/&lt;/code&gt; on plain HTTP, so Let’s Encrypt HTTP-01 validation is answered directly on port 80 and does not depend on the redirect or the HTTPS setup. The redirect is a 308, as in the TLSRef config.&lt;/p&gt;

&lt;h3 id=&quot;why-header-always-set-matters&quot;&gt;Why &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header always set&lt;/code&gt; matters&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mod_headers&lt;/code&gt; keeps two lists of response headers. The default one (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;onsuccess&lt;/code&gt;) is used for normal responses; the &lt;a href=&quot;https://httpd.apache.org/docs/2.4/mod/mod_headers.html#header&quot;&gt;mod_headers documentation&lt;/a&gt; says that for a locally generated non-2xx response, “such as a redirect”, only the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;always&lt;/code&gt; list is used.&lt;/p&gt;

&lt;p&gt;On the test server, with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header set&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header always set&lt;/code&gt; and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Redirect 302 /old /&lt;/code&gt; line in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*:443&lt;/code&gt; virtual host:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;GET /      -&amp;gt;  HTTP/2 200   strict-transport-security: max-age=63072000; includeSubDomains
GET /old   -&amp;gt;  HTTP/2 302   (no HSTS header)
GET /nope  -&amp;gt;  HTTP/2 404   (no HSTS header)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header always set&lt;/code&gt;, all three responses carried the header. This matters most when your home page redirects, for example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/en/&lt;/code&gt; or to a login page: the first HTTPS response a visitor gets is that redirect, and without &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;always&lt;/code&gt; it has no HSTS header.&lt;/p&gt;

&lt;p&gt;Other HSTS notes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age=63072000&lt;/code&gt;&lt;/strong&gt; is two years, the TLSRef value. SSL Labs needs at least 15768000 (six months) for the A+.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;includeSubDomains&lt;/code&gt;&lt;/strong&gt; makes every subdomain HTTPS-only in browsers that have seen the header. Leave it out until that is true for all of them.&lt;/li&gt;
  &lt;li&gt;The header belongs only in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*:443&lt;/code&gt; virtual host. Browsers ignore HSTS on plain HTTP, and &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc6797#section-7.2&quot;&gt;RFC 6797, section 7.2&lt;/a&gt; says servers must not send it there.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apache does not have nginx’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_header&lt;/code&gt; inheritance problem. A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header set Cache-Control ...&lt;/code&gt; inside a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;Location&amp;gt;&lt;/code&gt; block is added to the headers from the virtual host; on the test server the HSTS header stayed on those responses.&lt;/p&gt;

&lt;h2 id=&quot;step-4-watch-for-virtual-hosts-that-override-the-global-settings&quot;&gt;Step 4: Watch for virtual hosts that override the global settings&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt; sets the server-wide default. Any virtual host that has its own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLProtocol&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCipherSuite&lt;/code&gt; or an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Include&lt;/code&gt; of a file that sets them uses those values instead. Since Apache 2.4.42 with OpenSSL 1.1.1 or newer, the &lt;a href=&quot;https://httpd.apache.org/docs/2.4/mod/mod_ssl.html#sslprotocol&quot;&gt;SSLProtocol documentation&lt;/a&gt; says each name-based virtual host’s own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLProtocol&lt;/code&gt; is honored when the client sends SNI. Before that, the protocol of the first virtual host on the IP and port applied to all of them.&lt;/p&gt;

&lt;p&gt;Find every place that sets TLS options:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rn&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; SSLProtocol &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; SSLCipherSuite &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; SSLHonorCipherOrder &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; options-ssl-apache /etc/apache2/
apache2ctl &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The first command should show only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mods-available/ssl.conf&lt;/code&gt; and your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt;. The second lists which virtual host answers on which address, which helps when SSL Labs grades one IP differently from another.&lt;/p&gt;

&lt;h2 id=&quot;step-5-ocsp-stapling-and-lets-encrypt&quot;&gt;Step 5: OCSP stapling and Let’s Encrypt&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLUseStapling&lt;/code&gt; is off by default in Apache, and for Let’s Encrypt certificates it should stay off. Let’s Encrypt &lt;a href=&quot;https://letsencrypt.org/2024/12/05/ending-ocsp/&quot;&gt;ended OCSP support&lt;/a&gt;: from 7 May 2025 its certificates no longer contain an OCSP URL, and the responders were switched off on 6 August 2025. There is nothing to staple. (My 2015 post on &lt;a href=&quot;/2015/04/12/ocsp-stapling-di-nginx&quot;&gt;OCSP stapling in nginx&lt;/a&gt; predates this change.) OCSP stapling has no effect on the SSL Labs grade.&lt;/p&gt;

&lt;p&gt;For a certificate from a CA that still runs OCSP, enable it in the server config (outside any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;VirtualHost&amp;gt;&lt;/code&gt;), for example at the end of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;SSLUseStapling&lt;/span&gt;          &lt;span class=&quot;ss&quot;&gt;on&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLStaplingCache&lt;/span&gt;        &quot;shmcb:${APACHE_RUN_DIR}/ssl_stapling(32768)&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;step-6-the-configtest-trap&quot;&gt;Step 6: The configtest trap&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apache2ctl configtest&lt;/code&gt; checks the syntax, not whether OpenSSL accepts your values. On the test server, a curve name that OpenSSL does not know passed the syntax check and then stopped Apache:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ apache2ctl configtest
Syntax OK
$ apache2ctl graceful
# error log:
[ssl:emerg] AH02407: &quot;SSLOpenSSLConfCmd Curves FakeGroup999:X25519:prime256v1:secp384r1&quot; failed for example.test:443
[ssl:emerg] AH02312: Fatal error initialising mod_ssl, exiting.
[:emerg] AH00020: Configuration Failed, exiting
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A graceful reload does not protect you here. After that reload, no Apache process was left running, so plain HTTP was down too. OpenSSL older than 3.5 does not know &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X25519MLKEM768&lt;/code&gt;, so that name can cause the same failure there.&lt;/p&gt;

&lt;p&gt;So check the group names against OpenSSL before you reload. On the test server (OpenSSL 3.5.7):&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;openssl list &lt;span class=&quot;nt&quot;&gt;-tls-groups&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;:&apos;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;\n&apos;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-x&lt;/span&gt; X25519MLKEM768
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If that prints nothing, or your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl&lt;/code&gt; does not know the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-tls-groups&lt;/code&gt; option, remove &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X25519MLKEM768&lt;/code&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt;. Debian and Ubuntu build Apache against the system OpenSSL, so the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl&lt;/code&gt; command checks the same library; on a custom build, compare with the version in Apache’s startup log line. After any TLS change, reload and then confirm the site still answers (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl -sI https://example.com/&lt;/code&gt;) before you log out.&lt;/p&gt;

&lt;h2 id=&quot;step-7-test-locally-then-run-ssl-labs&quot;&gt;Step 7: Test locally, then run SSL Labs&lt;/h2&gt;

&lt;p&gt;Replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;example.com&lt;/code&gt; with your host:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# TLS 1.1 must be refused. SECLEVEL=0 lets a modern client even try it.&lt;/span&gt;
openssl s_client &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; example.com:443 &lt;span class=&quot;nt&quot;&gt;-servername&lt;/span&gt; example.com &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-tls1_1&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-cipher&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;DEFAULT@SECLEVEL=0&apos;&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;alert|Cipher is&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# TLS 1.3 must work. With OpenSSL 3.5+ on both sides the group is X25519MLKEM768.&lt;/span&gt;
openssl s_client &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; example.com:443 &lt;span class=&quot;nt&quot;&gt;-servername&lt;/span&gt; example.com &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-tls1_3&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Negotiated TLS1.3 group|Cipher is&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# CBC, plain RSA and DHE suites must be refused.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;c &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA&apos;&lt;/span&gt; AES256-GCM-SHA384 DHE-RSA-AES256-GCM-SHA384&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
  &lt;/span&gt;openssl s_client &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; example.com:443 &lt;span class=&quot;nt&quot;&gt;-servername&lt;/span&gt; example.com &lt;span class=&quot;nt&quot;&gt;-tls1_2&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;-cipher&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$c&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;alert|Cipher is&apos;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Full chain: the server must send at least 2 certificates (yours + intermediate).&lt;/span&gt;
openssl s_client &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; example.com:443 &lt;span class=&quot;nt&quot;&gt;-servername&lt;/span&gt; example.com &lt;span class=&quot;nt&quot;&gt;-showcerts&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;/dev/null | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;BEGIN CERTIFICATE&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# HSTS on a normal page and on an error page, plus the HTTP redirect.&lt;/span&gt;
curl &lt;span class=&quot;nt&quot;&gt;-sI&lt;/span&gt; https://example.com/ | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; strict-transport-security
curl &lt;span class=&quot;nt&quot;&gt;-sI&lt;/span&gt; https://example.com/does-not-exist | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;^HTTP&apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; strict-transport-security
curl &lt;span class=&quot;nt&quot;&gt;-sI&lt;/span&gt; http://example.com/ | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;^HTTP&apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;^location&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On the test setup, the output looked like this (condensed):&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tls1_1 :  tlsv1 alert protocol version ... Cipher is (NONE)
tls1_3 :  Negotiated TLS1.3 group: X25519MLKEM768
          New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
CBC    :  ssl/tls alert handshake failure
RSA    :  ssl/tls alert handshake failure
DHE    :  ssl/tls alert handshake failure
404    :  HTTP/2 404 + strict-transport-security: max-age=63072000; includeSubDomains
HTTP   :  HTTP/1.1 308 Permanent Redirect
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then open &lt;a href=&quot;https://www.ssllabs.com/ssltest/&quot;&gt;ssllabs.com/ssltest&lt;/a&gt;, enter your hostname, and tick “Do not show the results on the boards” if you do not want the result listed. After a config change, use “Clear cache” on the results page to force a new scan.&lt;/p&gt;

&lt;h2 id=&quot;troubleshooting-what-the-report-says-and-how-to-fix-it&quot;&gt;Troubleshooting: what the report says and how to fix it&lt;/h2&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;What you see&lt;/th&gt;
      &lt;th&gt;Cause&lt;/th&gt;
      &lt;th&gt;Fix&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade B, “This server supports TLS 1.0 and TLS 1.1”&lt;/td&gt;
      &lt;td&gt;A virtual host or include sets its own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLProtocol&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep&lt;/code&gt; from Step 4; remove the override&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;WEAK suites (CBC, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TLS_RSA_*&lt;/code&gt;) in the cipher list&lt;/td&gt;
      &lt;td&gt;Distribution default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCipherSuite&lt;/code&gt;, or an override in a virtual host&lt;/td&gt;
      &lt;td&gt;Enable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt;; check with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep&lt;/code&gt; from Step 4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade B, “Chain issues: Incomplete”&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLCertificateFile&lt;/code&gt; points to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cert.pem&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fullchain.pem&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade A-, “This server does not support TLS 1.3”&lt;/td&gt;
      &lt;td&gt;Apache older than 2.4.37, OpenSSL older than 1.1.1, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLProtocol&lt;/code&gt; without &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+TLSv1.3&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Upgrade; check both versions in the startup line of the error log&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade A-, HSTS missing although it is configured&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mod_headers&lt;/code&gt; not enabled, the header set in the wrong virtual host, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header set&lt;/code&gt; without &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;always&lt;/code&gt; on a redirecting page&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a2enmod headers&lt;/code&gt;; put &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Header always set&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*:443&lt;/code&gt; virtual host&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Invalid command &apos;Header&apos;&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;RewriteEngine&apos;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Module not enabled&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a2enmod headers rewrite&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Apache stops after a reload although &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;configtest&lt;/code&gt; said Syntax OK (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AH02407&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AH02312&lt;/code&gt;)&lt;/td&gt;
      &lt;td&gt;OpenSSL rejects a value, often &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X25519MLKEM768&lt;/code&gt; on OpenSSL older than 3.5&lt;/td&gt;
      &lt;td&gt;Remove that group, start Apache again; see Step 6&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;A+ on one IP, A- on another&lt;/td&gt;
      &lt;td&gt;IPv6 served by another virtual host or machine&lt;/td&gt;
      &lt;td&gt;Check &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apache2ctl -S&lt;/code&gt; and the AAAA record&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade does not change after you edit Apache&lt;/td&gt;
      &lt;td&gt;You are testing a CDN, not your server&lt;/td&gt;
      &lt;td&gt;See below&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Behind Cloudflare or another CDN?&lt;/strong&gt; With the proxy on, SSL Labs tests the CDN’s edge, not your Apache. The grade then depends on the CDN settings (minimum TLS version, TLS 1.3, HSTS). Keep the setup above on the origin and use Cloudflare’s “Full (strict)” mode so the connection to your server is checked too.&lt;/p&gt;

&lt;h2 id=&quot;optional-hsts-preload&quot;&gt;Optional: HSTS preload&lt;/h2&gt;

&lt;p&gt;HSTS preload puts your domain on a list built into browsers. SSL Labs does not need it for an A+. &lt;a href=&quot;https://hstspreload.org/&quot;&gt;hstspreload.org&lt;/a&gt; requires a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age&lt;/code&gt; of at least one year, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;includeSubDomains&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;preload&lt;/code&gt;, HTTPS on every subdomain, and an HTTP to HTTPS redirect on the same host. Removal takes months to reach users, so only submit a domain that will stay HTTPS-only everywhere.&lt;/p&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;Header&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;always&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;set&lt;/span&gt; Strict-Transport-Security &quot;max-age=63072000; includeSubDomains; preload&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-complete-config&quot;&gt;The complete config&lt;/h2&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# /etc/apache2/conf-available/tls.conf   (a2enconf tls)&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLProtocol&lt;/span&gt;             -all +TLSv1.2 +TLSv1.3
&lt;span class=&quot;nc&quot;&gt;SSLOpenSSLConfCmd&lt;/span&gt;       Curves X25519MLKEM768:X25519:prime256v1:secp384r1
&lt;span class=&quot;nc&quot;&gt;SSLCipherSuite&lt;/span&gt;          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305
&lt;span class=&quot;nc&quot;&gt;SSLCipherSuite&lt;/span&gt;          TLSv1.3 TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
&lt;span class=&quot;nc&quot;&gt;SSLHonorCipherOrder&lt;/span&gt;     &lt;span class=&quot;ss&quot;&gt;off&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLSessionTickets&lt;/span&gt;       &lt;span class=&quot;ss&quot;&gt;off&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# /etc/apache2/sites-available/example.com.conf   (a2ensite example.com)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;VirtualHost&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; *:80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;
&lt;/span&gt;    &lt;span class=&quot;nc&quot;&gt;ServerName&lt;/span&gt; example.com
    &lt;span class=&quot;nc&quot;&gt;ServerAlias&lt;/span&gt; www.example.com
    &lt;span class=&quot;nc&quot;&gt;RewriteEngine&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;On&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;RewriteCond&lt;/span&gt; %{REQUEST_URI} !^/\.well-known/acme-challenge/
    &lt;span class=&quot;nc&quot;&gt;RewriteRule&lt;/span&gt; ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R=308,QSA,L]
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;VirtualHost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;VirtualHost&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; *:443&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;
&lt;/span&gt;    &lt;span class=&quot;nc&quot;&gt;ServerName&lt;/span&gt; example.com
    &lt;span class=&quot;nc&quot;&gt;ServerAlias&lt;/span&gt; www.example.com
    &lt;span class=&quot;nc&quot;&gt;DocumentRoot&lt;/span&gt; /var/www/example.com
    &lt;span class=&quot;nc&quot;&gt;SSLEngine&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;on&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;SSLCertificateFile&lt;/span&gt;    /etc/letsencrypt/live/example.com/fullchain.pem
    &lt;span class=&quot;nc&quot;&gt;SSLCertificateKeyFile&lt;/span&gt; /etc/letsencrypt/live/example.com/privkey.pem
    &lt;span class=&quot;nc&quot;&gt;Protocols&lt;/span&gt; h2 http/1.1
    &lt;span class=&quot;nc&quot;&gt;Header&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;always&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;set&lt;/span&gt; Strict-Transport-Security &quot;max-age=63072000; includeSubDomains&quot;
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;VirtualHost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Modules: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a2enmod ssl headers rewrite http2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To serve both ECDSA and RSA certificates, repeat the certificate pair in the same virtual host; mod_ssl picks the right one per client:&lt;/p&gt;

&lt;div class=&quot;language-apache highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# ECDSA pair, from Step 1&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLCertificateFile&lt;/span&gt;    /etc/letsencrypt/live/example.com/fullchain.pem
&lt;span class=&quot;nc&quot;&gt;SSLCertificateKeyFile&lt;/span&gt; /etc/letsencrypt/live/example.com/privkey.pem
&lt;span class=&quot;c&quot;&gt;# RSA pair&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;SSLCertificateFile&lt;/span&gt;    /etc/letsencrypt/live/example.com-rsa/fullchain.pem
&lt;span class=&quot;nc&quot;&gt;SSLCertificateKeyFile&lt;/span&gt; /etc/letsencrypt/live/example.com-rsa/privkey.pem
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On the test server, a TLS 1.2 client that only offered &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ECDHE-RSA-AES128-GCM-SHA256&lt;/code&gt; received the 2048-bit RSA certificate, and other clients got ECDSA. With Certbot, run it again with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--key-type rsa --cert-name example.com-rsa&lt;/code&gt; for the RSA pair.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Mahyuddin Susanto is a Linux and networking sysadmin who runs his own servers and has written about Apache on this blog since 2007, starting with &lt;a href=&quot;/2007/09/27/apache-server-dengan-module-openssl&quot;&gt;Apache server dengan module OpenSSL&lt;/a&gt;. &lt;a href=&quot;/about&quot;&gt;About&lt;/a&gt; · &lt;a href=&quot;/contact&quot;&gt;Contact&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;sources&quot;&gt;Sources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Qualys SSL Labs, &lt;a href=&quot;https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide&quot;&gt;SSL Server Rating Guide&lt;/a&gt;, version 2009r, 16 May 2025&lt;/li&gt;
  &lt;li&gt;TLSRef, &lt;a href=&quot;https://data.tlsref.org/guidelines/6.0.json&quot;&gt;Server Side TLS guideline 6.0&lt;/a&gt; and &lt;a href=&quot;https://configurator.tlsref.org/&quot;&gt;TLS Configurator&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Apache HTTP Server 2.4, &lt;a href=&quot;https://httpd.apache.org/docs/2.4/mod/mod_ssl.html&quot;&gt;mod_ssl&lt;/a&gt; and &lt;a href=&quot;https://httpd.apache.org/docs/2.4/mod/mod_headers.html&quot;&gt;mod_headers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Let’s Encrypt, &lt;a href=&quot;https://letsencrypt.org/2024/12/05/ending-ocsp/&quot;&gt;Ending OCSP Support in 2025&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hstspreload.org/&quot;&gt;HSTS Preload List Submission&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;IETF, &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc6797&quot;&gt;RFC 6797: HTTP Strict Transport Security&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>Mahyuddin Susanto</name></author><category term="Linux" /><category term="apache" /><category term="tls" /><category term="ssl" /><category term="security" /><category term="hsts" /><summary type="html">To get an A+ on the Qualys SSL Labs server test with Apache httpd, you need the same five things as on any web server: TLS 1.2 and TLS 1.3 only, ECDHE key exchange with AEAD ciphers (GCM or ChaCha20-Poly1305), a certificate served with its full chain, an HSTS header with a max-age of at least six months, and the same setup on every IP address your hostname resolves to. On Apache, two details decide whether you get there: the HSTS header needs Header always set, not Header set, and a virtual host with its own SSLProtocol or SSLCipherSuite silently overrides your global settings.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.udienz.web.id/img/ssl-labs-a-plus-apache.png" /><media:content medium="image" url="https://www.udienz.web.id/img/ssl-labs-a-plus-apache.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Cara Mendapat A+ di SSL Labs dengan nginx (Panduan 2026)</title><link href="https://www.udienz.web.id/2026/11/05/ssl-labs-a-plus-nginx-id" rel="alternate" type="text/html" title="Cara Mendapat A+ di SSL Labs dengan nginx (Panduan 2026)" /><published>2026-11-05T00:00:00+00:00</published><updated>2026-11-05T00:00:00+00:00</updated><id>https://www.udienz.web.id/2026/11/05/ssl-labs-a-plus-nginx-id</id><content type="html" xml:base="https://www.udienz.web.id/2026/11/05/ssl-labs-a-plus-nginx-id">&lt;p&gt;Untuk dapat A+ di &lt;a href=&quot;https://www.ssllabs.com/ssltest/&quot;&gt;SSL Labs Server Test&lt;/a&gt; dari Qualys dengan nginx, ada lima syarat: hanya TLS 1.2 dan TLS 1.3, cipher ECDHE dengan AEAD (GCM atau ChaCha20-Poly1305), sertifikat dikirim bersama chain lengkapnya, header HSTS dengan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age&lt;/code&gt; minimal enam bulan, dan konfigurasi yang sama di semua alamat IP hostname tersebut. Tanpa TLS 1.3 atau tanpa HSTS, nilainya mentok di A-. Kalau TLS 1.0 atau 1.1 masih aktif, nilainya mentok di B.&lt;/p&gt;

&lt;p&gt;Tulisan ini membahas tiap syarat itu satu per satu, lengkap dengan konfigurasi yang bisa langsung dipakai. Ada juga dua perubahan yang bikin banyak tutorial lama jadi usang: Let’s Encrypt mematikan OCSP di 2025, dan SSL Labs mengubah aturan penilaiannya di Mei 2025.&lt;/p&gt;

&lt;p&gt;Konfigurasi di bawah sudah diuji di nginx 1.26.3 dengan OpenSSL 3.5.7, memakai &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx.conf&lt;/code&gt; bawaan Debian 13 (dua baris SSL-nya diberi &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#&lt;/code&gt;) ditambah file-file dari tulisan ini, lalu dicek dengan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl s_client&lt;/code&gt; dan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read in English:&lt;/strong&gt; &lt;a href=&quot;/2026/11/05/ssl-labs-a-plus-nginx&quot;&gt;How to Get an A+ on SSL Labs with nginx&lt;/a&gt;. Pakai Apache? Lihat &lt;a href=&quot;/2026/11/05/ssl-labs-a-plus-apache-id&quot;&gt;Cara Mendapat A+ di SSL Labs dengan Apache&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/ssl-labs-a-plus-nginx-id.png&quot; alt=&quot;Tangga grade SSL Labs untuk nginx: apa yang menahan server di B atau A-, dan syarat A+&quot; /&gt;&lt;/p&gt;

&lt;details class=&quot;toc&quot;&gt;
  &lt;summary&gt;Daftar isi&lt;/summary&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#cara-ssl-labs-memberi-nilai&quot; id=&quot;markdown-toc-cara-ssl-labs-memberi-nilai&quot;&gt;Cara SSL Labs memberi nilai&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#cek-versi-nginx-dan-openssl-dulu&quot; id=&quot;markdown-toc-cek-versi-nginx-dan-openssl-dulu&quot;&gt;Cek versi nginx dan OpenSSL dulu&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#langkah-1-sertifikat-dan-full-chain&quot; id=&quot;markdown-toc-langkah-1-sertifikat-dan-full-chain&quot;&gt;Langkah 1: Sertifikat dan full chain&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#langkah-2-taruh-pengaturan-tls-di-satu-file-bersama&quot; id=&quot;markdown-toc-langkah-2-taruh-pengaturan-tls-di-satu-file-bersama&quot;&gt;Langkah 2: Taruh pengaturan TLS di satu file bersama&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#langkah-3-server-block-hsts-dan-redirect-http&quot; id=&quot;markdown-toc-langkah-3-server-block-hsts-dan-redirect-http&quot;&gt;Langkah 3: Server block, HSTS, dan redirect HTTP&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#langkah-4-ocsp-stapling-dan-lets-encrypt&quot; id=&quot;markdown-toc-langkah-4-ocsp-stapling-dan-lets-encrypt&quot;&gt;Langkah 4: OCSP stapling dan Let’s Encrypt&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#langkah-5-hindari-jebakan-add_header&quot; id=&quot;markdown-toc-langkah-5-hindari-jebakan-add_header&quot;&gt;Langkah 5: Hindari jebakan add_header&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#langkah-6-uji-di-lokal-lalu-jalankan-ssl-labs&quot; id=&quot;markdown-toc-langkah-6-uji-di-lokal-lalu-jalankan-ssl-labs&quot;&gt;Langkah 6: Uji di lokal, lalu jalankan SSL Labs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#troubleshooting-arti-pesan-di-laporan-dan-cara-memperbaikinya&quot; id=&quot;markdown-toc-troubleshooting-arti-pesan-di-laporan-dan-cara-memperbaikinya&quot;&gt;Troubleshooting: arti pesan di laporan dan cara memperbaikinya&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#opsional-hsts-preload&quot; id=&quot;markdown-toc-opsional-hsts-preload&quot;&gt;Opsional: HSTS preload&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#konfigurasi-lengkap&quot; id=&quot;markdown-toc-konfigurasi-lengkap&quot;&gt;Konfigurasi lengkap&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#sumber&quot; id=&quot;markdown-toc-sumber&quot;&gt;Sumber&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;/details&gt;

&lt;h2 id=&quot;cara-ssl-labs-memberi-nilai&quot;&gt;Cara SSL Labs memberi nilai&lt;/h2&gt;

&lt;p&gt;SSL Labs menilai tiga kategori: dukungan protokol (30%), key exchange (30%), dan kekuatan cipher (40%). Skor 80 ke atas berarti A. Setelah itu berlaku batas atas (cap): masalah tertentu membatasi grade setinggi apa pun skornya. A+ adalah bonus untuk server ber-grade A yang tidak punya warning.&lt;/p&gt;

&lt;p&gt;Aturan yang berlaku sekarang adalah versi 2009r dari &lt;a href=&quot;https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide&quot;&gt;SSL Server Rating Guide&lt;/a&gt;, tertanggal 16 Mei 2025. Ini batas-batas yang relevan untuk server nginx pada umumnya:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Masalah&lt;/th&gt;
      &lt;th&gt;Grade maksimal&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;SSLv2, SSLv3 sebagai protokol terbaik, cipher export, bug sekelas Heartbleed&lt;/td&gt;
      &lt;td&gt;F&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Tidak mendukung TLS 1.2&lt;/td&gt;
      &lt;td&gt;C&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;TLS 1.0 atau TLS 1.1 aktif&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Tanpa forward secrecy (tanpa ECDHE/DHE)&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Tanpa cipher AEAD (GCM atau ChaCha20-Poly1305)&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;RC4 aktif&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Chain sertifikat tidak lengkap&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Key atau parameter DH di bawah 2048 bit&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Tidak mendukung TLS 1.3&lt;/td&gt;
      &lt;td&gt;A-&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;HSTS tidak ada atau tidak valid&lt;/td&gt;
      &lt;td&gt;A-&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Untuk A+, panduan itu mensyaratkan konfigurasi tanpa warning dan HSTS dengan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age&lt;/code&gt; minimal enam bulan (15768000 detik).&lt;/p&gt;

&lt;p&gt;Ada dua perubahan di 2025: sekadar dapat A sekarang butuh TLS 1.3 sekaligus header HSTS yang valid, dan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TLS_FALLBACK_SCSV&lt;/code&gt; tidak dihitung lagi. Kalau ada artikel lama yang menyuruh mengurus fallback SCSV, bagian itu bisa dilewati.&lt;/p&gt;

&lt;p&gt;Nilai 100 di semua kategori tidak diperlukan. Sertifikat ECDSA P-256 atau RSA 2048 dapat 90 di key exchange, dan selama AES-128 masih ditawarkan, kekuatan cipher juga 90. Keduanya tetap dapat A+. Pindah ke RSA 4096 cuma bikin handshake lebih lambat.&lt;/p&gt;

&lt;h2 id=&quot;cek-versi-nginx-dan-openssl-dulu&quot;&gt;Cek versi nginx dan OpenSSL dulu&lt;/h2&gt;

&lt;p&gt;Beberapa directive bergantung pada versi yang terpasang:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;nginx &lt;span class=&quot;nt&quot;&gt;-V&lt;/span&gt; 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-3&lt;/span&gt;
openssl version
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Fitur&lt;/th&gt;
      &lt;th&gt;Butuh&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;TLS 1.3 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TLSv1.3&lt;/code&gt; di &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_protocols&lt;/code&gt;)&lt;/td&gt;
      &lt;td&gt;OpenSSL 1.1.1+; jadi default sejak nginx 1.23.4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http2 on;&lt;/code&gt; sebagai directive terpisah&lt;/td&gt;
      &lt;td&gt;nginx 1.25.1+ (versi lama: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;listen 443 ssl http2;&lt;/code&gt;)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Rotasi otomatis key session ticket&lt;/td&gt;
      &lt;td&gt;nginx 1.23.2+ dengan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_session_cache&lt;/code&gt; shared&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grup hybrid post-quantum &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X25519MLKEM768&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;OpenSSL 3.5+&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_header_inherit merge;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;nginx 1.29.3+&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Yang penting di output &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx -V&lt;/code&gt; adalah baris &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;built with OpenSSL ...&lt;/code&gt;. Itu library yang benar-benar dipakai nginx, dan bisa berbeda dengan perintah &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl&lt;/code&gt; di server yang sama.&lt;/p&gt;

&lt;h2 id=&quot;langkah-1-sertifikat-dan-full-chain&quot;&gt;Langkah 1: Sertifikat dan full chain&lt;/h2&gt;

&lt;p&gt;Sertifikat apa pun yang dipercaya publik bisa dipakai. Dengan Let’s Encrypt dan Certbot, ambil sertifikatnya saja, lalu tulis konfigurasi TLS sendiri:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;certbot certonly &lt;span class=&quot;nt&quot;&gt;--nginx&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; example.com &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; www.example.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Certbot versi baru sudah memakai key ECDSA secara default, dan itu yang dibutuhkan. Arahkan nginx ke &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fullchain.pem&lt;/code&gt;, bukan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cert.pem&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;ssl_certificate&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com/fullchain.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_certificate_key&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com/privkey.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cert.pem&lt;/code&gt; hanya berisi sertifikat leaf. Browser sering melengkapi intermediate yang hilang sendiri, jadi situs terlihat normal, tapi SSL Labs akan menulis “Chain issues: Incomplete” dan membatasi grade di B. &lt;a href=&quot;https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate&quot;&gt;Dokumentasi nginx&lt;/a&gt; juga bilang begitu: sertifikat server ditaruh paling atas di file, diikuti sertifikat intermediate.&lt;/p&gt;

&lt;p&gt;Kalau memakai installer Certbot (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;certbot --nginx&lt;/code&gt; tanpa &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;certonly&lt;/code&gt;), ia menambahkan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;include /etc/letsencrypt/options-ssl-nginx.conf;&lt;/code&gt; ke server block. File itu juga mengatur protokol dan cipher. Hapus baris include tersebut supaya hanya pengaturan dari tulisan ini yang berlaku.&lt;/p&gt;

&lt;h2 id=&quot;langkah-2-taruh-pengaturan-tls-di-satu-file-bersama&quot;&gt;Langkah 2: Taruh pengaturan TLS di satu file bersama&lt;/h2&gt;

&lt;p&gt;Debian dan Ubuntu memuat semua file di &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nginx/conf.d/&lt;/code&gt; di dalam blok &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http&lt;/code&gt;, jadi satu file di sana berlaku untuk semua situs HTTPS.&lt;/p&gt;

&lt;p&gt;Pertama, bereskan dulu baris SSL yang sudah dipasang paket di &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nginx/nginx.conf&lt;/code&gt;. File bawaan Debian 13 punya blok ini di dalam &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http { }&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;##&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# SSL Settings&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;##&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;ssl_protocols&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;TLSv1.2&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;TLSv1.3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Dropping SSLv3 (POODLE), TLS 1.0, 1.1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_prefer_server_ciphers&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Don&apos;t force server cipher order.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;File di &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;conf.d/&lt;/code&gt; masuk ke blok &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http&lt;/code&gt; yang sama, jadi baris-baris ini akan bentrok. nginx menolak &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_prefer_server_ciphers&lt;/code&gt; kedua di level yang sama:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;nginx: [emerg] &quot;ssl_prefer_server_ciphers&quot; directive is duplicate in /etc/nginx/conf.d/tls.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_protocols&lt;/code&gt; kedua juga tidak menimpa yang pertama. nginx menggabungkan kedua daftar dan hanya memberi peringatan seperti &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[warn] duplicate value &quot;TLSv1.2&quot;&lt;/code&gt;, bukan error. Beri tanda &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#&lt;/code&gt; pada kedua baris itu (isinya bisa berbeda di rilis lain), lalu pastikan tidak ada file lain yang mengaturnya:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rn&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; ssl_protocols &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; ssl_prefer_server_ciphers &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; ssl_ciphers /etc/nginx/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sekarang buat &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nginx/conf.d/tls.conf&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Pengaturan TLS untuk semua server block (konteks http)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_protocols&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;TLSv1.2&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;TLSv1.3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# OpenSSL 3.5+: grup hybrid post-quantum di depan.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Di OpenSSL 3.0-3.4, hapus X25519MLKEM768 dari daftar ini.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_ecdh_curve&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;X25519MLKEM768:X25519:prime256v1:secp384r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Cipher TLS 1.2: hanya key exchange ECDHE + AEAD.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Suite TLS 1.3 diatur OpenSSL dan semuanya AEAD.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_ciphers&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_prefer_server_ciphers&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;ssl_session_timeout&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;1d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_session_cache&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;shared:TLS:10m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# sekitar 40000 sesi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Penjelasan per baris:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_protocols TLSv1.2 TLSv1.3&lt;/code&gt;&lt;/strong&gt; mematikan TLS 1.0 dan 1.1 (penyebab cap B) dan mengaktifkan TLS 1.3 (tanpanya grade mentok di A-). Ini sudah default sejak nginx 1.23.4, tapi ditulis eksplisit supaya jelas. Baris ini tidak menimpa &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_protocols&lt;/code&gt; lain di blok yang sama, karena itu baris lama tadi harus dimatikan.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_ecdh_curve&lt;/code&gt;&lt;/strong&gt; menentukan grup key exchange. Daftarnya diambil dari &lt;a href=&quot;https://data.tlsref.org/guidelines/6.0.json&quot;&gt;TLSRef guideline 6.0&lt;/a&gt;, penerus Server Side TLS guidelines dari Mozilla. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X25519MLKEM768&lt;/code&gt; menggabungkan X25519 klasik dengan algoritma post-quantum ML-KEM. Klien yang belum mendukungnya otomatis turun ke X25519.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_ciphers&lt;/code&gt;&lt;/strong&gt; hanya berisi suite ECDHE, yang memberi forward secrecy, dan hanya GCM atau ChaCha20-Poly1305, yang termasuk AEAD. Tidak ada CBC, tidak ada key exchange RSA, tidak ada 3DES. Menurut TLSRef, klien tertua yang masih bisa tersambung dengan profil ini adalah Firefox 31, Chrome 49, Safari 9, Android 4.4.2, IE 11 di Windows 10, dan Java 8u161. Daftar ini sekaligus menggantikan daftar cipher di tulisan saya tahun 2015, &lt;a href=&quot;/2015/04/12/ssl_cipher-di-nginx&quot;&gt;ssl_cipher di nginx&lt;/a&gt;, yang sudah usang.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_prefer_server_ciphers off&lt;/code&gt;&lt;/strong&gt; membiarkan klien yang memilih. Karena semua pilihan di daftar sudah kuat, klien paling tahu mana yang cocok: ponsel tanpa akselerasi AES di hardware akan memilih ChaCha20.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Tanpa &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_dhparam&lt;/code&gt;.&lt;/strong&gt; Daftar cipher tidak berisi suite DHE, jadi file parameter DH tidak diperlukan. Risiko lama “parameter DH di bawah 2048 bit” ikut hilang.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Session ticket&lt;/strong&gt; dibiarkan default (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;on&lt;/code&gt;). Sejak nginx 1.23.2, key ticket dirotasi otomatis selama &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_session_cache&lt;/code&gt; memakai shared memory, seperti di file di atas. Karena itu TLSRef hanya menambahkan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_session_tickets off;&lt;/code&gt; untuk versi yang lebih lama.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mozilla SSL Configuration Generator sekarang dialihkan ke &lt;a href=&quot;https://configurator.tlsref.org/&quot;&gt;TLSRef Configurator&lt;/a&gt;. File di atas sama dengan profil “Intermediate” di sana, pilihan yang tepat untuk website publik. Profil “Modern” (hanya TLS 1.3) juga dapat A+, tapi memutus klien lama seperti Android 4.4 dan IE 11.&lt;/p&gt;

&lt;h2 id=&quot;langkah-3-server-block-hsts-dan-redirect-http&quot;&gt;Langkah 3: Server block, HSTS, dan redirect HTTP&lt;/h2&gt;

&lt;p&gt;Sekarang konfigurasi situsnya, misalnya &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nginx/sites-available/example.com&lt;/code&gt; yang di-link ke &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sites-enabled/&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Port 80: semua dialihkan ke HTTPS&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;[::]:80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;server_name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;example.com&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;www.example.com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;308&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;https://&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$host$request_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;443&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ssl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;[::]:443&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ssl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;http2&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;                       &lt;span class=&quot;c1&quot;&gt;# nginx &amp;lt; 1.25.1: &quot;listen 443 ssl http2;&quot;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;server_name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;example.com&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;www.example.com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;ssl_certificate&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com/fullchain.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;ssl_certificate_key&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com/privkey.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# HSTS: 2 tahun. &quot;always&quot; juga mengirimnya di respons 3xx/4xx/5xx.&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Strict-Transport-Security&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;max-age=63072000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;includeSubDomains&quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/var/www/example.com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;index.html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Catatan soal baris HSTS:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age=63072000&lt;/code&gt;&lt;/strong&gt; sama dengan dua tahun, nilai dari TLSRef. SSL Labs butuh minimal 15768000 (enam bulan) untuk A+. Nilai yang lebih pendek atau salah ketik membuat grade turun ke A-.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;always&lt;/code&gt;&lt;/strong&gt; penting. Tanpa itu, nginx hanya menambahkan header di respons 200, 201, 204, 206, 301, 302, 303, 304, 307, dan 308. Dengan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;always&lt;/code&gt;, halaman error juga membawa header ini.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;includeSubDomains&lt;/code&gt;&lt;/strong&gt; memberi tahu browser bahwa semua subdomain juga wajib HTTPS. Jangan dipasang sebelum yakin itu benar. Kalau &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;intranet.example.com&lt;/code&gt; masih HTTP biasa, browser yang pernah menerima header ini akan menolak membukanya.&lt;/li&gt;
  &lt;li&gt;Header hanya dipasang di server HTTPS. Browser mengabaikan HSTS yang dikirim lewat HTTP biasa, dan spesifikasi HSTS (&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc6797#section-7.2&quot;&gt;RFC 6797 bagian 7.2&lt;/a&gt;) melarang server mengirimnya di sana.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dua baris &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;listen&lt;/code&gt; di tiap blok memang disengaja. Kalau domain punya record AAAA tapi nginx hanya listen di IPv4, SSL Labs akan menguji alamat IPv6 dan mendapat jawaban berbeda. Penjelasannya ada di tabel troubleshooting.&lt;/p&gt;

&lt;h2 id=&quot;langkah-4-ocsp-stapling-dan-lets-encrypt&quot;&gt;Langkah 4: OCSP stapling dan Let’s Encrypt&lt;/h2&gt;

&lt;p&gt;Banyak panduan A+ masih menyuruh menambahkan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_stapling on;&lt;/code&gt;, termasuk tulisan saya sendiri tahun 2015, &lt;a href=&quot;/2015/04/12/ocsp-stapling-di-nginx&quot;&gt;OCSP Stapling di nginx&lt;/a&gt;. Untuk sertifikat Let’s Encrypt, baris itu sebaiknya dibuang.&lt;/p&gt;

&lt;p&gt;Let’s Encrypt &lt;a href=&quot;https://letsencrypt.org/2024/12/05/ending-ocsp/&quot;&gt;menghentikan dukungan OCSP&lt;/a&gt;: sejak 7 Mei 2025 sertifikatnya tidak lagi memuat URL OCSP, dan responder OCSP dimatikan pada 6 Agustus 2025. Pengecekan revokasi sekarang lewat CRL. Dengan stapling aktif dan sertifikat Let’s Encrypt yang baru, nginx menulis peringatan seperti ini setiap kali reload:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[warn] &quot;ssl_stapling&quot; ignored, no OCSP responder URL in the certificate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Situs tetap jalan, tapi log jadi kotor. Hapus &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_stapling&lt;/code&gt; dan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_stapling_verify&lt;/code&gt;. OCSP stapling tidak memengaruhi grade SSL Labs.&lt;/p&gt;

&lt;p&gt;Kalau sertifikat berasal dari CA yang masih menjalankan OCSP, stapling tetap berguna. Yang dibutuhkan adalah resolver dan chain penerbit:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;ssl_stapling&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_stapling_verify&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_trusted_certificate&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/etc/ssl/certs/ca-chain.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# root + intermediate&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;resolver&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;127&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;.0.0.53&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;valid=300s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# contoh: systemd-resolved; ganti dengan resolver server Anda&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;langkah-5-hindari-jebakan-add_header&quot;&gt;Langkah 5: Hindari jebakan add_header&lt;/h2&gt;

&lt;p&gt;Di nginx, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_header&lt;/code&gt; hanya diwarisi dari blok luar kalau blok saat ini tidak punya &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_header&lt;/code&gt; sendiri. Begitu satu header ditambahkan di sebuah &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;location&lt;/code&gt;, semua header dari blok &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;server&lt;/code&gt; hilang di location itu, termasuk HSTS. Kalau location itu &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt;, grade turun ke A-. Kalau di path lain, laporan tetap A+ padahal sebagian situs jalan tanpa header itu.&lt;/p&gt;

&lt;p&gt;Ini hasil uji di server tes (port 8443) dengan konfigurasi di atas ditambah satu location:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/assets/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Cache-Control&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;public,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;max-age=3600&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ curl -sk -D- -o /dev/null https://127.0.0.1:8443/ | grep -i strict
strict-transport-security: max-age=63072000; includeSubDomains

$ curl -sk -D- -o /dev/null https://127.0.0.1:8443/assets/x | grep -i -e strict -e cache
cache-control: public, max-age=3600
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Respons kedua tidak punya HSTS.&lt;/p&gt;

&lt;p&gt;Ada tiga cara memperbaikinya, urut dari yang paling disarankan:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;nginx 1.29.3 ke atas:&lt;/strong&gt; pasang &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_header_inherit merge;&lt;/code&gt; di blok &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http&lt;/code&gt;. Header dari level luar akan ditambahkan ke header yang diset di blok dalam (&lt;a href=&quot;https://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header_inherit&quot;&gt;dokumentasi&lt;/a&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;nginx lama:&lt;/strong&gt; pindahkan header keamanan ke snippet, lalu include di setiap tempat yang memakai &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_header&lt;/code&gt; (contoh di bawah).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Kalau hanya untuk cache:&lt;/strong&gt; pakai &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;expires 1h;&lt;/code&gt;, bukan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_header Cache-Control&lt;/code&gt;. Directive ini mengirim &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cache-Control&lt;/code&gt; dan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expires&lt;/code&gt; sendiri, dan berbeda dengan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_header&lt;/code&gt;, tidak memutus header warisan dari blok &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;server&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cara snippet kira-kira seperti ini:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# /etc/nginx/snippets/security-headers.conf&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Strict-Transport-Security&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;max-age=63072000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;includeSubDomains&quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/assets/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;snippets/security-headers&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;.conf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Cache-Control&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;public,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;max-age=3600&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Dan hasil &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;location /assets/ { expires 1h; }&lt;/code&gt; di server tes yang sama:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ curl -sk -D- -o /dev/null https://127.0.0.1:8443/assets/x.css
HTTP/2 200
expires: Thu, 05 Nov 2026 01:41:51 GMT
cache-control: max-age=3600
strict-transport-security: max-age=63072000; includeSubDomains
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Aturan pewarisan yang sama berlaku untuk blok &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; dan location bertingkat.&lt;/p&gt;

&lt;h2 id=&quot;langkah-6-uji-di-lokal-lalu-jalankan-ssl-labs&quot;&gt;Langkah 6: Uji di lokal, lalu jalankan SSL Labs&lt;/h2&gt;

&lt;p&gt;Cek sintaks lalu reload:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;nginx &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sebelum ke SSL Labs, cek poin-poin penting dari terminal sendiri. Ganti &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;example.com&lt;/code&gt; dengan host Anda:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# TLS 1.1 harus ditolak. SECLEVEL=0 supaya klien modern mau mencobanya.&lt;/span&gt;
openssl s_client &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; example.com:443 &lt;span class=&quot;nt&quot;&gt;-servername&lt;/span&gt; example.com &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-tls1_1&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-cipher&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;DEFAULT@SECLEVEL=0&apos;&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;alert|Cipher is&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# TLS 1.3 harus jalan. Dengan OpenSSL 3.5+ di kedua sisi, grupnya X25519MLKEM768.&lt;/span&gt;
openssl s_client &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; example.com:443 &lt;span class=&quot;nt&quot;&gt;-servername&lt;/span&gt; example.com &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-tls1_3&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Negotiated TLS1.3 group|Cipher is&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Suite CBC harus ditolak (berlaku untuk sertifikat ECDSA maupun RSA).&lt;/span&gt;
openssl s_client &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; example.com:443 &lt;span class=&quot;nt&quot;&gt;-servername&lt;/span&gt; example.com &lt;span class=&quot;nt&quot;&gt;-tls1_2&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-cipher&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA&apos;&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;alert|Cipher is&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Full chain: harus ada baris &quot;depth=1&quot; (intermediate yang dikirim server).&lt;/span&gt;
openssl s_client &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; example.com:443 &lt;span class=&quot;nt&quot;&gt;-servername&lt;/span&gt; example.com &amp;lt;/dev/null 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;depth

&lt;span class=&quot;c&quot;&gt;# Header HSTS dan redirect.&lt;/span&gt;
curl &lt;span class=&quot;nt&quot;&gt;-sI&lt;/span&gt; https://example.com/ | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; strict-transport-security
curl &lt;span class=&quot;nt&quot;&gt;-sI&lt;/span&gt; http://example.com/  | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;^HTTP&apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;^location&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Di server tes, hasilnya seperti ini (diringkas):&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tls1_1 :  tlsv1 alert protocol version ... Cipher is (NONE)
tls1_3 :  Negotiated TLS1.3 group: X25519MLKEM768
          New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
CBC    :  ssl/tls alert handshake failure ... Cipher is (NONE)
HSTS   :  strict-transport-security: max-age=63072000; includeSubDomains
HTTP   :  HTTP/1.1 308 Permanent Redirect
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Kalau semuanya sudah sesuai, buka &lt;a href=&quot;https://www.ssllabs.com/ssltest/&quot;&gt;ssllabs.com/ssltest&lt;/a&gt;, masukkan hostname, dan centang “Do not show the results on the boards” kalau tidak ingin hasilnya tampil di daftar publik. SSL Labs menyimpan hasil scan untuk beberapa waktu. Setelah mengubah konfigurasi, klik tautan “Clear cache” di halaman hasil supaya scan diulang. Satu scan penuh butuh beberapa menit, lebih lama kalau hostname punya beberapa alamat IP.&lt;/p&gt;

&lt;h2 id=&quot;troubleshooting-arti-pesan-di-laporan-dan-cara-memperbaikinya&quot;&gt;Troubleshooting: arti pesan di laporan dan cara memperbaikinya&lt;/h2&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Yang muncul&lt;/th&gt;
      &lt;th&gt;Penyebab&lt;/th&gt;
      &lt;th&gt;Perbaikan&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade B, “This server supports TLS 1.0 and TLS 1.1”&lt;/td&gt;
      &lt;td&gt;Ada baris &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_protocols&lt;/code&gt; lama, sering di &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx.conf&lt;/code&gt; atau include dari Certbot&lt;/td&gt;
      &lt;td&gt;Jalankan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep&lt;/code&gt; dari Langkah 2 dan sisakan hanya &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx -t&lt;/code&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;ssl_prefer_server_ciphers&quot; directive is duplicate&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx.conf&lt;/code&gt; bawaan masih mengaturnya di blok &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http&lt;/code&gt; yang sama&lt;/td&gt;
      &lt;td&gt;Beri tanda &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#&lt;/code&gt; di &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx.conf&lt;/code&gt; (Langkah 2)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade B, “Chain issues: Incomplete”&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_certificate&lt;/code&gt; mengarah ke &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cert.pem&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Pakai &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fullchain.pem&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade B, warning cipher soal forward secrecy atau CBC&lt;/td&gt;
      &lt;td&gt;Daftar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_ciphers&lt;/code&gt; lama&lt;/td&gt;
      &lt;td&gt;Pakai daftar dari Langkah 2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade A-, “This server does not support TLS 1.3”&lt;/td&gt;
      &lt;td&gt;OpenSSL lebih lama dari 1.1.1, atau &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_protocols&lt;/code&gt; tanpa &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TLSv1.3&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Upgrade OS atau build nginx; cek &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx -V&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade A-, warning HSTS atau “HSTS not set”&lt;/td&gt;
      &lt;td&gt;Header tidak ada di halaman yang diuji, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age&lt;/code&gt; terlalu pendek, atau kena jebakan add_header&lt;/td&gt;
      &lt;td&gt;Cek dengan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl -sI&lt;/code&gt;; lihat Langkah 5&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;A+ di satu IP, A- di IP lain&lt;/td&gt;
      &lt;td&gt;IPv6 dilayani server block lain atau mesin lain&lt;/td&gt;
      &lt;td&gt;Tambahkan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;listen [::]:443 ssl;&lt;/code&gt; di semua blok, atau perbaiki record AAAA&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade tidak berubah walau nginx sudah diubah&lt;/td&gt;
      &lt;td&gt;Yang diuji CDN, bukan server Anda&lt;/td&gt;
      &lt;td&gt;Lihat di bawah&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx -t&lt;/code&gt; menulis &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSL_CTX_set1_curves_list(...) failed&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;OpenSSL di balik nginx tidak mengenal salah satu grup di &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_ecdh_curve&lt;/code&gt;, biasanya &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X25519MLKEM768&lt;/code&gt; di OpenSSL sebelum 3.5&lt;/td&gt;
      &lt;td&gt;Hapus grup itu dari daftar&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Pakai Cloudflare atau CDN lain?&lt;/strong&gt; Kalau proxy Cloudflare (awan oranye) aktif, SSL Labs menguji edge Cloudflare, bukan nginx Anda. Grade-nya bergantung pada pengaturan di Cloudflare: versi TLS minimum, TLS 1.3, dan HSTS di menu SSL/TLS &amp;gt; Edge Certificates. Konfigurasi nginx tetap penting untuk koneksi antara Cloudflare dan server origin, jadi pakai mode “Full (strict)” dan tetap pasang konfigurasi di atas di origin. (Blog ini juga ada di belakang Cloudflare; ceritanya ada di &lt;a href=&quot;/2014/11/10/migrasi-ke-cloudflare&quot;&gt;Migrasi ke Cloudflare&lt;/a&gt;.)&lt;/p&gt;

&lt;h2 id=&quot;opsional-hsts-preload&quot;&gt;Opsional: HSTS preload&lt;/h2&gt;

&lt;p&gt;Dengan HSTS preload, domain Anda masuk ke daftar HTTPS-only yang ditanam di dalam browser, jadi kunjungan pertama pun tidak pernah lewat HTTP. SSL Labs tidak mensyaratkannya untuk A+. Syarat di &lt;a href=&quot;https://hstspreload.org/&quot;&gt;hstspreload.org&lt;/a&gt; lebih ketat daripada syarat A+:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age&lt;/code&gt; minimal 31536000 (satu tahun), &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;includeSubDomains&lt;/code&gt;, dan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;preload&lt;/code&gt; di header&lt;/li&gt;
  &lt;li&gt;semua subdomain dilayani lewat HTTPS, termasuk subdomain internal&lt;/li&gt;
  &lt;li&gt;HTTP dialihkan ke HTTPS di host yang sama terlebih dulu&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Strict-Transport-Security&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;max-age=63072000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;includeSubDomains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;preload&quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Keluar dari daftar itu butuh waktu berbulan-bulan sampai ke pengguna lewat update browser, dan browser lain belum tentu ikut menghapus. Daftarkan hanya domain yang pasti tetap HTTPS-only di semua subdomain.&lt;/p&gt;

&lt;h2 id=&quot;konfigurasi-lengkap&quot;&gt;Konfigurasi lengkap&lt;/h2&gt;

&lt;p&gt;Sebagai rujukan, ini dua file yang dipakai saat pengujian di atas (sesuaikan path dan nama). Ditambah dua baris yang diberi &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#&lt;/code&gt; di &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx.conf&lt;/code&gt; pada Langkah 2, itulah seluruh perubahannya:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# /etc/nginx/conf.d/tls.conf&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_protocols&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;TLSv1.2&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;TLSv1.3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_ecdh_curve&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;X25519MLKEM768:X25519:prime256v1:secp384r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_ciphers&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_prefer_server_ciphers&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_session_timeout&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;1d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_session_cache&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;shared:TLS:10m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# add_header_inherit merge;   # nginx 1.29.3+&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# /etc/nginx/sites-available/example.com&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;[::]:80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;server_name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;example.com&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;www.example.com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;308&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;https://&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$host$request_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;443&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ssl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;[::]:443&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ssl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;http2&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;server_name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;example.com&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;www.example.com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;ssl_certificate&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com/fullchain.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;ssl_certificate_key&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com/privkey.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Strict-Transport-Security&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;max-age=63072000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;includeSubDomains&quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/var/www/example.com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;index.html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Kalau perlu melayani klien ECDSA dan RSA sekaligus, nginx bisa memuat dua sertifikat di server block yang sama dan memilih yang cocok untuk tiap klien:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;ssl_certificate&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com/fullchain.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;# ECDSA, dari Langkah 1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_certificate_key&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com/privkey.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_certificate&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com-rsa/fullchain.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_certificate_key&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com-rsa/privkey.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Di server tes, klien TLS 1.2 yang hanya menawarkan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ECDHE-RSA-AES128-GCM-SHA256&lt;/code&gt; menerima sertifikat RSA 2048 bit, sementara klien lain mendapat ECDSA. Dengan Certbot, jalankan sekali lagi dengan &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--key-type rsa --cert-name example.com-rsa&lt;/code&gt; untuk mendapat pasangan RSA.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Mahyuddin Susanto adalah sysadmin Linux dan jaringan yang mengelola server sendiri dan menulis soal nginx di blog ini sejak 2009, dimulai dari &lt;a href=&quot;/2009/05/09/nginx-dari-nol&quot;&gt;nginx, dari nol&lt;/a&gt;. &lt;a href=&quot;/about&quot;&gt;Tentang penulis&lt;/a&gt; · &lt;a href=&quot;/contact&quot;&gt;Kontak&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;sumber&quot;&gt;Sumber&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Qualys SSL Labs, &lt;a href=&quot;https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide&quot;&gt;SSL Server Rating Guide&lt;/a&gt;, versi 2009r, 16 Mei 2025&lt;/li&gt;
  &lt;li&gt;TLSRef, &lt;a href=&quot;https://data.tlsref.org/guidelines/6.0.json&quot;&gt;Server Side TLS guideline 6.0&lt;/a&gt; dan &lt;a href=&quot;https://configurator.tlsref.org/&quot;&gt;TLS Configurator&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;nginx, &lt;a href=&quot;https://nginx.org/en/docs/http/ngx_http_ssl_module.html&quot;&gt;ngx_http_ssl_module&lt;/a&gt;, &lt;a href=&quot;https://nginx.org/en/docs/http/ngx_http_headers_module.html&quot;&gt;ngx_http_headers_module&lt;/a&gt;, dan &lt;a href=&quot;https://nginx.org/en/CHANGES&quot;&gt;CHANGES&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Let’s Encrypt, &lt;a href=&quot;https://letsencrypt.org/2024/12/05/ending-ocsp/&quot;&gt;Ending OCSP Support in 2025&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hstspreload.org/&quot;&gt;HSTS Preload List Submission&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;IETF, &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc6797&quot;&gt;RFC 6797: HTTP Strict Transport Security&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>Mahyuddin Susanto</name></author><category term="Linux" /><category term="nginx" /><category term="tls" /><category term="ssl" /><category term="security" /><category term="hsts" /><summary type="html">Untuk dapat A+ di SSL Labs Server Test dari Qualys dengan nginx, ada lima syarat: hanya TLS 1.2 dan TLS 1.3, cipher ECDHE dengan AEAD (GCM atau ChaCha20-Poly1305), sertifikat dikirim bersama chain lengkapnya, header HSTS dengan max-age minimal enam bulan, dan konfigurasi yang sama di semua alamat IP hostname tersebut. Tanpa TLS 1.3 atau tanpa HSTS, nilainya mentok di A-. Kalau TLS 1.0 atau 1.1 masih aktif, nilainya mentok di B.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.udienz.web.id/img/ssl-labs-a-plus-nginx-id.png" /><media:content medium="image" url="https://www.udienz.web.id/img/ssl-labs-a-plus-nginx-id.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">How to Get an A+ on SSL Labs with nginx (2026 Guide)</title><link href="https://www.udienz.web.id/2026/11/05/ssl-labs-a-plus-nginx" rel="alternate" type="text/html" title="How to Get an A+ on SSL Labs with nginx (2026 Guide)" /><published>2026-11-05T00:00:00+00:00</published><updated>2026-11-05T00:00:00+00:00</updated><id>https://www.udienz.web.id/2026/11/05/ssl-labs-a-plus-nginx</id><content type="html" xml:base="https://www.udienz.web.id/2026/11/05/ssl-labs-a-plus-nginx">&lt;p&gt;To get an A+ on the &lt;a href=&quot;https://www.ssllabs.com/ssltest/&quot;&gt;Qualys SSL Labs server test&lt;/a&gt; with nginx, you need five things: TLS 1.2 and TLS 1.3 only, ECDHE key exchange with AEAD ciphers (GCM or ChaCha20-Poly1305), a certificate served with its full chain, an HSTS header with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age&lt;/code&gt; of at least six months, and the same setup on every IP address your hostname resolves to. Miss TLS 1.3 or HSTS and you land on A-. Leave TLS 1.0 or 1.1 on and you are stuck at B.&lt;/p&gt;

&lt;p&gt;This guide walks through each piece, gives you a config you can paste, and covers the two changes that break older tutorials: Let’s Encrypt shutting down OCSP in 2025, and the grading update SSL Labs shipped in May 2025.&lt;/p&gt;

&lt;p&gt;The configuration below was tested on nginx 1.26.3 with OpenSSL 3.5.7, using the stock Debian 13 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx.conf&lt;/code&gt; with its two SSL lines commented out and the files from this guide added, and checked with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl s_client&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Baca dalam Bahasa Indonesia:&lt;/strong&gt; &lt;a href=&quot;/2026/11/05/ssl-labs-a-plus-nginx-id&quot;&gt;Cara Mendapat A+ di SSL Labs dengan nginx&lt;/a&gt;. Running Apache? See &lt;a href=&quot;/2026/11/05/ssl-labs-a-plus-apache&quot;&gt;How to Get an A+ on SSL Labs with Apache httpd&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/ssl-labs-a-plus-nginx.png&quot; alt=&quot;SSL Labs grade ladder for nginx: what caps a server at B or A-, and what an A+ needs&quot; /&gt;&lt;/p&gt;

&lt;details class=&quot;toc&quot;&gt;
  &lt;summary&gt;Contents&lt;/summary&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#how-ssl-labs-grades-your-server&quot; id=&quot;markdown-toc-how-ssl-labs-grades-your-server&quot;&gt;How SSL Labs grades your server&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#check-your-nginx-and-openssl-versions-first&quot; id=&quot;markdown-toc-check-your-nginx-and-openssl-versions-first&quot;&gt;Check your nginx and OpenSSL versions first&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#step-1-get-a-certificate-and-serve-the-full-chain&quot; id=&quot;markdown-toc-step-1-get-a-certificate-and-serve-the-full-chain&quot;&gt;Step 1: Get a certificate and serve the full chain&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#step-2-put-the-tls-settings-in-one-shared-file&quot; id=&quot;markdown-toc-step-2-put-the-tls-settings-in-one-shared-file&quot;&gt;Step 2: Put the TLS settings in one shared file&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#step-3-the-server-blocks-hsts-and-the-http-redirect&quot; id=&quot;markdown-toc-step-3-the-server-blocks-hsts-and-the-http-redirect&quot;&gt;Step 3: The server blocks, HSTS and the HTTP redirect&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#step-4-ocsp-stapling-and-lets-encrypt&quot; id=&quot;markdown-toc-step-4-ocsp-stapling-and-lets-encrypt&quot;&gt;Step 4: OCSP stapling and Let’s Encrypt&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#step-5-avoid-the-add_header-trap&quot; id=&quot;markdown-toc-step-5-avoid-the-add_header-trap&quot;&gt;Step 5: Avoid the add_header trap&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#step-6-test-locally-then-run-ssl-labs&quot; id=&quot;markdown-toc-step-6-test-locally-then-run-ssl-labs&quot;&gt;Step 6: Test locally, then run SSL Labs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#troubleshooting-what-the-report-says-and-how-to-fix-it&quot; id=&quot;markdown-toc-troubleshooting-what-the-report-says-and-how-to-fix-it&quot;&gt;Troubleshooting: what the report says and how to fix it&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#optional-hsts-preload&quot; id=&quot;markdown-toc-optional-hsts-preload&quot;&gt;Optional: HSTS preload&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#the-complete-config&quot; id=&quot;markdown-toc-the-complete-config&quot;&gt;The complete config&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#sources&quot; id=&quot;markdown-toc-sources&quot;&gt;Sources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;/details&gt;

&lt;h2 id=&quot;how-ssl-labs-grades-your-server&quot;&gt;How SSL Labs grades your server&lt;/h2&gt;

&lt;p&gt;SSL Labs scores three categories: protocol support (30%), key exchange (30%) and cipher strength (40%). A score of 80 or more is an A. Then it applies caps: specific problems limit the grade no matter how high the score is. The A+ is a bonus on top of an A with no warnings.&lt;/p&gt;

&lt;p&gt;The current rules are version 2009r of the &lt;a href=&quot;https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide&quot;&gt;SSL Server Rating Guide&lt;/a&gt;, dated 16 May 2025. These are the caps that matter for a typical nginx server:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Problem&lt;/th&gt;
      &lt;th&gt;Grade limit&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;SSLv2, SSLv3 as the best protocol, export ciphers, Heartbleed-class bugs&lt;/td&gt;
      &lt;td&gt;F&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;TLS 1.2 not supported&lt;/td&gt;
      &lt;td&gt;C&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;TLS 1.0 or TLS 1.1 enabled&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;No forward secrecy (no ECDHE/DHE)&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;No AEAD cipher (GCM or ChaCha20-Poly1305)&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;RC4 enabled&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Incomplete certificate chain&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Key or DH parameters under 2048 bits&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;TLS 1.3 not supported&lt;/td&gt;
      &lt;td&gt;A-&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;HSTS missing or invalid&lt;/td&gt;
      &lt;td&gt;A-&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;For the A+, the guide asks for a configuration with no warnings and HSTS with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age&lt;/code&gt; of at least six months (15768000 seconds).&lt;/p&gt;

&lt;p&gt;Two things changed in 2025: a plain A now needs both TLS 1.3 and a valid HSTS header, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TLS_FALLBACK_SCSV&lt;/code&gt; no longer counts. If an older article tells you to chase fallback SCSV, skip that part.&lt;/p&gt;

&lt;p&gt;You do not need 100 in every category. An ECDSA P-256 or RSA 2048 certificate scores 90 on key exchange, and offering AES-128 keeps cipher strength at 90. Both still get an A+. Switching to RSA 4096 only makes handshakes slower.&lt;/p&gt;

&lt;h2 id=&quot;check-your-nginx-and-openssl-versions-first&quot;&gt;Check your nginx and OpenSSL versions first&lt;/h2&gt;

&lt;p&gt;A few directives depend on the version you run:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;nginx &lt;span class=&quot;nt&quot;&gt;-V&lt;/span&gt; 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-3&lt;/span&gt;
openssl version
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Feature&lt;/th&gt;
      &lt;th&gt;Needs&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;TLS 1.3 (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TLSv1.3&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_protocols&lt;/code&gt;)&lt;/td&gt;
      &lt;td&gt;OpenSSL 1.1.1+; default since nginx 1.23.4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http2 on;&lt;/code&gt; as a separate directive&lt;/td&gt;
      &lt;td&gt;nginx 1.25.1+ (older: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;listen 443 ssl http2;&lt;/code&gt;)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Automatic session ticket key rotation&lt;/td&gt;
      &lt;td&gt;nginx 1.23.2+ with a shared &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_session_cache&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Hybrid post-quantum group &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X25519MLKEM768&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;OpenSSL 3.5+&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_header_inherit merge;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;nginx 1.29.3+&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx -V&lt;/code&gt; line that matters is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;built with OpenSSL ...&lt;/code&gt;. That is the library nginx actually uses, and it can differ from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl&lt;/code&gt; command on the same box.&lt;/p&gt;

&lt;h2 id=&quot;step-1-get-a-certificate-and-serve-the-full-chain&quot;&gt;Step 1: Get a certificate and serve the full chain&lt;/h2&gt;

&lt;p&gt;Any publicly trusted certificate works. With Let’s Encrypt and Certbot, get the certificate only and write the TLS config yourself:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;certbot certonly &lt;span class=&quot;nt&quot;&gt;--nginx&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; example.com &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; www.example.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Recent Certbot releases issue ECDSA keys by default, which is what you want. Point nginx at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fullchain.pem&lt;/code&gt;, not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cert.pem&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;ssl_certificate&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com/fullchain.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_certificate_key&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com/privkey.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cert.pem&lt;/code&gt; holds only your leaf certificate. Browsers often fill in the missing intermediate on their own, so the site looks fine, but SSL Labs reports “Chain issues: Incomplete” and caps the grade at B. The &lt;a href=&quot;https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate&quot;&gt;nginx docs&lt;/a&gt; say the same: the server certificate comes first in the file, followed by the intermediates.&lt;/p&gt;

&lt;p&gt;If you use Certbot’s own installer (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;certbot --nginx&lt;/code&gt; without &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;certonly&lt;/code&gt;), it adds &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;include /etc/letsencrypt/options-ssl-nginx.conf;&lt;/code&gt; to your server block. That file sets protocols and ciphers too. Remove the include so your own settings are the only ones in play.&lt;/p&gt;

&lt;h2 id=&quot;step-2-put-the-tls-settings-in-one-shared-file&quot;&gt;Step 2: Put the TLS settings in one shared file&lt;/h2&gt;

&lt;p&gt;Debian and Ubuntu load every file in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nginx/conf.d/&lt;/code&gt; inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http&lt;/code&gt; block, so a single file there applies to all your HTTPS sites.&lt;/p&gt;

&lt;p&gt;First, clear the SSL lines that the package already put in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nginx/nginx.conf&lt;/code&gt;. The stock Debian 13 file has this block inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http { }&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;##&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# SSL Settings&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;##&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;ssl_protocols&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;TLSv1.2&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;TLSv1.3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Dropping SSLv3 (POODLE), TLS 1.0, 1.1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_prefer_server_ciphers&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Don&apos;t force server cipher order.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;conf.d/&lt;/code&gt; file lands in the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http&lt;/code&gt; block, so these lines would collide with it. nginx refuses a second &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_prefer_server_ciphers&lt;/code&gt; at the same level:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;nginx: [emerg] &quot;ssl_prefer_server_ciphers&quot; directive is duplicate in /etc/nginx/conf.d/tls.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A second &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_protocols&lt;/code&gt; does not replace the first one either. nginx merges the two lists and only prints warnings such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[warn] duplicate value &quot;TLSv1.2&quot;&lt;/code&gt;, not an error. Comment out both lines with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#&lt;/code&gt; (your release may have different values there), then check that nothing else sets them:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rn&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; ssl_protocols &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; ssl_prefer_server_ciphers &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; ssl_ciphers /etc/nginx/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nginx/conf.d/tls.conf&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# TLS settings for every server block (http context)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_protocols&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;TLSv1.2&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;TLSv1.3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# OpenSSL 3.5+: hybrid post-quantum group first.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# On OpenSSL 3.0-3.4, remove X25519MLKEM768 from this list.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_ecdh_curve&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;X25519MLKEM768:X25519:prime256v1:secp384r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# TLS 1.2 ciphers: ECDHE key exchange + AEAD only.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# TLS 1.3 suites are managed by OpenSSL and are all AEAD.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_ciphers&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_prefer_server_ciphers&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;ssl_session_timeout&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;1d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_session_cache&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;shared:TLS:10m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# about 40000 sessions&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Line by line:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_protocols TLSv1.2 TLSv1.3&lt;/code&gt;&lt;/strong&gt; turns off TLS 1.0 and 1.1 (the B cap) and turns on TLS 1.3 (without it you stop at A-). It is the default since nginx 1.23.4, but writing it here makes the intent clear. It does not override other &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_protocols&lt;/code&gt; lines in the same block, which is why you removed them above.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_ecdh_curve&lt;/code&gt;&lt;/strong&gt; sets the key exchange groups. The list comes from the &lt;a href=&quot;https://data.tlsref.org/guidelines/6.0.json&quot;&gt;TLSRef guideline 6.0&lt;/a&gt;, the successor of Mozilla’s Server Side TLS guidelines. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X25519MLKEM768&lt;/code&gt; combines classic X25519 with the ML-KEM post-quantum algorithm. Clients that do not support it fall back to X25519.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_ciphers&lt;/code&gt;&lt;/strong&gt; lists only ECDHE suites, which gives forward secrecy, and only GCM or ChaCha20-Poly1305, which are AEAD. No CBC, no RSA key exchange, no 3DES. TLSRef lists the oldest clients this profile still serves as Firefox 31, Chrome 49, Safari 9, Android 4.4.2, IE 11 on Windows 10 and Java 8u161. It also replaces the cipher list from my &lt;a href=&quot;/2015/04/12/ssl_cipher-di-nginx&quot;&gt;2015 post on ssl_cipher in nginx&lt;/a&gt; (in Indonesian), which is out of date now.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_prefer_server_ciphers off&lt;/code&gt;&lt;/strong&gt; lets the client pick. With an all-strong list, the client knows best: phones without AES hardware choose ChaCha20.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;No &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_dhparam&lt;/code&gt;.&lt;/strong&gt; The list has no DHE suites, so you do not need a DH parameters file. That also removes the old “DH parameters under 2048 bits” risk.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Session tickets&lt;/strong&gt; stay at the default (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;on&lt;/code&gt;). Since nginx 1.23.2 the ticket keys rotate automatically when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_session_cache&lt;/code&gt; uses shared memory, as it does here. That is why TLSRef only adds &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_session_tickets off;&lt;/code&gt; for older versions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Mozilla SSL Configuration Generator now redirects to the &lt;a href=&quot;https://configurator.tlsref.org/&quot;&gt;TLSRef Configurator&lt;/a&gt;. This file matches its “Intermediate” profile, which is the right choice for public websites. The “Modern” profile (TLS 1.3 only) also gets an A+, but cuts off older clients such as Android 4.4 and IE 11.&lt;/p&gt;

&lt;h2 id=&quot;step-3-the-server-blocks-hsts-and-the-http-redirect&quot;&gt;Step 3: The server blocks, HSTS and the HTTP redirect&lt;/h2&gt;

&lt;p&gt;Now the site itself, for example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nginx/sites-available/example.com&lt;/code&gt;, linked into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sites-enabled/&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Port 80: redirect everything to HTTPS&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;[::]:80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;server_name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;example.com&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;www.example.com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;308&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;https://&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$host$request_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;443&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ssl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;[::]:443&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ssl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;http2&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;                       &lt;span class=&quot;c1&quot;&gt;# nginx &amp;lt; 1.25.1: &quot;listen 443 ssl http2;&quot;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;server_name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;example.com&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;www.example.com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;ssl_certificate&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com/fullchain.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;ssl_certificate_key&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com/privkey.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# HSTS: 2 years. &quot;always&quot; also sends it on 3xx/4xx/5xx responses.&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Strict-Transport-Security&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;max-age=63072000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;includeSubDomains&quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/var/www/example.com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;index.html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Notes on the HSTS line:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age=63072000&lt;/code&gt;&lt;/strong&gt; is two years, the TLSRef value. SSL Labs needs at least 15768000 (six months) for the A+. A shorter value or a typo drops you to A-.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;always&lt;/code&gt;&lt;/strong&gt; matters. Without it, nginx adds the header only to 200, 201, 204, 206, 301, 302, 303, 304, 307 and 308 responses. With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;always&lt;/code&gt;, error pages carry it too.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;includeSubDomains&lt;/code&gt;&lt;/strong&gt; tells browsers that every subdomain is HTTPS-only as well. Leave it out until you are sure that is true. If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;intranet.example.com&lt;/code&gt; still serves plain HTTP, browsers that have seen the header will refuse to load it.&lt;/li&gt;
  &lt;li&gt;The header goes only on the HTTPS server. Browsers ignore HSTS on plain HTTP, and the HSTS spec (&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc6797#section-7.2&quot;&gt;RFC 6797, section 7.2&lt;/a&gt;) says servers must not send it there.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;listen&lt;/code&gt; lines in each block are deliberate. If your domain has an AAAA record and nginx listens only on IPv4, SSL Labs tests the IPv6 address and gets a different answer. More on that in the troubleshooting table.&lt;/p&gt;

&lt;h2 id=&quot;step-4-ocsp-stapling-and-lets-encrypt&quot;&gt;Step 4: OCSP stapling and Let’s Encrypt&lt;/h2&gt;

&lt;p&gt;Many A+ guides still tell you to add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_stapling on;&lt;/code&gt;, including my own &lt;a href=&quot;/2015/04/12/ocsp-stapling-di-nginx&quot;&gt;OCSP stapling post from 2015&lt;/a&gt;. For Let’s Encrypt certificates, drop it.&lt;/p&gt;

&lt;p&gt;Let’s Encrypt &lt;a href=&quot;https://letsencrypt.org/2024/12/05/ending-ocsp/&quot;&gt;ended OCSP support&lt;/a&gt;: from 7 May 2025 its certificates no longer contain an OCSP URL, and the OCSP responders were switched off on 6 August 2025. Revocation now goes through CRLs. With stapling on and a current Let’s Encrypt certificate, nginx logs a warning like this on every reload:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[warn] &quot;ssl_stapling&quot; ignored, no OCSP responder URL in the certificate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The site keeps working, but the line is noise. Remove &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_stapling&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_stapling_verify&lt;/code&gt;. OCSP stapling has no effect on the SSL Labs grade.&lt;/p&gt;

&lt;p&gt;If your certificate comes from a CA that still runs OCSP, stapling is still useful. You need a resolver and the issuer chain:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;ssl_stapling&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_stapling_verify&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_trusted_certificate&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/etc/ssl/certs/ca-chain.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# root + intermediates&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;resolver&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;127&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;.0.0.53&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;valid=300s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# e.g. systemd-resolved; use your server&apos;s resolver&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;step-5-avoid-the-add_header-trap&quot;&gt;Step 5: Avoid the add_header trap&lt;/h2&gt;

&lt;p&gt;In nginx, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_header&lt;/code&gt; is inherited from the outer block only if the current block has no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_header&lt;/code&gt; of its own. Add one header in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;location&lt;/code&gt; and every header from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;server&lt;/code&gt; block disappears in that location, HSTS included. If that location is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt;, the grade drops to A-. If it is another path, the report stays A+ while part of the site runs without the header.&lt;/p&gt;

&lt;p&gt;Here is the result on the test server (port 8443) with the config above plus one extra location:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/assets/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Cache-Control&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;public,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;max-age=3600&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ curl -sk -D- -o /dev/null https://127.0.0.1:8443/ | grep -i strict
strict-transport-security: max-age=63072000; includeSubDomains

$ curl -sk -D- -o /dev/null https://127.0.0.1:8443/assets/x | grep -i -e strict -e cache
cache-control: public, max-age=3600
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The second response has no HSTS.&lt;/p&gt;

&lt;p&gt;Three fixes, in order of preference:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;nginx 1.29.3 or newer:&lt;/strong&gt; put &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_header_inherit merge;&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http&lt;/code&gt; block. Headers from outer levels are then added to the ones you set in the inner block (&lt;a href=&quot;https://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header_inherit&quot;&gt;docs&lt;/a&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Older nginx:&lt;/strong&gt; move the security headers into a snippet and include it wherever you use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_header&lt;/code&gt; (example below).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;For caching only:&lt;/strong&gt; use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;expires 1h;&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_header Cache-Control&lt;/code&gt;. It sets &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cache-Control&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expires&lt;/code&gt; itself and, unlike &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_header&lt;/code&gt;, does not cancel the headers inherited from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;server&lt;/code&gt; block.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The snippet approach looks like this:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# /etc/nginx/snippets/security-headers.conf&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Strict-Transport-Security&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;max-age=63072000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;includeSubDomains&quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/assets/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;snippets/security-headers&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;.conf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Cache-Control&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;public,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;max-age=3600&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;location /assets/ { expires 1h; }&lt;/code&gt; on the same test server:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ curl -sk -D- -o /dev/null https://127.0.0.1:8443/assets/x.css
HTTP/2 200
expires: Thu, 05 Nov 2026 01:41:51 GMT
cache-control: max-age=3600
strict-transport-security: max-age=63072000; includeSubDomains
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The same inheritance rule applies to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; blocks and nested locations.&lt;/p&gt;

&lt;h2 id=&quot;step-6-test-locally-then-run-ssl-labs&quot;&gt;Step 6: Test locally, then run SSL Labs&lt;/h2&gt;

&lt;p&gt;Check the syntax and reload:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;nginx &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Before you go to SSL Labs, check the important points from your own terminal. Replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;example.com&lt;/code&gt; with your host:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# TLS 1.1 must be refused. SECLEVEL=0 lets a modern client even try it.&lt;/span&gt;
openssl s_client &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; example.com:443 &lt;span class=&quot;nt&quot;&gt;-servername&lt;/span&gt; example.com &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-tls1_1&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-cipher&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;DEFAULT@SECLEVEL=0&apos;&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;alert|Cipher is&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# TLS 1.3 must work. With OpenSSL 3.5+ on both sides the group is X25519MLKEM768.&lt;/span&gt;
openssl s_client &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; example.com:443 &lt;span class=&quot;nt&quot;&gt;-servername&lt;/span&gt; example.com &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-tls1_3&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Negotiated TLS1.3 group|Cipher is&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# CBC suites must be refused (covers both ECDSA and RSA certificates).&lt;/span&gt;
openssl s_client &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; example.com:443 &lt;span class=&quot;nt&quot;&gt;-servername&lt;/span&gt; example.com &lt;span class=&quot;nt&quot;&gt;-tls1_2&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-cipher&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA&apos;&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;alert|Cipher is&apos;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Full chain: there must be a &quot;depth=1&quot; line (the intermediate sent by the server).&lt;/span&gt;
openssl s_client &lt;span class=&quot;nt&quot;&gt;-connect&lt;/span&gt; example.com:443 &lt;span class=&quot;nt&quot;&gt;-servername&lt;/span&gt; example.com &amp;lt;/dev/null 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;depth

&lt;span class=&quot;c&quot;&gt;# HSTS header and redirect.&lt;/span&gt;
curl &lt;span class=&quot;nt&quot;&gt;-sI&lt;/span&gt; https://example.com/ | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; strict-transport-security
curl &lt;span class=&quot;nt&quot;&gt;-sI&lt;/span&gt; http://example.com/  | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;^HTTP&apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;^location&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On the test setup, the output looked like this (condensed):&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tls1_1 :  tlsv1 alert protocol version ... Cipher is (NONE)
tls1_3 :  Negotiated TLS1.3 group: X25519MLKEM768
          New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
CBC    :  ssl/tls alert handshake failure ... Cipher is (NONE)
HSTS   :  strict-transport-security: max-age=63072000; includeSubDomains
HTTP   :  HTTP/1.1 308 Permanent Redirect
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When all of that looks right, open &lt;a href=&quot;https://www.ssllabs.com/ssltest/&quot;&gt;ssllabs.com/ssltest&lt;/a&gt;, enter your hostname, and tick “Do not show the results on the boards” if you do not want the result listed publicly. SSL Labs caches results for a while. After a config change, use the “Clear cache” link on the results page to force a new scan. A full scan takes a few minutes, longer when the hostname has several IP addresses.&lt;/p&gt;

&lt;h2 id=&quot;troubleshooting-what-the-report-says-and-how-to-fix-it&quot;&gt;Troubleshooting: what the report says and how to fix it&lt;/h2&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;What you see&lt;/th&gt;
      &lt;th&gt;Cause&lt;/th&gt;
      &lt;th&gt;Fix&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade B, “This server supports TLS 1.0 and TLS 1.1”&lt;/td&gt;
      &lt;td&gt;Old &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_protocols&lt;/code&gt; line somewhere, often in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx.conf&lt;/code&gt; or a Certbot include&lt;/td&gt;
      &lt;td&gt;Run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep&lt;/code&gt; from Step 2 and keep only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tls.conf&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx -t&lt;/code&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;ssl_prefer_server_ciphers&quot; directive is duplicate&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;The stock &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx.conf&lt;/code&gt; still sets it in the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http&lt;/code&gt; block&lt;/td&gt;
      &lt;td&gt;Comment it out in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx.conf&lt;/code&gt; (Step 2)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade B, “Chain issues: Incomplete”&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_certificate&lt;/code&gt; points to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cert.pem&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fullchain.pem&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade B, cipher warnings about forward secrecy or CBC&lt;/td&gt;
      &lt;td&gt;Old &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_ciphers&lt;/code&gt; list&lt;/td&gt;
      &lt;td&gt;Use the list from Step 2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade A-, “This server does not support TLS 1.3”&lt;/td&gt;
      &lt;td&gt;OpenSSL older than 1.1.1, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_protocols&lt;/code&gt; without &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TLSv1.3&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Upgrade the OS or nginx build; check &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx -V&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade A-, HSTS warning or “HSTS not set”&lt;/td&gt;
      &lt;td&gt;Header missing on the tested page, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age&lt;/code&gt; too short, or the add_header trap&lt;/td&gt;
      &lt;td&gt;Check with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl -sI&lt;/code&gt;; see Step 5&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;A+ on one IP, A- on another&lt;/td&gt;
      &lt;td&gt;IPv6 handled by a different server block or a different machine&lt;/td&gt;
      &lt;td&gt;Add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;listen [::]:443 ssl;&lt;/code&gt; everywhere, or fix the AAAA record&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Grade does not change after you edit nginx&lt;/td&gt;
      &lt;td&gt;You are testing a CDN, not your server&lt;/td&gt;
      &lt;td&gt;See below&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx -t&lt;/code&gt; says &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSL_CTX_set1_curves_list(...) failed&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;The OpenSSL behind nginx does not know a group in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl_ecdh_curve&lt;/code&gt;, usually &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X25519MLKEM768&lt;/code&gt; on OpenSSL older than 3.5&lt;/td&gt;
      &lt;td&gt;Remove that group from the list&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Behind Cloudflare or another CDN?&lt;/strong&gt; If the orange cloud is on, SSL Labs tests Cloudflare’s edge, not your nginx. The grade then depends on your Cloudflare settings: minimum TLS version, TLS 1.3, and HSTS under SSL/TLS &amp;gt; Edge Certificates. Your nginx config still matters for the connection between Cloudflare and your origin, so use “Full (strict)” mode and keep the setup above on the origin. (This blog sits behind Cloudflare too; the move is described in &lt;a href=&quot;/2014/11/10/migrasi-ke-cloudflare&quot;&gt;Migrasi ke Cloudflare&lt;/a&gt;, in Indonesian.)&lt;/p&gt;

&lt;h2 id=&quot;optional-hsts-preload&quot;&gt;Optional: HSTS preload&lt;/h2&gt;

&lt;p&gt;With HSTS preload, browsers ship with your domain on a built-in HTTPS-only list, so even the very first visit never uses HTTP. SSL Labs does not need it for an A+. The requirements on &lt;a href=&quot;https://hstspreload.org/&quot;&gt;hstspreload.org&lt;/a&gt; are stricter than the A+ ones:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max-age&lt;/code&gt; of at least 31536000 (one year), &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;includeSubDomains&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;preload&lt;/code&gt; in the header&lt;/li&gt;
  &lt;li&gt;every subdomain served over HTTPS, including internal ones&lt;/li&gt;
  &lt;li&gt;HTTP redirected to HTTPS on the same host first&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Strict-Transport-Security&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;max-age=63072000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;includeSubDomains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;preload&quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Getting off the list takes months to reach users through browser updates, and other browsers are not guaranteed to follow. Only submit a domain you know will stay HTTPS-only on every subdomain.&lt;/p&gt;

&lt;h2 id=&quot;the-complete-config&quot;&gt;The complete config&lt;/h2&gt;

&lt;p&gt;For reference, here are the two files used in the test above (adjust paths and names). Together with the two commented lines in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx.conf&lt;/code&gt; from Step 2, that is the whole change:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# /etc/nginx/conf.d/tls.conf&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_protocols&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;TLSv1.2&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;TLSv1.3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_ecdh_curve&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;X25519MLKEM768:X25519:prime256v1:secp384r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_ciphers&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_prefer_server_ciphers&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_session_timeout&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;1d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_session_cache&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;shared:TLS:10m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# add_header_inherit merge;   # nginx 1.29.3+&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# /etc/nginx/sites-available/example.com&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;[::]:80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;server_name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;example.com&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;www.example.com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;308&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;https://&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$host$request_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;443&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ssl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;[::]:443&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ssl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;http2&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;server_name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;example.com&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;www.example.com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;ssl_certificate&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com/fullchain.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;ssl_certificate_key&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com/privkey.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;add_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Strict-Transport-Security&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;max-age=63072000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;includeSubDomains&quot;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/var/www/example.com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;index.html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you need to support both ECDSA and RSA clients, nginx can load two certificates in the same server block, and it picks the right one per client:&lt;/p&gt;

&lt;div class=&quot;language-nginx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;ssl_certificate&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com/fullchain.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;# ECDSA, from Step 1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_certificate_key&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com/privkey.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_certificate&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com-rsa/fullchain.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ssl_certificate_key&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/example.com-rsa/privkey.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On the test server, a TLS 1.2 client that only offered &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ECDHE-RSA-AES128-GCM-SHA256&lt;/code&gt; received the 2048-bit RSA certificate, and everyone else got ECDSA. With Certbot, run it a second time with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--key-type rsa --cert-name example.com-rsa&lt;/code&gt; to get the RSA pair.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Mahyuddin Susanto is a Linux and networking sysadmin who runs his own servers and has written about nginx on this blog since 2009, starting with &lt;a href=&quot;/2009/05/09/nginx-dari-nol&quot;&gt;nginx, dari nol&lt;/a&gt;. &lt;a href=&quot;/about&quot;&gt;About&lt;/a&gt; · &lt;a href=&quot;/contact&quot;&gt;Contact&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;sources&quot;&gt;Sources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Qualys SSL Labs, &lt;a href=&quot;https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide&quot;&gt;SSL Server Rating Guide&lt;/a&gt;, version 2009r, 16 May 2025&lt;/li&gt;
  &lt;li&gt;TLSRef, &lt;a href=&quot;https://data.tlsref.org/guidelines/6.0.json&quot;&gt;Server Side TLS guideline 6.0&lt;/a&gt; and &lt;a href=&quot;https://configurator.tlsref.org/&quot;&gt;TLS Configurator&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;nginx, &lt;a href=&quot;https://nginx.org/en/docs/http/ngx_http_ssl_module.html&quot;&gt;ngx_http_ssl_module&lt;/a&gt;, &lt;a href=&quot;https://nginx.org/en/docs/http/ngx_http_headers_module.html&quot;&gt;ngx_http_headers_module&lt;/a&gt; and &lt;a href=&quot;https://nginx.org/en/CHANGES&quot;&gt;CHANGES&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Let’s Encrypt, &lt;a href=&quot;https://letsencrypt.org/2024/12/05/ending-ocsp/&quot;&gt;Ending OCSP Support in 2025&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hstspreload.org/&quot;&gt;HSTS Preload List Submission&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;IETF, &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc6797&quot;&gt;RFC 6797: HTTP Strict Transport Security&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>Mahyuddin Susanto</name></author><category term="Linux" /><category term="nginx" /><category term="tls" /><category term="ssl" /><category term="security" /><category term="hsts" /><summary type="html">To get an A+ on the Qualys SSL Labs server test with nginx, you need five things: TLS 1.2 and TLS 1.3 only, ECDHE key exchange with AEAD ciphers (GCM or ChaCha20-Poly1305), a certificate served with its full chain, an HSTS header with a max-age of at least six months, and the same setup on every IP address your hostname resolves to. Miss TLS 1.3 or HSTS and you land on A-. Leave TLS 1.0 or 1.1 on and you are stuck at B.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.udienz.web.id/img/ssl-labs-a-plus-nginx.png" /><media:content medium="image" url="https://www.udienz.web.id/img/ssl-labs-a-plus-nginx.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Mobil Listrik (1/3): Pengertian dan Jenis-Jenisnya</title><link href="https://www.udienz.web.id/2026/11/04/mobil-listrik-pengertian-jenis-cara-kerja" rel="alternate" type="text/html" title="Mobil Listrik (1/3): Pengertian dan Jenis-Jenisnya" /><published>2026-11-04T00:00:03+00:00</published><updated>2026-11-04T00:00:03+00:00</updated><id>https://www.udienz.web.id/2026/11/04/mobil-listrik-pengertian-jenis-cara-kerja</id><content type="html" xml:base="https://www.udienz.web.id/2026/11/04/mobil-listrik-pengertian-jenis-cara-kerja">&lt;p&gt;Pada September 2026, BYD Atto 1 tercatat 4.840 unit dalam data Gaikindo, peringkat kedua dalam daftar 20 model terlaris di seluruh pasar mobil Indonesia bulan itu dan yang tertinggi di antara mobil listrik (&lt;a href=&quot;https://www.gaikindo.or.id/20-model-mobil-terlaris-september-2026-atto-1-menempel-gran-max/&quot;&gt;Gaikindo, 25 Oktober 2026&lt;/a&gt;). Gaikindo sendiri menulis bahwa mobil listrik “mulai menembus jajaran model terlaris”. Harga mobil listrik terlaris sekarang mulai dari sekitar Rp150 jutaan, yaitu VinFast VF 3 dengan sewa baterai. Data di tulisan ini diperiksa pada 4 November 2026, dan tanggal terbit tiap sumber ada di sampingnya.&lt;/p&gt;

&lt;p&gt;Tulisan ini menjelaskan apa itu mobil listrik dan apa bedanya dengan hybrid, bagaimana mobil itu bekerja dari colokan sampai roda, dan mobil listrik mana yang paling banyak tercatat penjualannya di Indonesia sepanjang 2026, lengkap dengan harga, kapasitas baterai, dan klaim jarak tempuhnya. Setiap harga dan angka penjualan saya beri tanggal sumbernya, karena angkanya berubah cepat dan beberapa media menulis angka berbeda untuk model yang sama.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/mobil-listrik-pengertian-jenis-cara-kerja.jpg&quot; alt=&quot;Mobil listrik putih yang sedang diisi daya lewat kabel dari wall charger di depan gedung kaca&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Foto: &lt;a href=&quot;https://unsplash.com/photos/a-white-car-plugged-in-to-a-charging-station-JkTjKEVcckg&quot;&gt;JUICE&lt;/a&gt; di &lt;a href=&quot;https://unsplash.com&quot;&gt;Unsplash&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Poin Penting&lt;/strong&gt;&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;Mobil listrik murni (BEV) bergerak dengan motor listrik yang disuplai baterai besar dan diisi dari colokan. Hybrid biasa dan plug-in hybrid masih punya mesin bensin, jadi bukan mobil listrik murni.&lt;/li&gt;
    &lt;li&gt;Mobil listrik mengubah lebih dari 77% energi listrik menjadi tenaga di roda, sedangkan mobil bensin hanya 12% sampai 30% dari energi bensinnya (U.S. Department of Energy).&lt;/li&gt;
    &lt;li&gt;Pengisian di rumah dengan tarif listrik rumah tangga Rp1.444,70 per kWh menghabiskan sekitar Rp60 ribu sampai Rp67 ribu untuk mengisi baterai 38,88 kWh dari kosong sampai penuh, menurut hitungan di tulisan ini. Di SPKLU umum tarifnya sampai Rp2.475 per kWh.&lt;/li&gt;
    &lt;li&gt;Sepuluh mobil listrik dengan penjualan terbesar pada Januari sampai September 2026 berharga dari Rp152 juta (VinFast VF 3 dengan sewa baterai) sampai Rp950 juta (Denza D9). Tiga yang terlaris, yaitu Jaecoo J5 EV, BYD Atto 1, dan Geely EX2, berada di kisaran Rp200 jutaan sampai Rp300 jutaan.&lt;/li&gt;
    &lt;li&gt;Insentif PPN ditanggung pemerintah dan keringanan bea masuk untuk mobil listrik tidak berlanjut pada 2026. Penggantinya masih dikaji pada Juni 2026, jadi harga bisa berubah lagi.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;details class=&quot;toc&quot;&gt;
  &lt;summary&gt;Daftar isi bagian ini&lt;/summary&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#apa-itu-mobil-listrik&quot; id=&quot;markdown-toc-apa-itu-mobil-listrik&quot;&gt;Apa itu mobil listrik?&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#kenapa-orang-beralih&quot; id=&quot;markdown-toc-kenapa-orang-beralih&quot;&gt;Kenapa orang beralih&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#skala-globalnya&quot; id=&quot;markdown-toc-skala-globalnya&quot;&gt;Skala globalnya&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#jenis-jenis-mobil-listrik&quot; id=&quot;markdown-toc-jenis-jenis-mobil-listrik&quot;&gt;Jenis-jenis mobil listrik&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#pembanding-mobil-konvensional-ice&quot; id=&quot;markdown-toc-pembanding-mobil-konvensional-ice&quot;&gt;Pembanding: mobil konvensional (ICE)&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#bev-mobil-listrik-murni&quot; id=&quot;markdown-toc-bev-mobil-listrik-murni&quot;&gt;BEV: mobil listrik murni&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#phev-hybrid-yang-bisa-dicolok&quot; id=&quot;markdown-toc-phev-hybrid-yang-bisa-dicolok&quot;&gt;PHEV: hybrid yang bisa dicolok&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#hev-hybrid-biasa&quot; id=&quot;markdown-toc-hev-hybrid-biasa&quot;&gt;HEV: hybrid biasa&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#fcev-mobil-listrik-berbahan-bakar-hidrogen&quot; id=&quot;markdown-toc-fcev-mobil-listrik-berbahan-bakar-hidrogen&quot;&gt;FCEV: mobil listrik berbahan bakar hidrogen&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;/details&gt;

&lt;h2 id=&quot;apa-itu-mobil-listrik&quot;&gt;Apa itu mobil listrik?&lt;/h2&gt;

&lt;p&gt;Mobil listrik adalah mobil yang digerakkan oleh motor listrik, bukan mesin pembakaran. Departemen Energi Amerika Serikat menyebut jenis yang paling murni sebagai all-electric vehicle atau battery electric vehicle (BEV): mobilnya punya baterai yang diisi dengan mencolokkan kendaraan ke peralatan pengisian, dan selalu berjalan dalam mode listrik penuh (&lt;a href=&quot;https://afdc.energy.gov/vehicles/electric&quot;&gt;U.S. DOE, Alternative Fuels Data Center&lt;/a&gt;). Tidak ada tangki bensin, pompa bahan bakar, atau saluran bahan bakar. Kendaraan seperti ini juga tidak mengeluarkan gas buang dari knalpot (&lt;a href=&quot;https://afdc.energy.gov/vehicles/how-do-all-electric-cars-work&quot;&gt;U.S. DOE&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Dalam aturan Indonesia, istilah resminya Kendaraan Bermotor Listrik Berbasis Baterai atau KBLBB. Istilah itu dipakai dalam &lt;a href=&quot;https://peraturan.bpk.go.id/Details/116973/perpres-no-55&quot;&gt;Perpres 55 Tahun 2019&lt;/a&gt; tentang percepatan program KBLBB untuk transportasi jalan, yang kemudian diubah dengan &lt;a href=&quot;https://peraturan.bpk.go.id/Details/273447&quot;&gt;Perpres 79 Tahun 2023&lt;/a&gt;. Di dealer dan di media otomotif, kamu akan lebih sering mendengar singkatan BEV atau sebutan “mobil listrik” saja.&lt;/p&gt;

&lt;h3 id=&quot;kenapa-orang-beralih&quot;&gt;Kenapa orang beralih&lt;/h3&gt;

&lt;p&gt;Alasan pertama adalah efisiensi. Menurut U.S. Department of Energy, mobil listrik mengubah lebih dari 77% energi listrik dari jaringan menjadi tenaga di roda. Mobil bensin konvensional hanya mengubah sekitar 12% sampai 30% energi tersimpan dalam bensin menjadi tenaga di roda (&lt;a href=&quot;https://www.fueleconomy.gov/feg/evtech.shtml&quot;&gt;FuelEconomy.gov&lt;/a&gt;). Angka itu berasal dari konteks Amerika Serikat, tetapi prinsip fisikanya sama di mana pun: motor listrik membuang jauh lebih sedikit energi sebagai panas dibanding mesin bensin.&lt;/p&gt;

&lt;p&gt;Alasan kedua adalah biaya energi per kilometer. Listrik rumah tangga di Indonesia dihargai Rp1.352 sampai Rp1.699,53 per kWh, tergantung golongan, untuk triwulan IV 2026 (&lt;a href=&quot;https://www.metrotvnews.com/read/NA0CzpEz-daftar-lengkap-tarif-listrik-pln-akhir-oktober-2026-per-kwh&quot;&gt;Metro TV, 29 Oktober 2026&lt;/a&gt;). Bagian hitung-hitungan ada di bawah, di bagian pengisian daya.&lt;/p&gt;

&lt;p&gt;Alasan ketiga adalah pengalaman berkendara. Menurut pengetahuan umum, motor listrik memberikan torsi sejak putaran pertama dan tidak memakai perpindahan gigi bertahap, jadi akselerasinya halus. Sisi lemahnya juga ada: jarak tempuh nyata bisa jauh di bawah angka brosur, dan pengisian bergantung pada colokan yang tersedia. Dua hal itu saya hitung dengan angka di bawah.&lt;/p&gt;

&lt;h3 id=&quot;skala-globalnya&quot;&gt;Skala globalnya&lt;/h3&gt;

&lt;p&gt;Mobil listrik bukan fenomena satu negara. Badan Energi Internasional (IEA) menulis dalam siaran pers Global EV Outlook 2026 bahwa hampir 30% mobil yang terjual pada 2026 diperkirakan berupa mobil listrik, seiring negara dan konsumen merespons krisis energi (&lt;a href=&quot;https://www.iea.org/reports/global-ev-outlook-2026&quot;&gt;IEA, Global EV Outlook 2026&lt;/a&gt;). Di Indonesia, sepuluh mobil listrik terlaris saja mencapai 89.502 unit pada sembilan bulan pertama 2026 menurut data Gaikindo, seperti yang dirinci di bagian daftar model.&lt;/p&gt;

&lt;h2 id=&quot;jenis-jenis-mobil-listrik&quot;&gt;Jenis-jenis mobil listrik&lt;/h2&gt;

&lt;p&gt;Istilah “mobil listrik” dipakai longgar untuk beberapa teknologi yang berbeda. Perbedaannya menentukan apakah kamu perlu mencari colokan, apakah masih harus ke SPBU, dan seberapa besar biaya bulanannya. Tabel berikut membandingkan mobil konvensional dengan empat jenis yang sering disebut mobil listrik. Tiap jenis dijabarkan di bawahnya dengan diagram alur energi.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Jenis&lt;/th&gt;
      &lt;th&gt;Singkatan&lt;/th&gt;
      &lt;th&gt;Sumber tenaga&lt;/th&gt;
      &lt;th&gt;Dicolok untuk diisi?&lt;/th&gt;
      &lt;th&gt;Masih pakai bensin?&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Mobil konvensional&lt;/td&gt;
      &lt;td&gt;ICE&lt;/td&gt;
      &lt;td&gt;Mesin pembakaran&lt;/td&gt;
      &lt;td&gt;Tidak&lt;/td&gt;
      &lt;td&gt;Ya&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Battery electric vehicle&lt;/td&gt;
      &lt;td&gt;BEV&lt;/td&gt;
      &lt;td&gt;Baterai besar dan motor listrik&lt;/td&gt;
      &lt;td&gt;Ya&lt;/td&gt;
      &lt;td&gt;Tidak&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Plug-in hybrid electric vehicle&lt;/td&gt;
      &lt;td&gt;PHEV&lt;/td&gt;
      &lt;td&gt;Baterai sedang, motor listrik, dan mesin bensin&lt;/td&gt;
      &lt;td&gt;Ya&lt;/td&gt;
      &lt;td&gt;Ya&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Hybrid electric vehicle&lt;/td&gt;
      &lt;td&gt;HEV&lt;/td&gt;
      &lt;td&gt;Mesin bensin dibantu motor listrik dan baterai kecil&lt;/td&gt;
      &lt;td&gt;Tidak&lt;/td&gt;
      &lt;td&gt;Ya&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Fuel cell electric vehicle&lt;/td&gt;
      &lt;td&gt;FCEV&lt;/td&gt;
      &lt;td&gt;Hidrogen yang diubah menjadi listrik oleh sel bahan bakar&lt;/td&gt;
      &lt;td&gt;Tidak (isi hidrogen)&lt;/td&gt;
      &lt;td&gt;Tidak&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Di semua diagram, garis oranye adalah bensin, biru listrik, hijau hidrogen, ungu energi yang kembali ke baterai saat mobil melambat, dan abu-abu tenaga mekanik atau sisa.&lt;/p&gt;

&lt;h3 id=&quot;pembanding-mobil-konvensional-ice&quot;&gt;Pembanding: mobil konvensional (ICE)&lt;/h3&gt;

&lt;p&gt;Mobil konvensional memakai mesin pembakaran dalam (internal combustion engine, ICE) yang membakar bensin atau solar. Semua jenis lain di bawah menambahkan atau menggantikan sebagian dari rantai ini.&lt;/p&gt;

&lt;figure class=&quot;blog-chart&quot;&gt;
&lt;svg viewBox=&quot;0 0 400 189&quot; width=&quot;400&quot; height=&quot;189&quot; role=&quot;img&quot; aria-label=&quot;Diagram mobil konvensional: bensin dari tangki masuk ke mesin pembakaran, tenaga mekanik diteruskan lewat transmisi ke roda, dan gas buang keluar lewat knalpot.&quot;&gt;
&lt;rect x=&quot;8.0&quot; y=&quot;13.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#f97316&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;62&quot; y=&quot;33&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Tangki&lt;/text&gt;
&lt;text x=&quot;62&quot; y=&quot;49&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;bensin&lt;/text&gt;
&lt;rect x=&quot;146.0&quot; y=&quot;13.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;200&quot; y=&quot;33&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Mesin&lt;/text&gt;
&lt;text x=&quot;200&quot; y=&quot;49&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;pembakaran&lt;/text&gt;
&lt;rect x=&quot;284.0&quot; y=&quot;13.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;338&quot; y=&quot;33&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Transmisi&lt;/text&gt;
&lt;text x=&quot;338&quot; y=&quot;49&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;(rasio gigi)&lt;/text&gt;
&lt;rect x=&quot;146.0&quot; y=&quot;97.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;200&quot; y=&quot;117&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Knalpot&lt;/text&gt;
&lt;text x=&quot;200&quot; y=&quot;133&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;gas buang&lt;/text&gt;
&lt;rect x=&quot;284.0&quot; y=&quot;97.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;338&quot; y=&quot;125&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Roda&lt;/text&gt;
&lt;line x1=&quot;116.0&quot; y1=&quot;36.0&quot; x2=&quot;140.0&quot; y2=&quot;36.0&quot; stroke=&quot;#f97316&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;146.0,36.0 139.0,40.0 139.0,32.0&quot; fill=&quot;#f97316&quot; stroke=&quot;#f97316&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;254.0&quot; y1=&quot;36.0&quot; x2=&quot;278.0&quot; y2=&quot;36.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;284.0,36.0 277.0,40.0 277.0,32.0&quot; fill=&quot;#9ca3af&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;338.0&quot; y1=&quot;59.0&quot; x2=&quot;338.0&quot; y2=&quot;91.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;338.0,97.0 334.0,90.0 342.0,90.0&quot; fill=&quot;#9ca3af&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;200.0&quot; y1=&quot;59.0&quot; x2=&quot;200.0&quot; y2=&quot;91.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;200.0,97.0 196.0,90.0 204.0,90.0&quot; fill=&quot;#9ca3af&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;8.0&quot; y1=&quot;173.0&quot; x2=&quot;26.0&quot; y2=&quot;173.0&quot; stroke=&quot;#f97316&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;32.0&quot; y=&quot;177&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;Bensin&lt;/text&gt;
&lt;line x1=&quot;208.0&quot; y1=&quot;173.0&quot; x2=&quot;226.0&quot; y2=&quot;173.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;232.0&quot; y=&quot;177&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;Mekanik&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption&gt;Alur energi mobil konvensional: bensin dibakar di mesin, tenaganya lewat transmisi ke roda, sisanya keluar sebagai gas buang dan panas.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Alurnya begini, menurut pengetahuan umum tentang mesin bensin. Pompa mengalirkan bahan bakar dari tangki ke mesin. Di dalam silinder, bahan bakar bercampur dengan udara lalu dibakar, dan pembakaran itu mendorong piston. Piston memutar poros engkol, dan putaran itu diteruskan lewat transmisi ke roda. Transmisi diperlukan karena mesin hanya bekerja baik pada rentang putaran tertentu, jadi rasio gigi diubah menurut kecepatan. Sisa pembakaran keluar lewat knalpot. Aki 12 volt menyalakan starter dan menyuplai listrik aksesori, lalu diisi ulang oleh alternator yang diputar mesin.&lt;/p&gt;

&lt;p&gt;Kelemahan utamanya ada pada efisiensi. Seperti sudah dikutip di atas, mobil bensin hanya mengubah sekitar 12% sampai 30% energi bensin menjadi tenaga di roda (&lt;a href=&quot;https://www.fueleconomy.gov/feg/evtech.shtml&quot;&gt;FuelEconomy.gov&lt;/a&gt;). Sisanya hilang sebagai panas. Kelebihannya sederhana: mengisi bahan bakar memakan beberapa menit, dan kebiasaan itu sudah dikenal semua orang. Itulah celah yang coba diisi oleh keempat jenis di bawah.&lt;/p&gt;

&lt;h3 id=&quot;bev-mobil-listrik-murni&quot;&gt;BEV: mobil listrik murni&lt;/h3&gt;

&lt;p&gt;BEV hanya punya motor listrik. Seluruh sepuluh model di daftar tulisan ini adalah BEV.&lt;/p&gt;

&lt;figure class=&quot;blog-chart&quot;&gt;
&lt;svg viewBox=&quot;0 0 400 189&quot; width=&quot;400&quot; height=&quot;189&quot; role=&quot;img&quot; aria-label=&quot;Diagram mobil listrik murni: listrik dari soket pengisian lewat pengisi daya onboard disimpan di baterai, lalu lewat elektronika daya ke motor listrik dan roda. Saat melambat, energi kembali dari motor ke baterai.&quot;&gt;
&lt;rect x=&quot;8.0&quot; y=&quot;13.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;62&quot; y=&quot;33&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Soket&lt;/text&gt;
&lt;text x=&quot;62&quot; y=&quot;49&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;pengisian&lt;/text&gt;
&lt;rect x=&quot;146.0&quot; y=&quot;13.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;200&quot; y=&quot;33&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Pengisi daya&lt;/text&gt;
&lt;text x=&quot;200&quot; y=&quot;49&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;onboard&lt;/text&gt;
&lt;rect x=&quot;284.0&quot; y=&quot;13.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#38bdf8&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;338&quot; y=&quot;33&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Baterai&lt;/text&gt;
&lt;text x=&quot;338&quot; y=&quot;49&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;traksi&lt;/text&gt;
&lt;rect x=&quot;284.0&quot; y=&quot;97.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;338&quot; y=&quot;117&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Elektronika&lt;/text&gt;
&lt;text x=&quot;338&quot; y=&quot;133&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;daya&lt;/text&gt;
&lt;rect x=&quot;146.0&quot; y=&quot;97.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;200&quot; y=&quot;117&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Motor&lt;/text&gt;
&lt;text x=&quot;200&quot; y=&quot;133&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;listrik&lt;/text&gt;
&lt;rect x=&quot;8.0&quot; y=&quot;97.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;62&quot; y=&quot;125&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Roda&lt;/text&gt;
&lt;line x1=&quot;116.0&quot; y1=&quot;36.0&quot; x2=&quot;140.0&quot; y2=&quot;36.0&quot; stroke=&quot;#38bdf8&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;146.0,36.0 139.0,40.0 139.0,32.0&quot; fill=&quot;#38bdf8&quot; stroke=&quot;#38bdf8&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;254.0&quot; y1=&quot;36.0&quot; x2=&quot;278.0&quot; y2=&quot;36.0&quot; stroke=&quot;#38bdf8&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;284.0,36.0 277.0,40.0 277.0,32.0&quot; fill=&quot;#38bdf8&quot; stroke=&quot;#38bdf8&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;333.0&quot; y1=&quot;59.0&quot; x2=&quot;333.0&quot; y2=&quot;91.0&quot; stroke=&quot;#38bdf8&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;333.0,97.0 329.0,90.0 337.0,90.0&quot; fill=&quot;#38bdf8&quot; stroke=&quot;#38bdf8&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;343.0&quot; y1=&quot;97.0&quot; x2=&quot;343.0&quot; y2=&quot;65.0&quot; stroke=&quot;#a78bfa&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;343.0,59.0 347.0,66.0 339.0,66.0&quot; fill=&quot;#a78bfa&quot; stroke=&quot;#a78bfa&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;284.0&quot; y1=&quot;115.0&quot; x2=&quot;260.0&quot; y2=&quot;115.0&quot; stroke=&quot;#38bdf8&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;254.0,115.0 261.0,111.0 261.0,119.0&quot; fill=&quot;#38bdf8&quot; stroke=&quot;#38bdf8&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;254.0&quot; y1=&quot;125.0&quot; x2=&quot;278.0&quot; y2=&quot;125.0&quot; stroke=&quot;#a78bfa&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;284.0,125.0 277.0,129.0 277.0,121.0&quot; fill=&quot;#a78bfa&quot; stroke=&quot;#a78bfa&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;146.0&quot; y1=&quot;120.0&quot; x2=&quot;122.0&quot; y2=&quot;120.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;116.0,120.0 123.0,116.0 123.0,124.0&quot; fill=&quot;#9ca3af&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;8.0&quot; y1=&quot;173.0&quot; x2=&quot;26.0&quot; y2=&quot;173.0&quot; stroke=&quot;#38bdf8&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;32.0&quot; y=&quot;177&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;Listrik&lt;/text&gt;
&lt;line x1=&quot;141.3&quot; y1=&quot;173.0&quot; x2=&quot;159.3&quot; y2=&quot;173.0&quot; stroke=&quot;#a78bfa&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;165.3&quot; y=&quot;177&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;Regenerasi&lt;/text&gt;
&lt;line x1=&quot;274.7&quot; y1=&quot;173.0&quot; x2=&quot;292.7&quot; y2=&quot;173.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;298.7&quot; y=&quot;177&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;Mekanik&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption&gt;Alur energi mobil listrik murni (BEV) saat diisi lewat colokan AC, tanpa tangki bensin dan mesin. Pengisian cepat DC mengalir langsung ke baterai tanpa melewati pengisi daya onboard. Garis ungu menunjukkan energi yang kembali ke baterai saat mobil melambat.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h4 id=&quot;cara-kerja-bev&quot;&gt;Cara kerja BEV&lt;/h4&gt;

&lt;p&gt;Listrik masuk lewat soket pengisian. Pengisi daya onboard mengubah arus bolak-balik (AC) menjadi arus searah (DC) dan menyimpannya di baterai traksi. Saat kamu menginjak gas, elektronika daya mengatur seberapa banyak energi mengalir dari baterai ke motor, dan motor memutar roda. Saat kamu melepas gas atau mengerem, motor berbalik menjadi generator dan mengirim sebagian energi kembali ke baterai (garis ungu di diagram). Tidak ada tangki bensin, pompa bahan bakar, atau saluran bahan bakar (&lt;a href=&quot;https://afdc.energy.gov/vehicles/how-do-all-electric-cars-work&quot;&gt;U.S. DOE&lt;/a&gt;).&lt;/p&gt;

&lt;h4 id=&quot;kelebihan-dan-batas-bev&quot;&gt;Kelebihan dan batas BEV&lt;/h4&gt;

&lt;p&gt;Departemen Energi AS menyebut jarak tempuh khas BEV antara 150 dan 400 mil (&lt;a href=&quot;https://afdc.energy.gov/vehicles/electric&quot;&gt;U.S. DOE&lt;/a&gt;), atau sekitar 240 sampai 640 km. Rentang itu terlihat juga di Indonesia: VinFast VF 3 mengklaim 210 km, sedangkan BYD Sealion 7 mengklaim lebih dari 540 km, keduanya berdasarkan siklus uji NEDC.&lt;/p&gt;

&lt;p&gt;Kelebihan BEV adalah efisiensi yang tinggi (lebih dari 77% energi listrik sampai ke roda), tidak ada gas buang dari knalpot, dan, menurut pengetahuan umum, mekanis yang lebih sederhana karena tidak ada oli mesin, busi, atau knalpot yang perlu dirawat. Kelemahannya adalah ketergantungan penuh pada pengisian: kalau baterai habis, tidak ada mesin cadangan. Baterainya juga mahal dan penggantiannya bisa mahal kalau rusak (&lt;a href=&quot;https://www.fueleconomy.gov/feg/evtech.shtml&quot;&gt;FuelEconomy.gov&lt;/a&gt;), dan jarak tempuh nyata bisa jauh di bawah klaim, seperti hitungan dari dua uji jalan Geely di bagian model.&lt;/p&gt;

&lt;h4 id=&quot;bev-cocok-untuk-siapa&quot;&gt;BEV cocok untuk siapa&lt;/h4&gt;

&lt;p&gt;BEV paling masuk akal untuk orang yang bisa mengisi di rumah atau kantor dan jarak hariannya jauh di bawah klaim jarak mobil. Di Indonesia pilihannya paling luas: dari Rp152 juta (VinFast VF 3 dengan sewa baterai) sampai Rp950 juta (Denza D9) di daftar sepuluh model terlaris pada September 2026.&lt;/p&gt;

&lt;h3 id=&quot;phev-hybrid-yang-bisa-dicolok&quot;&gt;PHEV: hybrid yang bisa dicolok&lt;/h3&gt;

&lt;p&gt;PHEV punya baterai dan motor listrik, tetapi juga mesin bensin dan tangki bensin. Menurut Departemen Energi AS, sebagian besar PHEV bisa menempuh sekitar 20 sampai 40 mil dengan listrik saja (&lt;a href=&quot;https://afdc.energy.gov/vehicles/electric&quot;&gt;U.S. DOE&lt;/a&gt;), kira-kira 32 sampai 64 km, sebelum berjalan seperti hybrid biasa dengan bensin.&lt;/p&gt;

&lt;figure class=&quot;blog-chart&quot;&gt;
&lt;svg viewBox=&quot;0 0 400 273&quot; width=&quot;400&quot; height=&quot;273&quot; role=&quot;img&quot; aria-label=&quot;Diagram plug-in hybrid: baterai diisi lewat soket pengisian dan menggerakkan motor listrik, sementara mesin bensin dari tangki bensin ikut menggerakkan roda lewat transmisi penggabung. Energi pengereman kembali ke baterai.&quot;&gt;
&lt;rect x=&quot;8.0&quot; y=&quot;13.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;62&quot; y=&quot;33&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Soket&lt;/text&gt;
&lt;text x=&quot;62&quot; y=&quot;49&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;pengisian&lt;/text&gt;
&lt;rect x=&quot;146.0&quot; y=&quot;13.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#38bdf8&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;200&quot; y=&quot;33&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Baterai&lt;/text&gt;
&lt;text x=&quot;200&quot; y=&quot;49&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;sedang&lt;/text&gt;
&lt;rect x=&quot;284.0&quot; y=&quot;13.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#f97316&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;338&quot; y=&quot;33&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Tangki&lt;/text&gt;
&lt;text x=&quot;338&quot; y=&quot;49&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;bensin&lt;/text&gt;
&lt;rect x=&quot;146.0&quot; y=&quot;97.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;200&quot; y=&quot;117&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Motor&lt;/text&gt;
&lt;text x=&quot;200&quot; y=&quot;133&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;listrik&lt;/text&gt;
&lt;rect x=&quot;284.0&quot; y=&quot;97.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;338&quot; y=&quot;117&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Mesin&lt;/text&gt;
&lt;text x=&quot;338&quot; y=&quot;133&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;bensin&lt;/text&gt;
&lt;rect x=&quot;146.0&quot; y=&quot;181.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;200&quot; y=&quot;201&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Transmisi /&lt;/text&gt;
&lt;text x=&quot;200&quot; y=&quot;217&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;penggabung&lt;/text&gt;
&lt;rect x=&quot;8.0&quot; y=&quot;181.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;62&quot; y=&quot;209&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Roda&lt;/text&gt;
&lt;line x1=&quot;116.0&quot; y1=&quot;36.0&quot; x2=&quot;140.0&quot; y2=&quot;36.0&quot; stroke=&quot;#38bdf8&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;146.0,36.0 139.0,40.0 139.0,32.0&quot; fill=&quot;#38bdf8&quot; stroke=&quot;#38bdf8&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;195.0&quot; y1=&quot;59.0&quot; x2=&quot;195.0&quot; y2=&quot;91.0&quot; stroke=&quot;#38bdf8&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;195.0,97.0 191.0,90.0 199.0,90.0&quot; fill=&quot;#38bdf8&quot; stroke=&quot;#38bdf8&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;205.0&quot; y1=&quot;97.0&quot; x2=&quot;205.0&quot; y2=&quot;65.0&quot; stroke=&quot;#a78bfa&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;205.0,59.0 209.0,66.0 201.0,66.0&quot; fill=&quot;#a78bfa&quot; stroke=&quot;#a78bfa&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;338.0&quot; y1=&quot;59.0&quot; x2=&quot;338.0&quot; y2=&quot;91.0&quot; stroke=&quot;#f97316&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;338.0,97.0 334.0,90.0 342.0,90.0&quot; fill=&quot;#f97316&quot; stroke=&quot;#f97316&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;200.0&quot; y1=&quot;143.0&quot; x2=&quot;200.0&quot; y2=&quot;175.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;200.0,181.0 196.0,174.0 204.0,174.0&quot; fill=&quot;#9ca3af&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;338.0&quot; y1=&quot;143.0&quot; x2=&quot;338.0&quot; y2=&quot;204.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;line x1=&quot;338.0&quot; y1=&quot;204.0&quot; x2=&quot;260.0&quot; y2=&quot;204.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;254.0,204.0 261.0,200.0 261.0,208.0&quot; fill=&quot;#9ca3af&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;146.0&quot; y1=&quot;204.0&quot; x2=&quot;122.0&quot; y2=&quot;204.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;116.0,204.0 123.0,200.0 123.0,208.0&quot; fill=&quot;#9ca3af&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;8.0&quot; y1=&quot;257.0&quot; x2=&quot;26.0&quot; y2=&quot;257.0&quot; stroke=&quot;#f97316&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;32.0&quot; y=&quot;261&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;Bensin&lt;/text&gt;
&lt;line x1=&quot;108.0&quot; y1=&quot;257.0&quot; x2=&quot;126.0&quot; y2=&quot;257.0&quot; stroke=&quot;#38bdf8&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;132.0&quot; y=&quot;261&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;Listrik&lt;/text&gt;
&lt;line x1=&quot;208.0&quot; y1=&quot;257.0&quot; x2=&quot;226.0&quot; y2=&quot;257.0&quot; stroke=&quot;#a78bfa&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;232.0&quot; y=&quot;261&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;Regenerasi&lt;/text&gt;
&lt;line x1=&quot;308.0&quot; y1=&quot;257.0&quot; x2=&quot;326.0&quot; y2=&quot;257.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;332.0&quot; y=&quot;261&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;Mekanik&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption&gt;Alur energi plug-in hybrid (PHEV): dua sumber tenaga, listrik dari colokan dan bensin dari tangki, bertemu di transmisi sebelum ke roda.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h4 id=&quot;cara-kerja-phev&quot;&gt;Cara kerja PHEV&lt;/h4&gt;

&lt;p&gt;Baterai PHEV diisi lewat colokan, lebih besar dari baterai hybrid biasa tetapi lebih kecil dari baterai BEV. Selama baterai terisi, mobil bisa berjalan hanya dengan motor listrik. Setelah baterai turun, mesin bensin ikut bekerja, dan dua sumber tenaga itu bertemu di transmisi atau penggabung tenaga sebelum ke roda. Pengereman regeneratif tetap mengisi sebagian baterai.&lt;/p&gt;

&lt;h4 id=&quot;kelebihan-dan-batas-phev&quot;&gt;Kelebihan dan batas PHEV&lt;/h4&gt;

&lt;p&gt;Kelebihannya adalah fleksibilitas. Untuk pemakaian harian dalam kota, PHEV bisa berjalan hampir sepenuhnya dengan listrik kalau dicolok tiap malam, dan untuk perjalanan jauh mesin bensinnya menjadi cadangan sehingga kamu tidak perlu mencari SPKLU. Batasnya ada dua. Mobil ini membawa dua sistem penggerak sekaligus, jadi lebih kompleks, dan pada contoh Darion di bawah harganya lebih tinggi dari versi listrik murninya. Dan manfaatnya hilang kalau jarang dicolok: tanpa listrik dari colokan, mobil bergantung pada mesin bensin dan membawa baterai yang jarang terpakai.&lt;/p&gt;

&lt;p&gt;Contoh di Indonesia adalah Wuling Darion, yang dijual dalam varian EV dan PHEV. Menurut daftar harga Otodriver edisi September 2026, Darion PHEV CE dan EX masing-masing dijual Rp449 juta dan Rp499 juta, sedangkan Darion EV CE dan EX Rp399 juta dan Rp459 juta (&lt;a href=&quot;https://otodriver.com/daftar-harga/2026/daftar-harga-wuling-terbaru-september-2026-dafefcff026&quot;&gt;Otodriver&lt;/a&gt;). Selisih Rp40 juta sampai Rp50 juta itu membeli mesin bensin sebagai cadangan.&lt;/p&gt;

&lt;h4 id=&quot;phev-cocok-untuk-siapa&quot;&gt;PHEV cocok untuk siapa&lt;/h4&gt;

&lt;p&gt;PHEV masuk akal untuk orang yang bisa mencolok di rumah tetapi sering menempuh perjalanan jauh tanpa jaminan ada SPKLU di rute. Kalau kamu hampir tidak pernah mencolok, PHEV kehilangan alasannya.&lt;/p&gt;

&lt;h3 id=&quot;hev-hybrid-biasa&quot;&gt;HEV: hybrid biasa&lt;/h3&gt;

&lt;p&gt;Pada HEV, baterai diisi lewat pengereman regeneratif dan mesin, bukan lewat colokan. Departemen Energi AS menegaskan hal itu: baterai hybrid diisi “through regenerative braking, not by plugging in” (&lt;a href=&quot;https://afdc.energy.gov/vehicles/electric&quot;&gt;U.S. DOE&lt;/a&gt;). Karena itu HEV tidak butuh SPKLU sama sekali.&lt;/p&gt;

&lt;figure class=&quot;blog-chart&quot;&gt;
&lt;svg viewBox=&quot;0 0 400 273&quot; width=&quot;400&quot; height=&quot;273&quot; role=&quot;img&quot; aria-label=&quot;Diagram hybrid biasa: bensin dari tangki masuk ke mesin. Mesin dan motor-generator bersama menggerakkan roda lewat transmisi penggabung. Baterai kecil diisi oleh mesin dan pengereman, tanpa soket pengisian.&quot;&gt;
&lt;rect x=&quot;8.0&quot; y=&quot;13.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#f97316&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;62&quot; y=&quot;33&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Tangki&lt;/text&gt;
&lt;text x=&quot;62&quot; y=&quot;49&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;bensin&lt;/text&gt;
&lt;rect x=&quot;146.0&quot; y=&quot;13.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;200&quot; y=&quot;33&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Mesin&lt;/text&gt;
&lt;text x=&quot;200&quot; y=&quot;49&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;bensin&lt;/text&gt;
&lt;rect x=&quot;8.0&quot; y=&quot;97.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#38bdf8&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;62&quot; y=&quot;117&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Baterai&lt;/text&gt;
&lt;text x=&quot;62&quot; y=&quot;133&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;kecil&lt;/text&gt;
&lt;rect x=&quot;146.0&quot; y=&quot;97.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;200&quot; y=&quot;117&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Motor-&lt;/text&gt;
&lt;text x=&quot;200&quot; y=&quot;133&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;generator&lt;/text&gt;
&lt;rect x=&quot;284.0&quot; y=&quot;97.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;338&quot; y=&quot;117&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Transmisi /&lt;/text&gt;
&lt;text x=&quot;338&quot; y=&quot;133&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;penggabung&lt;/text&gt;
&lt;rect x=&quot;284.0&quot; y=&quot;181.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;338&quot; y=&quot;209&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Roda&lt;/text&gt;
&lt;line x1=&quot;116.0&quot; y1=&quot;36.0&quot; x2=&quot;140.0&quot; y2=&quot;36.0&quot; stroke=&quot;#f97316&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;146.0,36.0 139.0,40.0 139.0,32.0&quot; fill=&quot;#f97316&quot; stroke=&quot;#f97316&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;195.0&quot; y1=&quot;59.0&quot; x2=&quot;195.0&quot; y2=&quot;91.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;195.0,97.0 191.0,90.0 199.0,90.0&quot; fill=&quot;#9ca3af&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;254.0&quot; y1=&quot;36.0&quot; x2=&quot;338.0&quot; y2=&quot;36.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;line x1=&quot;338.0&quot; y1=&quot;36.0&quot; x2=&quot;338.0&quot; y2=&quot;91.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;338.0,97.0 334.0,90.0 342.0,90.0&quot; fill=&quot;#9ca3af&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;116.0&quot; y1=&quot;115.0&quot; x2=&quot;140.0&quot; y2=&quot;115.0&quot; stroke=&quot;#38bdf8&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;146.0,115.0 139.0,119.0 139.0,111.0&quot; fill=&quot;#38bdf8&quot; stroke=&quot;#38bdf8&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;146.0&quot; y1=&quot;125.0&quot; x2=&quot;122.0&quot; y2=&quot;125.0&quot; stroke=&quot;#a78bfa&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;116.0,125.0 123.0,121.0 123.0,129.0&quot; fill=&quot;#a78bfa&quot; stroke=&quot;#a78bfa&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;254.0&quot; y1=&quot;120.0&quot; x2=&quot;278.0&quot; y2=&quot;120.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;284.0,120.0 277.0,124.0 277.0,116.0&quot; fill=&quot;#9ca3af&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;338.0&quot; y1=&quot;143.0&quot; x2=&quot;338.0&quot; y2=&quot;175.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;338.0,181.0 334.0,174.0 342.0,174.0&quot; fill=&quot;#9ca3af&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;8.0&quot; y1=&quot;257.0&quot; x2=&quot;26.0&quot; y2=&quot;257.0&quot; stroke=&quot;#f97316&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;32.0&quot; y=&quot;261&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;Bensin&lt;/text&gt;
&lt;line x1=&quot;108.0&quot; y1=&quot;257.0&quot; x2=&quot;126.0&quot; y2=&quot;257.0&quot; stroke=&quot;#38bdf8&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;132.0&quot; y=&quot;261&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;Listrik&lt;/text&gt;
&lt;line x1=&quot;208.0&quot; y1=&quot;257.0&quot; x2=&quot;226.0&quot; y2=&quot;257.0&quot; stroke=&quot;#a78bfa&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;232.0&quot; y=&quot;261&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;Regenerasi&lt;/text&gt;
&lt;line x1=&quot;308.0&quot; y1=&quot;257.0&quot; x2=&quot;326.0&quot; y2=&quot;257.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;332.0&quot; y=&quot;261&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;Mekanik&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption&gt;Alur energi hybrid biasa (HEV): bensin tetap sumber utama, motor-generator membantu, dan baterai kecil diisi dari mesin dan pengereman, bukan dari colokan.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h4 id=&quot;cara-kerja-hev&quot;&gt;Cara kerja HEV&lt;/h4&gt;

&lt;p&gt;Mesin bensin tetap sumber tenaga utama. Motor-generator membantu menggerakkan roda, terutama saat mobil mulai bergerak atau berjalan pelan, dan baterai kecilnya menyimpan energi dari pengereman regeneratif serta dari mesin yang memutar generator. Tidak ada soket pengisian, jadi kamu mengisi bensin seperti mobil biasa.&lt;/p&gt;

&lt;h4 id=&quot;kelebihan-dan-batas-hev&quot;&gt;Kelebihan dan batas HEV&lt;/h4&gt;

&lt;p&gt;Kelebihan HEV adalah kebiasaannya tidak berubah: tidak ada colokan, tidak ada kecemasan jarak, dan tidak bergantung pada infrastruktur pengisian. Bagi orang yang belum siap mengubah kebiasaan, HEV paling mudah diadopsi. Batasnya: mesin bensin tetap menjadi sumber tenaga utama, jadi mobil ini tidak menghilangkan gas buang, dan halaman Departemen Energi AS tentang kendaraan listrik tidak menyebut angka jarak listrik murni untuk HEV (&lt;a href=&quot;https://afdc.energy.gov/vehicles/electric&quot;&gt;U.S. DOE&lt;/a&gt;). Karena baterainya kecil, kemampuannya berjalan hanya dengan listrik terbatas, menurut gambaran umum.&lt;/p&gt;

&lt;h4 id=&quot;hev-cocok-untuk-siapa&quot;&gt;HEV cocok untuk siapa&lt;/h4&gt;

&lt;p&gt;HEV cocok untuk pemilik yang tidak punya tempat mengisi daya dan ingin pemakaian bensin lebih hemat tanpa mengubah rutinitas. Tulisan ini fokus ke mobil listrik murni, jadi model HEV tidak dibahas satu per satu.&lt;/p&gt;

&lt;h3 id=&quot;fcev-mobil-listrik-berbahan-bakar-hidrogen&quot;&gt;FCEV: mobil listrik berbahan bakar hidrogen&lt;/h3&gt;

&lt;p&gt;FCEV memakai hidrogen yang disimpan di tangki. Di dalam sel bahan bakar jenis polymer electrolyte membrane (PEM), hidrogen dipecah menjadi proton dan elektron. Elektron mengalir lewat rangkaian luar dan menggerakkan motor listrik, sementara di sisi katoda proton, elektron, dan oksigen dari udara bergabung menjadi air (&lt;a href=&quot;https://afdc.energy.gov/vehicles/fuel-cell&quot;&gt;U.S. DOE&lt;/a&gt;).&lt;/p&gt;

&lt;figure class=&quot;blog-chart&quot;&gt;
&lt;svg viewBox=&quot;0 0 400 303&quot; width=&quot;400&quot; height=&quot;303&quot; role=&quot;img&quot; aria-label=&quot;Diagram mobil sel bahan bakar hidrogen: hidrogen dari tangki dan oksigen dari udara bereaksi di sel bahan bakar menghasilkan listrik dan uap air. Listrik lewat elektronika daya ke motor dan roda, dengan baterai kecil sebagai penyangga.&quot;&gt;
&lt;rect x=&quot;8.0&quot; y=&quot;43.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#22c55e&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;62&quot; y=&quot;63&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Tangki&lt;/text&gt;
&lt;text x=&quot;62&quot; y=&quot;79&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;hidrogen&lt;/text&gt;
&lt;rect x=&quot;146.0&quot; y=&quot;43.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;200&quot; y=&quot;63&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Sel bahan&lt;/text&gt;
&lt;text x=&quot;200&quot; y=&quot;79&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;bakar (PEM)&lt;/text&gt;
&lt;rect x=&quot;284.0&quot; y=&quot;43.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;338&quot; y=&quot;63&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Uap air&lt;/text&gt;
&lt;text x=&quot;338&quot; y=&quot;79&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;keluar&lt;/text&gt;
&lt;rect x=&quot;8.0&quot; y=&quot;127.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;62&quot; y=&quot;147&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Motor&lt;/text&gt;
&lt;text x=&quot;62&quot; y=&quot;163&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;listrik&lt;/text&gt;
&lt;rect x=&quot;146.0&quot; y=&quot;127.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;200&quot; y=&quot;147&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Elektronika&lt;/text&gt;
&lt;text x=&quot;200&quot; y=&quot;163&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;daya&lt;/text&gt;
&lt;rect x=&quot;284.0&quot; y=&quot;127.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#38bdf8&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;338&quot; y=&quot;147&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Baterai&lt;/text&gt;
&lt;text x=&quot;338&quot; y=&quot;163&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;kecil&lt;/text&gt;
&lt;rect x=&quot;8.0&quot; y=&quot;211.0&quot; width=&quot;108&quot; height=&quot;46&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;62&quot; y=&quot;239&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; fill=&quot;currentColor&quot;&gt;Roda&lt;/text&gt;
&lt;line x1=&quot;116.0&quot; y1=&quot;66.0&quot; x2=&quot;140.0&quot; y2=&quot;66.0&quot; stroke=&quot;#22c55e&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;146.0,66.0 139.0,70.0 139.0,62.0&quot; fill=&quot;#22c55e&quot; stroke=&quot;#22c55e&quot;&gt;&lt;/polygon&gt;
&lt;text x=&quot;131.0&quot; y=&quot;61.0&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;H2&lt;/text&gt;
&lt;line x1=&quot;254.0&quot; y1=&quot;66.0&quot; x2=&quot;278.0&quot; y2=&quot;66.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;284.0,66.0 277.0,70.0 277.0,62.0&quot; fill=&quot;#9ca3af&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;200.0&quot; y1=&quot;89.0&quot; x2=&quot;200.0&quot; y2=&quot;121.0&quot; stroke=&quot;#38bdf8&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;200.0,127.0 196.0,120.0 204.0,120.0&quot; fill=&quot;#38bdf8&quot; stroke=&quot;#38bdf8&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;146.0&quot; y1=&quot;145.0&quot; x2=&quot;122.0&quot; y2=&quot;145.0&quot; stroke=&quot;#38bdf8&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;116.0,145.0 123.0,141.0 123.0,149.0&quot; fill=&quot;#38bdf8&quot; stroke=&quot;#38bdf8&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;116.0&quot; y1=&quot;155.0&quot; x2=&quot;140.0&quot; y2=&quot;155.0&quot; stroke=&quot;#a78bfa&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;146.0,155.0 139.0,159.0 139.0,151.0&quot; fill=&quot;#a78bfa&quot; stroke=&quot;#a78bfa&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;284.0&quot; y1=&quot;145.0&quot; x2=&quot;260.0&quot; y2=&quot;145.0&quot; stroke=&quot;#38bdf8&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;254.0,145.0 261.0,141.0 261.0,149.0&quot; fill=&quot;#38bdf8&quot; stroke=&quot;#38bdf8&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;254.0&quot; y1=&quot;155.0&quot; x2=&quot;278.0&quot; y2=&quot;155.0&quot; stroke=&quot;#a78bfa&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;284.0,155.0 277.0,159.0 277.0,151.0&quot; fill=&quot;#a78bfa&quot; stroke=&quot;#a78bfa&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;62.0&quot; y1=&quot;173.0&quot; x2=&quot;62.0&quot; y2=&quot;205.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;62.0,211.0 58.0,204.0 66.0,204.0&quot; fill=&quot;#9ca3af&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/polygon&gt;
&lt;line x1=&quot;200.0&quot; y1=&quot;13.0&quot; x2=&quot;200.0&quot; y2=&quot;37.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;polygon points=&quot;200.0,43.0 196.0,36.0 204.0,36.0&quot; fill=&quot;#9ca3af&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/polygon&gt;
&lt;text x=&quot;208.0&quot; y=&quot;29.0&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;O2 dari udara&lt;/text&gt;
&lt;line x1=&quot;8.0&quot; y1=&quot;287.0&quot; x2=&quot;26.0&quot; y2=&quot;287.0&quot; stroke=&quot;#22c55e&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;32.0&quot; y=&quot;291&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;Hidrogen&lt;/text&gt;
&lt;line x1=&quot;108.0&quot; y1=&quot;287.0&quot; x2=&quot;126.0&quot; y2=&quot;287.0&quot; stroke=&quot;#38bdf8&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;132.0&quot; y=&quot;291&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;Listrik&lt;/text&gt;
&lt;line x1=&quot;208.0&quot; y1=&quot;287.0&quot; x2=&quot;226.0&quot; y2=&quot;287.0&quot; stroke=&quot;#a78bfa&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;232.0&quot; y=&quot;291&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;Regenerasi&lt;/text&gt;
&lt;line x1=&quot;308.0&quot; y1=&quot;287.0&quot; x2=&quot;326.0&quot; y2=&quot;287.0&quot; stroke=&quot;#9ca3af&quot; stroke-width=&quot;2&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;332.0&quot; y=&quot;291&quot; font-size=&quot;12&quot; fill=&quot;currentColor&quot;&gt;Mekanik&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption&gt;Alur energi mobil hidrogen (FCEV): sel bahan bakar mengubah hidrogen dan oksigen udara menjadi listrik, dengan uap air dan udara hangat sebagai satu-satunya yang keluar dari knalpot.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;h4 id=&quot;cara-kerja-fcev&quot;&gt;Cara kerja FCEV&lt;/h4&gt;

&lt;p&gt;Dari motor ke roda, rantai FCEV mirip BEV: elektronika daya mengatur listrik ke motor, dan pengereman regeneratif menangkap energi yang tadinya hilang lalu menyimpannya di baterai (&lt;a href=&quot;https://afdc.energy.gov/vehicles/fuel-cell&quot;&gt;U.S. DOE&lt;/a&gt;). Bedanya ada di hulu. Listrik tidak berasal dari colokan, tetapi dibuat di dalam mobil dari hidrogen dan oksigen udara.&lt;/p&gt;

&lt;h4 id=&quot;kelebihan-dan-batas-fcev&quot;&gt;Kelebihan dan batas FCEV&lt;/h4&gt;

&lt;p&gt;Departemen Energi AS menyebut pengisian hidrogen memakan sekitar lima menit dengan jarak tempuh lebih dari 300 mil, atau sekitar 480 km (&lt;a href=&quot;https://afdc.energy.gov/vehicles/fuel-cell&quot;&gt;U.S. DOE&lt;/a&gt;). Mobilnya hanya mengeluarkan uap air dan udara hangat dari knalpot, dan lebih efisien dari mobil pembakaran, meski halaman itu tidak memberi angka efisiensinya. Halaman itu juga hanya membahas emisi dari knalpot, bukan emisi dari pembuatan hidrogen.&lt;/p&gt;

&lt;p&gt;Batas terbesarnya infrastruktur: Departemen Energi AS menggambarkan kendaraan dan fasilitas pengisiannya masih di tahap awal (&lt;a href=&quot;https://afdc.energy.gov/vehicles/fuel-cell&quot;&gt;U.S. DOE&lt;/a&gt;).&lt;/p&gt;

&lt;h4 id=&quot;fcev-cocok-untuk-siapa&quot;&gt;FCEV cocok untuk siapa&lt;/h4&gt;

&lt;p&gt;Di daftar sepuluh mobil listrik terlaris tulisan ini tidak ada FCEV, dan saya tidak menempatkannya sebagai pilihan pembelian umum. Kalau kamu tertarik, tanyakan ke agen pemegang merek soal ketersediaan unit dan stasiun pengisian hidrogen di kotamu sebelum mempertimbangkannya.&lt;/p&gt;</content><author><name>Mahyuddin Susanto</name></author><category term="Mobil" /><category term="Otomotif" /><category term="mobil listrik" /><category term="bev" /><category term="baterai" /><category term="spklu" /><category term="harga mobil listrik" /><summary type="html">Pada September 2026, BYD Atto 1 tercatat 4.840 unit dalam data Gaikindo, peringkat kedua dalam daftar 20 model terlaris di seluruh pasar mobil Indonesia bulan itu dan yang tertinggi di antara mobil listrik (Gaikindo, 25 Oktober 2026). Gaikindo sendiri menulis bahwa mobil listrik “mulai menembus jajaran model terlaris”. Harga mobil listrik terlaris sekarang mulai dari sekitar Rp150 jutaan, yaitu VinFast VF 3 dengan sewa baterai. Data di tulisan ini diperiksa pada 4 November 2026, dan tanggal terbit tiap sumber ada di sampingnya.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.udienz.web.id/img/mobil-listrik-pengertian-jenis-cara-kerja.jpg" /><media:content medium="image" url="https://www.udienz.web.id/img/mobil-listrik-pengertian-jenis-cara-kerja.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Mobil Listrik (2/3): Cara Kerja, Pengisian Daya, dan Harga</title><link href="https://www.udienz.web.id/2026/11/04/mobil-listrik-cara-kerja-pengisian-harga" rel="alternate" type="text/html" title="Mobil Listrik (2/3): Cara Kerja, Pengisian Daya, dan Harga" /><published>2026-11-04T00:00:02+00:00</published><updated>2026-11-04T00:00:02+00:00</updated><id>https://www.udienz.web.id/2026/11/04/mobil-listrik-cara-kerja-pengisian-harga</id><content type="html" xml:base="https://www.udienz.web.id/2026/11/04/mobil-listrik-cara-kerja-pengisian-harga">&lt;details class=&quot;toc&quot;&gt;
  &lt;summary&gt;Daftar isi bagian ini&lt;/summary&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#cara-kerja-mobil-listrik&quot; id=&quot;markdown-toc-cara-kerja-mobil-listrik&quot;&gt;Cara kerja mobil listrik&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#satu-perjalanan-dari-colokan-sampai-roda&quot; id=&quot;markdown-toc-satu-perjalanan-dari-colokan-sampai-roda&quot;&gt;Satu perjalanan dari colokan sampai roda&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#baterai-kwh-adalah-tangki-nya&quot; id=&quot;markdown-toc-baterai-kwh-adalah-tangki-nya&quot;&gt;Baterai: kWh adalah “tangki”-nya&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#dua-kimia-baterai-yang-paling-sering-kamu-dengar&quot; id=&quot;markdown-toc-dua-kimia-baterai-yang-paling-sering-kamu-dengar&quot;&gt;Dua kimia baterai yang paling sering kamu dengar&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#pengereman-regeneratif&quot; id=&quot;markdown-toc-pengereman-regeneratif&quot;&gt;Pengereman regeneratif&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#kenapa-pengisian-ac-dan-dc-berbeda&quot; id=&quot;markdown-toc-kenapa-pengisian-ac-dan-dc-berbeda&quot;&gt;Kenapa pengisian AC dan DC berbeda&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#berapa-lama-mengisi-penuh&quot; id=&quot;markdown-toc-berapa-lama-mengisi-penuh&quot;&gt;Berapa lama mengisi penuh&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#istilah-yang-akan-kamu-temui-di-brosur&quot; id=&quot;markdown-toc-istilah-yang-akan-kamu-temui-di-brosur&quot;&gt;Istilah yang akan kamu temui di brosur&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#pengisian-daya-di-indonesia&quot; id=&quot;markdown-toc-pengisian-daya-di-indonesia&quot;&gt;Pengisian daya di Indonesia&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#di-rumah&quot; id=&quot;markdown-toc-di-rumah&quot;&gt;Di rumah&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#di-spklu-umum&quot; id=&quot;markdown-toc-di-spklu-umum&quot;&gt;Di SPKLU umum&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#biaya-mengisi-penuh-untuk-tiap-model&quot; id=&quot;markdown-toc-biaya-mengisi-penuh-untuk-tiap-model&quot;&gt;Biaya mengisi penuh untuk tiap model&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#berapa-harga-mobil-listrik-dan-kenapa-angkanya-berubah-ubah&quot; id=&quot;markdown-toc-berapa-harga-mobil-listrik-dan-kenapa-angkanya-berubah-ubah&quot;&gt;Berapa harga mobil listrik dan kenapa angkanya berubah-ubah&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;/details&gt;

&lt;h2 id=&quot;cara-kerja-mobil-listrik&quot;&gt;Cara kerja mobil listrik&lt;/h2&gt;

&lt;p&gt;Alur energinya mudah diikuti kalau dilihat dari colokan sampai roda. Listrik masuk lewat soket pengisian, disimpan di baterai, dikendalikan oleh elektronika daya, lalu diubah menjadi putaran oleh motor. Departemen Energi AS mendaftar komponen utama mobil listrik murni seperti berikut (&lt;a href=&quot;https://afdc.energy.gov/vehicles/how-do-all-electric-cars-work&quot;&gt;U.S. DOE&lt;/a&gt;):&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Komponen&lt;/th&gt;
      &lt;th&gt;Fungsi&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Baterai traksi (traction battery pack)&lt;/td&gt;
      &lt;td&gt;Menyimpan listrik untuk motor penggerak&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Motor traksi listrik&lt;/td&gt;
      &lt;td&gt;Memakai tenaga baterai untuk memutar roda&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Pengendali elektronika daya&lt;/td&gt;
      &lt;td&gt;Mengatur aliran energi dari baterai serta kecepatan dan torsi motor&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Pengisi daya onboard (onboard charger)&lt;/td&gt;
      &lt;td&gt;Mengubah listrik AC dari soket menjadi DC untuk baterai, dan memantau kondisi baterai&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Konverter DC/DC&lt;/td&gt;
      &lt;td&gt;Menurunkan tegangan tinggi baterai untuk aksesori dan aki bantu&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Sistem termal&lt;/td&gt;
      &lt;td&gt;Menjaga motor, elektronika daya, dan komponen lain pada suhu kerja yang tepat&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Soket pengisian&lt;/td&gt;
      &lt;td&gt;Menghubungkan mobil ke sumber listrik luar&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id=&quot;satu-perjalanan-dari-colokan-sampai-roda&quot;&gt;Satu perjalanan dari colokan sampai roda&lt;/h3&gt;

&lt;p&gt;Ikuti satu siklus penuh dengan komponen di atas. Malam hari kamu mencolokkan mobil ke charger rumah. Listrik AC masuk lewat soket pengisian, dan pengisi daya onboard mengubahnya menjadi DC sambil memantau kondisi baterai. Baterai traksi menyimpan energi itu sampai penuh atau sampai batas yang kamu atur.&lt;/p&gt;

&lt;p&gt;Paginya, saat kamu menekan pedal gas, pengendali elektronika daya mengambil energi dari baterai dan menyalurkannya ke motor dalam jumlah yang sesuai posisi pedal. Motor memutar roda lewat transmisi listrik. Pada saat yang sama, konverter DC/DC menurunkan tegangan sebagian energi untuk lampu, layar, dan aksesori. Sistem termal menjaga semua bagian itu tetap dalam suhu kerjanya, karena baterai dan elektronika daya sama-sama tidak nyaman bekerja terlalu panas.&lt;/p&gt;

&lt;p&gt;Saat kamu melepas pedal dan mobil melambat, arahnya berbalik sebagian: motor menjadi generator dan mengirim sedikit energi kembali ke baterai.&lt;/p&gt;

&lt;h3 id=&quot;baterai-kwh-adalah-tangki-nya&quot;&gt;Baterai: kWh adalah “tangki”-nya&lt;/h3&gt;

&lt;p&gt;Kapasitas baterai diukur dalam kilowatt-jam (kWh). Anggap itu ukuran tangki. Baterai 38,88 kWh pada BYD Atto 1 Premium menyimpan energi lebih sedikit dari baterai 103,36 kWh pada Denza D9, dan itu salah satu sebab klaim jaraknya 380 km berbanding 600 km.&lt;/p&gt;

&lt;p&gt;Satuan kilowatt (kW) mengukur daya, bukan kapasitas. Motor Geely EX2 berdaya 85 kW (&lt;a href=&quot;https://www.carmudi.co.id/journal/harga-geely-ex2-setelah-resmi-meluncur-di-indonesia-mulai-segini/&quot;&gt;Carmudi, 21 Januari 2026&lt;/a&gt;), sedangkan motor Wuling Darion EV berdaya 150 kW (&lt;a href=&quot;https://oto.detik.com/mobil-listrik/d-8197085/spesifikasi-wuling-darion-ada-varian-ev-dan-phev-harga-mulai-rp-356-juta&quot;&gt;detikOto, 6 November 2025&lt;/a&gt;). Kapasitas baterai menentukan seberapa jauh mobil bisa berjalan, sedangkan daya motor menentukan seberapa kuat tarikannya.&lt;/p&gt;

&lt;h3 id=&quot;dua-kimia-baterai-yang-paling-sering-kamu-dengar&quot;&gt;Dua kimia baterai yang paling sering kamu dengar&lt;/h3&gt;

&lt;p&gt;Menurut pengetahuan umum, mobil listrik penumpang memakai baterai lithium-ion. Dua kimianya yang paling sering muncul di brosur adalah LFP (lithium iron phosphate) dan NMC (nikel-mangan-kobalt). Geely EX2 dan Wuling Darion EV, misalnya, memakai baterai LFP menurut sumber di bagian model di bawah.&lt;/p&gt;

&lt;p&gt;Secara umum, LFP dikenal lebih murah dan tahan banyak siklus pengisian, sedangkan NMC dikenal lebih padat energi, sehingga untuk kapasitas yang sama paketnya lebih ringan. Itu gambaran umum, bukan angka dari sumber yang dikutip di sini. Perbedaan kimia ini juga masuk ke kebijakan: rencana PPN DTP pemerintah yang dibahas di bagian harga memberi tarif berbeda untuk baterai berbasis nikel dan non-nikel.&lt;/p&gt;

&lt;h3 id=&quot;pengereman-regeneratif&quot;&gt;Pengereman regeneratif&lt;/h3&gt;

&lt;p&gt;Saat kamu melepas pedal gas atau menginjak rem, motor listrik bisa berbalik fungsi menjadi generator. Energi gerak mobil diubah kembali menjadi listrik dan dimasukkan ke baterai. Halaman Departemen Energi AS tentang mobil hidrogen menjelaskan prinsipnya sebagai penangkapan energi yang tadinya hilang saat pengereman, lalu menyimpannya di baterai (&lt;a href=&quot;https://afdc.energy.gov/vehicles/fuel-cell&quot;&gt;U.S. DOE&lt;/a&gt;). Menurut pengetahuan umum, efeknya paling terasa di lalu lintas macet, tempat kamu sering berhenti dan jalan. Di jalan tol dengan kecepatan konstan, manfaatnya jauh lebih kecil.&lt;/p&gt;

&lt;h3 id=&quot;kenapa-pengisian-ac-dan-dc-berbeda&quot;&gt;Kenapa pengisian AC dan DC berbeda&lt;/h3&gt;

&lt;p&gt;Listrik dari jaringan PLN berupa arus bolak-balik (AC), sedangkan baterai hanya menyimpan arus searah (DC). Pada pengisian AC, pengisi daya onboard di dalam mobil yang mengubahnya. Kemampuan alat itu terbatas, sehingga pengisian AC memakan waktu lama: FuelEconomy.gov menyebut 3 sampai 12 jam untuk mengisi penuh, seperti dikutip di bawah.&lt;/p&gt;

&lt;p&gt;Pengisian cepat DC melewati bagian itu. Charger di luar mobil sudah menyalurkan arus searah langsung ke baterai, sehingga dayanya bisa jauh lebih besar. Itu sebabnya waktu pengisian cepat dihitung dalam menit, bukan jam. Jaecoo J5 EV, misalnya, mendukung pengisian DC sampai 130 kW menurut &lt;a href=&quot;https://oto.detik.com/mobil-listrik/d-8182231/harga-resmi-jaecoo-j5-ev-diumumkan-3-november-ini-bocoran-spesifikasinya&quot;&gt;detikOto&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;berapa-lama-mengisi-penuh&quot;&gt;Berapa lama mengisi penuh&lt;/h3&gt;

&lt;p&gt;FuelEconomy.gov menyebut pengisian baterai penuh bisa memakan 3 sampai 12 jam, sedangkan pengisian cepat sampai 80% kapasitas bisa selesai dalam sekitar 30 menit (&lt;a href=&quot;https://www.fueleconomy.gov/feg/evtech.shtml&quot;&gt;FuelEconomy.gov&lt;/a&gt;). Angka dari produsen di Indonesia sejalan dengan itu: Geely EX5 mengklaim pengisian 30% ke 80% dalam 20 menit (&lt;a href=&quot;https://www.idxchannel.com/technology/hadir-kembali-di-pasar-otomotif-ri-geely-hadirkan-mobil-listrik-dengan-segudang-teknologi&quot;&gt;IDX Channel, 22 Februari 2025&lt;/a&gt;), dan Jaecoo J5 EV mengklaim 28 menit untuk rentang yang sama (&lt;a href=&quot;https://oto.detik.com/mobil-listrik/d-8182231/harga-resmi-jaecoo-j5-ev-diumumkan-3-november-ini-bocoran-spesifikasinya&quot;&gt;detikOto, 28 Oktober 2025&lt;/a&gt;).&lt;/p&gt;

&lt;h3 id=&quot;istilah-yang-akan-kamu-temui-di-brosur&quot;&gt;Istilah yang akan kamu temui di brosur&lt;/h3&gt;

&lt;p&gt;Beberapa singkatan muncul berulang di artikel dan brosur mobil listrik. Memahaminya mencegah salah bandingkan.&lt;/p&gt;

&lt;p&gt;NEDC adalah New European Driving Cycle, siklus uji laboratorium yang dipakai banyak pabrikan untuk mengklaim jarak tempuh. CLTC adalah siklus uji dari Tiongkok. Kedua siklus memakai kecepatan dan pola berhenti yang berbeda, jadi klaim 540 km (CLTC) pada Wuling Darion EV tidak bisa dibandingkan langsung dengan klaim 461 km (NEDC) pada Jaecoo J5 EV. Keduanya juga hasil uji standar, bukan hasil di jalan raya Indonesia.&lt;/p&gt;

&lt;p&gt;OTR berarti on the road, harga yang sudah memasukkan biaya yang diperlukan agar mobil bisa dipakai di jalan, seperti pajak dan pengurusan surat. Harga OTR berbeda antar kota, dan sebagian besar harga di tulisan ini berlaku untuk Jakarta.&lt;/p&gt;

&lt;p&gt;Wholesales adalah jumlah kendaraan yang dikirim dari pabrikan ke dealer, sedangkan penjualan eceran (retail) adalah yang diserahkan ke pembeli akhir. Data Gaikindo yang dikutip media biasanya wholesales. SPK adalah surat pemesanan kendaraan. Harga promo sering berlaku untuk konsumen yang membuat SPK sebelum tanggal tertentu, seperti pada Geely EX2.&lt;/p&gt;

&lt;h2 id=&quot;pengisian-daya-di-indonesia&quot;&gt;Pengisian daya di Indonesia&lt;/h2&gt;

&lt;p&gt;Dua hal menentukan apakah mobil listrik cocok untukmu: kamu bisa mengisi di mana, dan berapa biayanya.&lt;/p&gt;

&lt;h3 id=&quot;di-rumah&quot;&gt;Di rumah&lt;/h3&gt;

&lt;p&gt;Pengisian di rumah semalaman adalah cara termurah, seperti terlihat di hitungan di bawah. Tarif listrik PLN untuk triwulan IV 2026 adalah Rp1.352 per kWh untuk golongan R-1 900 VA nonsubsidi, Rp1.444,70 per kWh untuk R-1 1.300 VA dan 2.200 VA, serta Rp1.699,53 per kWh untuk R-2 dan R-3 (&lt;a href=&quot;https://www.metrotvnews.com/read/NA0CzpEz-daftar-lengkap-tarif-listrik-pln-akhir-oktober-2026-per-kwh&quot;&gt;Metro TV, 29 Oktober 2026&lt;/a&gt;). Tarif bersubsidi untuk 900 VA, yaitu Rp605 per kWh, tidak saya pakai dalam hitungan.&lt;/p&gt;

&lt;p&gt;Contoh hitungan dengan BYD Atto 1 Premium, baterai 38,88 kWh (&lt;a href=&quot;https://listrikindonesia.com/detail/17430/mengupas-kapasitas-baterai-dan-jarak-tempuh-byd-atto-1&quot;&gt;Listrik Indonesia, 2 Agustus 2025&lt;/a&gt;), pelanggan R-1 1.300 VA:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Mengisi 38,88 kWh dari kosong sampai penuh: 38,88 × Rp1.444,70 = sekitar Rp56 ribu.&lt;/li&gt;
  &lt;li&gt;FuelEconomy.gov menyebut efisiensi pengisian baterai sering berada di 84% sampai 93% (&lt;a href=&quot;https://www.fueleconomy.gov/feg/evtech.shtml&quot;&gt;FuelEconomy.gov&lt;/a&gt;). Dengan rugi itu, listrik yang ditarik dari dinding menjadi sekitar 41,8 sampai 46,3 kWh, sehingga biayanya sekitar Rp60 ribu sampai Rp67 ribu.&lt;/li&gt;
  &lt;li&gt;Dengan klaim jarak 380 km, itu berarti sekitar Rp160 sampai Rp176 per kilometer. Jarak nyata biasanya lebih pendek, jadi biaya per kilometer nyata lebih tinggi.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ini hitungan kasar. Tarif berubah per triwulan, dan rugi pengisian bergantung pada suhu, charger, dan kondisi baterai.&lt;/p&gt;

&lt;p&gt;Satu syarat praktis: mengisi di rumah butuh daya terpasang yang cukup dan titik colok yang aman. Tanyakan ke dealer atau PLN soal instalasinya sebelum memutuskan.&lt;/p&gt;

&lt;h3 id=&quot;di-spklu-umum&quot;&gt;Di SPKLU umum&lt;/h3&gt;

&lt;p&gt;SPKLU adalah singkatan stasiun pengisian kendaraan listrik umum. Kontan melaporkan PLN bersama mitra mengoperasikan 4.655 unit SPKLU di 3.007 lokasi sepanjang 2025, naik sekitar 44% dari 3.223 unit pada 2024 (&lt;a href=&quot;https://industri.kontan.co.id/news/meningkat-44-pln-operasikan-4655-spklu-sepanjang-2025&quot;&gt;Kontan, 8 Februari 2026&lt;/a&gt;). Kenaikannya cepat, dan titik pengisian di rute antarkota tetap perlu kamu cek sebelum berangkat.&lt;/p&gt;

&lt;p&gt;Okezone menyebut tarif dasar di SPKLU berada di kisaran Rp1.650 sampai Rp2.475 per kWh menurut aturan terbaru yang berlaku, tanpa menyebut nomor aturannya, dan SPKLU di jalan tol umumnya memasang tarif sekitar Rp2.466 sampai Rp2.475 per kWh (&lt;a href=&quot;https://www.rctiplus.com/news/detail/okezone/5343306/segini-tarif-cas-mobil-listrik-di-spklu-tol-untuk-mudik-lebaran-2026&quot;&gt;Okezone lewat RCTI+, 18 Maret 2026&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Pengisian cepat DC dikenai biaya tambahan per sesi: maksimal Rp25.000 untuk charger 25 sampai 50 kW, dan maksimal Rp57.000 untuk charger di atas 50 kW. Artikel itu merujuk Keputusan Menteri ESDM Nomor 182.K/TL.04/MEM.S/2023 untuk batas biaya tambahan tersebut.&lt;/p&gt;

&lt;p&gt;Kembali ke contoh Atto 1 Premium: mengisi 38,88 kWh pada tarif Rp2.475 per kWh menghabiskan sekitar Rp96 ribu, belum termasuk rugi pengisian dan biaya tambahan sesi. Selisihnya terhadap pengisian rumah sekitar Rp29 ribu sampai Rp40 ribu per pengisian penuh. Karena itu pola yang paling hemat adalah rumah untuk pemakaian harian dan SPKLU untuk perjalanan jauh. Sebelum membeli, tanyakan juga ke dealer jenis konektor AC dan DC yang dipakai mobilnya, karena tidak semua mobil dan SPKLU memakai colokan yang sama.&lt;/p&gt;

&lt;h3 id=&quot;biaya-mengisi-penuh-untuk-tiap-model&quot;&gt;Biaya mengisi penuh untuk tiap model&lt;/h3&gt;

&lt;p&gt;Dengan kapasitas baterai tiap model dan dua tarif di atas, kita bisa menghitung biaya mengisi dari kosong sampai penuh. Tabel ini memakai tarif rumah Rp1.444,70 per kWh (R-1 1.300 VA) dan tarif SPKLU Rp2.475 per kWh, tanpa rugi pengisian dan tanpa biaya tambahan sesi.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Model&lt;/th&gt;
      &lt;th&gt;Baterai (kWh)&lt;/th&gt;
      &lt;th&gt;Isi penuh di rumah&lt;/th&gt;
      &lt;th&gt;Isi penuh di SPKLU&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;VinFast VF 3&lt;/td&gt;
      &lt;td&gt;18,64&lt;/td&gt;
      &lt;td&gt;sekitar Rp27 ribu&lt;/td&gt;
      &lt;td&gt;sekitar Rp46 ribu&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;BYD Atto 1 Dynamic&lt;/td&gt;
      &lt;td&gt;30,08&lt;/td&gt;
      &lt;td&gt;sekitar Rp43 ribu&lt;/td&gt;
      &lt;td&gt;sekitar Rp74 ribu&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;BYD Atto 1 Premium&lt;/td&gt;
      &lt;td&gt;38,88&lt;/td&gt;
      &lt;td&gt;sekitar Rp56 ribu&lt;/td&gt;
      &lt;td&gt;sekitar Rp96 ribu&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Geely EX2&lt;/td&gt;
      &lt;td&gt;40,8&lt;/td&gt;
      &lt;td&gt;sekitar Rp59 ribu&lt;/td&gt;
      &lt;td&gt;sekitar Rp101 ribu&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;BYD M6 Standard&lt;/td&gt;
      &lt;td&gt;58&lt;/td&gt;
      &lt;td&gt;sekitar Rp84 ribu&lt;/td&gt;
      &lt;td&gt;sekitar Rp144 ribu&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Geely EX5&lt;/td&gt;
      &lt;td&gt;60,22&lt;/td&gt;
      &lt;td&gt;sekitar Rp87 ribu&lt;/td&gt;
      &lt;td&gt;sekitar Rp149 ribu&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Jaecoo J5 EV&lt;/td&gt;
      &lt;td&gt;60,9&lt;/td&gt;
      &lt;td&gt;sekitar Rp88 ribu&lt;/td&gt;
      &lt;td&gt;sekitar Rp151 ribu&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;MG S5 EV Magnify Max&lt;/td&gt;
      &lt;td&gt;62&lt;/td&gt;
      &lt;td&gt;sekitar Rp90 ribu&lt;/td&gt;
      &lt;td&gt;sekitar Rp153 ribu&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Wuling Darion EV&lt;/td&gt;
      &lt;td&gt;69,2&lt;/td&gt;
      &lt;td&gt;sekitar Rp100 ribu&lt;/td&gt;
      &lt;td&gt;sekitar Rp171 ribu&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;BYD Sealion 7&lt;/td&gt;
      &lt;td&gt;sekitar 82,6&lt;/td&gt;
      &lt;td&gt;sekitar Rp119 ribu&lt;/td&gt;
      &lt;td&gt;sekitar Rp204 ribu&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Denza D9&lt;/td&gt;
      &lt;td&gt;103,36&lt;/td&gt;
      &lt;td&gt;sekitar Rp149 ribu&lt;/td&gt;
      &lt;td&gt;sekitar Rp256 ribu&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Kapasitas baterai tiap model berasal dari sumber di bagian masing-masing mobil di &lt;a href=&quot;/2026/11/04/mobil-listrik-10-model-terlaris-cara-memilih&quot;&gt;Bagian 3&lt;/a&gt;. Dua hal perlu dicatat. Pertama, kamu jarang perlu mengisi dari 0% sampai 100% setiap hari, jadi biaya per pengisian biasanya lebih kecil dari angka tabel.&lt;/p&gt;

&lt;p&gt;Kedua, biaya per kilometer lebih berguna dari biaya per pengisian. Dengan klaim jarak pabrikan, baterai penuh di rumah menghabiskan sekitar Rp145 sampai Rp150 per kilometer untuk BYD Atto 1 dan Geely EX2, sekitar Rp190 untuk Jaecoo J5 EV dan BYD M6 Standard, dan sekitar Rp250 untuk Denza D9.&lt;/p&gt;

&lt;p&gt;Di SPKLU, angkanya sekitar 1,7 kali lipat. Karena jarak nyata biasanya lebih pendek dari klaim, biaya nyata per kilometer lebih tinggi dari angka ini.&lt;/p&gt;

&lt;h2 id=&quot;berapa-harga-mobil-listrik-dan-kenapa-angkanya-berubah-ubah&quot;&gt;Berapa harga mobil listrik dan kenapa angkanya berubah-ubah&lt;/h2&gt;

&lt;p&gt;Harga mobil listrik di Indonesia berubah cepat, dan satu model bisa muncul dengan angka berbeda di dua artikel yang terbit pada bulan yang sama. Ada tiga penyebab.&lt;/p&gt;

&lt;p&gt;Pertama, insentif pajak. Insentif PPN ditanggung pemerintah (PPN DTP) untuk mobil listrik dan keringanan bea masuk untuk mobil impor utuh (CBU) tidak berlanjut pada 2026. Listrik Indonesia memperkirakan kenaikan harga sekitar 5% sampai 15% setelah insentif dicabut (&lt;a href=&quot;https://listrikindonesia.com/detail/19930/insentif-pajak-dihapus-kapan-waktu-yang-tepat-beli-mobil-listrik&quot;&gt;Listrik Indonesia, 1 Mei 2026&lt;/a&gt;). Perkiraan itu pendapat media, bukan angka resmi.&lt;/p&gt;

&lt;p&gt;Kedua, rencana pengganti yang berkali-kali tertunda. Pemerintah merencanakan PPN DTP dengan tarif 100% untuk mobil listrik berbaterai berbasis nikel (NMC) dan 40% untuk baterai non-nikel seperti LFP (&lt;a href=&quot;https://news.ddtc.co.id/berita/nasional/1820265/ppn-dtp-kendaraan-listrik-belum-dirilis-airlangga-masih-dikaji-ulang&quot;&gt;DDTCNews, 23 Juni 2026&lt;/a&gt;).&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Waktu&lt;/th&gt;
      &lt;th&gt;Peristiwa&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Rencana awal&lt;/td&gt;
      &lt;td&gt;Mulai pertengahan 2026&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;26 Mei 2026&lt;/td&gt;
      &lt;td&gt;Menteri Keuangan Purbaya menyatakan pelaksanaan ditunda untuk menunggu perhitungan&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;23 Juni 2026&lt;/td&gt;
      &lt;td&gt;Menko Perekonomian Airlangga Hartarto menyebut insentif masih dikaji&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Sumber kronologi: &lt;a href=&quot;https://news.ddtc.co.id/berita/nasional/1820265/ppn-dtp-kendaraan-listrik-belum-dirilis-airlangga-masih-dikaji-ulang&quot;&gt;DDTCNews, 23 Juni 2026&lt;/a&gt;. Status setelah tanggal itu perlu kamu cek sendiri ke Kementerian Keuangan atau dealer sebelum membeli.&lt;/p&gt;

&lt;p&gt;Ketiga, promo dan harga peluncuran. Beberapa model dijual dengan harga khusus untuk pembeli pertama, lalu naik:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Jaecoo J5 EV naik dari Rp249,9 juta menjadi Rp279,9 juta untuk varian terendahnya (&lt;a href=&quot;https://oto.detik.com/mobil/d-8682899/harga-jaecoo-j5-naik-tak-ada-lagi-yang-di-bawah-rp-250-juta&quot;&gt;detikOto, 28 September 2026&lt;/a&gt;).&lt;/li&gt;
  &lt;li&gt;Wuling Darion EV dijual Rp356 juta (CE) untuk 1.500 pembeli pertama, lalu Rp399 juta pada September 2026 (&lt;a href=&quot;https://oto.detik.com/mobil-listrik/d-8197085/spesifikasi-wuling-darion-ada-varian-ev-dan-phev-harga-mulai-rp-356-juta&quot;&gt;detikOto&lt;/a&gt;; &lt;a href=&quot;https://otodriver.com/daftar-harga/2026/daftar-harga-wuling-terbaru-september-2026-dafefcff026&quot;&gt;Otodriver&lt;/a&gt;).&lt;/li&gt;
  &lt;li&gt;Geely EX2 mulai dari Rp229,9 juta (Pro) pada masa peluncuran, lalu Rp239,9 juta (&lt;a href=&quot;https://www.carmudi.co.id/journal/harga-geely-ex2-setelah-resmi-meluncur-di-indonesia-mulai-segini/&quot;&gt;Carmudi&lt;/a&gt;; &lt;a href=&quot;https://moladin.com/news/harga-otr-geely-terbaru-september-2026/&quot;&gt;Moladin&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Karena itu, setiap harga di tulisan ini saya tandai dengan sumber dan tanggal. Sumbernya media dan agregator otomotif, bukan daftar harga resmi merek, jadi anggap semua harga sebagai acuan awal, bukan penawaran.&lt;/p&gt;</content><author><name>Mahyuddin Susanto</name></author><category term="Mobil" /><category term="Otomotif" /><category term="mobil listrik" /><category term="bev" /><category term="baterai" /><category term="spklu" /><category term="harga mobil listrik" /><summary type="html">Daftar isi bagian ini</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.udienz.web.id/img/mobil-listrik-pengertian-jenis-cara-kerja.jpg" /><media:content medium="image" url="https://www.udienz.web.id/img/mobil-listrik-pengertian-jenis-cara-kerja.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Mobil Listrik (3/3): 10 Model Terlaris dan Cara Memilih</title><link href="https://www.udienz.web.id/2026/11/04/mobil-listrik-10-model-terlaris-cara-memilih" rel="alternate" type="text/html" title="Mobil Listrik (3/3): 10 Model Terlaris dan Cara Memilih" /><published>2026-11-04T00:00:01+00:00</published><updated>2026-11-04T00:00:01+00:00</updated><id>https://www.udienz.web.id/2026/11/04/mobil-listrik-10-model-terlaris-cara-memilih</id><content type="html" xml:base="https://www.udienz.web.id/2026/11/04/mobil-listrik-10-model-terlaris-cara-memilih">&lt;details class=&quot;toc&quot;&gt;
  &lt;summary&gt;Daftar isi bagian ini&lt;/summary&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#10-mobil-listrik-terlaris-di-indonesia&quot; id=&quot;markdown-toc-10-mobil-listrik-terlaris-di-indonesia&quot;&gt;10 mobil listrik terlaris di Indonesia&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#cara-saya-memilih-sepuluh-model-ini&quot; id=&quot;markdown-toc-cara-saya-memilih-sepuluh-model-ini&quot;&gt;Cara saya memilih sepuluh model ini&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#ringkasan-harga-baterai-dan-klaim-jarak&quot; id=&quot;markdown-toc-ringkasan-harga-baterai-dan-klaim-jarak&quot;&gt;Ringkasan: harga, baterai, dan klaim jarak&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#1-jaecoo-j5-ev&quot; id=&quot;markdown-toc-1-jaecoo-j5-ev&quot;&gt;1. Jaecoo J5 EV&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#2-byd-atto-1&quot; id=&quot;markdown-toc-2-byd-atto-1&quot;&gt;2. BYD Atto 1&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#3-geely-ex2&quot; id=&quot;markdown-toc-3-geely-ex2&quot;&gt;3. Geely EX2&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#4-byd-m6&quot; id=&quot;markdown-toc-4-byd-m6&quot;&gt;4. BYD M6&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#5-byd-sealion-7&quot; id=&quot;markdown-toc-5-byd-sealion-7&quot;&gt;5. BYD Sealion 7&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#6-wuling-darion-ev&quot; id=&quot;markdown-toc-6-wuling-darion-ev&quot;&gt;6. Wuling Darion EV&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#7-denza-d9&quot; id=&quot;markdown-toc-7-denza-d9&quot;&gt;7. Denza D9&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#8-mg-s5-ev&quot; id=&quot;markdown-toc-8-mg-s5-ev&quot;&gt;8. MG S5 EV&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#9-geely-ex5&quot; id=&quot;markdown-toc-9-geely-ex5&quot;&gt;9. Geely EX5&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#10-vinfast-vf-3&quot; id=&quot;markdown-toc-10-vinfast-vf-3&quot;&gt;10. VinFast VF 3&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#cara-memilih-mobil-listrik-yang-tepat&quot; id=&quot;markdown-toc-cara-memilih-mobil-listrik-yang-tepat&quot;&gt;Cara memilih mobil listrik yang tepat&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#berapa-jarak-harianmu&quot; id=&quot;markdown-toc-berapa-jarak-harianmu&quot;&gt;Berapa jarak harianmu?&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#bisakah-kamu-mengisi-di-rumah&quot; id=&quot;markdown-toc-bisakah-kamu-mengisi-di-rumah&quot;&gt;Bisakah kamu mengisi di rumah?&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#seberapa-jauh-kamu-percaya-angka-klaim&quot; id=&quot;markdown-toc-seberapa-jauh-kamu-percaya-angka-klaim&quot;&gt;Seberapa jauh kamu percaya angka klaim?&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#kapan-mobil-listrik-belum-cocok&quot; id=&quot;markdown-toc-kapan-mobil-listrik-belum-cocok&quot;&gt;Kapan mobil listrik belum cocok?&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#bagaimana-dengan-umur-baterai&quot; id=&quot;markdown-toc-bagaimana-dengan-umur-baterai&quot;&gt;Bagaimana dengan umur baterai?&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#pertanyaan-yang-sering-muncul&quot; id=&quot;markdown-toc-pertanyaan-yang-sering-muncul&quot;&gt;Pertanyaan yang sering muncul&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#berapa-lama-mengisi-mobil-listrik-sampai-penuh&quot; id=&quot;markdown-toc-berapa-lama-mengisi-mobil-listrik-sampai-penuh&quot;&gt;Berapa lama mengisi mobil listrik sampai penuh?&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#berapa-biaya-mengisi-mobil-listrik&quot; id=&quot;markdown-toc-berapa-biaya-mengisi-mobil-listrik&quot;&gt;Berapa biaya mengisi mobil listrik?&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#apakah-hybrid-termasuk-mobil-listrik&quot; id=&quot;markdown-toc-apakah-hybrid-termasuk-mobil-listrik&quot;&gt;Apakah hybrid termasuk mobil listrik?&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#apakah-insentif-pajak-mobil-listrik-masih-ada&quot; id=&quot;markdown-toc-apakah-insentif-pajak-mobil-listrik-masih-ada&quot;&gt;Apakah insentif pajak mobil listrik masih ada?&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#apakah-mobil-listrik-bisa-dipakai-mudik&quot; id=&quot;markdown-toc-apakah-mobil-listrik-bisa-dipakai-mudik&quot;&gt;Apakah mobil listrik bisa dipakai mudik?&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#penutup&quot; id=&quot;markdown-toc-penutup&quot;&gt;Penutup&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#tentang-tulisan-ini&quot; id=&quot;markdown-toc-tentang-tulisan-ini&quot;&gt;Tentang tulisan ini&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#sumber-utama&quot; id=&quot;markdown-toc-sumber-utama&quot;&gt;Sumber utama&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;/details&gt;

&lt;h2 id=&quot;10-mobil-listrik-terlaris-di-indonesia&quot;&gt;10 mobil listrik terlaris di Indonesia&lt;/h2&gt;

&lt;h3 id=&quot;cara-saya-memilih-sepuluh-model-ini&quot;&gt;Cara saya memilih sepuluh model ini&lt;/h3&gt;

&lt;p&gt;“Populer” bisa diartikan banyak hal. Saya memakai ukuran yang bisa diperiksa: jumlah unit yang tercatat menurut Gaikindo pada periode Januari sampai September 2026, sebagaimana dilaporkan Kontan pada 12 Oktober 2026 (&lt;a href=&quot;https://industri.kontan.co.id/news/10-mobil-listrik-terlaris-di-indonesia-hingga-september-2026&quot;&gt;Kontan&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Angka Gaikindo adalah angka distribusi dari pabrik ke dealer (wholesales), bukan penjualan eceran ke konsumen akhir. GoodStats menjelaskan istilah itu sebagai “jumlah kendaraan yang dikirim dari pabrikan ke dealer” (&lt;a href=&quot;https://data.goodstats.id/statistic/10-mobil-listrik-terlaris-semester-i-2026-jaecoo-j5-di-puncak-dRODE&quot;&gt;GoodStats, 23 Juli 2026&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Jadi urutan di bawah mencerminkan pengiriman ke dealer, yang biasanya sejalan dengan pembelian tetapi tidak persis sama.&lt;/p&gt;

&lt;p&gt;Total sepuluh model ini 89.502 unit pada sembilan bulan pertama 2026. Grafik di bawah menunjukkan sebaran per model.&lt;/p&gt;

&lt;figure class=&quot;blog-chart&quot;&gt;
&lt;svg viewBox=&quot;0 0 400 396&quot; width=&quot;400&quot; height=&quot;396&quot; role=&quot;img&quot; aria-label=&quot;Diagram batang penjualan wholesales sepuluh mobil listrik terlaris di Indonesia, Januari sampai September 2026, data Gaikindo via Kontan. Jaecoo J5 EV 26.635 unit, BYD Atto 1 24.749 unit, Geely EX2 11.659 unit, BYD M6 7.043 unit, BYD Sealion 7 4.266 unit, Wuling Darion EV 4.020 unit, Denza D9 3.009 unit, MG S5 EV 2.914 unit, Geely EX5 2.760 unit, VinFast VF 3 2.447 unit.&quot;&gt;
&lt;text x=&quot;200&quot; y=&quot;24&quot; text-anchor=&quot;middle&quot; font-size=&quot;16&quot; fill=&quot;currentColor&quot;&gt;Penjualan 10 mobil listrik terlaris (unit)&lt;/text&gt;
&lt;text x=&quot;200&quot; y=&quot;45&quot; text-anchor=&quot;middle&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;Januari sampai September 2026, wholesales Gaikindo&lt;/text&gt;
&lt;line x1=&quot;130&quot; y1=&quot;58&quot; x2=&quot;130&quot; y2=&quot;378&quot; stroke=&quot;#9ca3af&quot;&gt;&lt;/line&gt;
&lt;text x=&quot;122&quot; y=&quot;80&quot; text-anchor=&quot;end&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;Jaecoo J5 EV&lt;/text&gt;
&lt;rect x=&quot;130&quot; y=&quot;64&quot; width=&quot;190.0&quot; height=&quot;22&quot; rx=&quot;4&quot; fill=&quot;#f97316&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;326.0&quot; y=&quot;80&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;26.635&lt;/text&gt;
&lt;text x=&quot;122&quot; y=&quot;112&quot; text-anchor=&quot;end&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;BYD Atto 1&lt;/text&gt;
&lt;rect x=&quot;130&quot; y=&quot;96&quot; width=&quot;176.5&quot; height=&quot;22&quot; rx=&quot;4&quot; fill=&quot;#38bdf8&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;312.5&quot; y=&quot;112&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;24.749&lt;/text&gt;
&lt;text x=&quot;122&quot; y=&quot;144&quot; text-anchor=&quot;end&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;Geely EX2&lt;/text&gt;
&lt;rect x=&quot;130&quot; y=&quot;128&quot; width=&quot;83.2&quot; height=&quot;22&quot; rx=&quot;4&quot; fill=&quot;#38bdf8&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;219.2&quot; y=&quot;144&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;11.659&lt;/text&gt;
&lt;text x=&quot;122&quot; y=&quot;176&quot; text-anchor=&quot;end&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;BYD M6&lt;/text&gt;
&lt;rect x=&quot;130&quot; y=&quot;160&quot; width=&quot;50.2&quot; height=&quot;22&quot; rx=&quot;4&quot; fill=&quot;#38bdf8&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;186.2&quot; y=&quot;176&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;7.043&lt;/text&gt;
&lt;text x=&quot;122&quot; y=&quot;208&quot; text-anchor=&quot;end&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;BYD Sealion 7&lt;/text&gt;
&lt;rect x=&quot;130&quot; y=&quot;192&quot; width=&quot;30.4&quot; height=&quot;22&quot; rx=&quot;4&quot; fill=&quot;#38bdf8&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;166.4&quot; y=&quot;208&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;4.266&lt;/text&gt;
&lt;text x=&quot;122&quot; y=&quot;240&quot; text-anchor=&quot;end&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;Wuling Darion EV&lt;/text&gt;
&lt;rect x=&quot;130&quot; y=&quot;224&quot; width=&quot;28.7&quot; height=&quot;22&quot; rx=&quot;4&quot; fill=&quot;#38bdf8&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;164.7&quot; y=&quot;240&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;4.020&lt;/text&gt;
&lt;text x=&quot;122&quot; y=&quot;272&quot; text-anchor=&quot;end&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;Denza D9&lt;/text&gt;
&lt;rect x=&quot;130&quot; y=&quot;256&quot; width=&quot;21.5&quot; height=&quot;22&quot; rx=&quot;4&quot; fill=&quot;#38bdf8&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;157.5&quot; y=&quot;272&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;3.009&lt;/text&gt;
&lt;text x=&quot;122&quot; y=&quot;304&quot; text-anchor=&quot;end&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;MG S5 EV&lt;/text&gt;
&lt;rect x=&quot;130&quot; y=&quot;288&quot; width=&quot;20.8&quot; height=&quot;22&quot; rx=&quot;4&quot; fill=&quot;#38bdf8&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;156.8&quot; y=&quot;304&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;2.914&lt;/text&gt;
&lt;text x=&quot;122&quot; y=&quot;336&quot; text-anchor=&quot;end&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;Geely EX5&lt;/text&gt;
&lt;rect x=&quot;130&quot; y=&quot;320&quot; width=&quot;19.7&quot; height=&quot;22&quot; rx=&quot;4&quot; fill=&quot;#38bdf8&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;155.7&quot; y=&quot;336&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;2.760&lt;/text&gt;
&lt;text x=&quot;122&quot; y=&quot;368&quot; text-anchor=&quot;end&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;VinFast VF 3&lt;/text&gt;
&lt;rect x=&quot;130&quot; y=&quot;352&quot; width=&quot;17.5&quot; height=&quot;22&quot; rx=&quot;4&quot; fill=&quot;#38bdf8&quot;&gt;&lt;/rect&gt;
&lt;text x=&quot;153.5&quot; y=&quot;368&quot; font-size=&quot;13&quot; fill=&quot;currentColor&quot;&gt;2.447&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption&gt;Sumber: &lt;a href=&quot;https://industri.kontan.co.id/news/10-mobil-listrik-terlaris-di-indonesia-hingga-september-2026&quot;&gt;Kontan&lt;/a&gt;, 12 Oktober 2026, mengutip data Gaikindo. Angka wholesales, yaitu pengiriman pabrikan ke dealer. Batang oranye: peringkat pertama.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Daftar ini bisa berubah menurut periode. Pada data semester I 2026 (Januari sampai Juni), GAC Aion V dan Wuling Eksion masuk sepuluh besar, sedangkan MG S5 EV dan VinFast VF 3 belum (&lt;a href=&quot;https://data.goodstats.id/statistic/10-mobil-listrik-terlaris-semester-i-2026-jaecoo-j5-di-puncak-dRODE&quot;&gt;GoodStats&lt;/a&gt;). Mobil di peringkat 1 sampai 7 sama di kedua periode (&lt;a href=&quot;https://data.goodstats.id/statistic/10-mobil-listrik-terlaris-semester-i-2026-jaecoo-j5-di-puncak-dRODE&quot;&gt;GoodStats&lt;/a&gt;; &lt;a href=&quot;https://industri.kontan.co.id/news/10-mobil-listrik-terlaris-di-indonesia-hingga-september-2026&quot;&gt;Kontan&lt;/a&gt;), dengan urutan yang konsisten.&lt;/p&gt;

&lt;h3 id=&quot;ringkasan-harga-baterai-dan-klaim-jarak&quot;&gt;Ringkasan: harga, baterai, dan klaim jarak&lt;/h3&gt;

&lt;p&gt;Harga di tabel berikut dalam rupiah, umumnya OTR Jakarta, dan sumber tiap angka ada di bagian masing-masing model. Klaim jarak tempuh berasal dari pabrikan berdasarkan siklus uji NEDC, kecuali ada keterangan lain.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;#&lt;/th&gt;
      &lt;th&gt;Model&lt;/th&gt;
      &lt;th&gt;Harga (jutaan Rp)&lt;/th&gt;
      &lt;th&gt;Baterai&lt;/th&gt;
      &lt;th&gt;Klaim jarak&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;Jaecoo J5 EV&lt;/td&gt;
      &lt;td&gt;279,9 (Standard) sampai 324,9 (Premium)&lt;/td&gt;
      &lt;td&gt;60,9 kWh&lt;/td&gt;
      &lt;td&gt;461 km&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;BYD Atto 1&lt;/td&gt;
      &lt;td&gt;199 sampai 245&lt;/td&gt;
      &lt;td&gt;30,08 sampai 38,88 kWh&lt;/td&gt;
      &lt;td&gt;300 sampai 380 km&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;3&lt;/td&gt;
      &lt;td&gt;Geely EX2&lt;/td&gt;
      &lt;td&gt;239,9 (Pro) sampai 269,9 (Max)&lt;/td&gt;
      &lt;td&gt;40,8 kWh LFP&lt;/td&gt;
      &lt;td&gt;395 km&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;4&lt;/td&gt;
      &lt;td&gt;BYD M6&lt;/td&gt;
      &lt;td&gt;395 sampai 445&lt;/td&gt;
      &lt;td&gt;58 kWh (Standard)&lt;/td&gt;
      &lt;td&gt;hingga 450 km (Standard)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;5&lt;/td&gt;
      &lt;td&gt;BYD Sealion 7&lt;/td&gt;
      &lt;td&gt;629 sampai 719 (harga tercantum, ketersediaan perlu dicek)&lt;/td&gt;
      &lt;td&gt;sekitar 82,6 kWh&lt;/td&gt;
      &lt;td&gt;542 sampai 567 km&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;6&lt;/td&gt;
      &lt;td&gt;Wuling Darion EV&lt;/td&gt;
      &lt;td&gt;399 (CE) sampai 459 (EX)&lt;/td&gt;
      &lt;td&gt;69,2 kWh LFP&lt;/td&gt;
      &lt;td&gt;540 km (CLTC)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;7&lt;/td&gt;
      &lt;td&gt;Denza D9&lt;/td&gt;
      &lt;td&gt;950&lt;/td&gt;
      &lt;td&gt;103,36 kWh&lt;/td&gt;
      &lt;td&gt;600 km&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;8&lt;/td&gt;
      &lt;td&gt;MG S5 EV&lt;/td&gt;
      &lt;td&gt;333,9 (harga khusus awal) sampai 410,9&lt;/td&gt;
      &lt;td&gt;62 kWh (Magnify Max)&lt;/td&gt;
      &lt;td&gt;410 sampai 545 km&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;9&lt;/td&gt;
      &lt;td&gt;Geely EX5&lt;/td&gt;
      &lt;td&gt;465 sampai 515&lt;/td&gt;
      &lt;td&gt;60,22 kWh&lt;/td&gt;
      &lt;td&gt;490 sampai 495 km&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;10&lt;/td&gt;
      &lt;td&gt;VinFast VF 3&lt;/td&gt;
      &lt;td&gt;152 (sewa baterai) sampai 215&lt;/td&gt;
      &lt;td&gt;18,64 kWh&lt;/td&gt;
      &lt;td&gt;210 km&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Berikut penjelasan tiap model.&lt;/p&gt;

&lt;h3 id=&quot;1-jaecoo-j5-ev&quot;&gt;1. Jaecoo J5 EV&lt;/h3&gt;

&lt;p&gt;Jaecoo J5 EV memimpin penjualan kumulatif dengan 26.635 unit pada Januari sampai September 2026, dan tercatat 3.276 unit pada September saja (&lt;a href=&quot;https://industri.kontan.co.id/news/10-mobil-listrik-terlaris-di-indonesia-hingga-september-2026&quot;&gt;Kontan&lt;/a&gt;; &lt;a href=&quot;https://www.gaikindo.or.id/20-model-mobil-terlaris-september-2026-atto-1-menempel-gran-max/&quot;&gt;Gaikindo&lt;/a&gt;). J5 EV unggul secara kumulatif, sedangkan pada September BYD Atto 1 tercatat lebih banyak dalam sebulan, yaitu 4.840 berbanding 3.276 unit.&lt;/p&gt;

&lt;p&gt;Harga per akhir September 2026 adalah Rp279,9 juta untuk Standard dan Rp324,9 juta untuk Premium, tercantum di situs resmi Jaecoo Indonesia (&lt;a href=&quot;https://oto.detik.com/mobil/d-8682899/harga-jaecoo-j5-naik-tak-ada-lagi-yang-di-bawah-rp-250-juta&quot;&gt;detikOto, 28 September 2026&lt;/a&gt;). Sebelumnya harganya Rp249,9 juta dan Rp299,9 juta. Menurut detikOto, per September 2026 tidak ada lagi J5 yang dijual di bawah Rp250 juta.&lt;/p&gt;

&lt;p&gt;Spesifikasinya: baterai 60,9 kWh, klaim 461 km (NEDC), motor 155 kW, dan pengisian DC sampai 130 kW dengan 30% ke 80% dalam 28 menit (&lt;a href=&quot;https://oto.detik.com/mobil-listrik/d-8182231/harga-resmi-jaecoo-j5-ev-diumumkan-3-november-ini-bocoran-spesifikasinya&quot;&gt;detikOto, 28 Oktober 2025&lt;/a&gt;). Standard dan Premium memakai motor dan baterai yang sama, dan selisihnya ada di fitur (&lt;a href=&quot;https://listrikindonesia.com/detail/17505/membedah-perbedaan-fitur-jaecoo-j5-ev-standard-vs-premium&quot;&gt;Listrik Indonesia, 10 Agustus 2025&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Dari tiga model terlaris, J5 EV punya klaim jarak terpanjang, dengan harga yang juga paling tinggi.&lt;/p&gt;

&lt;h3 id=&quot;2-byd-atto-1&quot;&gt;2. BYD Atto 1&lt;/h3&gt;

&lt;p&gt;BYD Atto 1 mencatat 24.749 unit pada sembilan bulan pertama 2026 dan 4.840 unit pada September, angka bulanan tertinggi di antara semua mobil listrik pada bulan itu.&lt;/p&gt;

&lt;p&gt;Daftar harga BYD edisi September 2026 mencantumkan tiga varian: Standard Rp199 juta, Dynamic Rp210 juta, dan Premium Rp245 juta (&lt;a href=&quot;https://otodriver.com/daftar-harga/2026/daftar-harga-byd-terbaru-september-2026-dafefdaa026&quot;&gt;Otodriver, 15 September 2026&lt;/a&gt;). Moladin pada 8 September 2026 mencatat angka yang sama (&lt;a href=&quot;https://moladin.com/news/daftar-mobil-listrik-termurah-september-2026/?show_all=1&quot;&gt;Moladin&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Varian Dynamic memakai baterai 30,08 kWh dengan klaim 300 km (NEDC), dan Premium memakai 38,88 kWh dengan klaim 380 km (&lt;a href=&quot;https://listrikindonesia.com/detail/17430/mengupas-kapasitas-baterai-dan-jarak-tempuh-byd-atto-1&quot;&gt;Listrik Indonesia, 2 Agustus 2025&lt;/a&gt;). Selisih harga Dynamic ke Premium Rp35 juta membeli baterai lebih besar dan fitur tambahan.&lt;/p&gt;

&lt;h3 id=&quot;3-geely-ex2&quot;&gt;3. Geely EX2&lt;/h3&gt;

&lt;p&gt;Geely EX2 tercatat 11.659 unit pada Januari sampai September 2026 dan 1.890 unit pada September, peringkat ke-15 dalam daftar semua model Gaikindo bulan itu (&lt;a href=&quot;https://www.gaikindo.or.id/20-model-mobil-terlaris-september-2026-atto-1-menempel-gran-max/&quot;&gt;Gaikindo&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Menurut Moladin edisi 2 September 2026, EX2 Pro Rp239,9 juta dan EX2 Max Rp269,9 juta OTR Jakarta (&lt;a href=&quot;https://moladin.com/news/harga-otr-geely-terbaru-september-2026/&quot;&gt;Moladin&lt;/a&gt;). Pada masa peluncuran, Geely menawarkan harga khusus Rp229,9 juta untuk Pro dan Rp259,9 juta untuk Max bagi pemesan sampai 15 Februari 2026 atau 2.000 konsumen pertama, dengan harga normal Rp255 juta dan Rp285 juta OTR Jakarta (&lt;a href=&quot;https://www.carmudi.co.id/journal/harga-geely-ex2-setelah-resmi-meluncur-di-indonesia-mulai-segini/&quot;&gt;Carmudi&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Baterainya 40,8 kWh LFP, klaim 395 km (NEDC), dan motornya 85 kW (&lt;a href=&quot;https://www.carmudi.co.id/journal/harga-geely-ex2-setelah-resmi-meluncur-di-indonesia-mulai-segini/&quot;&gt;Carmudi, 21 Januari 2026&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Dalam uji Carmudi sejauh sekitar 100 km dari Jakarta ke kawasan Cibodas dan Puncak, konsumsinya rata-rata 18,1 kWh per 100 km dengan mode Sport dan Comfort, dan baterai berkurang 49% (&lt;a href=&quot;https://www.carmudi.co.id/journal/test-drive-jakarta-cianjur-berapa-konsumsi-listrik-dan-daya-geely-ex2/&quot;&gt;Carmudi, 3 Februari 2026&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Baterai yang berkurang 49% untuk sekitar 100 km setara jarak sekitar 205 km per pengisian penuh, dan konsumsi 18,1 kWh per 100 km dengan baterai 40,8 kWh setara sekitar 225 km, jadi hasilnya sekitar 205 sampai 225 km. Ini hitungan saya dari satu uji jalan, bukan angka resmi, tetapi memberi gambaran bahwa jarak nyata di rute itu jauh dari klaim 395 km. Untuk mobil kota yang jarang melewati rute seperti itu, selisihnya lebih kecil.&lt;/p&gt;

&lt;h3 id=&quot;4-byd-m6&quot;&gt;4. BYD M6&lt;/h3&gt;

&lt;p&gt;BYD M6 adalah MPV listrik BYD dan tercatat 7.043 unit pada Januari sampai September 2026.&lt;/p&gt;

&lt;p&gt;Daftar harga BYD September 2026: Standard Rp395 juta, Superior Rp435 juta, dan Superior Captain Seat Rp445 juta (&lt;a href=&quot;https://otodriver.com/daftar-harga/2026/daftar-harga-byd-terbaru-september-2026-dafefdaa026&quot;&gt;Otodriver, 15 September 2026&lt;/a&gt;). Varian Standard pada 2026 mendapat baterai Blade 58 kWh dengan klaim sampai 450 km, dan tersedia dengan susunan enam atau tujuh kursi (&lt;a href=&quot;https://www.carmudi.co.id/journal/harga-rp395-juta-ini-pembaruan-byd-m6-ev-2026-varian-standard-di-giias-2026/&quot;&gt;Carmudi, 31 Juli 2026&lt;/a&gt;).&lt;/p&gt;

&lt;h3 id=&quot;5-byd-sealion-7&quot;&gt;5. BYD Sealion 7&lt;/h3&gt;

&lt;p&gt;BYD Sealion 7 tercatat 4.266 unit pada Januari sampai September 2026. Harga yang tercantum untuk Sealion 7 adalah Rp629 juta untuk Premium dan Rp719 juta untuk Performance (&lt;a href=&quot;https://www.zigwheels.co.id/en/mobil-baru/byd/sealion-7/harga/&quot;&gt;Zigwheels, dibuka 4 November 2026&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Ada catatan penting soal ketersediaan. Otodriver pada September 2026 mencatat bahwa Sealion 7 tidak lagi tampil di situs resmi BYD Indonesia (&lt;a href=&quot;https://otodriver.com/daftar-harga/2026/daftar-harga-byd-terbaru-september-2026-dafefdaa026&quot;&gt;Otodriver, 15 September 2026&lt;/a&gt;). Per 4 November 2026, halaman model BYD Indonesia memang hanya menampilkan Seal, Atto 3, M6 DM, M6, dan Atto 1 (&lt;a href=&quot;https://www.byd.com/id&quot;&gt;BYD Indonesia&lt;/a&gt;). Alasannya tidak dijelaskan di sumber mana pun yang dikutip di sini. Kalau kamu mengincar Sealion 7, tanyakan stok dan harga terkini langsung ke dealer.&lt;/p&gt;

&lt;p&gt;Spesifikasinya: baterai Blade sekitar 82,6 kWh, klaim 567 km untuk Premium dan 542 km untuk Performance (NEDC), dan Performance berpenggerak semua roda dengan tenaga 523 hp (&lt;a href=&quot;https://www.carmudi.co.id/journal/spesifikasi-byd-sealion-7-sanggup-tempuh-567-km-sekali-cas/&quot;&gt;Carmudi, 16 Februari 2025&lt;/a&gt;).&lt;/p&gt;

&lt;h3 id=&quot;6-wuling-darion-ev&quot;&gt;6. Wuling Darion EV&lt;/h3&gt;

&lt;p&gt;Wuling Darion EV tercatat 4.020 unit pada sembilan bulan pertama 2026. Daftar harga Wuling edisi September 2026 mencantumkan CE Rp399 juta dan EX Rp459 juta OTR Jakarta (&lt;a href=&quot;https://otodriver.com/daftar-harga/2026/daftar-harga-wuling-terbaru-september-2026-dafefcff026&quot;&gt;Otodriver&lt;/a&gt;). Harga peluncurannya Rp356 juta untuk CE dan Rp416 juta untuk EX bagi 1.500 pembeli pertama.&lt;/p&gt;

&lt;p&gt;Baterainya LFP 69,2 kWh, klaim 540 km berdasarkan siklus CLTC, motor 150 kW penggerak roda depan, dan susunan tujuh kursi (&lt;a href=&quot;https://oto.detik.com/mobil-listrik/d-8197085/spesifikasi-wuling-darion-ada-varian-ev-dan-phev-harga-mulai-rp-356-juta&quot;&gt;detikOto, 6 November 2025&lt;/a&gt;). CLTC dan NEDC memakai pola uji yang berbeda, jadi jangan bandingkan 540 km ini langsung dengan angka NEDC mobil lain di daftar.&lt;/p&gt;

&lt;h3 id=&quot;7-denza-d9&quot;&gt;7. Denza D9&lt;/h3&gt;

&lt;p&gt;Denza D9 tercatat 3.009 unit pada Januari sampai September 2026, dan merupakan satu-satunya model berharga di atas Rp900 juta di daftar ini. Harganya Rp950 juta untuk varian FWD (&lt;a href=&quot;https://otodriver.com/daftar-harga/2026/daftar-harga-byd-terbaru-september-2026-dafefdaa026&quot;&gt;Otodriver, 15 September 2026&lt;/a&gt;), sama dengan harga peluncurannya, Rp950 juta OTR Jakarta (&lt;a href=&quot;https://listrikindonesia.com/detail/15468/harganya-bikin-alphard-ketar-ketir-ini-spesifikasi-byd-denza-d9&quot;&gt;Listrik Indonesia, 24 Januari 2025&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Baterainya 103,36 kWh dengan klaim 600 km dan motor tunggal 308 dk, dalam susunan kursi 2+2+3 atau 2+3+3, menurut artikel peluncuran Listrik Indonesia yang sama. Artikel itu menyebut siklus ujinya “NDC”, jadi bandingkan klaim ini dengan hati-hati. Media otomotif sering menempatkannya sebagai alternatif listrik untuk MPV mewah seperti Toyota Alphard.&lt;/p&gt;

&lt;h3 id=&quot;8-mg-s5-ev&quot;&gt;8. MG S5 EV&lt;/h3&gt;

&lt;p&gt;MG S5 EV tercatat 2.914 unit pada sembilan bulan pertama 2026. Harganya berubah beberapa kali sepanjang tahun, jadi saya susun jejaknya dalam satu tabel (OTR Jakarta).&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Waktu&lt;/th&gt;
      &lt;th&gt;Ignite&lt;/th&gt;
      &lt;th&gt;Magnify&lt;/th&gt;
      &lt;th&gt;Magnify Max&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Peluncuran, Februari 2026&lt;/td&gt;
      &lt;td&gt;Rp357,9 juta&lt;/td&gt;
      &lt;td&gt;Rp374,9 juta&lt;/td&gt;
      &lt;td&gt;Rp455,9 juta&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Harga khusus 1.500 pembeli pertama&lt;/td&gt;
      &lt;td&gt;Rp333,9 juta&lt;/td&gt;
      &lt;td&gt;Rp355,9 juta&lt;/td&gt;
      &lt;td&gt;tidak disebut&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Juli 2026&lt;/td&gt;
      &lt;td&gt;Rp333,9 juta&lt;/td&gt;
      &lt;td&gt;Rp355,9 juta&lt;/td&gt;
      &lt;td&gt;Rp399,9 juta sampai akhir September 2026, dari Rp410,9 juta&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Sumber: &lt;a href=&quot;https://www.kabarbursa.com/otomotif/mg-s5-ev-resmi-meluncur-di-iims-2026-harga-mulai-rp3339-juta.md&quot;&gt;Kabarbursa, 6 Februari 2026&lt;/a&gt; dan &lt;a href=&quot;https://www.kabarbursa.com/otomotif/mg-potong-harga-s5-ev-jadi-rp3999-juta-sekaligus-pamer-suv-hybrid-baru.md&quot;&gt;Kabarbursa, 17 Juli 2026&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Promo Magnify Max sudah berakhir pada akhir September, jadi Rp410,9 juta lebih aman dipakai. Angka itu lebih rendah dari Rp455,9 juta saat peluncuran, dan artikelnya tidak menjelaskan alasannya. Ignite dan Magnify masih tertulis Rp333,9 juta dan Rp355,9 juta pada Juli, padahal itu harga khusus 1.500 pembeli pertama, jadi tanyakan apakah harga itu masih berlaku.&lt;/p&gt;

&lt;p&gt;Klaim jarak Ignite sampai 415 km dan Magnify sampai 410 km. Magnify Max memakai baterai 62 kWh dengan motor 201,2 HP dan klaim 545 km (NEDC), menurut artikel Juli yang sama. Artikel peluncuran mencatat garansi baterai 8 tahun atau 160.000 km.&lt;/p&gt;

&lt;h3 id=&quot;9-geely-ex5&quot;&gt;9. Geely EX5&lt;/h3&gt;

&lt;p&gt;Geely EX5 tercatat 2.760 unit pada Januari sampai September 2026. Harga OTR Jakarta menurut Moladin edisi 2 September 2026: Pro Rp465 juta sampai Rp475 juta dan Max Rp505 juta sampai Rp515 juta, tergantung apakah harga khusus masih berlaku (&lt;a href=&quot;https://moladin.com/news/harga-otr-geely-terbaru-september-2026/&quot;&gt;Moladin&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Baterainya 60,22 kWh (short blade), klaim 495 km untuk Pro dan 490 km untuk Max (NEDC), dengan pengisian cepat 30% ke 80% dalam 20 menit dan daya tahan lebih dari 3.500 siklus pengisian menurut klaim (&lt;a href=&quot;https://www.idxchannel.com/technology/hadir-kembali-di-pasar-otomotif-ri-geely-hadirkan-mobil-listrik-dengan-segudang-teknologi&quot;&gt;IDX Channel, 22 Februari 2025&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Uji jalan Carmudi pada Mei 2025 dari Jakarta ke Bandung sejauh sekitar 154 km dengan tiga penumpang dan bagasi, kecepatan rata-rata sekitar 80 km/jam di tol, menghasilkan konsumsi 19,4 kWh per 100 km (&lt;a href=&quot;https://www.carmudi.co.id/journal/test-drive-jakarta-bandung-segini-konsumsi-daya-geely-ex5/&quot;&gt;Carmudi, 20 Mei 2025&lt;/a&gt;). Dengan baterai 60,22 kWh, itu setara sekitar 310 km per pengisian penuh, jauh di bawah klaim 490 sampai 495 km. Hitungan itu dari saya dan hanya berlaku untuk kondisi uji tersebut.&lt;/p&gt;

&lt;h3 id=&quot;10-vinfast-vf-3&quot;&gt;10. VinFast VF 3&lt;/h3&gt;

&lt;p&gt;VinFast VF 3 tercatat 2.447 unit pada Januari sampai September 2026. Moladin pada 8 September 2026 mencatat dua harga: Rp152 juta dengan skema sewa baterai dan Rp215 juta di luar skema sewa (&lt;a href=&quot;https://moladin.com/news/daftar-mobil-listrik-termurah-september-2026/?show_all=1&quot;&gt;Moladin&lt;/a&gt;). Halaman yang sama menampilkan kisaran Rp156 juta sampai Rp230,1 juta pada widget harga, jadi cek ulang angkanya ke dealer.&lt;/p&gt;

&lt;p&gt;Dengan sewa baterai, kamu membayar harga mobil yang lebih rendah, tetapi ada biaya sewa baterai berkala dan baterai tidak otomatis menjadi milikmu. Hitung total biaya selama tiga sampai lima tahun sebelum memilih skema.&lt;/p&gt;

&lt;p&gt;Spesifikasinya: baterai 18,64 kWh, klaim 210 km (NEDC), dan motor 32 kW (&lt;a href=&quot;https://listrikindonesia.com/detail/15531/siap-ramaikan-pasar-ev-indonesia-ini-spesifikasi-vf-3&quot;&gt;Listrik Indonesia, 31 Januari 2025&lt;/a&gt;).&lt;/p&gt;

&lt;h2 id=&quot;cara-memilih-mobil-listrik-yang-tepat&quot;&gt;Cara memilih mobil listrik yang tepat&lt;/h2&gt;

&lt;p&gt;Daftar di atas mengurutkan model berdasarkan penjualan, bukan kecocokan. Tabel berikut mengelompokkannya menurut kebutuhan, memakai harga dan klaim yang sudah dibahas di atas. Angkanya tetap angka klaim dan harga September 2026, jadi cek ulang sebelum memutuskan.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Kebutuhan&lt;/th&gt;
      &lt;th&gt;Model yang layak dilihat&lt;/th&gt;
      &lt;th&gt;Dasar pertimbangan&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Harga masuk termurah&lt;/td&gt;
      &lt;td&gt;VinFast VF 3, BYD Atto 1&lt;/td&gt;
      &lt;td&gt;VF 3 mulai Rp152 juta dengan sewa baterai (klaim 210 km); Atto 1 Dynamic Rp210 juta (klaim 300 km)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Mobil kota dengan jarak menengah&lt;/td&gt;
      &lt;td&gt;Geely EX2, BYD Atto 1 Premium&lt;/td&gt;
      &lt;td&gt;EX2 Pro Rp239,9 juta (klaim 395 km); Atto 1 Premium Rp245 juta (klaim 380 km)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Klaim jarak terpanjang di bawah Rp350 juta&lt;/td&gt;
      &lt;td&gt;Jaecoo J5 EV&lt;/td&gt;
      &lt;td&gt;Standard Rp279,9 juta dengan klaim 461 km; MG S5 EV Ignite Rp333,9 juta (harga khusus awal, cek) dengan klaim 415 km&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Keluarga enam atau tujuh kursi&lt;/td&gt;
      &lt;td&gt;BYD M6, Wuling Darion EV&lt;/td&gt;
      &lt;td&gt;M6 Standard Rp395 juta (klaim 450 km); Darion EV CE Rp399 juta (klaim 540 km, siklus CLTC)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Pengisian cepat yang diklaim singkat&lt;/td&gt;
      &lt;td&gt;Geely EX5, Jaecoo J5 EV&lt;/td&gt;
      &lt;td&gt;EX5 mengklaim 20 menit untuk 30% ke 80%, J5 EV 28 menit&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Segmen premium&lt;/td&gt;
      &lt;td&gt;BYD Sealion 7, Denza D9&lt;/td&gt;
      &lt;td&gt;Sealion 7 Rp629 juta sampai Rp719 juta (ketersediaan perlu dicek); D9 Rp950 juta dengan klaim 600 km&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Lima pertanyaan berikut lebih menentukan daripada peringkat penjualan.&lt;/p&gt;

&lt;h3 id=&quot;berapa-jarak-harianmu&quot;&gt;Berapa jarak harianmu?&lt;/h3&gt;

&lt;p&gt;Hitung dulu jarak rata-rata hariannya. Kalau kamu menempuh sekitar 50 km pulang pergi, klaim 300 km BYD Atto 1 Dynamic sudah jauh di atas kebutuhan, dan kamu tidak perlu membayar mahal untuk baterai yang jauh lebih besar. Kalau kamu sering ke luar kota, jarak tempuh nyata dan kecepatan pengisian cepat jadi lebih penting dari harga.&lt;/p&gt;

&lt;h3 id=&quot;bisakah-kamu-mengisi-di-rumah&quot;&gt;Bisakah kamu mengisi di rumah?&lt;/h3&gt;

&lt;p&gt;Ini pertanyaan yang paling menentukan. Mengisi di rumah semalaman membuat jarak tempuh hampir tidak jadi masalah untuk pemakaian harian. Tanpa titik pengisian di rumah atau kantor, kamu bergantung penuh pada SPKLU, dan tarifnya lebih tinggi seperti dihitung di atas.&lt;/p&gt;

&lt;h3 id=&quot;seberapa-jauh-kamu-percaya-angka-klaim&quot;&gt;Seberapa jauh kamu percaya angka klaim?&lt;/h3&gt;

&lt;p&gt;Klaim jarak tempuh pabrikan adalah angka uji di bawah kondisi standar. Dua uji jalan di atas, yaitu Geely EX2 dan Geely EX5, menghasilkan jarak hitungan sekitar 205 sampai 225 km dan 310 km, atau sekitar 52% sampai 57% dan 63% dari klaim 395 km dan 490 sampai 495 km. Dua contoh itu bukan bukti untuk semua mobil. Konsumsi dipengaruhi kecepatan, medan, jumlah penumpang, penyejuk udara, dan mode berkendara. Perlakukan klaim sebagai batas atas, lalu sesuaikan perencanaanmu setelah tahu konsumsi nyata mobilmu.&lt;/p&gt;

&lt;h3 id=&quot;kapan-mobil-listrik-belum-cocok&quot;&gt;Kapan mobil listrik belum cocok?&lt;/h3&gt;

&lt;p&gt;Ada situasi yang membuat mobil listrik kurang praktis, dan lebih jujur membahasnya sebelum membeli.&lt;/p&gt;

&lt;p&gt;Kalau kamu tinggal di apartemen atau rumah tanpa titik pengisian dan tempat parkirmu tidak punya colokan, kamu bergantung pada SPKLU. Hitungan biaya di &lt;a href=&quot;/2026/11/04/mobil-listrik-cara-kerja-pengisian-harga#biaya-mengisi-penuh-untuk-tiap-model&quot;&gt;Bagian 2&lt;/a&gt; menunjukkan SPKLU sekitar 1,7 kali lebih mahal dari rumah dan butuh waktu khusus untuk singgah. PLN dan mitranya mengoperasikan 3.007 lokasi SPKLU pada 2025.&lt;/p&gt;

&lt;p&gt;Rute yang panjang tanpa cadangan menambah risiko: misalnya sering melewati daerah tanpa SPKLU, klaim jarak yang tampak cukup di brosur bisa menjadi tipis. Dua uji jalan Geely di atas menunjukkan jarak hitungan 52% sampai 63% dari klaim. Pada rute seperti itu, PHEV atau hybrid bisa lebih masuk akal, karena mesin bensin menutup kekurangan jarak.&lt;/p&gt;

&lt;p&gt;Untuk anggaran yang ketat dan nilai jual kembali, ingat bahwa harga mobil listrik di Indonesia berubah cepat, seperti yang terlihat dari kenaikan harga Jaecoo J5 EV dan perubahan harga Wuling Darion EV dalam beberapa bulan.&lt;/p&gt;

&lt;p&gt;Mobil listrik paling masuk akal ketika kamu bisa mengisi di rumah, rutemu rata-rata pendek, dan kamu menghitung biaya per tahun termasuk listrik, tidak berhenti di harga beli.&lt;/p&gt;

&lt;h3 id=&quot;bagaimana-dengan-umur-baterai&quot;&gt;Bagaimana dengan umur baterai?&lt;/h3&gt;

&lt;p&gt;Studi Departemen Energi AS menyebut baterai bisa bertahan 12 sampai 15 tahun di iklim sedang dan 8 sampai 12 tahun di iklim berat, dan penggantiannya bisa mahal kalau baterai rusak (&lt;a href=&quot;https://www.fueleconomy.gov/feg/evtech.shtml&quot;&gt;FuelEconomy.gov&lt;/a&gt;). Sumber itu tidak merinci iklim tropis, jadi pakai rentang bawah sebagai acuan hati-hati. Cek masa garansi baterai: MG, misalnya, menyebut 8 tahun atau 160.000 km untuk S5 EV.&lt;/p&gt;

&lt;h2 id=&quot;pertanyaan-yang-sering-muncul&quot;&gt;Pertanyaan yang sering muncul&lt;/h2&gt;

&lt;h3 id=&quot;berapa-lama-mengisi-mobil-listrik-sampai-penuh&quot;&gt;Berapa lama mengisi mobil listrik sampai penuh?&lt;/h3&gt;

&lt;p&gt;Pengisian penuh lewat AC bisa memakan 3 sampai 12 jam, tergantung kapasitas baterai dan daya charger. Pengisian cepat DC sampai 80% biasanya sekitar 20 sampai 30 menit untuk mobil yang mendukungnya.&lt;/p&gt;

&lt;h3 id=&quot;berapa-biaya-mengisi-mobil-listrik&quot;&gt;Berapa biaya mengisi mobil listrik?&lt;/h3&gt;

&lt;p&gt;Untuk BYD Atto 1 Premium dengan baterai 38,88 kWh, mengisi penuh di rumah dengan tarif Rp1.444,70 per kWh menghabiskan sekitar Rp60 ribu sampai Rp67 ribu setelah memperhitungkan rugi pengisian. Di SPKLU dengan tarif Rp2.475 per kWh, biayanya sekitar Rp96 ribu atau lebih.&lt;/p&gt;

&lt;h3 id=&quot;apakah-hybrid-termasuk-mobil-listrik&quot;&gt;Apakah hybrid termasuk mobil listrik?&lt;/h3&gt;

&lt;p&gt;Tidak, kalau yang dimaksud mobil listrik murni. HEV dan PHEV masih memakai mesin bensin. PHEV bisa dicolok dan menempuh sekitar 32 sampai 64 km dengan listrik saja, sedangkan HEV tidak bisa dicolok sama sekali.&lt;/p&gt;

&lt;h3 id=&quot;apakah-insentif-pajak-mobil-listrik-masih-ada&quot;&gt;Apakah insentif pajak mobil listrik masih ada?&lt;/h3&gt;

&lt;p&gt;Insentif lama berakhir. Rencana PPN DTP baru (100% untuk baterai nikel, 40% untuk non-nikel) masih dikaji pada 23 Juni 2026. Cek status terbarunya ke Kementerian Keuangan atau dealer.&lt;/p&gt;

&lt;h3 id=&quot;apakah-mobil-listrik-bisa-dipakai-mudik&quot;&gt;Apakah mobil listrik bisa dipakai mudik?&lt;/h3&gt;

&lt;p&gt;Bisa, dengan perencanaan. Pastikan baterai penuh sebelum berangkat, rencanakan titik SPKLU di sepanjang rute, dan jangan mengandalkan klaim jarak penuh. Pengisian cepat 30% ke 80% yang diklaim 20 sampai 28 menit pada Geely EX5 dan Jaecoo J5 EV membuat singgah di SPKLU relatif singkat, tetapi antrean dan SPKLU yang sedang rusak tetap mungkin terjadi.&lt;/p&gt;

&lt;h2 id=&quot;penutup&quot;&gt;Penutup&lt;/h2&gt;

&lt;p&gt;Mobil listrik sudah masuk jajaran model terlaris di Indonesia pada 2026, tetapi memilihnya tidak cukup dengan membandingkan harga. Untuk pemakaian dalam kota dengan titik pengisian di rumah, BYD Atto 1, Geely EX2, dan Jaecoo J5 EV memberi jarak tempuh klaim yang cukup di kisaran Rp200 jutaan sampai Rp300 jutaan. Untuk keluarga besar, BYD M6 dan Wuling Darion EV menawarkan kursi lebih banyak. Untuk perjalanan antarkota, kecepatan pengisian cepat dan ketersediaan SPKLU lebih menentukan daripada angka kapasitas baterai.&lt;/p&gt;

&lt;p&gt;Sebelum membeli, tanyakan tiga hal ke dealer: harga OTR terbaru dengan semua biaya, konektor pengisian yang dipakai mobilnya, dan masa garansi baterai. Ketiganya menentukan biaya sebenarnya, dan tidak bisa dibaca dari brosur saja.&lt;/p&gt;

&lt;h2 id=&quot;tentang-tulisan-ini&quot;&gt;Tentang tulisan ini&lt;/h2&gt;

&lt;p&gt;Saya Mahyuddin Susanto, penulis blog ini. Latar belakang saya di jaringan dan infrastruktur TI, bukan otomotif (profil lengkap ada di halaman &lt;a href=&quot;/about&quot;&gt;About&lt;/a&gt;), jadi artikel ini adalah rangkuman dari sumber publik yang dikutip di dalam teks, ditambah hitungan dari data sumber itu. Saya tidak menguji mobilnya sendiri. Kalau kamu menemukan angka yang sudah berubah atau keliru, kirim lewat halaman &lt;a href=&quot;/contact&quot;&gt;Contact&lt;/a&gt;. Angka yang terbukti berubah akan saya perbarui di artikel ini dan tanggalnya saya catat.&lt;/p&gt;

&lt;h2 id=&quot;sumber-utama&quot;&gt;Sumber utama&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Gaikindo, &lt;a href=&quot;https://www.gaikindo.or.id/20-model-mobil-terlaris-september-2026-atto-1-menempel-gran-max/&quot;&gt;20 model mobil terlaris September 2026&lt;/a&gt;, 25 Oktober 2026&lt;/li&gt;
  &lt;li&gt;Kontan, &lt;a href=&quot;https://industri.kontan.co.id/news/10-mobil-listrik-terlaris-di-indonesia-hingga-september-2026&quot;&gt;10 mobil listrik terlaris hingga September 2026&lt;/a&gt;, 12 Oktober 2026&lt;/li&gt;
  &lt;li&gt;GoodStats Data, &lt;a href=&quot;https://data.goodstats.id/statistic/10-mobil-listrik-terlaris-semester-i-2026-jaecoo-j5-di-puncak-dRODE&quot;&gt;10 mobil listrik terlaris semester I 2026&lt;/a&gt;, 23 Juli 2026&lt;/li&gt;
  &lt;li&gt;U.S. Department of Energy, &lt;a href=&quot;https://afdc.energy.gov/vehicles/electric&quot;&gt;Alternative Fuels Data Center&lt;/a&gt; dan &lt;a href=&quot;https://www.fueleconomy.gov/feg/evtech.shtml&quot;&gt;FuelEconomy.gov&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Metro TV, &lt;a href=&quot;https://www.metrotvnews.com/read/NA0CzpEz-daftar-lengkap-tarif-listrik-pln-akhir-oktober-2026-per-kwh&quot;&gt;tarif listrik PLN akhir Oktober 2026&lt;/a&gt;, 29 Oktober 2026&lt;/li&gt;
  &lt;li&gt;Okezone, &lt;a href=&quot;https://www.rctiplus.com/news/detail/okezone/5343306/segini-tarif-cas-mobil-listrik-di-spklu-tol-untuk-mudik-lebaran-2026&quot;&gt;tarif cas mobil listrik di SPKLU tol&lt;/a&gt;, 18 Maret 2026&lt;/li&gt;
  &lt;li&gt;Kontan, &lt;a href=&quot;https://industri.kontan.co.id/news/meningkat-44-pln-operasikan-4655-spklu-sepanjang-2025&quot;&gt;PLN operasikan 4.655 SPKLU sepanjang 2025&lt;/a&gt;, 8 Februari 2026&lt;/li&gt;
  &lt;li&gt;DDTCNews, &lt;a href=&quot;https://news.ddtc.co.id/berita/nasional/1820265/ppn-dtp-kendaraan-listrik-belum-dirilis-airlangga-masih-dikaji-ulang&quot;&gt;PPN DTP kendaraan listrik belum dirilis&lt;/a&gt;, 23 Juni 2026&lt;/li&gt;
  &lt;li&gt;Otodriver, daftar harga &lt;a href=&quot;https://otodriver.com/daftar-harga/2026/daftar-harga-byd-terbaru-september-2026-dafefdaa026&quot;&gt;BYD&lt;/a&gt; dan &lt;a href=&quot;https://otodriver.com/daftar-harga/2026/daftar-harga-wuling-terbaru-september-2026-dafefcff026&quot;&gt;Wuling&lt;/a&gt;, September 2026&lt;/li&gt;
  &lt;li&gt;Moladin, &lt;a href=&quot;https://moladin.com/news/harga-otr-geely-terbaru-september-2026/&quot;&gt;harga OTR Geely&lt;/a&gt; dan &lt;a href=&quot;https://moladin.com/news/daftar-mobil-listrik-termurah-september-2026/?show_all=1&quot;&gt;mobil listrik termurah&lt;/a&gt;, September 2026&lt;/li&gt;
  &lt;li&gt;Kabarbursa, &lt;a href=&quot;https://www.kabarbursa.com/otomotif/mg-s5-ev-resmi-meluncur-di-iims-2026-harga-mulai-rp3339-juta.md&quot;&gt;MG S5 EV&lt;/a&gt;, 6 Februari dan 17 Juli 2026&lt;/li&gt;
  &lt;li&gt;detikOto, &lt;a href=&quot;https://oto.detik.com/mobil/d-8682899/harga-jaecoo-j5-naik-tak-ada-lagi-yang-di-bawah-rp-250-juta&quot;&gt;harga Jaecoo J5 naik&lt;/a&gt;, 28 September 2026, &lt;a href=&quot;https://oto.detik.com/mobil-listrik/d-8182231/harga-resmi-jaecoo-j5-ev-diumumkan-3-november-ini-bocoran-spesifikasinya&quot;&gt;spesifikasi J5 EV&lt;/a&gt;, 28 Oktober 2025, dan &lt;a href=&quot;https://oto.detik.com/mobil-listrik/d-8197085/spesifikasi-wuling-darion-ada-varian-ev-dan-phev-harga-mulai-rp-356-juta&quot;&gt;spesifikasi Wuling Darion&lt;/a&gt;, 6 November 2025&lt;/li&gt;
  &lt;li&gt;Listrik Indonesia, &lt;a href=&quot;https://listrikindonesia.com/detail/17430/mengupas-kapasitas-baterai-dan-jarak-tempuh-byd-atto-1&quot;&gt;Atto 1&lt;/a&gt; (2 Agustus 2025), &lt;a href=&quot;https://listrikindonesia.com/detail/17505/membedah-perbedaan-fitur-jaecoo-j5-ev-standard-vs-premium&quot;&gt;Jaecoo J5 EV&lt;/a&gt; (10 Agustus 2025), &lt;a href=&quot;https://listrikindonesia.com/detail/15468/harganya-bikin-alphard-ketar-ketir-ini-spesifikasi-byd-denza-d9&quot;&gt;Denza D9&lt;/a&gt; (24 Januari 2025), &lt;a href=&quot;https://listrikindonesia.com/detail/15531/siap-ramaikan-pasar-ev-indonesia-ini-spesifikasi-vf-3&quot;&gt;VinFast VF 3&lt;/a&gt; (31 Januari 2025), dan &lt;a href=&quot;https://listrikindonesia.com/detail/19930/insentif-pajak-dihapus-kapan-waktu-yang-tepat-beli-mobil-listrik&quot;&gt;insentif pajak&lt;/a&gt; (1 Mei 2026)&lt;/li&gt;
  &lt;li&gt;Carmudi, &lt;a href=&quot;https://www.carmudi.co.id/journal/harga-geely-ex2-setelah-resmi-meluncur-di-indonesia-mulai-segini/&quot;&gt;Geely EX2&lt;/a&gt; (21 Januari 2026), &lt;a href=&quot;https://www.carmudi.co.id/journal/test-drive-jakarta-cianjur-berapa-konsumsi-listrik-dan-daya-geely-ex2/&quot;&gt;uji EX2&lt;/a&gt; (3 Februari 2026), &lt;a href=&quot;https://www.carmudi.co.id/journal/test-drive-jakarta-bandung-segini-konsumsi-daya-geely-ex5/&quot;&gt;uji EX5&lt;/a&gt; (20 Mei 2025), &lt;a href=&quot;https://www.carmudi.co.id/journal/harga-rp395-juta-ini-pembaruan-byd-m6-ev-2026-varian-standard-di-giias-2026/&quot;&gt;BYD M6&lt;/a&gt; (31 Juli 2026), dan &lt;a href=&quot;https://www.carmudi.co.id/journal/spesifikasi-byd-sealion-7-sanggup-tempuh-567-km-sekali-cas/&quot;&gt;BYD Sealion 7&lt;/a&gt; (16 Februari 2025)&lt;/li&gt;
  &lt;li&gt;IDX Channel, &lt;a href=&quot;https://www.idxchannel.com/technology/hadir-kembali-di-pasar-otomotif-ri-geely-hadirkan-mobil-listrik-dengan-segudang-teknologi&quot;&gt;spesifikasi Geely EX5&lt;/a&gt;, 22 Februari 2025&lt;/li&gt;
  &lt;li&gt;Foto hero: &lt;a href=&quot;https://unsplash.com/photos/a-white-car-plugged-in-to-a-charging-station-JkTjKEVcckg&quot;&gt;JUICE&lt;/a&gt; di &lt;a href=&quot;https://unsplash.com&quot;&gt;Unsplash&lt;/a&gt;, dipotong ke 1200 x 630&lt;/li&gt;
  &lt;li&gt;IEA, &lt;a href=&quot;https://www.iea.org/reports/global-ev-outlook-2026&quot;&gt;Global EV Outlook 2026&lt;/a&gt;; BPK, &lt;a href=&quot;https://peraturan.bpk.go.id/Details/116973/perpres-no-55&quot;&gt;Perpres 55/2019&lt;/a&gt; dan &lt;a href=&quot;https://peraturan.bpk.go.id/Details/273447&quot;&gt;Perpres 79/2023&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Zigwheels, &lt;a href=&quot;https://www.zigwheels.co.id/en/mobil-baru/byd/sealion-7/harga/&quot;&gt;harga BYD Sealion 7&lt;/a&gt;, dan &lt;a href=&quot;https://www.byd.com/id&quot;&gt;BYD Indonesia&lt;/a&gt;, keduanya dibuka 4 November 2026&lt;/li&gt;
&lt;/ul&gt;</content><author><name>Mahyuddin Susanto</name></author><category term="Mobil" /><category term="Otomotif" /><category term="mobil listrik" /><category term="bev" /><category term="baterai" /><category term="spklu" /><category term="harga mobil listrik" /><summary type="html">Daftar isi bagian ini</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.udienz.web.id/img/mobil-listrik-pengertian-jenis-cara-kerja.jpg" /><media:content medium="image" url="https://www.udienz.web.id/img/mobil-listrik-pengertian-jenis-cara-kerja.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Jenis Konektor Fiber Optic: SC, LC, FC, ST, MPO, VSFF</title><link href="https://www.udienz.web.id/2026/11/03/jenis-jenis-konektor-fiber-optic" rel="alternate" type="text/html" title="Jenis Konektor Fiber Optic: SC, LC, FC, ST, MPO, VSFF" /><published>2026-11-03T00:00:00+00:00</published><updated>2026-11-03T00:00:00+00:00</updated><id>https://www.udienz.web.id/2026/11/03/jenis-jenis-konektor-fiber-optic</id><content type="html" xml:base="https://www.udienz.web.id/2026/11/03/jenis-jenis-konektor-fiber-optic">&lt;p&gt;Pegang patch cord fiber dari laci, lalu lihat ujungnya. Bentuknya bisa persegi, bisa kecil berpasangan, bisa bulat berulir. Semuanya tugasnya sama: mempertemukan dua inti serat sehingga cahaya lewat dengan rugi sekecil mungkin. Yang beda adalah ukuran, cara kopling, dan tempat konektor itu cocok dipakai.&lt;/p&gt;

&lt;p&gt;Tulisan ini merangkum jenis konektor fiber optic yang paling sering ketemu di lapangan, mulai dari SC dan LC sampai konektor VSFF untuk transceiver 400G/800G. Saya juga bahas perbedaan UPC dan APC yang sering bikin salah beli, arti kode warna, dan angka insertion loss yang boleh dijadikan pegangan.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/jenis-konektor-fiber-optic-ferrule.png&quot; alt=&quot;Diagram perbandingan ferrule konektor fiber optic: 2,5 mm untuk SC, FC, ST dan 1,25 mm untuk LC, MU&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;Dua hal yang membedakan konektor: ukuran ferrule (2,5 mm untuk SC, FC, ST; 1,25 mm untuk LC dan MU) dan cara koplingnya.&lt;/li&gt;
    &lt;li&gt;UPC (biru) dan APC (hijau) tidak boleh dikawinkan langsung. Kalau polish-nya harus ganti, pakai patch cord hibrida.&lt;/li&gt;
    &lt;li&gt;Warna konektor membantu, tapi tanda cetak di kabel lebih bisa dipercaya.&lt;/li&gt;
    &lt;li&gt;Untuk densitas tinggi, LC adalah titik awal. MPO/MTP dan VSFF (SN, MDC) masuk saat port-nya sudah 400G/800G.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;apa-yang-membedakan-satu-konektor-dari-yang-lain&quot;&gt;Apa yang membedakan satu konektor dari yang lain?&lt;/h2&gt;

&lt;p&gt;Sebuah konektor fiber memegang serat di dalam ferrule, yaitu tabung kecil dengan lubang tepat di tengah. Dua ferrule dipertemukan di dalam adapter, dan kualitas pertemuan itulah yang menentukan loss. Ada tiga hal yang membedakan konektor.&lt;/p&gt;

&lt;p&gt;Pertama, diameter ferrule. SC, FC, dan ST memakai ferrule 2,5 mm, sedangkan LC dan MU memakai 1,25 mm sehingga bodinya bisa jauh lebih kecil (&lt;a href=&quot;https://thefoa.org/tech/connID.htm&quot;&gt;FOA, Connector Identifier&lt;/a&gt;). Kedua, mekanisme kopling: snap-in (SC), bayonet (ST), ulir (FC), atau push-on dengan pin pemandu (MPO). Ketiga, polish ujung ferrule, rata (PC/UPC) atau miring 8 derajat (APC), yang saya bahas tersendiri di bawah.&lt;/p&gt;

&lt;h2 id=&quot;konektor-satu-ukuran-25-mm-sc-fc-st&quot;&gt;Konektor satu ukuran 2,5 mm: SC, FC, ST&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;SC&lt;/strong&gt; dipakai luas dan tersedia dalam bentuk duplex. Koplingnya snap-in dengan gerakan push-pull, dan menurut &lt;a href=&quot;https://thefoa.org/tech/connID.htm&quot;&gt;FOA&lt;/a&gt; konektor ini distandardisasi di TIA-568-A, edisi lama (nilai loss di bawah merujuk TIA-568.3-E).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FC&lt;/strong&gt; memakai ulir. Dulu populer untuk singlemode, sekarang sebagian besar sudah digantikan SC dan LC. Kalau kamu ketemu FC, kemungkinan besar itu instalasi lama.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ST&lt;/strong&gt; memakai kopling bayonet dengan ferrule 2,5 mm, biasanya keramik. FOA mencatat ST sebagai konektor multimode paling populer sampai sekitar tahun 2005. Nama ST juga merek dagang AT&amp;amp;T.&lt;/p&gt;
&lt;h2 id=&quot;konektor-kecil-125-mm-lc-dan-mu&quot;&gt;Konektor kecil 1,25 mm: LC dan MU&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;LC&lt;/strong&gt; (FOA menyebutnya “Lucent LC”) memakai ferrule 1,25 mm, sehingga bisa dipasang jauh lebih rapat daripada SC. FOA mencatat konektor small form factor mulai naik pada akhir 1990-an, dan LC kini jadi pilihan utama untuk singlemode di telco serta LAN/SAN berkecepatan tinggi.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MU&lt;/strong&gt; juga berferrule 1,25 mm, bentuknya mirip SC versi mini. Konektor ini populer di Jepang dan Asia Timur, jadi di Indonesia jarang ketemu.&lt;/p&gt;

&lt;h2 id=&quot;mpomtp-banyak-serat-dalam-satu-konektor&quot;&gt;MPO/MTP: banyak serat dalam satu konektor&lt;/h2&gt;

&lt;p&gt;MPO memuat 12 atau 16 serat dalam satu ferrule plastik yang berbentuk baris. Kopling-nya push-on, dan keselarasan dijaga oleh pin di salah satu ferrule yang masuk ke lubang di ferrule lawannya (&lt;a href=&quot;https://thefoa.org/tech/connID.htm&quot;&gt;FOA&lt;/a&gt;). “MTP” adalah nama komersial untuk konektor jenis ini.&lt;/p&gt;

&lt;p&gt;Konektor ini biasa dijual dalam bentuk kabel preterminated, dan dipakai untuk paralel optik seperti multimode 40G/100G.&lt;/p&gt;

&lt;p&gt;Yang sering bikin bingung ada tiga. Pertama, gender: male punya dua pin pemandu dan female punya lubang untuk pin itu. Menurut &lt;a href=&quot;https://www.ampcom.com/blogs/tech-lab/mpo-mtp-polarization-types-explained-type-a-b-c&quot;&gt;AMPCOM&lt;/a&gt;, male ke male bisa merusak kedua ferrule, jadi satu sisi harus male dan sisi lain female.&lt;/p&gt;

&lt;p&gt;Kedua, polaritas. Ada tipe A (lurus, posisi 1 ke 1), tipe B (terbalik penuh, 1 ke 12), dan tipe C (pair-flipped). Ringkasan ini dari &lt;a href=&quot;https://www.ampcom.com/blogs/tech-lab/mpo-mtp-polarization-types-explained-type-a-b-c&quot;&gt;AMPCOM Tech Lab&lt;/a&gt;, blog vendor, jadi anggap sebagai gambaran awal. Untuk desain sungguhan, rujuk TIA-568.3 atau panduan vendor kabel yang kamu pakai.&lt;/p&gt;

&lt;p&gt;Ketiga, hubungan pin dan key. Sumber yang saya baca tidak sepakat soal aturannya, jadi cek dokumentasi produk yang kamu beli dan jangan menghafal satu aturan umum.&lt;/p&gt;

&lt;h2 id=&quot;konektor-vsff-untuk-400g-dan-800g-sn-dan-mdc&quot;&gt;Konektor VSFF untuk 400G dan 800G: SN dan MDC&lt;/h2&gt;

&lt;p&gt;Panel 19 inci makin padat, jadi muncul keluarga &lt;em&gt;very small form factor&lt;/em&gt; (VSFF). Dua yang terdokumentasi paling jelas adalah SN dan MDC. Keduanya berisi dua ferrule keramik berpegas 1,25 mm berbasis teknologi LC. Menurut Rosenberger OSI, SN adalah Senko Nano dari SENKO, sedangkan MDC (Miniature Duplex Connector) dari US Conec.&lt;/p&gt;

&lt;p&gt;Menurut &lt;a href=&quot;https://osi.rosenberger.com/us/news-media/blog-vlog/vsff-connector-in-400-and-800-gigabit-applications/&quot;&gt;Rosenberger OSI&lt;/a&gt;, konektor VSFF muat hingga 128 port per rack unit di panel 19 inci, dibanding maksimum 96 port untuk LC duplex. Versi SN Quad dan MDC Quad dipakai untuk 400G DR4 dan 800G DR4 sampai sekitar 500 m.&lt;/p&gt;

&lt;p&gt;Satu peringatan praktis: ferrule 1,25 mm yang sama bukan berarti housing dan adapternya cocok. Jangan asumsikan konektor VSFF yang berbeda bisa saling dikawinkan.&lt;/p&gt;

&lt;h2 id=&quot;upc-vs-apc-jangan-dicampur&quot;&gt;UPC vs APC: jangan dicampur&lt;/h2&gt;

&lt;p&gt;Polish ujung ferrule menentukan seberapa banyak cahaya yang memantul balik ke sumber. Menurut &lt;a href=&quot;https://www.l-com.com/resources/blog/apc-vs-upc-fiber-connectors&quot;&gt;L-com&lt;/a&gt; (28 Oktober 2026):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;UPC punya return loss sekitar 50 dB atau lebih baik. Polish PC yang lebih lama sekitar 40 dB.&lt;/li&gt;
  &lt;li&gt;APC dipoles dengan sudut 8 derajat, sehingga cahaya pantul diarahkan ke cladding dan tidak balik ke laser. Return loss-nya sekitar 60 dB atau lebih baik.&lt;/li&gt;
  &lt;li&gt;Pada singlemode, UPC berwarna biru dan APC berwarna hijau.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Menurut L-com juga, APC jadi standar untuk PON/FTTx, terutama bila ada overlay video RF 1550 nm (biasanya SC APC), plus RF over fiber, CATV, dan DAS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jangan pernah mengawinkan UPC dengan APC.&lt;/strong&gt; Menurut L-com, sudut ferrule-nya tidak pas, sehingga ada celah udara yang menambah beberapa dB loss, dan ferrule bisa rusak. Untuk berpindah antar-polish, pakai patch cord hibrida APC-ke-UPC. Adapter tidak menyelesaikan masalah ini.&lt;/p&gt;

&lt;h2 id=&quot;kode-warna-bantu-tapi-jangan-dijadikan-satu-satunya-pegangan&quot;&gt;Kode warna: bantu, tapi jangan dijadikan satu-satunya pegangan&lt;/h2&gt;

&lt;p&gt;Berdasarkan &lt;a href=&quot;https://www.thefoa.org/tech/ColCodes.htm&quot;&gt;FOA, Fiber Optic Cable And Connector Color&lt;/a&gt;:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Jenis serat&lt;/th&gt;
      &lt;th&gt;Warna&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Singlemode PC/UPC&lt;/td&gt;
      &lt;td&gt;Biru&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Singlemode APC&lt;/td&gt;
      &lt;td&gt;Hijau&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Multimode OM1 (62,5/125)&lt;/td&gt;
      &lt;td&gt;Beige&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Multimode OM2 (50/125)&lt;/td&gt;
      &lt;td&gt;Konektor hitam, jaket oranye&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Multimode OM3/OM4&lt;/td&gt;
      &lt;td&gt;Aqua&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Multimode OM5&lt;/td&gt;
      &lt;td&gt;Lime&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Warna lime untuk jaket kabel OM5 diresmikan lewat ANSI/TIA-598-D-2 pada Januari 2018 (&lt;a href=&quot;https://www.commscope.com/Blog/Call-me-a-limey&quot;&gt;CommScope&lt;/a&gt;). Hati-hati: L-com mencatat lime OM5 bisa terlihat seperti hijau APC di cahaya redup. Warna violet untuk OM4 yang kadang ditemui adalah konvensi pabrikan, bukan warna standar TIA-598.&lt;/p&gt;

&lt;p&gt;FOA sendiri mengingatkan bahwa pewarnaan konektor tidak seragam antarpabrikan. Cek tanda cetak di jaket kabel sebelum menyimpulkan jenis serat dari warna konektornya.&lt;/p&gt;

&lt;h2 id=&quot;berapa-loss-yang-wajar&quot;&gt;Berapa loss yang wajar?&lt;/h2&gt;

&lt;p&gt;Fluke Networks menulis bahwa TIA menetapkan 0,75 dB sebagai batas maksimum worst-case untuk satu pasangan konektor, dan menyebut angka itu “cukup tinggi dan kurang realistis” (&lt;a href=&quot;https://de.flukenetworks.com/blog/cabling-chronicles/cable-testing-101-standard-says-075-db&quot;&gt;Fluke, 18 April 2018&lt;/a&gt;). Nilai tipikal yang disebut Fluke di artikel yang sama jauh lebih rendah:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Kelas konektor&lt;/th&gt;
      &lt;th&gt;Insertion loss tipikal&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Standar&lt;/td&gt;
      &lt;td&gt;0,3 sampai 0,5 dB&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Low loss&lt;/td&gt;
      &lt;td&gt;0,15 sampai 0,2 dB&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Untuk pengukuran dengan kabel referensi, &lt;a href=&quot;https://www.flukenetworks.com/knowledge-base/certifiber-pro/new-loss-budget-values-reference-grade-connectors-ansitia-5683-d&quot;&gt;Fluke KB&lt;/a&gt; mencatat nilai yang selaras TIA-568.3-E untuk sambungan reference ke standard: singlemode 0,50 dB. Nilai multimode (0,30 dB dan 0,50 dB) tergantung versi dan konfigurasi pengukuran, jadi baca artikel Fluke-nya sebelum memakainya. Untuk pasangan konektor reference-grade, Fluke menyebut maksimum 0,10 dB untuk multimode dan 0,20 dB untuk singlemode.&lt;/p&gt;

&lt;p&gt;Satu peringatan: jangan memetakan 0,75 dB TIA ke “Grade B” atau “Grade C” di IEC 61753-1. Grade IEC adalah statistik untuk sambungan acak, bukan batas lulus-gagal seperti TIA.&lt;/p&gt;

&lt;h2 id=&quot;kebersihan-ujung-konektor&quot;&gt;Kebersihan ujung konektor&lt;/h2&gt;

&lt;p&gt;Loss atau return loss yang jelek tidak selalu salah jenis konektor. Bisa juga debu. Partikel di permukaan ferrule menghalangi cahaya atau menimbulkan pantulan.&lt;/p&gt;

&lt;p&gt;Langkahnya sederhana: inspeksi dulu dengan scope sebelum mengawinkan konektor, bersihkan kalau kotor, dan pasang tutup debu saat konektor tidak dipakai.&lt;/p&gt;
&lt;h2 id=&quot;cara-memilih&quot;&gt;Cara memilih&lt;/h2&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Kebutuhan&lt;/th&gt;
      &lt;th&gt;Konektor yang biasanya cocok&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Jaringan akses FTTH/PON&lt;/td&gt;
      &lt;td&gt;SC APC (hijau) atau LC APC&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Patch panel dan transceiver dengan port duplex kecil&lt;/td&gt;
      &lt;td&gt;LC duplex&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Instalasi lama&lt;/td&gt;
      &lt;td&gt;FC atau ST&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Backbone paralel optik 40G/100G&lt;/td&gt;
      &lt;td&gt;MPO/MTP&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Port 400G/800G berdensitas tinggi&lt;/td&gt;
      &lt;td&gt;SN atau MDC (VSFF), sesuai transceiver&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Aturan praktisnya: pilih konektor mengikuti port perangkat, lalu pilih polish mengikuti jenis layanan, dan terakhir cocokkan warna dengan jenis serat. Kalau ragu, baca datasheet transceiver atau ODF yang akan dipakai sebelum memesan patch cord.&lt;/p&gt;

&lt;p&gt;Konektor APC dipakai di PON/FTTx (lihat bagian UPC vs APC di atas). Untuk melihat posisinya dalam arsitektur jaringan PON, baca &lt;a href=&quot;/2026/11/03/mengenal-gpon-fungsi-manfaat-arsitektur&quot;&gt;Mengenal GPON&lt;/a&gt;. Kondisi internet rumah berbasis fiber di Indonesia saya bahas di &lt;a href=&quot;/2026/11/03/target-100-mbps-fixed-broadband-indonesia&quot;&gt;target 100 Mbps fixed broadband&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;sumber&quot;&gt;Sumber&lt;/h2&gt;

&lt;p&gt;Hampir semua sumber di bawah adalah dokumentasi vendor atau asosiasi industri (FOA). Standar TIA dan IEC berbayar, jadi saya merujuknya lewat sumber-sumber ini dan bukan membaca dokumennya langsung. Untuk desain atau pengadaan, cek ke dokumen standar dan datasheet produknya.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://thefoa.org/tech/connID.htm&quot;&gt;FOA, Connector Identifier&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.thefoa.org/tech/ColCodes.htm&quot;&gt;FOA, Fiber Optic Cable And Connector Color&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.l-com.com/resources/blog/apc-vs-upc-fiber-connectors&quot;&gt;L-com, APC vs UPC Fiber Connectors&lt;/a&gt; (28 Oktober 2026)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://de.flukenetworks.com/blog/cabling-chronicles/cable-testing-101-standard-says-075-db&quot;&gt;Fluke Networks, Cable Testing 101: But the Standard Says 0.75 dB!&lt;/a&gt; (18 April 2018)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.flukenetworks.com/knowledge-base/certifiber-pro/new-loss-budget-values-reference-grade-connectors-ansitia-5683-d&quot;&gt;Fluke Networks, New Loss Budget Values for Reference Grade Connectors&lt;/a&gt; (20 Februari 2019)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.commscope.com/Blog/Call-me-a-limey&quot;&gt;CommScope, Call me a limey&lt;/a&gt; (9 Maret 2018)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://osi.rosenberger.com/us/news-media/blog-vlog/vsff-connector-in-400-and-800-gigabit-applications/&quot;&gt;Rosenberger OSI, VSFF connector in 400 and 800 Gigabit applications&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.ampcom.com/blogs/tech-lab/mpo-mtp-polarization-types-explained-type-a-b-c&quot;&gt;AMPCOM Tech Lab, MPO/MTP Polarization Types Explained&lt;/a&gt; (10 Juli 2026, blog vendor)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Penulis: &lt;a href=&quot;/about&quot;&gt;Mahyuddin Susanto&lt;/a&gt;. Koreksi atau tambahan bisa dikirim lewat &lt;a href=&quot;/contact&quot;&gt;halaman kontak&lt;/a&gt;.&lt;/p&gt;</content><author><name>Mahyuddin Susanto</name></author><category term="Komputer" /><category term="fiber optic" /><category term="konektor" /><category term="Networking" /><category term="ftth" /><category term="datacenter" /><summary type="html">Pegang patch cord fiber dari laci, lalu lihat ujungnya. Bentuknya bisa persegi, bisa kecil berpasangan, bisa bulat berulir. Semuanya tugasnya sama: mempertemukan dua inti serat sehingga cahaya lewat dengan rugi sekecil mungkin. Yang beda adalah ukuran, cara kopling, dan tempat konektor itu cocok dipakai.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.udienz.web.id/img/jenis-konektor-fiber-optic-ferrule.png" /><media:content medium="image" url="https://www.udienz.web.id/img/jenis-konektor-fiber-optic-ferrule.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>