06 Nov 2026

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).

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.

Garis waktu skandal penyadapan kepala negara dari Moorer-Radford 1971 dan Watergate 1972 sampai kasus 2026 yang menyasar Presiden Prabowo

Poin Penting

  • 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.
  • 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.
  • 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.
  • Status Listyo Sigit dan dua perwira lain masih tersangka. Tuduhan makar baru disebut pejabat pemerintah dan belum diuji di pengadilan.

Delapan kasus dalam satu tabel

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

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.

Watergate dan Moorer-Radford: ketika Gedung Putih jadi medan pengintaian

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 (National Archives).

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 United States v. Nixon memutuskan 8-0 bahwa presiden wajib menyerahkan rekaman itu, karena klaim umum hak istimewa eksekutif tidak bisa mengalahkan kebutuhan akan bukti dalam perkara pidana (Oyez). Sejumlah rekaman tersebut kini dibuka untuk publik oleh Perpustakaan Kepresidenan Nixon. Nixon mengundurkan diri pada 9 Agustus 1974.

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 (Federation of American Scientists).

Cara kasus ini diselesaikan menunjukkan dilema yang muncul setiap kali pelakunya orang dalam. Pada akhirnya tidak seorang pun dipenjara (Federation of American Scientists). Rincian lengkapnya baru bisa dipelajari puluhan tahun kemudian, setelah rekaman Gedung Putih dan dokumen terkait dideklasifikasi (History News Network). 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.

SBY 2009: ponsel presiden dalam daftar intelijen tetangga

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 (ABC, 18 November 2013; The Guardian, 18 November 2013).

Jakarta bereaksi keras. Indonesia menarik duta besarnya dari Canberra dan menghentikan sementara kerja sama latihan militer, pertukaran intelijen, dan penanganan penyelundupan manusia (Al Jazeera, 21 November 2013). 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 (The Jakarta Post, 29 Agustus 2014).

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.

Merkel dan Rousseff 2013: “memata-matai teman itu tidak bisa diterima”

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 (NPR, 23 Oktober 2013). 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 (The Local, 24 Oktober 2013).

Jaksa Agung Federal Jerman membuka penyidikan pada 2014, lalu menutupnya pada 12 Juni 2015 karena tidak menemukan bukti yang bisa bertahan di pengadilan (APR/AP, 12 Juni 2015). 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 (Al Jazeera, 31 Mei 2021). Dalam versi ini, ada dua negara sekutu Jerman yang terlibat.

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 (Foreign Policy, 17 September 2013).

Macron 2021: dari kabel ke spyware

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” (Al Jazeera, 20 Juli 2021).

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.

Yunani 2004-2005: fitur penyadapan sah yang dibajak

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 lawful interception, 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 (IEEE Spectrum, 29 Juni 2007). Vodafone Yunani kemudian dijatuhi denda.

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.

Kasus 2026: alat sah dan akses dari dalam

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 Lawful Interception Management System 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 (Kompas, 4 November 2026).

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 (Detik, 4 November 2026). Listyo, yang sejak 1 Oktober 2026 menjabat Kepala Staf Kepresidenan (Kompas, 4 November 2026), diberhentikan Presiden dari jabatan itu pada 4 November (Detik, 5 November 2026).

Dari penyadapan ilegal ke dugaan makar

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 (Detik, 4 November 2026). Ia juga menyebut penyidik mendalami kemungkinan adanya keinginan “untuk melumpuhkan” presiden, sambil menegaskan bahwa hal itu “masih dalam proses pendalaman” (Kompas, 4 November 2026).

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 (UU 1/2023, JDIH BPK). 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.

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.

Pelakunya sekutu, mitra, atau orang dalam

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.

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.

Kenapa terus berulang

Lebih dari lima puluh tahun memisahkan Watergate dari kasus 2026, dan dalam rentang itu ada tiga pola yang terus berulang.

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.

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.

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.

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.


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 (tentang penulis, kontak). Tulisan ini dibantu oleh AI.

by Mahyuddin Susanto on 06 Nov 2026 12:00 AM tagged with Sejarah, Keamanan, penyadapan, sejarah, watergate, snowden, pegasus

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.

Poin Penting

  • Planet Venus, mesin lama Planet Ubuntu-ID, berbasis Python 2 dan tidak punya commit baru sejak 2017. Saya menggantinya dengan satu skrip Python 3, build.py.
  • Hasilnya situs statis, jadi cukup di Cloudflare tanpa server sendiri. Isinya diperbarui tiap 6 jam lewat Deploy Hook yang dipanggil GitHub Actions.
  • Dari 73 feed lama, 35 yang masih bisa diambil. Satu feed ternyata sudah berisi iklan judi slot.

Kenapa kode lama tidak bisa dipakai

README lama menyuruh memasang python-libxslt1, python-genshi, dan sejenisnya, lalu menjalankan python planet.py. Semuanya Python 2. Mesinnya, Planet Venus, tidak punya commit baru sejak Maret 2017 (riwayat cabang dev); cabang master berhenti pada Februari 2011. Daripada menghidupkan Python 2 di mesin baru, saya menulis ulang pembangunnya dengan feedparser dan Jinja2. config.ini tetap dipakai apa adanya, dan template tema Ubuntu hanya berpindah dari format htmltmpl ke Jinja2, jadi tampilannya sama.

build.py membaca config.ini, mengambil semua feed secara paralel, mengambil maksimal 5 entri per feed dan 20 entri untuk halaman utama, lalu menulis index.html, rss20.xml, dan opml.xml ke folder public/.

feedparser.parse(url) (feedparser 6.0.14) macet saat menyambung ke beberapa host blogspot, padahal curl dan urllib lancar di mesin yang sama. Jalan keluarnya, unduh feed sendiri dengan timeout eksplisit, lalu serahkan isinya ke feedparser:

AGENT = "PlanetUbuntuID/2.0 (+https://github.com/ubuntu-id/planet)"

req = urllib.request.Request(url, headers={"User-Agent": AGENT})
with urllib.request.urlopen(req, timeout=15) as r:
    d = feedparser.parse(r.read(), response_headers={"content-location": r.geturl()})

Feed yang gagal dilewati dan dicatat di stderr, jadi satu blog yang mati tidak menggagalkan seluruh build.

Membersihkan daftar feed

Pada 6 November 2026 saya mengambil ke-73 feed di config.ini satu per satu lewat build.py. 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 config.ini. Hasil akhirnya, dari 73 feed: 35 berhasil, 37 gagal, 1 dikeluarkan.

Hasil Jumlah feed
Berhasil diambil 35
Domain tidak resolve (DNS) 14
Bukan feed XML yang valid 7
HTTP 404, 410, atau 503 7
Timeout 6
Server tidak terjangkau 2
Respons tanpa Content-Type atau feed kosong 1
Dikeluarkan karena iklan judi slot 1
Total 73

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

# ERROR (cek 2026-11-06): domain tidak resolve (DNS)
# [http://feeds.fajran.web.id/all/feed.xml]
# name = Fajran Iman Rusadi

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.

Deploy ke Cloudflare

Karena hasilnya statis, saya pakai static assets di Cloudflare Workers. Satu file wrangler.jsonc cukup untuk menunjuk folder yang diunggah:

{
  "name": "planet-ubuntu-id",
  "compatibility_date": "2026-11-06",
  "assets": { "directory": "./public" }
}

Pengaturan build-nya: pip install -r requirements.txt && python build.py sebagai build command, npx wrangler deploy sebagai deploy command, dan Python 3.13 lewat file .python-version (versi bawaan lingkungan build Workers bisa diganti dengan cara itu). Nama project hanya boleh huruf kecil, angka, dan tanda hubung, jadi spasi di nama awal saya harus diganti.

Build pertama gagal dalam 11 detik, saat master belum berisi build.py. Setelah pull request #1 di-merge, build berikutnya lolos.

Kalau Anda lebih suka menjalankan server sendiri daripada memakai Cloudflare, hasil public/ bisa disajikan nginx biasa. Atur TLS-nya dengan panduan A+ di SSL Labs untuk nginx.

Situs statis tidak ikut berubah saat blog anggota memposting sesuatu. Karena itu pull request #2 menambah workflow GitHub Actions yang memanggil Deploy Hook Cloudflare tiap 6 jam. URL hook-nya disimpan sebagai secret repositori, tidak pernah masuk ke kode. Run manual pertamanya sukses.

Pendaftaran anggota baru

Alur lama lewat tiket Launchpad saya ganti dengan pull request yang mengubah config.ini. Template PR meminta:

  • nama lengkap dan profil Launchpad,
  • alamat feed,
  • pernyataan bahwa pemohon sudah menandatangani Ubuntu Code of Conduct.

Pernyataan itu tetap diperiksa manual lewat profil Launchpad sebelum PR di-merge. Selain itu, CI di setiap PR memeriksa sintaks, menjalankan build, dan memastikan rss20.xml serta opml.xml valid.

Planet Ubuntu-ID sekarang hidup lagi di planet.ubuntu-id.org, dan kodenya terbuka di GitHub. Kalau Anda punya blog tentang Ubuntu atau Linux dan sudah menandatangani Ubuntu Code of Conduct, silakan kirim pull request.


Penulis: Mahyuddin Susanto, penulis blog ini dan mantan pemelihara repositori Planet Ubuntu-ID (tentang penulis, kontak). Foto sampul oleh Cong Long Vu di Unsplash. Tulisan ini dibantu oleh AI.

by Mahyuddin Susanto on 06 Nov 2026 12:00 AM tagged with Linux, planet, ubuntu, python, cloudflare, rss

05 Nov 2026

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.

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.

Konfigurasi di bawah sudah diuji di Apache 2.4.69 dengan OpenSSL 3.5.7, memakai layout /etc/apache2 bawaan Debian 13 dengan modul, tls.conf, dan file site dari tulisan ini diaktifkan, lalu dicek dengan openssl s_client dan curl.

Read in English: How to Get an A+ on SSL Labs with Apache httpd. Pakai nginx? Lihat Cara Mendapat A+ di SSL Labs dengan nginx.

Tangga grade SSL Labs untuk Apache: apa yang menahan server di B atau A-, dan syarat A+

Daftar isi

Cara SSL Labs memberi nilai

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 SSL Server Rating Guide, tertanggal 16 Mei 2025. Batas-batas yang relevan untuk server Apache pada umumnya:

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

Untuk A+, panduan itu mensyaratkan konfigurasi tanpa warning dan HSTS dengan max-age minimal enam bulan (15768000 detik). Sejak revisi Mei 2025, sekadar dapat A pun butuh TLS 1.3 sekaligus header HSTS yang valid, dan TLS_FALLBACK_SCSV tidak dihitung lagi.

Sertifikat ECDSA P-256 atau RSA 2048 sudah cukup. Nilai key exchange-nya 90 dan tetap dapat A+.

Cek versi Apache dan OpenSSL dulu

apache2 -v
apache2ctl -M | grep -e ssl -e headers -e rewrite -e http2

Versi OpenSSL yang dipakai Apache tercetak di error log saat start, di baris seperti Apache/2.4.69 (Debian) OpenSSL/3.5.7 configured -- resuming normal operations.

Fitur Butuh
TLS 1.3 (dan baris SSLCipherSuite TLSv1.3 ...) Apache 2.4.37+ dengan OpenSSL 1.1.1+ (dukungan TLS 1.3 tercatat di 2.4.36, versi yang tidak pernah dirilis)
Intermediate di SSLCertificateFile (tanpa SSLCertificateChainFile) Apache 2.4.8+
SSLOpenSSLConfCmd (dipakai di sini untuk mengatur kurva) Apache 2.4.8+ dengan OpenSSL 1.0.2+
Protocols h2 http/1.1 (HTTP/2) Apache 2.4.17+
SSLProtocol per virtual host dihormati saat ada SNI Apache 2.4.42+ dengan OpenSSL 1.1.1+
Grup hybrid post-quantum X25519MLKEM768 OpenSSL 3.5+

Langkah 1: Sertifikat dan full chain

Dengan Let’s Encrypt dan Certbot, ambil sertifikatnya saja, lalu tulis konfigurasi TLS sendiri:

sudo certbot certonly --apache -d example.com -d www.example.com

Certbot 2.0 ke atas membuat key ECDSA secara default.

Arahkan Apache ke fullchain.pem:

SSLCertificateFile    /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

Sejak Apache 2.4.8, SSLCertificateFile boleh berisi sertifikat intermediate setelah sertifikat utama, dan dokumentasi mod_ssl menyebut SSLCertificateChainFile sudah usang. Kalau SSLCertificateFile diarahkan ke cert.pem dan chain file dibuang, intermediate-nya hilang. Browser sering melengkapinya sendiri, tapi SSL Labs akan menulis “Chain issues: Incomplete” dan membatasi grade di B.

Kalau memakai installer Certbot (certbot --apache tanpa certonly), ia menambahkan Include /etc/letsencrypt/options-ssl-apache.conf 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: options-ssl-apache.conf versi sekarang diawali SSLEngine on. Cek dengan grep -n SSLEngine /etc/letsencrypt/options-ssl-apache.conf dan, kalau ada, tambahkan SSLEngine on ke virtual host itu sendiri. Tanpa baris itu, Apache melayani HTTP biasa di port 443 tanpa pesan error.

Langkah 2: Aktifkan modul dan atur TLS secara global

Aktifkan modul yang dipakai di tulisan ini:

sudo a2enmod ssl headers rewrite http2

a2enmod ssl sekaligus mengaktifkan socache_shmcb untuk session cache. Di Debian 13, /etc/apache2/mods-available/ssl.conf bawaan lalu berisi baris-baris ini (komentar dibuang):

SSLSessionCache     shmcb:${APACHE_RUN_DIR}/ssl_scache(512000)
SSLSessionCacheTimeout  300
SSLCipherSuite HIGH:!aNULL
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLSessionTickets off

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:

-cipher 'ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA'  ->  Cipher is ECDHE-ECDSA-AES128-SHA
-cipher 'AES256-GCM-SHA384'                            ->  Cipher is AES256-GCM-SHA384
-cipher 'DHE-RSA-AES256-GCM-SHA384'                    ->  Cipher is DHE-RSA-AES256-GCM-SHA384

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 grep -v '^\s*#' /etc/apache2/mods-available/ssl.conf.

Biarkan ssl.conf apa adanya, lalu taruh pengaturan di /etc/apache2/conf-available/tls.conf:

# Pengaturan TLS untuk semua virtual host HTTPS (konteks server config)
SSLProtocol             -all +TLSv1.2 +TLSv1.3

# OpenSSL 3.5+: grup hybrid post-quantum di depan.
# Di OpenSSL 3.0-3.4, hapus X25519MLKEM768 dari daftar ini.
SSLOpenSSLConfCmd       Curves X25519MLKEM768:X25519:prime256v1:secp384r1

# TLS 1.2: hanya key exchange ECDHE + AEAD. TLS 1.3: tiga suite standar.
SSLCipherSuite          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
SSLCipherSuite          TLSv1.3 TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
SSLHonorCipherOrder     off
SSLSessionTickets       off

Aktifkan:

sudo a2enconf tls

apache2.conf di Debian membaca mods-enabled/*.conf lebih dulu dan conf-enabled/*.conf belakangan. Untuk directive-directive ini, nilai global yang datang belakangan menggantikan yang sebelumnya, jadi tls.conf menang atas ssl.conf tanpa perlu mengedit file itu. Di server tes, ketiga suite lemah di atas ditolak begitu tls.conf aktif.

Penjelasan per baris:

  • SSLProtocol -all +TLSv1.2 +TLSv1.3 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-.
  • SSLOpenSSLConfCmd Curves meneruskan daftar grup key exchange ke OpenSSL. Daftarnya diambil dari TLSRef guideline 6.0, penerus Server Side TLS guidelines dari Mozilla, dan sama dengan yang dihasilkan TLSRef Configurator untuk Apache. X25519MLKEM768 menggabungkan X25519 dengan algoritma post-quantum ML-KEM; klien yang belum mendukungnya turun ke X25519.
  • SSLCipherSuite pertama 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.
  • SSLCipherSuite TLSv1.3 ... mengatur suite TLS 1.3. Ketiganya memang default OpenSSL; baris ini membuatnya eksplisit.
  • SSLHonorCipherOrder off membiarkan klien memilih dari daftar. Semua pilihan sudah kuat, dan ponsel tanpa akselerasi AES di hardware akan memilih ChaCha20.
  • SSLSessionTickets off. 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 shmcb dari ssl.conf.
  • Tanpa parameter DH. Daftar cipher tidak berisi suite DHE, jadi parameter DH tidak perlu ditambahkan ke file sertifikat.

Langkah 3: Virtual host, HSTS, dan redirect HTTP

Buat /etc/apache2/sites-available/example.com.conf:

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com

    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/
    RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R=308,QSA,L]
</VirtualHost>

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com

    SSLEngine on
    SSLCertificateFile    /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

    Protocols h2 http/1.1

    # HSTS: 2 tahun. "always" juga mengirimnya di redirect dan halaman error.
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
</VirtualHost>

Lalu aktifkan site-nya dan reload:

sudo a2ensite example.com
sudo apache2ctl configtest && sudo systemctl reload apache2

Baris RewriteCond membiarkan /.well-known/acme-challenge/ 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.

Kenapa harus Header always set

mod_headers menyimpan dua daftar header respons. Daftar default (onsuccess) dipakai untuk respons normal; dokumentasi mod_headers menyebut bahwa untuk respons non-2xx yang dibuat server sendiri, seperti redirect, hanya daftar always yang dipakai.

Di server tes, dengan Header set alih-alih Header always set dan baris Redirect 302 /old / di virtual host *:443:

GET /      ->  HTTP/2 200   strict-transport-security: max-age=63072000; includeSubDomains
GET /old   ->  HTTP/2 302   (tanpa header HSTS)
GET /nope  ->  HTTP/2 404   (tanpa header HSTS)

Dengan Header always set, ketiga respons membawa header itu. Ini paling terasa kalau halaman utama Anda me-redirect, misalnya / ke /en/ atau ke halaman login: respons HTTPS pertama yang diterima pengunjung adalah redirect itu, dan tanpa always ia tidak membawa HSTS.

Catatan HSTS lainnya:

  • max-age=63072000 sama dengan dua tahun, nilai dari TLSRef. SSL Labs butuh minimal 15768000 (enam bulan) untuk A+.
  • includeSubDomains membuat semua subdomain wajib HTTPS di browser yang pernah menerima header ini. Jangan dipasang sebelum itu benar untuk semua subdomain.
  • Header ini hanya di virtual host *:443. Browser mengabaikan HSTS lewat HTTP biasa, dan RFC 6797 bagian 7.2 melarang server mengirimnya di sana.

Apache tidak punya masalah pewarisan add_header seperti nginx. Header set Cache-Control ... di dalam blok <Location> ditambahkan ke header dari virtual host; di server tes, header HSTS tetap ada di respons tersebut.

Langkah 4: Waspadai virtual host yang menimpa pengaturan global

tls.conf mengatur nilai default untuk seluruh server. Virtual host yang punya SSLProtocol, SSLCipherSuite sendiri, atau meng-Include file yang mengaturnya, akan memakai nilai itu. Sejak Apache 2.4.42 dengan OpenSSL 1.1.1 ke atas, dokumentasi SSLProtocol menyebut SSLProtocol 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.

Cari semua tempat yang mengatur opsi TLS:

grep -rn -e SSLProtocol -e SSLCipherSuite -e SSLHonorCipherOrder -e options-ssl-apache /etc/apache2/
apache2ctl -S

Perintah pertama seharusnya hanya menampilkan mods-available/ssl.conf dan tls.conf Anda. Perintah kedua menunjukkan virtual host mana yang menjawab di alamat mana, berguna kalau SSL Labs memberi nilai berbeda untuk IP yang berbeda.

Langkah 5: OCSP stapling dan Let’s Encrypt

SSLUseStapling mati secara default di Apache, dan untuk sertifikat Let’s Encrypt sebaiknya tetap begitu. Let’s Encrypt menghentikan dukungan OCSP: 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, OCSP Stapling di nginx, ditulis sebelum perubahan ini.) OCSP stapling juga tidak memengaruhi grade SSL Labs.

Untuk sertifikat dari CA yang masih menjalankan OCSP, aktifkan di server config (di luar <VirtualHost>), misalnya di akhir tls.conf:

SSLUseStapling          on
SSLStaplingCache        "shmcb:${APACHE_RUN_DIR}/ssl_stapling(32768)"

Langkah 6: Jebakan configtest

apache2ctl configtest 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:

$ apache2ctl configtest
Syntax OK
$ apache2ctl graceful
# error log:
[ssl:emerg] AH02407: "SSLOpenSSLConfCmd Curves FakeGroup999:X25519:prime256v1:secp384r1" failed for example.test:443
[ssl:emerg] AH02312: Fatal error initialising mod_ssl, exiting.
[:emerg] AH00020: Configuration Failed, exiting

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 X25519MLKEM768, jadi nama itu bisa memicu kegagalan yang sama.

Karena itu, cek nama grup ke OpenSSL sebelum reload. Di server tes (OpenSSL 3.5.7):

openssl list -tls-groups | tr ':' '\n' | grep -x X25519MLKEM768

Kalau tidak ada output, atau openssl Anda tidak mengenal opsi -tls-groups, hapus X25519MLKEM768 dari tls.conf. Debian dan Ubuntu membangun Apache dengan OpenSSL sistem, jadi perintah openssl 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 (curl -sI https://example.com/) sebelum logout.

Langkah 7: Uji di lokal, lalu jalankan SSL Labs

Ganti example.com dengan host Anda:

# TLS 1.1 harus ditolak. SECLEVEL=0 supaya klien modern mau mencobanya.
openssl s_client -connect example.com:443 -servername example.com \
  -tls1_1 -cipher 'DEFAULT@SECLEVEL=0' </dev/null 2>&1 | grep -E 'alert|Cipher is'

# TLS 1.3 harus jalan. Dengan OpenSSL 3.5+ di kedua sisi, grupnya X25519MLKEM768.
openssl s_client -connect example.com:443 -servername example.com \
  -tls1_3 </dev/null 2>&1 | grep -E 'Negotiated TLS1.3 group|Cipher is'

# Suite CBC, RSA biasa, dan DHE harus ditolak.
for c in 'ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA' AES256-GCM-SHA384 DHE-RSA-AES256-GCM-SHA384; do
  openssl s_client -connect example.com:443 -servername example.com -tls1_2 \
    -cipher "$c" </dev/null 2>&1 | grep -E 'alert|Cipher is' | head -1
done

# Full chain: server harus mengirim minimal 2 sertifikat (milik Anda + intermediate).
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null | grep -c 'BEGIN CERTIFICATE'

# HSTS di halaman normal dan halaman error, plus redirect HTTP.
curl -sI https://example.com/ | grep -i strict-transport-security
curl -sI https://example.com/does-not-exist | grep -i -e '^HTTP' -e strict-transport-security
curl -sI http://example.com/ | grep -i -e '^HTTP' -e '^location'

Di server tes, hasilnya seperti ini (diringkas):

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

Setelah itu buka ssllabs.com/ssltest, 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.

Troubleshooting: arti pesan di laporan dan cara memperbaikinya

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

Pakai Cloudflare atau CDN lain? 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.

Opsional: HSTS preload

HSTS preload memasukkan domain Anda ke daftar yang ditanam di dalam browser. SSL Labs tidak mensyaratkannya untuk A+. hstspreload.org mensyaratkan max-age minimal satu tahun, includeSubDomains, preload, 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.

Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"

Konfigurasi lengkap

# /etc/apache2/conf-available/tls.conf   (a2enconf tls)
SSLProtocol             -all +TLSv1.2 +TLSv1.3
SSLOpenSSLConfCmd       Curves X25519MLKEM768:X25519:prime256v1:secp384r1
SSLCipherSuite          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
SSLCipherSuite          TLSv1.3 TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
SSLHonorCipherOrder     off
SSLSessionTickets       off
# /etc/apache2/sites-available/example.com.conf   (a2ensite example.com)
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/
    RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R=308,QSA,L]
</VirtualHost>

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com
    SSLEngine on
    SSLCertificateFile    /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    Protocols h2 http/1.1
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
</VirtualHost>

Modul: a2enmod ssl headers rewrite http2.

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

# Pasangan ECDSA, dari Langkah 1
SSLCertificateFile    /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
# Pasangan RSA
SSLCertificateFile    /etc/letsencrypt/live/example.com-rsa/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com-rsa/privkey.pem

Di server tes, klien TLS 1.2 yang hanya menawarkan ECDHE-RSA-AES128-GCM-SHA256 menerima sertifikat RSA 2048 bit, sementara klien lain mendapat ECDSA. Dengan Certbot, jalankan sekali lagi dengan --key-type rsa --cert-name example.com-rsa untuk mendapat pasangan RSA.

Mahyuddin Susanto adalah sysadmin Linux dan jaringan yang mengelola server sendiri dan menulis soal Apache di blog ini sejak 2007, dimulai dari Apache server dengan module OpenSSL. Tentang penulis · Kontak

Sumber

by Mahyuddin Susanto on 05 Nov 2026 12:00 AM tagged with Linux, apache, tls, ssl, security, hsts

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.

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.

The configuration below was tested on Apache 2.4.69 with OpenSSL 3.5.7, using the stock Debian 13 /etc/apache2 layout with the modules, tls.conf and site file from this guide enabled, and checked with openssl s_client and curl.

Baca dalam Bahasa Indonesia: Cara Mendapat A+ di SSL Labs dengan Apache. Running nginx? See How to Get an A+ on SSL Labs with nginx.

SSL Labs grade ladder for Apache: what caps a server at B or A-, and what an A+ needs

Contents

How SSL Labs grades your server

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 SSL Server Rating Guide, dated 16 May 2025. The caps that matter for a typical Apache server:

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

For the A+, the guide asks for a configuration with no warnings and HSTS with a max-age 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 TLS_FALLBACK_SCSV no longer counts.

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

Check your Apache and OpenSSL versions first

apache2 -v
apache2ctl -M | grep -e ssl -e headers -e rewrite -e http2

The OpenSSL version that Apache uses is printed in the error log at startup, in a line like Apache/2.4.69 (Debian) OpenSSL/3.5.7 configured -- resuming normal operations.

Feature Needs
TLS 1.3 (and the SSLCipherSuite TLSv1.3 ... line) Apache 2.4.37+ with OpenSSL 1.1.1+ (TLS 1.3 support is listed under 2.4.36, which was never released)
Intermediates in SSLCertificateFile (no SSLCertificateChainFile) Apache 2.4.8+
SSLOpenSSLConfCmd (used here to set curves) Apache 2.4.8+ with OpenSSL 1.0.2+
Protocols h2 http/1.1 (HTTP/2) Apache 2.4.17+
Per-virtual-host SSLProtocol honored with SNI Apache 2.4.42+ with OpenSSL 1.1.1+
Hybrid post-quantum group X25519MLKEM768 OpenSSL 3.5+

Step 1: Get a certificate and serve the full chain

With Let’s Encrypt and Certbot, get the certificate only and write the TLS config yourself:

sudo certbot certonly --apache -d example.com -d www.example.com

Certbot 2.0 and newer create an ECDSA key by default.

Point Apache at fullchain.pem:

SSLCertificateFile    /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

Since Apache 2.4.8, SSLCertificateFile can hold the intermediate certificates after your own certificate, and the mod_ssl documentation marks SSLCertificateChainFile as obsolete. If you point SSLCertificateFile at cert.pem 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.

If you use Certbot’s installer (certbot --apache without certonly), it adds Include /etc/letsencrypt/options-ssl-apache.conf 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 options-ssl-apache.conf starts with SSLEngine on. Check with grep -n SSLEngine /etc/letsencrypt/options-ssl-apache.conf and, if it is there, add SSLEngine on to the virtual host itself. Without it, Apache serves plain HTTP on port 443 and reports no error.

Step 2: Enable the modules and set TLS globally

Enable the modules this guide uses:

sudo a2enmod ssl headers rewrite http2

a2enmod ssl also enables socache_shmcb for the session cache. On Debian 13, the stock /etc/apache2/mods-available/ssl.conf then contains these lines (comments removed):

SSLSessionCache     shmcb:${APACHE_RUN_DIR}/ssl_scache(512000)
SSLSessionCacheTimeout  300
SSLCipherSuite HIGH:!aNULL
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLSessionTickets off

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:

-cipher 'ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA'  ->  Cipher is ECDHE-ECDSA-AES128-SHA
-cipher 'AES256-GCM-SHA384'                            ->  Cipher is AES256-GCM-SHA384
-cipher 'DHE-RSA-AES256-GCM-SHA384'                    ->  Cipher is DHE-RSA-AES256-GCM-SHA384

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 grep -v '^\s*#' /etc/apache2/mods-available/ssl.conf.

Leave ssl.conf as it is and put your settings in /etc/apache2/conf-available/tls.conf:

# TLS settings for every HTTPS virtual host (server config context)
SSLProtocol             -all +TLSv1.2 +TLSv1.3

# OpenSSL 3.5+: hybrid post-quantum group first.
# On OpenSSL 3.0-3.4, remove X25519MLKEM768 from this list.
SSLOpenSSLConfCmd       Curves X25519MLKEM768:X25519:prime256v1:secp384r1

# TLS 1.2: ECDHE key exchange + AEAD only. TLS 1.3: the three standard suites.
SSLCipherSuite          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
SSLCipherSuite          TLSv1.3 TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
SSLHonorCipherOrder     off
SSLSessionTickets       off

Enable it:

sudo a2enconf tls

Debian’s apache2.conf reads mods-enabled/*.conf first and conf-enabled/*.conf later. For these directives, the later global value replaces the earlier one, so tls.conf wins over ssl.conf without any edits there. On the test server, the three weak suites above were refused once tls.conf was enabled.

Line by line:

  • SSLProtocol -all +TLSv1.2 +TLSv1.3 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-.
  • SSLOpenSSLConfCmd Curves passes the key exchange groups to OpenSSL. The list comes from the TLSRef guideline 6.0, the successor of Mozilla’s Server Side TLS guidelines, and matches what the TLSRef Configurator generates for Apache. X25519MLKEM768 combines X25519 with the ML-KEM post-quantum algorithm; clients without it fall back to X25519.
  • The first SSLCipherSuite 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.
  • SSLCipherSuite TLSv1.3 ... sets the TLS 1.3 suites. These three are OpenSSL’s defaults anyway; the line makes them explicit.
  • SSLHonorCipherOrder off lets the client choose from the list. Every option is strong, and phones without AES hardware pick ChaCha20.
  • SSLSessionTickets off. 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 shmcb session cache from ssl.conf.
  • No DH parameters. The list has no DHE suites, so you do not need to append DH parameters to the certificate file.

Step 3: The virtual hosts, HSTS and the HTTP redirect

Create /etc/apache2/sites-available/example.com.conf:

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com

    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/
    RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R=308,QSA,L]
</VirtualHost>

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com

    SSLEngine on
    SSLCertificateFile    /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

    Protocols h2 http/1.1

    # HSTS: 2 years. "always" also sends it on redirects and error pages.
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
</VirtualHost>

Then enable the site and reload:

sudo a2ensite example.com
sudo apache2ctl configtest && sudo systemctl reload apache2

The RewriteCond line keeps /.well-known/acme-challenge/ 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.

Why Header always set matters

mod_headers keeps two lists of response headers. The default one (onsuccess) is used for normal responses; the mod_headers documentation says that for a locally generated non-2xx response, “such as a redirect”, only the always list is used.

On the test server, with Header set instead of Header always set and a Redirect 302 /old / line in the *:443 virtual host:

GET /      ->  HTTP/2 200   strict-transport-security: max-age=63072000; includeSubDomains
GET /old   ->  HTTP/2 302   (no HSTS header)
GET /nope  ->  HTTP/2 404   (no HSTS header)

With Header always set, all three responses carried the header. This matters most when your home page redirects, for example / to /en/ or to a login page: the first HTTPS response a visitor gets is that redirect, and without always it has no HSTS header.

Other HSTS notes:

  • max-age=63072000 is two years, the TLSRef value. SSL Labs needs at least 15768000 (six months) for the A+.
  • includeSubDomains makes every subdomain HTTPS-only in browsers that have seen the header. Leave it out until that is true for all of them.
  • The header belongs only in the *:443 virtual host. Browsers ignore HSTS on plain HTTP, and RFC 6797, section 7.2 says servers must not send it there.

Apache does not have nginx’s add_header inheritance problem. A Header set Cache-Control ... inside a <Location> block is added to the headers from the virtual host; on the test server the HSTS header stayed on those responses.

Step 4: Watch for virtual hosts that override the global settings

tls.conf sets the server-wide default. Any virtual host that has its own SSLProtocol, SSLCipherSuite or an Include of a file that sets them uses those values instead. Since Apache 2.4.42 with OpenSSL 1.1.1 or newer, the SSLProtocol documentation says each name-based virtual host’s own SSLProtocol 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.

Find every place that sets TLS options:

grep -rn -e SSLProtocol -e SSLCipherSuite -e SSLHonorCipherOrder -e options-ssl-apache /etc/apache2/
apache2ctl -S

The first command should show only mods-available/ssl.conf and your tls.conf. The second lists which virtual host answers on which address, which helps when SSL Labs grades one IP differently from another.

Step 5: OCSP stapling and Let’s Encrypt

SSLUseStapling is off by default in Apache, and for Let’s Encrypt certificates it should stay off. Let’s Encrypt ended OCSP support: 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 OCSP stapling in nginx predates this change.) OCSP stapling has no effect on the SSL Labs grade.

For a certificate from a CA that still runs OCSP, enable it in the server config (outside any <VirtualHost>), for example at the end of tls.conf:

SSLUseStapling          on
SSLStaplingCache        "shmcb:${APACHE_RUN_DIR}/ssl_stapling(32768)"

Step 6: The configtest trap

apache2ctl configtest 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:

$ apache2ctl configtest
Syntax OK
$ apache2ctl graceful
# error log:
[ssl:emerg] AH02407: "SSLOpenSSLConfCmd Curves FakeGroup999:X25519:prime256v1:secp384r1" failed for example.test:443
[ssl:emerg] AH02312: Fatal error initialising mod_ssl, exiting.
[:emerg] AH00020: Configuration Failed, exiting

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 X25519MLKEM768, so that name can cause the same failure there.

So check the group names against OpenSSL before you reload. On the test server (OpenSSL 3.5.7):

openssl list -tls-groups | tr ':' '\n' | grep -x X25519MLKEM768

If that prints nothing, or your openssl does not know the -tls-groups option, remove X25519MLKEM768 from tls.conf. Debian and Ubuntu build Apache against the system OpenSSL, so the openssl 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 (curl -sI https://example.com/) before you log out.

Step 7: Test locally, then run SSL Labs

Replace example.com with your host:

# TLS 1.1 must be refused. SECLEVEL=0 lets a modern client even try it.
openssl s_client -connect example.com:443 -servername example.com \
  -tls1_1 -cipher 'DEFAULT@SECLEVEL=0' </dev/null 2>&1 | grep -E 'alert|Cipher is'

# TLS 1.3 must work. With OpenSSL 3.5+ on both sides the group is X25519MLKEM768.
openssl s_client -connect example.com:443 -servername example.com \
  -tls1_3 </dev/null 2>&1 | grep -E 'Negotiated TLS1.3 group|Cipher is'

# CBC, plain RSA and DHE suites must be refused.
for c in 'ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA' AES256-GCM-SHA384 DHE-RSA-AES256-GCM-SHA384; do
  openssl s_client -connect example.com:443 -servername example.com -tls1_2 \
    -cipher "$c" </dev/null 2>&1 | grep -E 'alert|Cipher is' | head -1
done

# Full chain: the server must send at least 2 certificates (yours + intermediate).
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null | grep -c 'BEGIN CERTIFICATE'

# HSTS on a normal page and on an error page, plus the HTTP redirect.
curl -sI https://example.com/ | grep -i strict-transport-security
curl -sI https://example.com/does-not-exist | grep -i -e '^HTTP' -e strict-transport-security
curl -sI http://example.com/ | grep -i -e '^HTTP' -e '^location'

On the test setup, the output looked like this (condensed):

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

Then open ssllabs.com/ssltest, 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.

Troubleshooting: what the report says and how to fix it

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

Behind Cloudflare or another CDN? 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.

Optional: HSTS preload

HSTS preload puts your domain on a list built into browsers. SSL Labs does not need it for an A+. hstspreload.org requires a max-age of at least one year, includeSubDomains, preload, 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.

Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"

The complete config

# /etc/apache2/conf-available/tls.conf   (a2enconf tls)
SSLProtocol             -all +TLSv1.2 +TLSv1.3
SSLOpenSSLConfCmd       Curves X25519MLKEM768:X25519:prime256v1:secp384r1
SSLCipherSuite          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
SSLCipherSuite          TLSv1.3 TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
SSLHonorCipherOrder     off
SSLSessionTickets       off
# /etc/apache2/sites-available/example.com.conf   (a2ensite example.com)
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/
    RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R=308,QSA,L]
</VirtualHost>

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com
    SSLEngine on
    SSLCertificateFile    /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    Protocols h2 http/1.1
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
</VirtualHost>

Modules: a2enmod ssl headers rewrite http2.

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

# ECDSA pair, from Step 1
SSLCertificateFile    /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
# RSA pair
SSLCertificateFile    /etc/letsencrypt/live/example.com-rsa/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com-rsa/privkey.pem

On the test server, a TLS 1.2 client that only offered ECDHE-RSA-AES128-GCM-SHA256 received the 2048-bit RSA certificate, and other clients got ECDSA. With Certbot, run it again with --key-type rsa --cert-name example.com-rsa for the RSA pair.

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 Apache server dengan module OpenSSL. About · Contact

Sources

by Mahyuddin Susanto on 05 Nov 2026 12:00 AM tagged with Linux, apache, tls, ssl, security, hsts

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.

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.

Konfigurasi di bawah sudah diuji di nginx 1.26.3 dengan OpenSSL 3.5.7, memakai nginx.conf bawaan Debian 13 (dua baris SSL-nya diberi #) ditambah file-file dari tulisan ini, lalu dicek dengan openssl s_client dan curl.

Read in English: How to Get an A+ on SSL Labs with nginx. Pakai Apache? Lihat Cara Mendapat A+ di SSL Labs dengan Apache.

Tangga grade SSL Labs untuk nginx: apa yang menahan server di B atau A-, dan syarat A+

Daftar isi

Cara SSL Labs memberi nilai

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.

Aturan yang berlaku sekarang adalah versi 2009r dari SSL Server Rating Guide, tertanggal 16 Mei 2025. Ini batas-batas yang relevan untuk server nginx pada umumnya:

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

Untuk A+, panduan itu mensyaratkan konfigurasi tanpa warning dan HSTS dengan max-age minimal enam bulan (15768000 detik).

Ada dua perubahan di 2025: sekadar dapat A sekarang butuh TLS 1.3 sekaligus header HSTS yang valid, dan TLS_FALLBACK_SCSV tidak dihitung lagi. Kalau ada artikel lama yang menyuruh mengurus fallback SCSV, bagian itu bisa dilewati.

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.

Cek versi nginx dan OpenSSL dulu

Beberapa directive bergantung pada versi yang terpasang:

nginx -V 2>&1 | head -3
openssl version
Fitur Butuh
TLS 1.3 (TLSv1.3 di ssl_protocols) OpenSSL 1.1.1+; jadi default sejak nginx 1.23.4
http2 on; sebagai directive terpisah nginx 1.25.1+ (versi lama: listen 443 ssl http2;)
Rotasi otomatis key session ticket nginx 1.23.2+ dengan ssl_session_cache shared
Grup hybrid post-quantum X25519MLKEM768 OpenSSL 3.5+
add_header_inherit merge; nginx 1.29.3+

Yang penting di output nginx -V adalah baris built with OpenSSL .... Itu library yang benar-benar dipakai nginx, dan bisa berbeda dengan perintah openssl di server yang sama.

Langkah 1: Sertifikat dan full chain

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

sudo certbot certonly --nginx -d example.com -d www.example.com

Certbot versi baru sudah memakai key ECDSA secara default, dan itu yang dibutuhkan. Arahkan nginx ke fullchain.pem, bukan cert.pem:

ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

cert.pem 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. Dokumentasi nginx juga bilang begitu: sertifikat server ditaruh paling atas di file, diikuti sertifikat intermediate.

Kalau memakai installer Certbot (certbot --nginx tanpa certonly), ia menambahkan include /etc/letsencrypt/options-ssl-nginx.conf; ke server block. File itu juga mengatur protokol dan cipher. Hapus baris include tersebut supaya hanya pengaturan dari tulisan ini yang berlaku.

Langkah 2: Taruh pengaturan TLS di satu file bersama

Debian dan Ubuntu memuat semua file di /etc/nginx/conf.d/ di dalam blok http, jadi satu file di sana berlaku untuk semua situs HTTPS.

Pertama, bereskan dulu baris SSL yang sudah dipasang paket di /etc/nginx/nginx.conf. File bawaan Debian 13 punya blok ini di dalam http { }:

##
# SSL Settings
##

ssl_protocols TLSv1.2 TLSv1.3; # Dropping SSLv3 (POODLE), TLS 1.0, 1.1
ssl_prefer_server_ciphers off; # Don't force server cipher order.

File di conf.d/ masuk ke blok http yang sama, jadi baris-baris ini akan bentrok. nginx menolak ssl_prefer_server_ciphers kedua di level yang sama:

nginx: [emerg] "ssl_prefer_server_ciphers" directive is duplicate in /etc/nginx/conf.d/tls.conf

ssl_protocols kedua juga tidak menimpa yang pertama. nginx menggabungkan kedua daftar dan hanya memberi peringatan seperti [warn] duplicate value "TLSv1.2", bukan error. Beri tanda # pada kedua baris itu (isinya bisa berbeda di rilis lain), lalu pastikan tidak ada file lain yang mengaturnya:

grep -rn -e ssl_protocols -e ssl_prefer_server_ciphers -e ssl_ciphers /etc/nginx/

Sekarang buat /etc/nginx/conf.d/tls.conf:

# Pengaturan TLS untuk semua server block (konteks http)
ssl_protocols TLSv1.2 TLSv1.3;

# OpenSSL 3.5+: grup hybrid post-quantum di depan.
# Di OpenSSL 3.0-3.4, hapus X25519MLKEM768 dari daftar ini.
ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1:secp384r1;

# Cipher TLS 1.2: hanya key exchange ECDHE + AEAD.
# Suite TLS 1.3 diatur OpenSSL dan semuanya AEAD.
ssl_ciphers 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;
ssl_prefer_server_ciphers off;

ssl_session_timeout 1d;
ssl_session_cache shared:TLS:10m;   # sekitar 40000 sesi

Penjelasan per baris:

  • ssl_protocols TLSv1.2 TLSv1.3 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 ssl_protocols lain di blok yang sama, karena itu baris lama tadi harus dimatikan.
  • ssl_ecdh_curve menentukan grup key exchange. Daftarnya diambil dari TLSRef guideline 6.0, penerus Server Side TLS guidelines dari Mozilla. X25519MLKEM768 menggabungkan X25519 klasik dengan algoritma post-quantum ML-KEM. Klien yang belum mendukungnya otomatis turun ke X25519.
  • ssl_ciphers 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, ssl_cipher di nginx, yang sudah usang.
  • ssl_prefer_server_ciphers off 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.
  • Tanpa ssl_dhparam. Daftar cipher tidak berisi suite DHE, jadi file parameter DH tidak diperlukan. Risiko lama “parameter DH di bawah 2048 bit” ikut hilang.
  • Session ticket dibiarkan default (on). Sejak nginx 1.23.2, key ticket dirotasi otomatis selama ssl_session_cache memakai shared memory, seperti di file di atas. Karena itu TLSRef hanya menambahkan ssl_session_tickets off; untuk versi yang lebih lama.

Mozilla SSL Configuration Generator sekarang dialihkan ke TLSRef Configurator. 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.

Langkah 3: Server block, HSTS, dan redirect HTTP

Sekarang konfigurasi situsnya, misalnya /etc/nginx/sites-available/example.com yang di-link ke sites-enabled/:

# Port 80: semua dialihkan ke HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    return 308 https://$host$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;                       # nginx < 1.25.1: "listen 443 ssl http2;"
    server_name example.com www.example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # HSTS: 2 tahun. "always" juga mengirimnya di respons 3xx/4xx/5xx.
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;

    root /var/www/example.com;
    index index.html;
}

Catatan soal baris HSTS:

  • max-age=63072000 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-.
  • always penting. Tanpa itu, nginx hanya menambahkan header di respons 200, 201, 204, 206, 301, 302, 303, 304, 307, dan 308. Dengan always, halaman error juga membawa header ini.
  • includeSubDomains memberi tahu browser bahwa semua subdomain juga wajib HTTPS. Jangan dipasang sebelum yakin itu benar. Kalau intranet.example.com masih HTTP biasa, browser yang pernah menerima header ini akan menolak membukanya.
  • Header hanya dipasang di server HTTPS. Browser mengabaikan HSTS yang dikirim lewat HTTP biasa, dan spesifikasi HSTS (RFC 6797 bagian 7.2) melarang server mengirimnya di sana.

Dua baris listen 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.

Langkah 4: OCSP stapling dan Let’s Encrypt

Banyak panduan A+ masih menyuruh menambahkan ssl_stapling on;, termasuk tulisan saya sendiri tahun 2015, OCSP Stapling di nginx. Untuk sertifikat Let’s Encrypt, baris itu sebaiknya dibuang.

Let’s Encrypt menghentikan dukungan OCSP: 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:

[warn] "ssl_stapling" ignored, no OCSP responder URL in the certificate

Situs tetap jalan, tapi log jadi kotor. Hapus ssl_stapling dan ssl_stapling_verify. OCSP stapling tidak memengaruhi grade SSL Labs.

Kalau sertifikat berasal dari CA yang masih menjalankan OCSP, stapling tetap berguna. Yang dibutuhkan adalah resolver dan chain penerbit:

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/ssl/certs/ca-chain.pem;   # root + intermediate
resolver 127.0.0.53 valid=300s;   # contoh: systemd-resolved; ganti dengan resolver server Anda

Langkah 5: Hindari jebakan add_header

Di nginx, add_header hanya diwarisi dari blok luar kalau blok saat ini tidak punya add_header sendiri. Begitu satu header ditambahkan di sebuah location, semua header dari blok server hilang di location itu, termasuk HSTS. Kalau location itu /, grade turun ke A-. Kalau di path lain, laporan tetap A+ padahal sebagian situs jalan tanpa header itu.

Ini hasil uji di server tes (port 8443) dengan konfigurasi di atas ditambah satu location:

location /assets/ {
    add_header Cache-Control "public, max-age=3600";
}
$ 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

Respons kedua tidak punya HSTS.

Ada tiga cara memperbaikinya, urut dari yang paling disarankan:

  1. nginx 1.29.3 ke atas: pasang add_header_inherit merge; di blok http. Header dari level luar akan ditambahkan ke header yang diset di blok dalam (dokumentasi).
  2. nginx lama: pindahkan header keamanan ke snippet, lalu include di setiap tempat yang memakai add_header (contoh di bawah).
  3. Kalau hanya untuk cache: pakai expires 1h;, bukan add_header Cache-Control. Directive ini mengirim Cache-Control dan Expires sendiri, dan berbeda dengan add_header, tidak memutus header warisan dari blok server.

Cara snippet kira-kira seperti ini:

# /etc/nginx/snippets/security-headers.conf
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
location /assets/ {
    include snippets/security-headers.conf;
    add_header Cache-Control "public, max-age=3600";
}

Dan hasil location /assets/ { expires 1h; } di server tes yang sama:

$ 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

Aturan pewarisan yang sama berlaku untuk blok if dan location bertingkat.

Langkah 6: Uji di lokal, lalu jalankan SSL Labs

Cek sintaks lalu reload:

sudo nginx -t && sudo systemctl reload nginx

Sebelum ke SSL Labs, cek poin-poin penting dari terminal sendiri. Ganti example.com dengan host Anda:

# TLS 1.1 harus ditolak. SECLEVEL=0 supaya klien modern mau mencobanya.
openssl s_client -connect example.com:443 -servername example.com \
  -tls1_1 -cipher 'DEFAULT@SECLEVEL=0' </dev/null 2>&1 | grep -E 'alert|Cipher is'

# TLS 1.3 harus jalan. Dengan OpenSSL 3.5+ di kedua sisi, grupnya X25519MLKEM768.
openssl s_client -connect example.com:443 -servername example.com \
  -tls1_3 </dev/null 2>&1 | grep -E 'Negotiated TLS1.3 group|Cipher is'

# Suite CBC harus ditolak (berlaku untuk sertifikat ECDSA maupun RSA).
openssl s_client -connect example.com:443 -servername example.com -tls1_2 \
  -cipher 'ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA' </dev/null 2>&1 | grep -E 'alert|Cipher is'

# Full chain: harus ada baris "depth=1" (intermediate yang dikirim server).
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>&1 | grep depth

# Header HSTS dan redirect.
curl -sI https://example.com/ | grep -i strict-transport-security
curl -sI http://example.com/  | grep -i -e '^HTTP' -e '^location'

Di server tes, hasilnya seperti ini (diringkas):

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

Kalau semuanya sudah sesuai, buka ssllabs.com/ssltest, 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.

Troubleshooting: arti pesan di laporan dan cara memperbaikinya

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

Pakai Cloudflare atau CDN lain? 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 > 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 Migrasi ke Cloudflare.)

Opsional: HSTS preload

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 hstspreload.org lebih ketat daripada syarat A+:

  • max-age minimal 31536000 (satu tahun), includeSubDomains, dan preload di header
  • semua subdomain dilayani lewat HTTPS, termasuk subdomain internal
  • HTTP dialihkan ke HTTPS di host yang sama terlebih dulu
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

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.

Konfigurasi lengkap

Sebagai rujukan, ini dua file yang dipakai saat pengujian di atas (sesuaikan path dan nama). Ditambah dua baris yang diberi # di nginx.conf pada Langkah 2, itulah seluruh perubahannya:

# /etc/nginx/conf.d/tls.conf
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1:secp384r1;
ssl_ciphers 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;
ssl_prefer_server_ciphers off;
ssl_session_timeout 1d;
ssl_session_cache shared:TLS:10m;
# add_header_inherit merge;   # nginx 1.29.3+
# /etc/nginx/sites-available/example.com
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    return 308 https://$host$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name example.com www.example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;

    root /var/www/example.com;
    index index.html;
}

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:

ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;       # ECDSA, dari Langkah 1
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_certificate     /etc/letsencrypt/live/example.com-rsa/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com-rsa/privkey.pem;

Di server tes, klien TLS 1.2 yang hanya menawarkan ECDHE-RSA-AES128-GCM-SHA256 menerima sertifikat RSA 2048 bit, sementara klien lain mendapat ECDSA. Dengan Certbot, jalankan sekali lagi dengan --key-type rsa --cert-name example.com-rsa untuk mendapat pasangan RSA.

Mahyuddin Susanto adalah sysadmin Linux dan jaringan yang mengelola server sendiri dan menulis soal nginx di blog ini sejak 2009, dimulai dari nginx, dari nol. Tentang penulis · Kontak

Sumber

by Mahyuddin Susanto on 05 Nov 2026 12:00 AM tagged with Linux, nginx, tls, ssl, security, hsts

27 Feb 2025

Well, when I tried out to full update my system I just got error like this
error: failed to prepare transaction (could not satisfy dependencies)
:: installing icu (76.1-1) breaks dependency 'libicui18n.so=75-64' required by electron30
:: installing icu (76.1-1) breaks dependency 'libicuuc.so=75-64' required by electron30
:: installing flac (1.5.0-1) breaks dependency 'libFLAC.so=12-64' required by electron30
Resolution To quick fixing the issue above, we just need to remove electron30 package.
$ sudo pacman -Rs electron30
After that, we can do full update the system again
$ sudo pacman -Syu
Reference: https://bbs.archlinux.org/viewtopic.php?id=303573
by Darmanex on 27 Feb 2025 02:54 PM tagged with archlinux, icu
12 Journaling Practices That Will Clear Your Mind and Boost Your Creativity (You Need to Try #6!)

In a world overflowing with distractions, finding clarity and creativity can feel impossible. Journaling has emerged as a powerful tool for personal development, allowing individuals to navigate their thoughts and emotions while unlocking their creative potential. This listicle explores twelve transformative journaling practices designed to enhance mental clarity and encourage self-reflection. Whether you're a seasoned journaler or just starting out, there’s something here for everyone.

Imagine a cozy writing nook filled with sunlight, surrounded by potted plants, an open notebook with a beautiful cover, and a steaming mug of tea on a wooden table. The scene is inviting, evoking a sense of peace and creativity, perfect for journaling.





1. Morning Pages: A Daily Brain Dump

12 Journaling Practices That Will Clear Your Mind and Boost Your Creativity (You Need to Try #6!) - 1. Morning Pages: A Daily Brain Dump

Start your day by writing three pages of stream-of-consciousness thoughts. This practice, known as Morning Pages, helps clear mental clutter and opens the door to creative insights. Don’t worry about grammar or structure; simply let your thoughts flow. Over time, this exercise unveils patterns in your thinking, allowing for deeper self-reflection and clarity in your day-to-day life.

Visualize a serene morning scene with sunlight streaming through a window, illuminating a messy desk where a hand-written page fills the frame with scribbled thoughts and doodles, a steaming cup of coffee beside it, embodying the essence of a fresh start.





2. Gratitude Journaling: Cultivating Positivity

12 Journaling Practices That Will Clear Your Mind and Boost Your Creativity (You Need to Try #6!) - 2. Gratitude Journaling: Cultivating Positivity

Gratitude journaling involves listing things you are thankful for, creating a positive mindset that can significantly enhance your mental clarity. This practice encourages you to focus on the good in your life, shifting your perspective away from negativity. By regularly acknowledging your blessings, you foster resilience and creativity, as your mind becomes more attuned to opportunities and solutions.

Picture an elegant journal open to a page filled with beautifully penned gratitude notes, surrounded by fresh flowers and a calming candle. The scene radiates warmth, inviting you to reflect on and appreciate the little joys in life.





3. Bullet Journaling: Organize and Inspire

12 Journaling Practices That Will Clear Your Mind and Boost Your Creativity (You Need to Try #6!) - 3. Bullet Journaling: Organize and Inspire

Bullet journaling is a customizable planning method that combines organization with creativity. It's a versatile system where you can track your tasks, goals, and ideas in a visually appealing way. This practice not only fosters mental clarity by organizing your thoughts but also allows for artistic expression with doodles and color coding, making planning enjoyable.

Imagine a vibrant bullet journal open to a colorful spread filled with doodles, monthly goals, and beautifully drawn headers. The layout showcases a mixture of creativity and structure, with colorful washi tapes and markers scattered around, igniting inspiration.





4. Dream Journaling: Unlocking Your Subconscious

12 Journaling Practices That Will Clear Your Mind and Boost Your Creativity (You Need to Try #6!) - 4. Dream Journaling: Unlocking Your Subconscious

Dream journaling is a powerful practice that allows you to capture dreams as soon as you wake. This technique helps in understanding your subconscious mind, revealing insights about your emotions and desires. By documenting your dreams, you can gain clarity and inspire creativity, as dreams often carry unique ideas and symbols that can fuel your artistic endeavors.

Visualize a bedside table adorned with a dream journal, open to a page filled with scribbled notes about the previous night’s dreams. A soft, inviting bed and a small lamp cast a warm glow, creating a tranquil atmosphere perfect for reflecting on nighttime visions.





5. Creative Writing Prompts: Fuel Your Imagination

12 Journaling Practices That Will Clear Your Mind and Boost Your Creativity (You Need to Try #6!) - 5. Creative Writing Prompts: Fuel Your Imagination

Using creative writing prompts can break through mental blocks and ignite your imagination. These prompts encourage you to think outside the box and can lead to unexpected insights. By allowing your creativity to flow without judgment, you create space for innovative ideas to emerge, enhancing both self-reflection and artistic expression.

Picture a writing desk filled with various creative writing prompts printed on colorful cards, surrounded by a notepad filled with ideas and sketches. The scene is lively, filled with inspiration and endless possibilities, inviting you to pick a prompt and start writing.





6. Mind Mapping: Visualize Your Thoughts

12 Journaling Practices That Will Clear Your Mind and Boost Your Creativity (You Need to Try #6!) - 6. Mind Mapping: Visualize Your Thoughts

Mind mapping is an innovative technique that helps visualize connections between ideas, facilitating clearer thinking. This practice allows you to organize your thoughts in a free-flowing format, making it easier to explore relationships between concepts. By visually mapping your ideas, you enhance your mental clarity and can uncover creative solutions to challenges you may face.

Imagine a large sheet of paper spread out on a table, filled with colorful mind maps connecting various thoughts and ideas. Markers and highlighters are scattered around, showcasing the vibrant, dynamic process of brainstorming. The ambiance is energetic and full of potential, inviting you to explore new concepts.





7. Reflective Journaling: Deepen Your Understanding

12 Journaling Practices That Will Clear Your Mind and Boost Your Creativity (You Need to Try #6!) - 7. Reflective Journaling: Deepen Your Understanding

Reflective journaling involves writing about significant experiences and emotions, allowing for deeper self-understanding. This practice encourages you to analyze your thoughts and reactions, leading to greater mental clarity. By reflecting on your experiences, you cultivate a richer perspective on life, which can inspire creativity and personal growth.

Visualize a peaceful outdoor setting with a journal resting on a picnic blanket, open to a page filled with reflections on personal experiences. The serene environment with nature in the background enhances the reflective process, inviting contemplation and insight.





8. Art Journaling: Express Without Words

12 Journaling Practices That Will Clear Your Mind and Boost Your Creativity (You Need to Try #6!) - 8. Art Journaling: Express Without Words

Art journaling combines writing with visual art, enabling you to express your emotions in a multifaceted way. This practice allows for creativity to blossom as you incorporate drawings, paintings, or collages alongside your written words. Art journaling not only nurtures mental clarity but also serves as a therapeutic outlet for self-expression.

Picture an art journal open to a colorful page filled with vibrant paintings and expressive doodles, accompanied by handwritten thoughts. Brushes and paints scattered around create an artistic mess that reflects the joy of creative exploration, inviting you to unleash your inner artist.





9. Affirmation Journaling: Empower Your Mind

12 Journaling Practices That Will Clear Your Mind and Boost Your Creativity (You Need to Try #6!) - 9. Affirmation Journaling: Empower Your Mind

Affirmation journaling involves writing positive affirmations that reinforce your self-worth and capabilities. This practice helps counteract negative thoughts, fostering a more empowering mindset. By regularly affirming your strengths and abilities, you enhance your self-reflection process and boost your overall creativity and mental clarity.

Visualize an elegant journal page filled with beautifully written affirmations, surrounded by inspiring quotes and vibrant colors. The uplifting environment radiates positivity, making it an ideal space for self-empowerment and creative thinking.





10. Travel Journaling: Capture Your Adventures

12 Journaling Practices That Will Clear Your Mind and Boost Your Creativity (You Need to Try #6!) - 10. Travel Journaling: Capture Your Adventures

Travel journaling allows you to document your adventures, experiences, and reflections while exploring new places. This practice encourages you to engage with your surroundings and enhances your creativity by capturing memories in writing and visuals. Reflecting on your travels can provide mental clarity and inspire new ideas for future adventures.

Imagine an open travel journal adorned with sketches of landmarks, photographs, and handwritten notes about a recent trip. A scenic view in the background enhances the wanderlust feeling, inviting you to embark on your next journey.





11. Goal Setting Journaling: Chart Your Path

12 Journaling Practices That Will Clear Your Mind and Boost Your Creativity (You Need to Try #6!) - 11. Goal Setting Journaling: Chart Your Path

Goal setting journaling is a proactive practice that involves writing down your aspirations and breaking them into actionable steps. This method enhances mental clarity by providing a clear roadmap for achieving your dreams. By regularly revisiting and adjusting your goals, you foster self-reflection and maintain motivation to unleash your creativity.

Visualize a journal page filled with neatly written goals, accompanied by colorful charts and progress trackers. The structured yet artistic layout inspires action and clarity, creating an environment that motivates you to pursue your dreams.





12. Collaborative Journaling: Share and Inspire

12 Journaling Practices That Will Clear Your Mind and Boost Your Creativity (You Need to Try #6!) - 12. Collaborative Journaling: Share and Inspire

Collaborative journaling involves sharing your journal with others, encouraging dialogue, and inspiring each other’s creativity. This practice fosters community and connection, enhancing mental clarity through shared experiences and insights. By collaborating, you not only reflect on your own thoughts but also gain new perspectives that can fuel your creativity.

Picture a group of friends gathered around a table, each with their own journal, sharing ideas and insights. The scene is filled with laughter and creativity, showcasing the beauty of collaboration and the richness it brings to the journaling experience.





Conclusion

12 Journaling Practices That Will Clear Your Mind and Boost Your Creativity (You Need to Try #6!) - Conclusion

Incorporating these journaling practices into your daily routine can lead to profound transformations in mental clarity, self-reflection, and creativity. By exploring different styles and techniques, you’ll discover which resonates with you and your unique journey. So, grab your favorite journal and start experimenting with these practices today.

Visualize a cozy writing space filled with various journals, pens, and art supplies, all inviting you to embark on your journaling adventure. The ambiance is warm and welcoming, creating a perfect environment for self-discovery and creative exploration.





by Darmanex on 27 Feb 2025 04:56 AM tagged with art, creativity

19 Jan 2025

Apa itu Burp Suite?

Secara singkat, Burp Suite adalah alat keamanan aplikasi web yang sering digunakan untuk pengujian penetrasi dan analisis keamanan aplikasi web. Dikembangkan oleh PortSwigger, alat ini memberikan berbagai fitur untuk membantu mengidentifikasi kerentanan dan eksploitasi dalam aplikasi web. Burp Suite biasanya digunakan oleh pentester, ethical hacker, dan security engineer untuk memastikan keamanan aplikasi web sebelum dirilis atau dalam proses perbaikan keamanan. Burp Suite menawarkan versi Community Edition dan Professional Edition. Saya sendiri cukup sering menggunakan Burp Suite untuk keperluan pentesting aplikasi web, dan cukup terbantu dengan adanya fitur-fitur yang ditawarkan pada Burp Suite. 

Masalah

Ketika menjalankan aplikasi Burp Suite pada sitem operasi yang saya gunakan, terdapat error seperti berikut: 


Error: LinkageError occurred while loading main class burp.StartBurp
        java.lang.UnsupportedClassVersionError: burp/StartBurp has been compiled by a more recent version of the Java Runtime (class file version 65.0), this version of the Java Runtime only recognizes class file versions up to 55.0
Seperti yang kita ketahui, bahwa Burp Suite ini adalah aplikasi berbasis java, jadi ketika ingin menjalankan Burp Suite kita harus memasang perangkat lunak Java. Jika saya cek versi java pada sistem operasi saya adalah sebagai berikut:

Perbaikan

Untuk mengatasi masalah seperti yang ditunjukkan diatas ketika menjalankan Burp Suite, caranya cukup mudah. Pada kasus saya ini, karena saya menggunakan sistem operasi Arch Linux, saya cukup memasang Java versi jdk21-openjdk, dengan menjalankan perintah berikut:

$ sudo pacman -S jdk21-openjdk
Kemudian kita set java-nya, agar menggunakan versi java yang baru saja kita pasang dengan perintah:
$ sudo archlinux-java set java-21-openjdk
Kita cek kembali versi java yang baru saja kita set

Kesimpulan

Dengan melakukan perubahan versi pada java yang saya gunakan, saya sudah dapat menjalankan Burp Suite tanpa ada masalah seperti sebelumnya.

by Darmanex on 19 Jan 2025 12:56 PM tagged with burpsuite, java

13 Jan 2025

Tak kenal, maka tak sayang
Sebenarnya apa itu FreeBSD? Jika kita baca sekilas dari laman web wikipedia berbahasa inggris, FreeBSD adalah...
a free and open-source Unix-like operating system descended from the Berkeley Software Distribution (BSD) which currently runs on IA-32, x86-64, ARM, PowerPC and RISC-V based computers. The first version was released in 1993 developed from 386BSD. The first fully functional and free Unix clone and has since continuously been the most commonly used BSD-derived operating system.
Pada artikel ini, saya akan melakukan upgrade sistem operasi FreeBSD, karena home server yang saya gunakan masih menggunakan versi FreeBSD yang tidak di support lagi atau sudah masuk dalam daftar EOL dates. 
Jika di cek versi rilis pada sistem operasi FreeBSD yang saya gunakan adalah 13.2-RELEASE-p12.
Dengan mengetahui versi yang saya gunakan tersebut, yang berarti sudah masuk dalam daftar Unsupported FreeBSD Releases, waktunya untuk melakukan upgrade. 

Backup data! 
Untuk berjaga-jaga, hal yang perlu diperhatikan sebelum melakukan upgrade pada FreeBSD adalah:
  • pastikan melakukan backup data-data
  • backup file konfigurasi-konfigurasi pada server seperti /boot/loader.conf, /etc/rc.conf, etc

Perbarui Sistem
Jika semua sudah dilakukan backup. Selanjutnya, lakukan update sistem terlebih dahulu menggunakan freebsd-update tool
# freebsd-update fetch
# freebsd-update install
Dan tidak lupa, saya juga meng-update paket-paket yang sudah terpasang sebelumnya
# pkg update
# pkg upgrade
Mulai Upgrade
Sebelum memulai proses upgrade sistem FreeBSD, baiknya menggunakan terminal multiplexer seperti GNU screen atau tmux, ini bertujuan untuk berjaga-jaga ketika remote ke server mengalami putus koneksi, agar dapat kita gunakan kembali terminal session yang terbuat sebelumnya. 
Untuk memasang screen pada FreeBSD cukup jalankan perintah berikut
# pkg install screen
Kemudian jalankan perintah berikut untuk memulai upgrade sistem FreeBSD
# freebsd-update upgrade -r 14.2-RELEASE
Pada proses upgrade ke versi 14.2 akan melakukan download semua patch pada rilis tersebut. Karena ini akan membutuhkan waktu, silakan ditunggu saja prosesnya sampai selesai. 
Setelah proses download semua patch selesai, jalankan perintah berikut
# freebsd-update install
Hal wajib yang harus dilakukan setelah update sistem, lakukan reboot pada server untuk mendapatkan kernel baru yang sudah update
# shutdown -r now
Jika sistem sudah selesai reboot dan up, remote kembali server FreeBSD dan jalankan lagi perintah
# freebsd-update install
Rebuild paket Setelah proses update selesai, lakukan rebuild paket-paket binary
# pkg update
# pkg upgrade
Langkah terakhir, jalankan update install sekali lagi dan reboot
# freebsd-update install
# shutdown -r now
Upgrade selesai Kemudian cek kembali pada sistem dengan remote ke server FreeBSD untuk memastikan proses upgrade FreeBSD ke versi 14.2 telah selesai.
# freebsd-version
Referensi: https://www.freebsd.org/releases/14.2R/installation/
by Darmanex on 13 Jan 2025 03:07 PM tagged with FreeBSD

10 Jan 2025

Minikube adalah sebuah tool sumber terbuka yang dimana kita dapat membuat cluster Kubernetes di komputer lokal. Tool ini digunakan untuk pengembangan dan menguji aplikasi di Kubernetes tanpa memerlukan cluster cloud yang berskala penuh.
Syarat minimum yang dibutuhkan
  • 2 CPUs atau lebih
  • 2GB free memory
  • 20GB free disk space
  • Koneksi internet

Memasang software pendukung
$ sudo pacman -S virtualbox
$ sudo pacman -S minikube
$ sudo pacman -S kubectl

Setelah semua software pendukung sudah dipasang, kita tinggal menjalankan minikube pada terminal
$ minikube start
Kemudian kita cek untuk memastikan apakah minikube sudah berjalan pada komputer lokal kita
$ VBoxManage list runningvms
Deploy aplikasi
Selanjutnya kita dapat membuat sebuah service dengan menjalankan perintah berikut.
Membuat deployment app dan expose ke port 8080
$ kubectl create deployment my-app --image=kicbase/echo-server:1.0
$ kubectl expose deployment my-app --type=NodePort --port=8080
Kemudian cek apakah service my-app sudah up
$ kubectl get svc my-app
Untuk mengakses service yang baru saja di deploy, kita dapat melakukan port forwarding seperti berikut
$ kubectl port-forward svc/my-app 8180:8080
Service yang baru saja kita deploy dapat diakses melalui http://localhost:8180

by Darmanex on 10 Jan 2025 06:39 AM tagged with kubernetes, minikube

09 Jan 2024

Dart is a programming language developed by Google. It is designed for building web, mobile, and server applications. Dart is known for its focus on simplicity, productivity, and performance. Dart can connect to various types of databases through different libraries and packages. The choice of database depends on the specific requirements of your project.

The problem is, mostly guidelines that available in Youtube or websites explain about connecting database inside frameworks like Flutter or Aqueduct. It’s common to use the database solutions that are well-supported and integrated with those frameworks but you need also a high hardware resource. I still can’t find a website explain about how to connect Dart outside the framework.

So, I will explain in this article about it. I assume that you’ve already familiar with MySQL dan Dart. I use Dart SDK version: 3.1.5 (stable) (Tue Oct 24 04:57:17 2023 +0000) on “windows_x64” and mysql Ver 15.1 Distrib 10.4.28-MariaDB, for Win64 (AMD64), source revision c8f2e9a5c0ac5905f28b050b7df5a9ffd914b7e7.

I’m sure you are questioning why I wrote the code in Windows instead of Linux. Actually, dart and Xampp can run both in Windows and Linux. And the moment, I’m in the middle of working with Visual Code in Windows, so why not.

Step 1. Create a new user, make a database and table in MySQL.
When I use ‘root’ user that has no password, it didn’t work. So I create a new user because I don’t want to change the default configuration in MySQL. You can create your own database.

Step 2.Download the MySQL library in Dart.
Open file pubspec.yaml, add

dependencies:
   mysql1: ^0.19.0


On the terminal, type:

c:\> dart pub get
Resolving dependencies... (1.1s)
  js 0.6.7 (0.7.0 available)
  lints 2.1.1 (3.0.0 available)
  mysql1 0.19.2 (0.20.0 available)
  web_socket_channel 2.4.0 (2.4.1 available)
Got dependencies!
c:\>

Step 3. Write the dart code.

import 'package:mysql1/mysql1.dart';

Future createConnection() async {
  final MySqlConnection connection = await MySqlConnection.connect(ConnectionSettings(
    host: 'localhost',
    port: 3306,
    user: 'testing',
    db: 'contact',
    password:'testing'
  ));
  return connection;
}

Future fetchData() async {
  final MySqlConnection connection = await createConnection();
  Results results = await connection.query('SELECT * FROM person');
  
  for (var row in results) {
    print('${row['id']}'
    '${row['name']}'    
    '${row['mobile']}'
    '${row['category']}'
    '${row['city']}');  
  }
}

void main() {
    fetchData();
}

Run and the output will be:

C:\bin> dart run .\temp.dart
1Michael Angelo0812-12341234FriendJakarta
2Natalia0811-321321FriendJakarta
3Andri0815-33334444vseafoodBogor
4Mike0815-33334444vfoodBogor    
C:\bin>

You can modify the output to make it more nice to see.

import 'package:mysql1/mysql1.dart';

Future createConnection() async {
  final MySqlConnection connection = await MySqlConnection.connect(ConnectionSettings(
    host: 'localhost',
    port: 3306,
    user: 'testing',
    db: 'contact',
    password:'testing'
  ));

  return connection;
}

Future fetchData() async {
  final MySqlConnection connection = await createConnection();
  Results results = await connection.query('SELECT * FROM person');

  //----------------------------------------------------------
  //Pengaturan agar tabulasi kolom bisa disesuaikan dengan
  //panjang character di dalam data kolom.
  int Lid= 3;  //panjang id 34=9999 kontak)
  int Lname= 25;
  int Lmobile = 15;
  int Lcategory=20;
  int Lcity=20;
    
  //cetak header
  var baris='-';
  print(baris*70);
  print("ID${' '*(Lid-2)}Name${' '*(Lname-2)}Mobile${' '*(Lmobile-5)}Category${' '*(Lcategory-13)} City${' '*(Lcity-2)}");
  print(baris*70);
    
  //panjang character data di database
  int Lrec_id,Lrec_name,Lrec_mobile,Lrec_category,Lrec_city;
  //----------------------------------------------------------
  //Print out table

  for (var row in results) {
    Lrec_id=row['id'].toString().length;        //hitung panjang data id
    Lrec_name=row['name'].toString().length;      //hitung panjang data name
    Lrec_mobile=row['mobile'].toString().length;    //hitung panjang data mobile
    Lrec_category=row['category'].toString().length;    //hitung panjang data category
    Lrec_city=row['city'].toString().length;    //hitung panjang data city

    print('${row['id']}${' '*(Lid-Lrec_id+1)}' //kurangi panjang field dgn panjang data
    '${row['name']}${' '*(Lname-Lrec_name+1)}'    
    '${row['mobile']}${' '*(Lmobile-Lrec_mobile+1)}'
    '${row['category']}${' '*(Lcategory-Lrec_category-4)}'
    '${row['city']}${' '*(Lcity-Lrec_city+2)}');  
  }
  print(baris*70);
  await connection.close();
  //----------------------------------------------------------
}

void main() {
    fetchData();
}

by Taufan Lubis on 09 Jan 2024 10:04 AM tagged with Programming-Dart, database, mysql, programming

06 Dec 2023

I've been Near Everest




Andika Triwidada

This is a report of my activities while attending GNOME Asia 2023 in Kathmandu, Nepal. I have given several FOSS conference presentations, but this is my first time I went abroad to deliver it.I feel at home in Kathmandu, Nepal. Many things are similar between Indonesia and Nepal. Right in front of my hotel, cable installation are spaghetti-like, not far from what we have in Indonesia.Another
by Andika Triwidada on 06 Dec 2023 10:45 AM tagged with Everest, gnome, Kathmandu, l10n, Nepal, traveling

18 Nov 2023


Visualizing trigonometric graphs using Python can be done with the help of various libraries, such as Matplotlib and NumPy. These libraries provide powerful tools for numerical operations and creating high-quality plots. In this introduction, I’ll walk you through the basic steps to visualize trigonometric functions using Matplotlib.

import matplotlib.pyplot as plt
import numpy as np
from math import radians
x=np.arange(0,360,1)
y1=np.sin(np.radians(x))
y2=np.cos(np.radians(x))
plt.title('Trigonometric Graphics')
plt.grid()
plt.xlabel('x')
plt.ylabel('y')
plt.plot(x,y1,label='y=sin(x)')
plt.plot(x,y2,label='y=cos(x)')
plt.legend()
plt.show()
by Taufan Lubis on 18 Nov 2023 11:36 AM tagged with Programming-Python, Python Library Matplotlib, python library-Numpy

12 Oct 2023

Another year, another cool conference! This time is LOUCA 2023, a combined conference for LibreOffice and Ubuntu. It was on Saturday and Sunday, October 7th & 8th, 2023 in Universitas Sebelas Maret, Surakarta. I presented a lightning talk on first day, titled "State of Ubuntu Indonesian Translation". My first time giving a lightning talk (only 10 minutes! usually I have longer session, but
by Andika Triwidada on 12 Oct 2023 01:00 PM tagged with foss, l10n, ubuntu

21 Aug 2023

Builing an IT infrastructure is an important process for supporting company efficiency. It has to be a well-planned system. If it works optimally the company can reduce costs and even help increase the productivity of the business.

However, the standard procedure may vary depending on the specific requirements, size of the building, and the complexity of the network.
Below are the general outline of the steps.

1.Need Assessment
This is the most important step. You have to know the client’s need. You have to determine the networks requirements and objectives for the building. How many users that will use the system, types of devices, bandwidth requirements, coverage areas dan future scalability because the company may have plans for expansion.

There are few criteria must be fulfilled when you setup an IT Infrastructure.

2.Network design
The next step is network design. You have to plan the placement of networking equipment, such as routers, switches, and wireless access points. There are few consider factors:
-limited space on the corner, you may have to use a mounted rack that provide access to devices both from the front and rear, cabling requirements, network segmentation
and location of the server rooms.

1.Zero Latency
Latency can be interpreted as the time needed to move data from one place to another. Each device can have different latency depending on the level of network quality it has. Inappropriate router or switches can cause latency.
2.Zero Downtime
Any downtime will interfere with the company’s operational activities.That’s why proper installation and infrastructure are very important.
3.Capacity storage
Storage system that can deliver superior performance.
4.Virtualization
Virtualization has benefits as follows:
-energy saving (no hardware)
-faster server provision (deployment is faster)
-improved disaster recovery (replication can be done easily)
5.Security
Security is one of the most important in having the ideal IT infrastructure. The main role of security system is to remove any vulnerable and put the system into optimized status.

3.Cabling Infrastructure
You have to make sure that you follow the industry standards for cable instalation and labeling. Well organized cabling will make your life easier for future troubleshooting. UTP cable maximum range is 100m, if the server location is far, Fiber-optic cable is a good solution.

4.Network Equipment Installation
Installation and configure the network equipments. Using Mikrotik or Cisco will make easier to remote the device. I give example for these 2 brands because I only familiar with it.

5.Network Configuration
Setting IP address, subnet masks, routing protocols, VLAN’s, security, DHCP (Dynami Host Configuration Protocol) servers, Firewall rules and network monitoring tools.

6.Wireless Network Configuration
Optimize the location to ensure reliable coverage and minimize interference. Use appropriate SSIDs (SErvice Set Identifiers) and latest security setting (WPA2/WPA3 Encryption).

7.Testing and Troubleshooting
In this step, you have to verify cable integrity, measure signal strength, and test network throughput. You have to ensure proper connectivity, data transmission, and performance.

8.Security Implementation
Configure access controls, user authentication, and network segmentation as needed. Implement security measures such as firewalls, intrusion detection systems, and encryption protocols to protect the network from unauthorized access and potential threats.

9.Documentation and Labeling
Network cabling infrastructure is the backbone of any network, connecting devices, servers, switches, routers, etc. Without proper documentation and lebeling, network cabling can become a mess. Proper documentation and labeling will save your time and help you maintain consistency and standards across your network, ensuring compatibility and performance.

10.Network monitoring and maintenance
Set up network monitoring tools to monitor the network performance, security incidents, and potential faults. Regular update firmware or security patches for network devices. Regular inspection for all equipments. Periodic cable testing.

by Taufan Lubis on 21 Aug 2023 07:38 AM tagged with Networking, Uncategorized

28 Jan 2023


Blockchain diharapkan akan digunakan dalam berbagai bidang, seperti keuangan, perdagangan, pemerintahan, kesehatan, dan lainnya. Beberapa contoh penggunaan yang diharapkan adalah:
  • Sistem pembayaran yang lebih efisien dan aman
  • Penyimpanan data yang lebih aman dan mudah diakses
  • Smart contract yang memungkinkan transaksi otomatis
  • Supply chain management yang lebih transparan
  • Sistem voting yang lebih adil dan aman
  • Pencatatan aset digital yang aman dan mudah diakses
Namun, ada juga beberapa halangan yang harus diatasi sebelum penggunaan blockchain dapat digunakan secara luas, seperti regulasi yang belum jelas dan masalah skalabilitas.

Regulasi yang belum jelas dapat menghambat perkembangan dan penggunaan blockchain karena masih ada ketidakpastian tentang bagaimana teknologi ini harus diatur. Beberapa negara belum memiliki regulasi yang jelas mengenai penggunaan mata uang digital, smart contract, atau aset digital lainnya yang dibangun di atas blockchain. Hal ini dapat menimbulkan masalah bagi perusahaan atau individu yang ingin menggunakan teknologi ini dalam bisnis mereka.

Masalah skalabilitas di blockchain terkait dengan jumlah transaksi yang dapat ditangani oleh jaringan dalam satu periode waktu tertentu. Saat ini, beberapa jaringan blockchain seperti Bitcoin dan Ethereum hanya dapat menangani sekitar 7-15 transaksi per detik. Ini sangat sedikit jika dibandingkan dengan sistem pembayaran tradisional seperti Visa yang dapat menangani hingga 65,000 transaksi per detik. Ini menyebabkan masalah ketika jaringan sibuk dan membuat transaksi menjadi lambat atau terganggu. Beberapa solusi yang dikembangkan untuk mengatasi masalah skalabilitas ini, seperti SegWit, sharding dan off-chain scaling. Namun, masalah ini masih dalam proses pengembangan dan penyelesaiannya.

-- sumber dari chatGPT --

by Takdir on 28 Jan 2023 06:39 AM tagged with blockchain

07 May 2022

Jupyter Notebook is part of Project Jupyter which is announced by Fernando Pérez in 2014. It’s a spin-off project from IPython and become the kernel for Jupyter.
Jupyter is a language agnostic and support other programming language like Python, Julia, R, Haskel and Ruby. It’s 100% open-source.
The file format for Jupyter is ‘.ipynb’.
The Jupyter kernel is responsible for handling various type of request (code execution, code completion, inspection) and providing a reply. Since it can connect to many kernels,
it can provide programming in different languages.

In this tutorial, I use:
-Xubuntu 18.04
-Docker 20.10.14

STEP1.FIND THE IMAGES
First, we have to get the docker image. Make sure you are connected to the Internet.

darklinux@darklinuxpc:~$ docker search jupyter
NAME                                   DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
jupyter/datascience-notebook           Jupyter Notebook Data Science Stack from htt…   917                  
jupyter/all-spark-notebook             Jupyter Notebook Python, Scala, R, Spark, Me…   375                  
jupyter/scipy-notebook                 Jupyter Notebook Scientific Python Stack fro…   340                  
jupyterhub/jupyterhub                  JupyterHub: multi-user Jupyter notebook serv…   310                  [OK]
jupyter/tensorflow-notebook            Jupyter Notebook Scientific Python Stack w/ …   301                  
jupyter/pyspark-notebook               Jupyter Notebook Python, Spark, Mesos Stack …   224                  
jupyter/base-notebook                  Small base image for Jupyter Notebook stacks…   169                  
jupyter/minimal-notebook               Minimal Jupyter Notebook Stack from https://…   154                  
jupyter/r-notebook                     Jupyter Notebook R Stack from https://github…   44                   
jupyterhub/singleuser                  single-user docker images for use with Jupyt…   43                   [OK]
jupyter/nbviewer                       Jupyter Notebook Viewer                         27                   [OK]
bitnami/jupyter-base-notebook                                                          24                   
jupyterhub/k8s-hub                                                                     18                   
bitnami/jupyterhub                                                                     11                   
jupyterhub/k8s-singleuser-sample                                                       9                    
jupyterhub/configurable-http-proxy     node-http-proxy + REST API                      6                    [OK]
jupyterhub/k8s-network-tools                                                           2                    
graphcore/pytorch-jupyter              The Poplar® SDK plus PyTorch for IPUs includ…   1                    
ibmcom/jupyter-base-notebook-ppc64le   Small base image for Jupyter Notebook stacks…   1                    
pachyderm/jupyterhub-pachyderm-user                                                    0                    
ibmcom/jupyter-nb-nb2kg                                                                0                    
pachyderm/jupyterhub-pachyderm-hub                                                     0                    
graphcore/tensorflow-jupyter           The Poplar® SDK plus TensorFlow 1 & 2 for IP…   0                    
ibmcom/jupyter-ppc64le                                                                 0                    
ibmcom/jupyter                                                                         0                    
darklinux@darklinuxpc:~$

STEP 3. DOWNLOAD THE IMAGE

darklinux@darklinuxpc:~$ docker pull jupyter/datascience-notebook
Using default tag: latest
latest: Pulling from jupyter/datascience-notebook
d5fd17ec1767: Pull complete 
9288915018bc: Pull complete 
ad895732ee5c: Pull complete 
4f4fb700ef54: Pull complete 
7b053b0d567d: Pull complete 
577d6f3bb6f4: Pull complete 
1d18b5a5f242: Pull complete 
ffc9ad0a0b36: Pull complete 
75f3e04b1547: Pull complete 
e9036ae1aec3: Pull complete 
8016e50184c6: Pull complete 
55f4c93ee7b8: Pull complete 
17c3e54db24b: Pull complete 
e8c81a9b6c9a: Pull complete
530f1db1e9d7: Pull complete 
44fa9360bdc5: Pull complete 
6f59df66069f: Pull complete 
a8c1c1bcf1d4: Pull complete 
5784e3ca1d66: Pull complete 
60e2c9b0e0a4: Pull complete 
4866b0f6598a: Pull complete 
613fc67c0714: Pull complete 
2a41639ceb55: Pull complete 
fa391f2a4b79: Pull complete 
Digest: sha256:acd52864dd364e2e5c494ccefa661e6f58f551c9006ec7263d7b5afd5d1852e9
Status: Downloaded newer image for jupyter/datascience-notebook:latest
docker.io/jupyter/datascience-notebook:latest
darklinux@darklinuxpc:~$

STEP3. CHECK THE IMAGE

darklinux@darklinuxpc:~$ sudo docker images
REPOSITORY                     TAG       IMAGE ID       CREATED        SIZE
jupyter/datascience-notebook   latest    0376841b7305   15 hours ago   4.42GB
jupyter/datascience-notebook   <none>    02e55f7a76b5   3 months ago   4.22GB
ubuntu                         latest    ba6acccedd29   6 months ago   72.8MB
ubuntu                         18.04     5a214d77f5d7   7 months ago   63.1MB
32bit/ubuntu                   bionic    c0f69fac47fc   2 years ago    423MB
ubuntu                         bionic    c3c304cb4f22   2 years ago    64.2MB
hello-world                    latest    bf756fb1ae65   2 years ago    13.3kB
mongo                          4.1       d93e3cc722d8   2 years ago    360MB
garland/xampp-base             latest    21861acf735a   7 years ago    1.44GB
darklinux@darklinuxpc:~$

I’ve downloaded Jupyter/datascience-notebook before, that’s why there are 2 now. Docker will not replace the image although the image name is the same. The images are differentiated with Image ID.

STEP4. RUNNING THE IMAGE

The image is ready. Now, we can run it to create the docker container.
If you don’t specify the container name, docker will create it for you.
$ docker run -p 8888:8888 jupyter/datascience-notebook
If you specify the name, you will get the container as you specified.
$ docker run -p 8888:8888 –name=jupyter-notebook jupyter/datascience-notebook

darklinux@darklinuxpc:~$ docker run -p 8888:8888 --name=jupyter-notebook jupyter/datascience-notebook
Entered start.sh with args: jupyter lab
Executing the command: jupyter lab
[I 2022-05-06 04:36:30.541 ServerApp] jupyterlab | extension was successfully linked.
[W 2022-05-06 04:36:30.563 NotebookApp] 'ip' has moved from NotebookApp to ServerApp. This config will be passed to ServerApp. Be sure to update your config before our next release.
[W 2022-05-06 04:36:30.563 NotebookApp] 'port' has moved from NotebookApp to ServerApp. This config will be passed to ServerApp. Be sure to update your config before our next release.
[W 2022-05-06 04:36:30.563 NotebookApp] 'port' has moved from NotebookApp to ServerApp. This config will be passed to ServerApp. Be sure to update your config before our next release.
[I 2022-05-06 04:36:30.578 ServerApp] nbclassic | extension was successfully linked.
[I 2022-05-06 04:36:30.607 ServerApp] Writing Jupyter server cookie secret to /home/jovyan/.local/share/jupyter/runtime/jupyter_cookie_secret
[I 2022-05-06 04:36:32.379 ServerApp] notebook_shim | extension was successfully linked.
[I 2022-05-06 04:36:32.507 ServerApp] notebook_shim | extension was successfully loaded.
[I 2022-05-06 04:36:32.510 LabApp] JupyterLab extension loaded from /opt/conda/lib/python3.9/site-packages/jupyterlab
[I 2022-05-06 04:36:32.510 LabApp] JupyterLab application directory is /opt/conda/share/jupyter/lab
[I 2022-05-06 04:36:32.530 ServerApp] jupyterlab | extension was successfully loaded.
[I 2022-05-06 04:36:32.555 ServerApp] nbclassic | extension was successfully loaded.
[I 2022-05-06 04:36:32.557 ServerApp] Serving notebooks from local directory: /home/jovyan
[I 2022-05-06 04:36:32.557 ServerApp] Jupyter Server 1.17.0 is running at:
[I 2022-05-06 04:36:32.558 ServerApp] http://2557ebac7ab1:8888/lab?token=de96fd0d44694ef387ae34c27a4222d1976dbdb795aaa308
[I 2022-05-06 04:36:32.559 ServerApp]  or http://127.0.0.1:8888/lab?token=de96fd0d44694ef387ae34c27a4222d1976dbdb795aaa308
[I 2022-05-06 04:36:32.559 ServerApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 2022-05-06 04:36:32.566 ServerApp] 
    
    To access the server, open this file in a browser:
        file:///home/jovyan/.local/share/jupyter/runtime/jpserver-7-open.html
    Or copy and paste one of these URLs:
        http://2557ebac7ab1:8888/lab?token=de96fd0d44694ef387ae34c27a4222d1976dbdb795aaa308
     or http://127.0.0.1:8888/lab?token=de96fd0d44694ef387ae34c27a4222d1976dbdb795aaa308

STEP5. RUNNING FROM CONTAINER
Open other linux terminal and check the docker IP address.
In my device is: 172.17.0.1

darklinux@darklinuxpc:~$ ifconfig docker0
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::42:85ff:fefe:69a5  prefixlen 64  scopeid 0x20<link>
        ether 02:42:85:fe:69:a5  txqueuelen 0  (Ethernet)
        RX packets 697  bytes 6827968 (6.8 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 805  bytes 249616 (249.6 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

darklinux@darklinuxpc:~$

Use this IP address and Jupyter port, to open Jupyter_notebook in browser.
So, it become: 172.17.0.1:8888

Use the token for the password.
de96fd0d44694ef387ae34c27a4222d1976dbdb795aaa308

STEP6. CHANGE THE PASSWORD

You can login with the Token, but I prefer login via password.
So,you have to set the password first.
Scrool down the webpage, copy paste the Token in Token text box and Enter a new password.

If you everthing run well, you will the screen below:

Jupyter Notebook is ready to use.

by Taufan Lubis on 07 May 2022 02:30 AM tagged with docker, Programming in Linux, Programming-Python

05 May 2022

Getting Market Stock Data from Yahoo Finance is not difficult with Python Module – Pandas.
To follow this tutorial at least you know how to run python code.
In this tutorial, I use:
-Python 3.6.9 (default, Dec 8 2021, 21:08:43)
-Matplotlib-3.3.4
-Pandas 1.1.5
-Xubuntu 18.04
and Vim for text editor

Before you start, make sure you are connected to the Internet.

If you don’t have Python, Matplotlib and Pandas, you can install it from Linux Terminal with commands below:

$ sudo apt-get install python3
$ pip3 install matplotlib
$ pip3 install pandas

The source codes:

import datetime as dt
import matplotlib.pyplot as plt
import pandas as pd
import pandas_datareader.data as web

start=dt.datetime(2010,1,1)
end=dt.datetime(2022,4,22)

df1 = web.DataReader('MSFT','yahoo',start,end)
df2 = web.DataReader('AAPL','yahoo',start,end)

plt.plot(df1.Close)
plt.plot(df2.Close)

plt.legend(['MSFT','APPL'])
plt.grid()
plt.xlabel('Year')
plt.ylabel('Price (USD)')
plt.title('STOCK PRICE COMPARISON MICROFSOFT AND APPLE \n JAN 2010 - APR 2022')
plt.show()

You can run it in Linux Terminal, Python IDLE, Jupiter notebook or any Python environtment.

by Taufan Lubis on 05 May 2022 01:12 AM tagged with Programming in Linux, Programming-Python, python library - pandas, Python Library Matplotlib

11 Nov 2020

Tahun 2020. Bisnis yang memanfaatkan Internet sudah berjalan puluhan tahun. Tapi mengapa masih banyak perusahaan yang beroperasi di Indonesia belum melaksanakan verifikasi kepemilikan alamat email, ketika pelanggannya mendaftar ke sistem mereka? Saat ini terlalu banyak perusahaan daring yang tidak peduli etika. Pengguna ketika mendaftar, memakai alamat surel apapun, diterima tanpa konfirmasi
by Andika Triwidada on 11 Nov 2020 03:49 AM

17 Oct 2020

Lanjut ke bagian berikutnya, gaes. Seperti yang sudah dipaparkan pada tulisan sebelumnya, yang akan kita bahas dalam tulisan ini yaitu menjelaskan tentang bagaimana melakukan proses penyimpanan data, langkah-langkah apa saja yang harus dilakukan supaya hasil akhir berkas .csv dapat diimpor dengan baik oleh SLiMS.

Setelah kita paham kenapa berkas .csv yang dibuat, tidak dapat diimpor dengan baik oleh SLiMS, langkah selanjutnya adalah kembali ke aplikasi LibreOffice, di mana dalam tulisan sebelumnya digunakan untuk membuat berkas .csv.

Proses perbaikan berkas dilakukan ketika proses Save As.


Berkas .csv yang telah dibuka, kemudian akan disimpan menggunakan menu Save As. Ketika jendela Save As terbuka, pastikan bahwa, 1) ruas "Save as type" masih berisi format "Text CSV (*.csv)". Lalu, 2) Perhatikan gambar berikut, dengan tanda kotak merah. Centang opsi "Edit filter settings". Dengan mencentang opsi tersebut, kita akan menemukan langkah penting selanjutnya.


Ini dia langkah terpentingnya. Menentukan "Field delimiter". Silahkan tentukan isian ruas tersebut. Dalam opsi drop down yang disediakan, terdapat pilihan (,), (:), (;), {tab}, {space}. Pilihan paling aman kalau tidak mau merubah ruas "Field Separator" di sub-menu Biblio Data Import, adalah menggunakan tanda koma titik koma atau semicolon (,) (;). Silahkan berimprovisasi menggunakan tanda lain. Setelah dipertimbangkan, kenapa tanda titik koma atau semicolon adalah pilihan yang aman, asumsinya, banyak bagian dari kolom nama pengarang atau judul atau bahkan kolom lainnya, yang mungkin, mungkin, ditulis atau dipisahkan dengan tanda koma. Kalau kasusnya demikian, khawatirnya susunan data ketika diimpor akan berantakan. Yang perlu diingat, isian pada ruas Field delimiter ketika melakukan Save As, HARUS SAMA dengan isian ruas Field Separator di SLiMS.

Opsi yang diberi tanda kotak merah, boleh dipilih. Tidak dipilih pun tidak mengapa. Namun, ketika opsi dalam kotak merah dicentang, maka nilai dalam ruas "String delimiter" akan diterapkan ketika data disimpan. Saat terdapat karakter String delimiter dalam data, maka waktu melakukan impor ke SLiMS, isian ruas "Field Enclosed With" di sub-menu Biblio Data Import juga harus disesuaikan dengan nilai yang dimasukkan tadi. 

Nah, sudah. Dengan dijelaskan langkah terakhir tadi, harapannya, berkas .csv yang disiapkan dapat diterima dengan baik, ketika diimpor ke dalam SLiMS. Hmmm ... harusnya, tip ini juga bisa digunakan ketika Anda akan melakukan impor data eksemplar dan atau impor data anggota. Karena kebutuhan data yang diperlukan sama. Berkas dalam format .csv.

Semoga bermanfaat. Sekali lagi, apabila ada metode yang lebih baik atau apa yang saya tuliskan kurang tepat dan perlu diperbaiki, kolom komentar tersedia sebagai media diskusi.

Tabik.

Bahan bacaan:
by Arif Syamsudin on 17 Oct 2020 04:26 PM tagged with belajar bareng SLiMS, CSV, Data Export, Data Import, Ekspor Data SLiMS, Impor Data SLiMS, Konversi Data, LibreOffice, slims, SLiMS 9, SLiMS 9 Bulian, SLiMS Data Conversion, Sublime Text