<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="id"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://bandithijo.dev/feed.xml" rel="self" type="application/atom+xml" /><link href="https://bandithijo.dev/" rel="alternate" type="text/html" hreflang="id" /><updated>2026-07-14T08:59:21+08:00</updated><id>https://bandithijo.dev/feed.xml</id><title type="html">BanditHijo.dev</title><subtitle>Here&apos;s where I started writing some notes that someday I will call it, a book</subtitle><author><name>Rizqi Nur Assyaufi</name></author><entry><title type="html">Review Split Keyboard Chocofi</title><link href="https://bandithijo.dev/blog/review-split-keyboard-chocofi" rel="alternate" type="text/html" title="Review Split Keyboard Chocofi" /><published>2026-07-08T06:05:00+08:00</published><updated>2026-07-08T06:05:00+08:00</updated><id>https://bandithijo.dev/blog/review-split-keyboard-chocofi</id><content type="html" xml:base="https://bandithijo.dev/blog/review-split-keyboard-chocofi"><![CDATA[<h2 id="prakata">Prakata</h2>

<p>Saya sebelumnya tidak pernah tertarik dengan split keyboard atau ergo keyboard. Menurut saya bentuknya cukup aneh seperti keyboard biasa yang dibelah jadi dua bagian. Saya tidak suka bentuknya. Ini murni preferensi pribadi saja. Tidak suka bukan berarti jelek.</p>

<p>Namun, semua berubah sejak saya menemukan <strong>Corne</strong> keyboard. Split keyboard, low profile, dengan jumlah key yang sedikit (hanya 42 atau 36 keys), case yang tipis, dimensi yang mini (seukurang telapak tangan), configurable, remapable (programmable), dan case yang customizeable.</p>

<h2 id="cerita-dulu">Cerita dulu</h2>

<p>Berhubung ini adalah artikel pertama saya yang membahas tentang <em>typing</em>, saya akan cerita dulu <em>background history</em> saya berkenalan dengan keyboard.</p>

<p>SD kelas 4 atau 5 saya pertama kali bertemu komputer dan keyboard, karena ikut les komputer yang diadakan dari sekolah SD tapi ruang komputernya ada di gedung SMA. Saat itu kami dikenalkan dengan game di komputer. Saya paling suka bermain Mario Teaches Typing (1993).</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_01.webp" alt="gambar 1" /></p>

<p>Gambar 1. Mario Teaches Typing (1993). Source <a href="https://www.uvlist.net/game-211662-Mario+Teaches+Typing">https://www.uvlist.net/game-211662-Mario+Teaches+Typing</a></p>

<p>Saat SMP, orang tua saya membeli komputer untuk di rumah. Alhamdulillah menang dorprize sehingga dapat komputer hadiah, Pentium MMX yang diletakkan di kamar saya.</p>

<p>Saat kelas 2 SMA, untuk pertama kali ada guru (pak Taufik) yang <em>notice</em> kalau saya cukup cepat dalam mengetik. Sempat 1-2 kali diminta untuk mengetik di laptop beliau.</p>

<p>Kelas 2 SMA, saya mengikuti lomba web beregu tingkat nasional. Di tim ini saya kebagian mengetik konten yang akan dipajang di website yang akan dilombakan.</p>

<p>Singkat cerita, sampai kuliah yang kedua, salah satu teman yang juga seorang Finance, menilai ketikan saya cukup cepat tapi jarinya tidak sesuai. Tidak <em>touch typing</em>. Karena ia sempat belajar <em>touch typing</em> di kampus dan menjadi persyaratan lulus. Dari sini saya pertama kali mengetahui tentang <em>touch typing</em> (mengetik tanpa melihat tuts keyboard).</p>

<p>Sampai saat COVID-19 saya sudah bekerja sebagai software engineer, saya menyadari dalam proses mengetik, proses problem solving di pikiran saya juga bercampur dengan proses mengetik. Saya masih memikirkan beberapa lokasi key yang belum saya hafal, terutama key yang berkaitan dengan simbol-simbol code. Terkadang juga harus melihat posisi dari key yang ingin saya tekan jika saya kehilangan referensi posisinya. Pada tahap ini, saya mulai menyadari <em>touch typing</em> mungkin bisa membuat proses mengetik code tidak bercampur dengan proses berfikir.</p>

<p>Saya putuskan untuk mulai belajar <em>touch typing</em>. Ternyata saya harus mulai belajar dari awal lagi untuk membiasakan jari-jari agar mengetik sesuai dengan posisi dan porsinya masing-masing.</p>

<p>Dari informasi yang saya kumpulkan, belajar <em>touch typing</em> banyak yang merekomendasikan untuk memulai dari <a href="https://keybr.com">keybr.com</a>. Karena keybr dapat mengidentifikasi jari mana yang lemah dan akan terus men-generate kata yang mengandung huruf yang menjadi kelemahan kita. Di sini saya mulai membangun fondasi <em>touch typing</em> yang benar. Kalau dilihat dari data log yang ada di keybr, saya mulai latihan dari November 2021 sampai Februari 2022.</p>

<p>Setelah mulai nyaman dan terbiasa dengan <em>touch typing</em>, saya mulai beralih ke <a href="https://monkeytype.com">monkeytype.com</a>. Di sini saya pergunakan untuk melancarkan dan membangun <em>muscle memory</em> yang lebih solid. Hingga hari ini, saya masih menggunakan monkeytype untuk membangun kecepatan mengetik dalam satuan <em>Words per Minute</em> (WPM).</p>

<h2 id="keychron-k6">Keychron K6</h2>

<p>Setelah sangat lancar dengan <em>touch typing</em>, WPM sudah rata-rata di 70-80. Kejenuhan mengetik mulai muncul. Saya mengatasi dengan mencoba menggunakan <em>mechanical keyboard</em>.</p>

<p>Saya pilih Keychron karena ini adalah <em>mechanical keyboard</em> pertama saya, dan saya igin mendapatkan pengalaman yang baik.</p>

<p>Singkat cerita saya juga sudah mulai <del>jenuh</del>/<em>fatigue</em> dengan <em>high profile switch</em>. Saya pun ingin mencoba <em>low profile switch</em>. Tapi, sekalian saja saya coba split keyboard.</p>

<p>Saya merasa saat menggunakan standard keyboard sering tertukar antara kiri dan kanan. Seperti terjadi semacam interfere signal karena tangan kanan dan kiri berdekatan. Mungkin kalau diilustrasikan akan seperti ini.</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_02.webp" alt="gambar 2" /></p>

<p>Gambar 2. Ilustrasi tentang interfere signal yang saya bayangkan</p>

<p>Dengan menggunakan split keyboard, akan memberikan jarak antara kedua tangan, sehingga tidak ada signal yang beririsan (ini bercanda ya).</p>

<h2 id="chocofi">Chocofi</h2>

<p>Sebelum mengenal Chocofi, sebenarnya saya hanya mengincar Corne. Tapi setelah berkeliling marketplace, saya tidak menemukan pre-built model Corne yang saya suka. Saya cenderung menyukai Chocofi pre-built yang sudah sesuai dengan selera saya, yaitu:</p>

<ol>
  <li>Full black</li>
  <li>Low profile</li>
  <li>Wireless (bluetooth)</li>
  <li>Menggunakan case (agar board tidak terekspose)</li>
</ol>

<p>Pilihan pun jatuh kepada Chocofi.</p>

<p>Berikut ini profil dari Chocofi.</p>

<ol>
  <li>Keyboard shield dan casing 3D print dengan kontroler NRF528540 yang support ZMK Studio</li>
  <li>Tiap sisi punya 3 baris, 5 kolom, dan 3 tombol buat ibu jari (thumb cluster)</li>
  <li>Column Staggered dengan kolom pinky (kolom ke 5) dibuat lebih turun mengikuti bentuk anatomi jari kelingking. Menurut saya, layout ini cocok untuk tipikal jari orang asia yang memiliki jari jemari yang mungil</li>
  <li>Terinspirasi dari keyboard Fifi, dan menggunakan firmware Seperti Corne dan Miryoku</li>
  <li>Support ZMK Studio untuk kebutuhan custom mapping keys sesuai kebutuhan tanpa perlu flash tinggal copy &amp; paste</li>
  <li>Dilengkapi Switch On-Off dan menggunakan baterai 500 mAh di masing-masing sisi.</li>
</ol>

<p>Berikut ini spesifikasi dari Chocofi.</p>

<ol>
  <li>3x5 Column staggered + 3 buttons on thumb cluster</li>
  <li>NRF52840 controller (type c, ble, bluetooth)</li>
  <li>OLED 0.91 inchi 128x32 pixel SSD1306 I2C</li>
  <li>Socket Kailh choc hot swap low profile 1350</li>
  <li>Switch Kailh choc v1 red pro low profile (linear)</li>
  <li>Keycap Kailh choc v1 PBT black blank</li>
  <li>3D Printed PLA+ Case</li>
  <li>Programmable buttons</li>
  <li>Support ZMK Studio (menggunakan ZMK Firmware)</li>
  <li>Rubber Feets</li>
  <li>Suport 5 Multiple Device through Bluetooth</li>
  <li>Li-Po Battery 500 mAh</li>
  <li>Type C Connector</li>
  <li>1 Meter braided USB Type C Cable</li>
</ol>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_03.jpg" alt="gambar 3" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_04.jpg" alt="gambar 4" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_05.jpg" alt="gambar 5" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_06.jpg" alt="gambar 6" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_07.jpg" alt="gambar 7" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_08.jpg" alt="gambar 8" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_09.jpg" alt="gambar 9" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_15.jpg" alt="gambar 15" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_16.jpg" alt="gambar 16" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_17.jpg" alt="gambar 17" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_18.jpg" alt="gambar 18" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_19.jpg" alt="gambar 19" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_20.jpg" alt="gambar 20" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_21.jpg" alt="gambar 21" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_22.jpg" alt="gambar 22" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_23.jpg" alt="gambar 23" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_24.jpg" alt="gambar 24" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_25.jpg" alt="gambar 25" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_26.jpg" alt="gambar 26" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_27.jpg" alt="gambar 27" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_28.jpg" alt="gambar 28" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_29.jpg" alt="gambar 29" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_30.jpg" alt="gambar 30" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_31.jpg" alt="gambar 31" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_32.jpg" alt="gambar 32" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_33.jpg" alt="gambar 33" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_34.jpg" alt="gambar 34" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_35.jpg" alt="gambar 35" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_36.jpg" alt="gambar 36" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_37.jpg" alt="gambar 37" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_38.jpg" alt="gambar 38" /></p>

<div class="mb-8">
  <div class="relative w-full pb-[56.25%] h-0 overflow-hidden max-w-full">
    <iframe class="absolute top-0 left-0 w-full h-full" src="https://www.youtube.com/embed/0SucDZzEbdA" loading="lazy" frameborder="0" allowfullscreen=""></iframe>
  </div>
</div>

<p>Karena keyboard ini tidak ada case dan karena bentuknya yang kecil dan terlihat ringkih, saya khawatir jika dimasukkan tas akan baku hantam dengan barang-barang lain di dalam tas, maka saya putuskan untuk membeli case. Setelah saya hitung-hitung dimensinya cocok dengan Fujifilm Instax Mini case.</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_39.jpg" alt="gambar 39" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_40.jpg" alt="gambar 40" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_41.jpg" alt="gambar 41" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_42.jpg" alt="gambar 42" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_43.jpg" alt="gambar 43" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_44.jpg" alt="gambar 44" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_45.jpg" alt="gambar 45" /></p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_46.jpg" alt="gambar 46" /></p>

<div class="mb-8">
  <div class="relative w-full pb-[56.25%] h-0 overflow-hidden max-w-full">
    <iframe class="absolute top-0 left-0 w-full h-full" src="https://www.youtube.com/embed/Dsu2pJZkFy4" loading="lazy" frameborder="0" allowfullscreen=""></iframe>
  </div>
</div>

<p>Awal mula mencoba mengetik, saya hanya mendapatkan 5 WPM. Beberapa jam kemudian mulai naik ke 15 WPM. Setalah 24 jam mulai naik ke 40 WPM.</p>

<p>Ini adalah progres setelah seminggu.</p>

<div class="mb-8">
  <div class="relative w-full pb-[56.25%] h-0 overflow-hidden max-w-full">
    <iframe class="absolute top-0 left-0 w-full h-full" src="https://www.youtube.com/embed/m-6jMmMTF6w" loading="lazy" frameborder="0" allowfullscreen=""></iframe>
  </div>
</div>

<p><em>Surprisingly</em>, mengetik di keyboard ini ternyata menyenangkan. Tidak ada <em>fatigue</em> pada otot-otot digitorum (kelompok otot yang mengontrol gerakan jari tangan). Mengetiknya memang masih <em>dragged</em> karena masih harus membiasakan dengan konsep layer. Karena keyboard ini hanya memiliki 36 key, maka key yang tidak ada di base layer akan disimpan di layer berbeda.</p>

<h2 id="layering">Layering</h2>

<p>36 key tentu tidak akan memenuhi semua kebutuhan mengetik. Maka dari itu keyboard-keyboard dengan key yang sedikit seperti ini biasanya menggunakan konsep <em>layering</em>. Dimana mapping key akan dibagi berdasarkan beberapa layer.</p>

<p>Berikut ini layer-layer yang saya pergunakan.</p>

<ol>
  <li>layer 0 (qwerty_layer), base layer atau front layer</li>
  <li>layer 1 (numsym_layer), numeric &amp; symbol layer</li>
  <li>layer 2 (fun_layer), function buttons</li>
  <li>layer 3 (sys_layer), system layer untuk pengaturan konektifitas bluetooth</li>
</ol>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_10.png" alt="gambar 10" /></p>

<p>Gambar 10. layer 0 (qwerty_layer), base layer atau front layer</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_11.png" alt="gambar 11" /></p>

<p>Gambar 11. layer 1 (numsym_layer), numeric &amp; symbol layer</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_12.png" alt="gambar 12" /></p>

<p>Gambar 12. layer 2 (fun_layer), function buttons</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_13.png" alt="gambar 13" /></p>

<p>Gambar 13. layer 3 (sys_layer), system layer untuk pengaturan konektifitas bluetooth</p>

<p>Pada layer-layer tersebut dapat dilihat pada layer 0 atau base layer atau qwerty_layer, terdapat tombol referensi untuk mengakse layer 1 dan 2 yang terdapat pada thumb cluster kiri dan kanan.</p>

<p>Untuk mengakses layer 1, saya menekan dan tahan tombol space. Dengan begini, saya sudah masuk ke layer 1, tinggal menekan button apa yang ingin ditekan pada layer 1. Begitu juga untuk mengakses layer 2.</p>

<p>Untuk mengakses layer 3, saya perlu berada di layer 2, lalu menekan button referensi untuk ke layer 3 yang juga terdapat di thumb cluster sebelah kanan.</p>

<p>Saya masih bereksperimen dengan layout layering seperti apa yang cocok. Jadi akan sangat besar dikemudian hari layout ini akan berubah.</p>

<p>Saya menghindari menggunakan layer yang terlalu banyak agar tidak terjadi “layering fatigue” yaitu kondisi “keblinger” atau kelelahan otak karena kebanyakan layer. Hahaha.</p>

<p>Selain pendekatan layer juga ada pendekatan combo button.</p>

<h2 id="combo">Combo</h2>

<p>Sesuai namanya combo button berarti menekan 2 atau lebih button secara bersama-sama untuk memanggil fungsinya.</p>

<p>Saya tidak terlalu banyak menggunakan combo button. Hanya saya pergunakan untuk hal-hal yang berkaitan dengan pengaturan saja.</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-07-08-review-split-keyboard-chocofi/gambar_14.png" alt="gambar 14" /></p>

<h2 id="kesan-penulis">Kesan penulis</h2>

<p>Beberapa manfaat yang saya rasakan setelah mencoba menggunakan Chocofi split keyboard.</p>

<ol>
  <li>Kita di-<em>encourage</em> untuk menggunakan <em>touch typing</em>. Karena (dengan split keyboard) jika tidak menggunakan <em>touch typing</em> artinya kita akan melihat ke dua sisi keyboard, bisa di sisi kanan atau kiri. Split keyboard membuat proses mengetik menjadi tidak efektif.</li>
  <li>Karena “dipaksa” untuk menggunakan <em>touch typing</em>, membuat jari-jemari menjadi lebih disiplin dengan porsinya masing-masing. Ini sangat cocok dengan layout split keyboard yang terbelah jadi dua di sisi kanan dan kiri. Tidak ada jari di tangan kiri yang menyeberang ke sisi kanan, begitu pula sebaliknya.</li>
  <li>Minim typo. Karena jarak tangan cukup berjarak dan tidak saling berdekatan. Ini menyebabkan tidak terjadi <em>race condition</em> saat pengiriman sinyal dari otak ke dua sisi tangan (note: ini pendapat saya, saya belum mencari literaturenya).</li>
  <li>Proses adaptasi jika sudah bisa mengetik dengan <em>touch typing</em> tidak terlalu lama. Adaptasi dari staggered ke column-staggered juga tidak terlalu lama. Saya 1 pekan sudah bisa menyesuaikan dengan column-staggered dari staggered. Jujur lebih nyaman menggetik di column-staggered (bisa jadi ortholinear juga lebih nyaman, saya belum punya keyboard dengan ortholinear). Karena posisi jari dari homerow hanya perlu bergerak ke atas atau ke bawah, bukan serong atas atas atau serong bawah.</li>
  <li>Sangat mudah diprogram ulang. Karena menggunakan ZMK Firmware, sehingga sangat mudah untuk diprogram ulang jika kita mau memodifikasi tombol dan layer sesuai dengan kebutuhan kita.</li>
  <li>Berpotensi besar untuk dicustom sendiri sesuai keinginan dan kebutuhan. Misal ingin ganti keycaps, ganti switch, ingin ganti case shield nya, dan lain-lain.</li>
  <li>Karena point 6, artinya juga mudah untuk diperbaiki sendiri.</li>
</ol>

<blockquote>
  <p>Dari beberapa kesan tersebut, dapat terlihat jelas bahwa fondasi utama jika ingin menikmati mengetik dengan keyboard adalah <em>touch typing</em>.</p>
</blockquote>

<p>Beberapa hal yang saya tidak begitu nyaman dengan Chocofi split keyboard.</p>

<ol>
  <li>Barangnya sulit didapat. Karena builder ada di luar negeri, yang tersedia di marketplace Indo tidak begitu beragam.</li>
  <li>Learning cuve nya lumayan. Untuk dapat menggunakan split keyboard, kita harus menyediakan waktu untuk menggunakan. Berteman dengan ketidaknyamanan untuk beberapa saat.</li>
  <li>Chocofi tidak sepopuler Corne. Sehingga tidak banyak yang membuat modifikasi, terutama dibagian case. Karena kelebihan dari keyboard seperti ini adalah sangat mudah untuk bergonta-ganti case.</li>
</ol>

<h2 id="pesan-penulis">Pesan penulis</h2>

<p>Split keyboard bukanlah level tertinggi dari penggunaan keyboard. Split keyboard hanya opsi atau pilihan dari beberapa pilihan model keyboard yang beredar di pasaran saat ini. Tidak semua orang cocok menggunakan split keyboard. Pergunakan perkakas/tools (dalam hal ini keyboard) yang memang nyaman kamu gunakan.</p>

<h2 id="referensi">Referensi</h2>

<ol>
  <li>
    <p><a href="https://zmk.dev/">ZMK Firmware</a> <br />
Diakses tanggal: 2026-07-11</p>
  </li>
  <li>
    <p><a href="https://nickcoutsos.github.io/keymap-editor/">Nickcoutsos Keymap Editor</a> <br />
Diakses tanggal: 2026-07-11</p>
  </li>
</ol>]]></content><author><name>BanditHijo</name></author><category term="blog" /><category term="splitkeyboard" /><category term="chocofi" /><summary type="html"><![CDATA[Baru 1 jam menggunakan split keyboard, otak serasa terbelah jadi dua.]]></summary></entry><entry><title type="html">Setup Meja Kerja 5.1</title><link href="https://bandithijo.dev/blog/setup-meja-kerja-5-1" rel="alternate" type="text/html" title="Setup Meja Kerja 5.1" /><published>2026-06-23T06:00:00+08:00</published><updated>2026-06-23T06:00:00+08:00</updated><id>https://bandithijo.dev/blog/setup-meja-kerja-5-1</id><content type="html" xml:base="https://bandithijo.dev/blog/setup-meja-kerja-5-1"><![CDATA[<h2 id="pendahuluan">Pendahuluan</h2>

<p>Meja belajar merupakan hal yang sangat personal untuk saya. Sejak SD saya diberikan meja belajar di kamar oleh orang tua saya. Sejauh ingatan saya, di masa sekolah, sejak SD sampai SMA, saya pernah punya 3 model meja belajar. Mulai dari yang model seperti meja kantoran, kemudian model yang memiliki rak 2 tingkat di atas meja belajar, yang terakhir adalah model meja belajar yang terintegrasi untuk meletakkan komputer (layar monitor CRT beserta CPU di bagian bawahnya). Saat kuliah saya juga memilih untuk menggunakan meja belajar. Saya sudah benar-benar melekat erat dengan meja belajar. Sebagian besar waktu saya di rumah mungkin di depan meja belajar.</p>

<p>Oh yaa, berhubung sekarang meja belajar ini sudah berubah jadi meja kerja, maka penamaan meja belajar untuk selanjutnya akan saya sebut dengan meja kerja.</p>

<p>Penamaan meja kerja 5.1 ini artinya meja kerja yang saya gunakan saat ini adalah meja kelima dengan modifikasi versi 1.</p>

<blockquote>
  <p>INFO</p>

  <p>Sebenarnya proses modifikasi meja ini sudah terjadi sejak 1 Desember 2024. Tapi baru sempat saya dokumentasikan sekarang. 🤣</p>
</blockquote>

<p>Berikut ini adalah perjalanan modifikasi meja kerja 5.0 menjadi 5.1.</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-23-setup-meja-kerja-5-1/gambar_01.jpg" alt="Gambar 1" /></p>

<p>Gambar 1. Setup meja belajar 5.0 sebelum dimodifikasi (tampak depan)</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-23-setup-meja-kerja-5-1/gambar_02.jpg" alt="Gambar 2" /></p>

<p>Gambar 2. Setup meja belajar 5.0 sebelum dimodifikasi (tampak samping)</p>

<h2 id="alasan-memodifikasi-meja-kerja">Alasan memodifikasi meja kerja</h2>

<p>Alasan saya memodifikasi meja kerja adalah karena saya menambah perangkat baru yang ingin saya letakkan di meja belajar. Namun, karena tidak mungkin semua alat berada di atas meja utama, saya memutuskan untuk menambahkan rak untuk meletakkan peralatan tambahan tersebut.</p>

<p>Saya sebut sebagai “rak level 1” karena berada 1 level (tingkat) di atas meja belajar.</p>

<p>Setelah banyak mempertimbangkan mau seperti apa rak yang saya buat, akhirnya saya memutuskan untuk membuat rak semi-permanent dengan menggunakan besi siku.</p>

<h2 id="bahan-bahan-yang-dibutuhkan">Bahan-bahan yang dibutuhkan</h2>

<p>Bahan-bahan yang saya beli untuk membuat rak level 1, sebagai berikut:</p>
<ol>
  <li>Besi siku panjang 3 meter, tebal 1 mm x 2 batang</li>
  <li>Triplek 3 mm x 1 lembar</li>
  <li>Mur baut untuk besi siku x 25 biji</li>
  <li>Plat siku x 12 lembar</li>
  <li>Kaki karet untuk besi siku x 2 buah</li>
</ol>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-23-setup-meja-kerja-5-1/gambar_03.jpg" alt="Gambar 3" /></p>

<p>Gambar 3. Wah ternyata tripleknya kebesaran, padahal saya cuma akan menggunakan 120x20 cm</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-23-setup-meja-kerja-5-1/gambar_04.jpg" alt="Gambar 4" /></p>

<p>Gambar 4. Besi siku (tampak jauh)</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-23-setup-meja-kerja-5-1/gambar_05.jpg" alt="Gambar 5" /></p>

<p>Gambar 5. Besi siku (tampak dekat)</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-23-setup-meja-kerja-5-1/gambar_06.jpg" alt="Gambar 6" /></p>

<p>Gambar 6. Mur, Baut, dan kaki karet untuk besi siku</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-23-setup-meja-kerja-5-1/gambar_07.jpg" alt="Gambar 7" /></p>

<p>Gambar 7. Plat siku</p>

<h2 id="alat-alat-yang-diperlukan">Alat-alat yang diperlukan</h2>

<p>Alat-alat yang dibutuhkan, sebagai berikut:</p>
<ol>
  <li>Gergaji besi</li>
  <li>Kunci pas ukuran 12</li>
  <li>Meteran</li>
  <li>Penggaris</li>
  <li>Pulpen</li>
  <li>Paki dan Palu (untuk melubangi triplek)</li>
</ol>

<p>Setelah alat dan bahan lengkap, selanjutnya buat desainnya.</p>

<h2 id="desain-dan-rancangan">Desain dan rancangan</h2>

<p>Dari desain yang saya buat, saya membutuhkan ukuran:</p>

<table>
  <thead>
    <tr>
      <th>Panjang</th>
      <th>Jumlah</th>
      <th>Keterangan</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>20 cm</td>
      <td>x 2</td>
      <td>untuk rak</td>
    </tr>
    <tr>
      <td>120 cm</td>
      <td>x 4</td>
      <td>2 untuk kaki, 2 untuk rak</td>
    </tr>
  </tbody>
</table>

<blockquote>
  <p>INFO</p>

  <p>Panjang dari meja saya 120 x 60 cm, karena itu saya membuat panjang rak level 1 ini 120 cm, dengan tinggi 120 cm juga.</p>
</blockquote>

<h2 id="implementasi">Implementasi</h2>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-23-setup-meja-kerja-5-1/gambar_08.jpg" alt="Gambar 8" /></p>

<p>Gambar 8. Besi siku yang sudah dipotong sesuai desain</p>

<p>Setelah dipotong, selanjutnya dirakit dengan mur dan baut dan setiap sudut sikunya dibantu dengan plat siku agar bentuknya tidak berubah.</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-23-setup-meja-kerja-5-1/gambar_09.jpg" alt="Gambar 9" /></p>

<p>Gambar 9. Setelah dirakit mulai kelihatan bentuknya</p>

<p>Selanjutnya tinggal diberikan papan. Tapi saya memilih menggunakan triplek agar tidak berat.</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-23-setup-meja-kerja-5-1/gambar_10.jpg" alt="Gambar 10" /></p>

<p>Gambar 10. Proses pembuatan lubang di triplek</p>

<p>Setelah keempat sudut triplek sudah dilubangi, selanjutnya tinggal dirakit ke rak.</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-23-setup-meja-kerja-5-1/gambar_11.jpg" alt="Gambar 11" /></p>

<p>Gambar 11. Meja kerja setelah ditambahkan rak level 1 dengan besi siku (tampak samping)</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-23-setup-meja-kerja-5-1/gambar_12.jpg" alt="Gambar 12" /></p>

<p>Gambar 12. Meja kerja setelah ditambahkan rak level 1 dengan besi siku (tampak depan)</p>

<p>Selesai!</p>

<p>Sekarang saya sudah punya rak level 1. Sekarang meja saya tidak terlalu penuh dengan peralatan lagi.</p>

<h2 id="2026">2026</h2>

<p>Setelah 1 tahun menggunakan rak ini, saya merasa raknya kurang tinggi. Jadi saya tinggikan kakinya 10 cm. Penambahan tinggi 10 cm ini lumayan memberikan tambahan space untuk monitor eksternal agar bisa lebih tinggi selevel mata saya.</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-23-setup-meja-kerja-5-1/gambar_13.jpg" alt="Gambar 13" /></p>

<p>Gambar 13. Sebelum ditinggikan (kiri), setelah ditinggikan (kanan)</p>

<h2 id="pesan-penulis">Pesan Penulis</h2>

<p>Meja belajar atau meja kerja adalah tempat saya paling banyak menghabiskan waktu untuk belajar, membaca, dan bekerja. Meja kerja menjadi sesuatu yang sangat personal untuk saya. Maka dari itu saya tidak berusaha meniru setup meja orang lain. Yang menurut orang lain bagus, belum tentu menurut saya. Begitu juga sebaliknya, yang menurut orang lain jelek, belum tentu menurut saya jelek.</p>]]></content><author><name>BanditHijo</name></author><category term="blog" /><category term="desk" /><summary type="html"><![CDATA[Sejak masih SD, saya punya meja belajar di kamar. Meja belajar adalah tempat saya banyak menghabiskan waktu membaca buku maupun ngulik dengan komputer. Oleh karena itu, meskipun saya kerja dari rumah, saya prefer bekerja menggunakan meja kerja.]]></summary></entry><entry><title type="html">Mengganti Fingerprint ThinkPad X260</title><link href="https://bandithijo.dev/blog/mengganti-fingerprint-thinkpad-x260" rel="alternate" type="text/html" title="Mengganti Fingerprint ThinkPad X260" /><published>2026-06-22T06:17:00+08:00</published><updated>2026-06-22T06:17:00+08:00</updated><id>https://bandithijo.dev/blog/mengganti-fingerprint-thinkpad-x260</id><content type="html" xml:base="https://bandithijo.dev/blog/mengganti-fingerprint-thinkpad-x260"><![CDATA[<p>Fingerprint di ThinkPad X260 adalah peripheral yang sangat memudahkan saya untuk authentikasi, terutama saat menjalankan command terminal yang menggunakan <code class="language-plaintext highlighter-rouge">sudo</code>. Sangat praktis, tinggal finger scroll, tidak perlu mengetik password.</p>

<p>Meskipun saya menggunakan Linux, tapi fingerprint tetap dapat digunakan. Saya sudah pernah menulis artikel tentang ini, <a href="https://bandithijo.dev/blog/mengatur-fungsi-fingerprint-arch-linux">Mengatur Fungsi dari Fingerprint pada Arch Linux</a>.</p>

<p>Kepraktisan tersebut tidak berlangsung lama, karena plafon kamar saya bocor, dan tetesannya mengenai palmrest (kejadian sekitar tahun 2017-2018). Untungnya fingerprint di ThinkPad X260 ini adalah modul board terpisah dari Motherboard, jika rusak, cukup mengganti fingerprint board module saja.</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-22-mengganti-fingerprint-thinkpad-x260/gambar_01.jpg" alt="Gambar 1" /></p>

<p>Gambar 1. Fingerprint Board (Tampak Atas)</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-22-mengganti-fingerprint-thinkpad-x260/gambar_02.jpg" alt="Gambar 2" /></p>

<p>Gambar 2. Fingerprint Board (Tampak Bawah)</p>

<p><em>Long story short</em>, fingerprint board yang saya pakai ini (berdasarkan keterangan seller) adalah copotan dari fingerprint board ThinkPad X250. Berdasarkan bentuk ThinkPad X260 memang memiliki kesamaan dengan seri X240 dan X250. Ketiga lineup seri ini memang memiliki parts yang bisa digunakan bersama.</p>

<p>Untuk mengganti fingerprint, harus mengangkat: internal battery (jika ada), drive (SSD) case, speaker left &amp; right, dan motherboard.</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-22-mengganti-fingerprint-thinkpad-x260/gambar_03.jpg" alt="Gambar 3" /></p>

<p>Gambar 3. Bongkar ThinkPad X260 sampai Motherboard</p>

<p>Kita melepas plat cover besi yang menutupi fingerprint board (Gambar 4).</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-22-mengganti-fingerprint-thinkpad-x260/gambar_04.jpg" alt="Gambar 4" /></p>

<p>Gambar 4. Fingerprint Board Baru (Kiri) dan Fingerpint Board Lama (Kanan, masih tercover plat)</p>

<p>Setelah plat cover besi terlepas, fingerprint board sudah bisa untuk diganti. Jangan lupa untuk melepaskan kabel flexiblenya.</p>

<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-06-22-mengganti-fingerprint-thinkpad-x260/gambar_05.jpg" alt="Gambar 5" /></p>

<p>Gambar 5. Fingerprint Board Baru (Kiri) dan Fingerpint Board Lama (Kanan, cover sudah terlepas, siap diganti)</p>

<p>Selesai.</p>

<p>Meskipun terlihat mengerikan, sebenarnya proses pembongkaran ini tidak terlalu sulit. Yang terpenting pelan-pelan dan hati-hati.</p>]]></content><author><name>BanditHijo</name></author><category term="blog" /><category term="thinkpad" /><category term="fingerprint" /><summary type="html"><![CDATA[Proses penggantian fingerprint ThinkPad X260.]]></summary></entry><entry><title type="html">Menggabungkan Beberapa Sub-Region Geofabrik</title><link href="https://bandithijo.dev/blog/menggabungkan-beberapa-sub-region-geofabrik" rel="alternate" type="text/html" title="Menggabungkan Beberapa Sub-Region Geofabrik" /><published>2026-02-23T01:46:00+08:00</published><updated>2026-02-23T01:46:00+08:00</updated><id>https://bandithijo.dev/blog/menggabungkan-beberapa-sub-region-geofabrik</id><content type="html" xml:base="https://bandithijo.dev/blog/menggabungkan-beberapa-sub-region-geofabrik"><![CDATA[<h2 id="pendahuluan">Pendahuluan</h2>

<p>Saya tidak ingin mengunduh data geofabrik untuk region Indonesia yang berukuran besar (per-tulisan ini dibuat, 1.6 GB), karena saya hanya memerlukan data untuk tiga sub-region: pulau Sumatra (258 MB), Java (847 MB), dan Kalimantan (138 MB). Oleh karena itu, saya hanya akan mengunduh data untuk ketiga sub-region tersebut dan menggabungkannya menjadi satu file .osm.pbf.</p>

<h2 id="mengunduh-data-sub-region-geofabrik">Mengunduh Data Sub-Region Geofabrik</h2>

<p>Unduh data untuk ketiga sub-region yang diperlukan dari situs Geofabrik:</p>
<ol>
  <li><a href="https://download.geofabrik.de/asia/indonesia/sumatra-latest.osm.pbf">https://download.geofabrik.de/asia/indonesia/sumatra-latest.osm.pbf</a></li>
  <li><a href="https://download.geofabrik.de/asia/indonesia/java-latest.osm.pbf">https://download.geofabrik.de/asia/indonesia/java-latest.osm.pbf</a></li>
  <li><a href="https://download.geofabrik.de/asia/indonesia/kalimantan-latest.osm.pbf">https://download.geofabrik.de/asia/indonesia/kalimantan-latest.osm.pbf</a></li>
</ol>

<p>Letakkan ketiga file .osm.pbf yang telah diunduh ke dalam satu folder, misal: <code class="language-plaintext highlighter-rouge">geofabrik/</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cd geofabrik/
$ wget -c https://download.geofabrik.de/asia/indonesia/sumatra-latest.osm.pbf
$ wget -c https://download.geofabrik.de/asia/indonesia/java-latest.osm.pbf
$ wget -c https://download.geofabrik.de/asia/indonesia/kalimantan-latest.osm.pbf
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>geofabrik/
│ java-latest.osm.pbf
│ kalimantan-latest.osm.pbf
└ sumatra-latest.osm.pbf
</code></pre></div></div>

<h2 id="menggabungkan-data-sub-region-dengan-osmium-tool">Menggabungkan Data Sub-Region dengan Osmium Tool</h2>

<p>Setelah ketiga file .osm.pbf untuk sub-region yang diperlukan telah diunduh, langkah selanjutnya adalah menggabungkannya menjadi satu file .osm.pbf menggunakan Osmium Tool.</p>

<p>Instalasi Osmium Tool dapat dilakukan dengan mengikuti petunjuk di situs resminya: <a href="https://osmcode.org/osmium-tool/">https://osmcode.org/osmium-tool/</a>.</p>

<p>Setelah Osmium Tool terinstal, jalankan perintah berikut untuk menggabungkan ketiga file .osm.pbf menjadi satu file .osm.pbf baru, misal: <code class="language-plaintext highlighter-rouge">indonesia-3pulau-latest.osm.pbf</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ osmium merge sumatra-latest.osm.pbf java-latest.osm.pbf kalimantan-latest.osm.pbf -o indonesia-3pulau-latest.osm.pbf
</code></pre></div></div>

<p>Tunggu hingga proses penggabungan selesai.</p>

<h2 id="kesimpulan">Kesimpulan</h2>

<p>Dalam catatan ini, saya telah mendemonstrasikan proses penggabungan data untuk pulau Sumatra, Java, dan Kalimantan menjadi satu file .osm.pbf baru yang berukuran lebih kecil dibandingkan dengan data untuk seluruh region Indonesia.</p>

<h2 id="referensi">Referensi</h2>

<ol>
  <li>
    <p><a href="https://download.geofabrik.de/asia/indonesia.html">https://download.geofabrik.de/asia/indonesia.html</a> <br />
  Diakses tanggal: 2026-02-22</p>
  </li>
  <li>
    <p><a href="https://osmcode.org/osmium-tool/">https://osmcode.org/osmium-tool/</a> <br />
  Diakses tanggal: 2026-02-22</p>
  </li>
</ol>]]></content><author><name>BanditHijo</name></author><category term="blog" /><category term="openstreetmap" /><category term="geofabrik" /><summary type="html"><![CDATA[Jika data geofabrik untuk Indonesia terlalu besar dan hanya memerlukan data sub-region tertentu, misal: pulau Sumatra, Java, dan Kalimantan. Maka tiga data sub-region tersebut dapat di-merger menjadi satu file .osm.pbf.]]></summary></entry><entry><title type="html">OpenStreetMap Overpass API dengan Docker</title><link href="https://bandithijo.dev/blog/openstreetmap-overpass-api-dengan-docker" rel="alternate" type="text/html" title="OpenStreetMap Overpass API dengan Docker" /><published>2026-02-15T10:05:00+08:00</published><updated>2026-02-15T10:05:00+08:00</updated><id>https://bandithijo.dev/blog/openstreetmap-overpass-api-dengan-docker</id><content type="html" xml:base="https://bandithijo.dev/blog/openstreetmap-overpass-api-dengan-docker"><![CDATA[<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-02-09-openstreetmap-overpass-api-dengan-docker/gambar_01.png" alt="Gambar 1" /></p>

<h2 id="apa-itu-overpass-api">Apa itu Overpass API?</h2>

<p>Overpass API memungkinkan kita untuk melakukan query terhadap data OpenStreetMap (OSM) yang dapat digunakan untuk mencari POI (Point of Interest) pada radius tertentu dari lokasi yang didefinisikan. Overpass API menggunakan bahasa query yang disebut Overpass QL. Dengan Overpass API, kita dapat melakukan query untuk mencari data OSM berdasarkan kriteria tertentu, seperti jenis POI, lokasi, dan lain-lain.</p>

<h2 id="overpass-api-dengan-docker">Overpass API dengan Docker</h2>

<h3 id="1-buat-docker-compose-untuk-overpass-api">1. Buat Docker Compose untuk Overpass API</h3>

<p>Buat file <code class="language-plaintext highlighter-rouge">docker-compose.yml</code> dengan isi seperti ini,</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">services</span><span class="pi">:</span>
  <span class="na">overpass</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">openzonedev/overpass-api:0.7.57.2</span>
    <span class="na">container_name</span><span class="pi">:</span> <span class="s">osm-overpass</span>
    <span class="na">restart</span><span class="pi">:</span> <span class="s">unless-stopped</span>
    <span class="na">environment</span><span class="pi">:</span>
      <span class="na">OVERPASS_META</span><span class="pi">:</span> <span class="s2">"</span><span class="s">yes"</span>
      <span class="na">OVERPASS_MODE</span><span class="pi">:</span> <span class="s2">"</span><span class="s">init"</span>
      <span class="na">OVERPASS_PLANET_URL</span><span class="pi">:</span> <span class="s">file:///overpass/data/kalimantan-latest.osm.bz2</span>
    <span class="na">volumes</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">./geofabrik/kalimantan-new.latest.bz2:/overpass/data/kalimantan-latest.osm.bz2:ro</span>
      <span class="pi">-</span> <span class="s">overpass-data:/db</span>
    <span class="na">expose</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s2">"</span><span class="s">80"</span>
    <span class="na">ports</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s2">"</span><span class="s">8081:80"</span>

<span class="na">volumes</span><span class="pi">:</span>
  <span class="na">overpass-data</span><span class="pi">:</span>
</code></pre></div></div>

<h3 id="2-persiapkan-data-osm-untuk-overpass-api">2. Persiapkan data OSM untuk Overpass API</h3>

<p>Pada contoh di atas, saya menggunakan data OSM untuk wilayah Kalimantan yang saya unduh dari Geofabrik.</p>

<blockquote>
  <p>INFO</p>

  <p>Overpass API membutuhkan file data OSM dalam format <code class="language-plaintext highlighter-rouge">.osm.bz2</code> untuk proses import data. <br />
Saya akan merubah file <code class="language-plaintext highlighter-rouge">.osm.pbf</code> yang kita unduh dari Geofabrik menjadi format <code class="language-plaintext highlighter-rouge">.osm.bz2</code> menggunakan tool <code class="language-plaintext highlighter-rouge">osmium-tool</code>.</p>
</blockquote>

<p>File <code class="language-plaintext highlighter-rouge">.osm.pbf</code> ini bisa didapatkan dari situs <a href="https://download.geofabrik.de/">Geofabrik</a>.</p>

<p>Setelah mengunduh file <code class="language-plaintext highlighter-rouge">.osm.pbf</code>, letakkan file tersebut di dalam direktori <code class="language-plaintext highlighter-rouge">geofabrik/</code> yang berada di root project. Buat direktori <code class="language-plaintext highlighter-rouge">geofabrik/</code> jika belum ada.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ mkdir geofabrik
$ cd geofabrik
$ wget -c https://download.geofabrik.de/asia/indonesia/kalimantan-latest.osm.pbf
</code></pre></div></div>

<p>Tunggu proses download selesai, setelah itu pastikan file <code class="language-plaintext highlighter-rouge">.osm.pbf</code> sudah berada di dalam direktori <code class="language-plaintext highlighter-rouge">geofabrik/</code>.</p>

<p>Berikut adalah struktur direktori yang diharapkan setelah menambahkan file <code class="language-plaintext highlighter-rouge">.osm.pbf</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>geofabrik/
└── kalimantan-latest.osm.pbf
docker-compose.yml
</code></pre></div></div>

<h4 id="21-konversi-file-osmpbf-ke-format-osmbz2">2.1 Konversi file <code class="language-plaintext highlighter-rouge">.osm.pbf</code> ke format <code class="language-plaintext highlighter-rouge">.osm.bz2</code></h4>

<p>Untuk mengkonversi file <code class="language-plaintext highlighter-rouge">.osm.pbf</code> ke format <code class="language-plaintext highlighter-rouge">.osm.bz2</code>, bisa menggunakan tool <code class="language-plaintext highlighter-rouge">osmium-tool</code>. Pastikan <code class="language-plaintext highlighter-rouge">osmium-tool</code> sudah terinstall di sistem.</p>

<p>Jika belum, bisa menginstalnya dengan mengikuti petunjuk di <a href="https://osmcode.org/osmium-tool/">situs resmi osmium-tool</a>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ brew install osmium-tool
</code></pre></div></div>

<p>Setelah <code class="language-plaintext highlighter-rouge">osmium-tool</code> terinstall, jalankan perintah berikut untuk mengkonversi file <code class="language-plaintext highlighter-rouge">.osm.pbf</code> ke format <code class="language-plaintext highlighter-rouge">.osm.bz2</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ osmium cat geofabrik/kalimantan-latest.osm.pbf -o geofabrik/kalimantan-latest.osm.bz2
</code></pre></div></div>

<p>Tunggu proses konversi selesai, setelah itu pastikan file <code class="language-plaintext highlighter-rouge">.osm.bz2</code> sudah berada di dalam direktori <code class="language-plaintext highlighter-rouge">geofabrik/</code>.</p>

<p>Sip, sekarang file <code class="language-plaintext highlighter-rouge">.osm.bz2</code> sudah siap untuk digunakan dalam proses import data oleh Overpass API.</p>

<h3 id="3-jalankan-docker-compose">3. Jalankan Docker Compose</h3>

<p>Setelah file <code class="language-plaintext highlighter-rouge">docker-compose.yml</code> sudah siap dan file data OSM dalam format <code class="language-plaintext highlighter-rouge">.osm.bz2</code> sudah berada di dalam direktori <code class="language-plaintext highlighter-rouge">geofabrik/</code>, jalankan perintah berikut untuk memulai Docker Compose:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker-compose up -d
</code></pre></div></div>

<blockquote>
  <p>PERHATIAN</p>

  <p>Untuk pertama kali menjalankan docker compose, Overpass API service akan melakukan proses import data dari file <code class="language-plaintext highlighter-rouge">.osm.bz2</code> ke dalam Overpass Data, proses ini membutuhkan waktu yang cukup lama, tergantung pada ukuran file <code class="language-plaintext highlighter-rouge">.osm.bz2</code> yang digunakan. Untuk file <code class="language-plaintext highlighter-rouge">kalimantan-latest.osm.bz2</code> yang berukuran 318 MB, proses import data bisa memakan waktu sekitar 30 menit hingga 1 jam.</p>
</blockquote>

<p>Untuk melihat log dari container, bisa menggunakan perintah berikut:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker compose logs overpass -f
</code></pre></div></div>

<p>Tunggu proses import data selesai. Biasanya akan muncul log seperti berikut ketika proses import data sudah selesai:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Overpass container initialization complete. Exiting.
</code></pre></div></div>

<p>Setelah proses import data selesai, Overpass API service sudah siap untuk digunakan. Overpass API bisa diakses melalui <code class="language-plaintext highlighter-rouge">http://localhost:8081/</code>.</p>

<h3 id="4-akses-overpass-api">4. Akses Overpass API</h3>

<h4 id="41-apistatus">4.1 /api/status</h4>

<p>Untuk memastikan bahwa Overpass API service sudah berjalan dengan baik, coba akses endpoint <code class="language-plaintext highlighter-rouge">/api/status</code> untuk melihat status dari Overpass API service.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ curl http://localhost:8081/api/status
</code></pre></div></div>

<p>Outputnya akan seperti ini,</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Connected as: 3232252161
Current time: 2026-02-16T10:25:16Z
Rate limit: 0
</code></pre></div></div>

<h4 id="42-apiinterpreter">4.2 /api/interpreter</h4>

<p>Setelah Overpass API service sudah siap, coba lakukan query untuk mencari data OSM berdasarkan kriteria tertentu.</p>

<p>Base URL nya seperti ini,</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ curl -X POST http://localhost:8081/api/interpreter
</code></pre></div></div>

<p>Outputnya akan seperti ini,</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="cp">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;</span>
<span class="nt">&lt;html</span> <span class="na">xmlns=</span><span class="s">"http://www.w3.org/1999/xhtml"</span> <span class="na">xml:lang=</span><span class="s">"en"</span> <span class="na">lang=</span><span class="s">"en"</span><span class="nt">&gt;</span>
<span class="nt">&lt;head&gt;</span>
  <span class="nt">&lt;meta</span> <span class="na">http-equiv=</span><span class="s">"content-type"</span> <span class="na">content=</span><span class="s">"text/html; charset=utf-8"</span> <span class="na">lang=</span><span class="s">"en"</span><span class="nt">/&gt;</span>
  <span class="nt">&lt;title&gt;</span>OSM3S Response<span class="nt">&lt;/title&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>

<span class="nt">&lt;p&gt;</span>The data included in this document is from www.openstreetmap.org. The data is made available under ODbL.<span class="nt">&lt;/p&gt;</span>
<span class="nt">&lt;p&gt;&lt;strong</span> <span class="na">style=</span><span class="s">"color:#FF0000"</span><span class="nt">&gt;</span>Error<span class="nt">&lt;/strong&gt;</span>: encoding error: Your input contains only whitespace. <span class="nt">&lt;/p&gt;</span>

<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>

<p>Nah, tinggal tambahkan query untuk mencari data OSM berdasarkan kriteria tertentu.</p>

<p>Gunakan juga header <code class="language-plaintext highlighter-rouge">Content-Type: application/x-www-form-urlencoded</code> untuk mengirim data query dalam format URL encoded.</p>

<p>Misalnya, untuk mencari semua POI dengan tag <code class="language-plaintext highlighter-rouge">amenity=cafe</code> pada radius 5000 meter dari titik user berada (<code class="language-plaintext highlighter-rouge">-1.2286365, 116.8941987</code>), kita bisa menggunakan query berikut:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ curl -X POST http://localhost:8081/api/interpreter -H "Content-Type: application/x-www-form-urlencoded" --data "data=[out:json];node[amenity=cafe](around:5000, -1.2286365, 116.8941987);out center;"
</code></pre></div></div>

<p>Outputnya dalam bentuk JSON akan seperti ini,</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.6</span><span class="p">,</span><span class="w">
  </span><span class="nl">"generator"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Overpass API 0.7.57.2 48842a1b"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"osm3s"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"timestamp_osm_base"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2026-01-18T20:51:44Z"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"copyright"</span><span class="p">:</span><span class="w"> </span><span class="s2">"The data included in this document is from www.openstreetmap.org. The data is made available under ODbL."</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"elements"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"node"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">9898980886</span><span class="p">,</span><span class="w">
      </span><span class="nl">"lat"</span><span class="p">:</span><span class="w"> </span><span class="mf">-1.2420011</span><span class="p">,</span><span class="w">
      </span><span class="nl">"lon"</span><span class="p">:</span><span class="w"> </span><span class="mf">116.8730133</span><span class="p">,</span><span class="w">
      </span><span class="nl">"tags"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"amenity"</span><span class="p">:</span><span class="w"> </span><span class="s2">"cafe"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Excelso - Living Plaza"</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"node"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">9899039726</span><span class="p">,</span><span class="w">
      </span><span class="nl">"lat"</span><span class="p">:</span><span class="w"> </span><span class="mf">-1.2437437</span><span class="p">,</span><span class="w">
      </span><span class="nl">"lon"</span><span class="p">:</span><span class="w"> </span><span class="mf">116.8607824</span><span class="p">,</span><span class="w">
      </span><span class="nl">"tags"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"amenity"</span><span class="p">:</span><span class="w"> </span><span class="s2">"cafe"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Excelso Cafe Mall Fantasy"</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"node"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">9899398634</span><span class="p">,</span><span class="w">
      </span><span class="nl">"lat"</span><span class="p">:</span><span class="w"> </span><span class="mf">-1.2449160</span><span class="p">,</span><span class="w">
      </span><span class="nl">"lon"</span><span class="p">:</span><span class="w"> </span><span class="mf">116.8603869</span><span class="p">,</span><span class="w">
      </span><span class="nl">"tags"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"amenity"</span><span class="p">:</span><span class="w"> </span><span class="s2">"cafe"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"CPM Coffee Shop Balikpapan Baru - Damai"</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"node"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">9899400587</span><span class="p">,</span><span class="w">
      </span><span class="nl">"lat"</span><span class="p">:</span><span class="w"> </span><span class="mf">-1.2452571</span><span class="p">,</span><span class="w">
      </span><span class="nl">"lon"</span><span class="p">:</span><span class="w"> </span><span class="mf">116.8597143</span><span class="p">,</span><span class="w">
      </span><span class="nl">"tags"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"amenity"</span><span class="p">:</span><span class="w"> </span><span class="s2">"cafe"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Balgas Cafe - Damai"</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"node"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">9899406395</span><span class="p">,</span><span class="w">
      </span><span class="nl">"lat"</span><span class="p">:</span><span class="w"> </span><span class="mf">-1.2452690</span><span class="p">,</span><span class="w">
      </span><span class="nl">"lon"</span><span class="p">:</span><span class="w"> </span><span class="mf">116.8606450</span><span class="p">,</span><span class="w">
      </span><span class="nl">"tags"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"amenity"</span><span class="p">:</span><span class="w"> </span><span class="s2">"cafe"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Kopi Lawe - Damai Baru"</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"node"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">9900996432</span><span class="p">,</span><span class="w">
      </span><span class="nl">"lat"</span><span class="p">:</span><span class="w"> </span><span class="mf">-1.2511856</span><span class="p">,</span><span class="w">
      </span><span class="nl">"lon"</span><span class="p">:</span><span class="w"> </span><span class="mf">116.8696109</span><span class="p">,</span><span class="w">
      </span><span class="nl">"tags"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"amenity"</span><span class="p">:</span><span class="w"> </span><span class="s2">"cafe"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"branch"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Ruko Jalan MT Haryono"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"brand"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Kopi Kenangan"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"brand:wikidata"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Q97221992"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"cuisine"</span><span class="p">:</span><span class="w"> </span><span class="s2">"coffee_shop"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"diet:halal"</span><span class="p">:</span><span class="w"> </span><span class="s2">"only"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Kopi Kenangan"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"takeaway"</span><span class="p">:</span><span class="w"> </span><span class="s2">"yes"</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"node"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">10036595776</span><span class="p">,</span><span class="w">
      </span><span class="nl">"lat"</span><span class="p">:</span><span class="w"> </span><span class="mf">-1.2460153</span><span class="p">,</span><span class="w">
      </span><span class="nl">"lon"</span><span class="p">:</span><span class="w"> </span><span class="mf">116.8594667</span><span class="p">,</span><span class="w">
      </span><span class="nl">"tags"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"amenity"</span><span class="p">:</span><span class="w"> </span><span class="s2">"cafe"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Dialog Cafe - Balikpapan Baru"</span><span class="w">
      </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Dari data di atas, kita bisa melihat bahwa terdapat beberapa POI dengan tag <code class="language-plaintext highlighter-rouge">amenity=cafe</code> pada radius 5000 meter dari latitude dan longitude yang saya definisikan  yang berhasil ditemukan oleh Overpass API.</p>

<p>Silahkan sesuaikan query sesuai dengan kebutuhan untuk mencari data OSM berdasarkan kriteria tertentu. Berikut adalah contoh query dalam format Overpass QL yang digunakan di atas:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[out:json];
(
  node[amenity=cafe](around:5000, -1.2286365, 116.8941987);
);
out center;
</code></pre></div></div>

<h3 id="5-stop-docker-compose">5. Stop Docker Compose</h3>

<p>Jika sudah selesai menggunakan Overpass API service, jangan lupa untuk menghentikan Docker Compose dengan perintah berikut:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker-compose download
</code></pre></div></div>

<h2 id="kesimpulan">Kesimpulan</h2>

<p>Saya telah mencatat langkah-langkah untuk menjalankan instance Overpass API menggunakan Docker. Dengan mengikuti langkah-langkah di atas, kita dapat dengan mudah menjalankan Overpass API service di lingkungan lokal kita dan melakukan query terhadap data OpenStreetMap untuk mencari POI berdasarkan kriteria tertentu.</p>

<h2 id="referensi">Referensi</h2>

<ol>
  <li><a href="https://overpass-api.de/">https://overpass-api.de/</a> <br />
  Diakses tanggal: 2026-02-15</li>
  <li><a href="https://osmcode.org/osmium-tool/">https://osmcode.org/osmium-tool/</a> <br />
  Diakses tanggal: 2026-02-15</li>
</ol>]]></content><author><name>BanditHijo</name></author><category term="blog" /><category term="openstreetmap" /><category term="overpass" /><category term="overpassapi" /><summary type="html"><![CDATA[Overpass API memungkinkan kita untuk melakukan query terhadap data OpenStreetMap yang dapat digunakan untuk mencari POI (Point of Interest) pada radius tertentu dari lokasi yang didefinisikan. Pada artikel ini, saya akan mencatat langkah-langkah untuk menjalankan instance Overpass API menggunakan Docker.]]></summary></entry><entry><title type="html">Menggunakan Nominatim Self-Hosted pada Geocoder Gem</title><link href="https://bandithijo.dev/blog/menggunakan-nominatim-self-hosted-pada-geocoder-gem" rel="alternate" type="text/html" title="Menggunakan Nominatim Self-Hosted pada Geocoder Gem" /><published>2026-02-08T23:22:00+08:00</published><updated>2026-02-08T23:22:00+08:00</updated><id>https://bandithijo.dev/blog/menggunakan-nominatim-self-hosted-pada-geocoder-gem</id><content type="html" xml:base="https://bandithijo.dev/blog/menggunakan-nominatim-self-hosted-pada-geocoder-gem"><![CDATA[<h2 id="pendahuluan">Pendahuluan</h2>

<p>Pada catatan sebelumnya “<a href="https://bandithijo.dev/blog/openstreetmap-nominatim-dengan-docker">OpenStreetMap Nominatim (Geocoding Machine) dengan Docker</a>” saya telah membahas cara menjalankan instance Nominatim menggunakan Docker. Pada artikel ini, saya akan mencatat langkah-langkah untuk mengonfigurasi Geocoder gem di aplikasi Ruby on Rails agar menggunakan instance Nominatim self-hosted sebagai geocoding service lookup.</p>

<h2 id="konfigurasi-geocoder-gem">Konfigurasi Geocoder Gem</h2>

<p>Jika sebelumnya sudah memiliki config file untuk Geocoder di <code class="language-plaintext highlighter-rouge">config/initializers/geocoder.rb</code>, buka file tersebut.</p>

<p>Dan tambahkan atau modifikasi konfigurasi seperti ini,</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">!</span><span class="ss">filename: </span><span class="n">config</span><span class="o">/</span><span class="n">initializers</span><span class="o">/</span><span class="n">geocoder</span><span class="p">.</span><span class="nf">rb</span>
<span class="no">Geocoder</span><span class="p">.</span><span class="nf">configure</span><span class="p">(</span>
  <span class="c1"># Geocoding options</span>
  <span class="c1"># timeout: 3,                 # geocoding service timeout (secs)</span>
  <span class="c1"># lookup: :nominatim,         # name of geocoding service (symbol)</span>
  <span class="c1"># ip_lookup: :ipinfo_io,      # name of IP address geocoding service (symbol)</span>
  <span class="c1"># language: :en,              # ISO-639 language code</span>
  <span class="c1"># use_https: false,           # use HTTPS for lookup requests? (if supported)</span>
  <span class="c1"># http_proxy: nil,            # HTTP proxy server (user:pass@host:port)</span>
  <span class="c1"># https_proxy: nil,           # HTTPS proxy server (user:pass@host:port)</span>
  <span class="c1"># api_key: nil,               # API key for geocoding service</span>
  <span class="c1"># cache: nil,                 # cache object (must respond to #[], #[]=, and #del)</span>

  <span class="c1"># Exceptions that should not be rescued by default</span>
  <span class="c1"># (if you want to implement custom error handling);</span>
  <span class="c1"># supports SocketError and Timeout::Error</span>
  <span class="c1"># always_raise: [],</span>

  <span class="c1"># Calculation options</span>
  <span class="c1"># units: :km,                 # :km for kilometers or :mi for miles</span>
  <span class="c1"># distances: :linear          # :spherical or :linear</span>

  <span class="c1"># Cache configuration</span>
  <span class="c1"># cache_options: {</span>
  <span class="c1">#   expiration: 2.days,</span>
  <span class="c1">#   prefix: 'geocoder:'</span>
  <span class="c1"># }</span>

  <span class="ss">use_https: </span><span class="kp">false</span><span class="p">,</span>
  <span class="ss">lookup: :nominatim</span><span class="p">,</span>
  <span class="ss">nominatim: </span><span class="p">{</span>
    <span class="ss">host: </span><span class="n">localhost</span><span class="p">:</span><span class="mi">8080</span>
  <span class="p">},</span>
<span class="p">)</span>
</code></pre></div></div>

<p>Saya menggunakan <code class="language-plaintext highlighter-rouge">localhost:8080</code> karena pada catatan sebelumnya saya menjalankan Nominatim di Docker dengan port mapping <code class="language-plaintext highlighter-rouge">8080:8080</code> dan karena di localhost sehingga tidak menggunakan https.</p>

<p>Bisa juga disesuaikan dengan host dan port tempat Nominatim dijalankan. Misal, saya sudah punya service yang saya jalankan di <code class="language-plaintext highlighter-rouge">https://nominatim.bandithijo.dev</code>, maka konfigurasi <code class="language-plaintext highlighter-rouge">nominatim</code> akan seperti ini,</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">!</span><span class="ss">filename: </span><span class="n">config</span><span class="o">/</span><span class="n">initializers</span><span class="o">/</span><span class="n">geocoder</span><span class="p">.</span><span class="nf">rb</span>
<span class="no">Geocoder</span><span class="p">.</span><span class="nf">configure</span><span class="p">(</span>
  <span class="c1"># ...</span>
  <span class="c1"># ...</span>

  <span class="ss">use_https: </span><span class="kp">true</span><span class="p">,</span>
  <span class="ss">lookup: :nominatim</span><span class="p">,</span>
  <span class="ss">nominatim: </span><span class="p">{</span>
    <span class="ss">host: </span><span class="s1">'nominatim.bandithijo.dev'</span><span class="p">,</span>
  <span class="p">},</span>
<span class="p">)</span>
</code></pre></div></div>

<p>Dengan begini saya sudah berhasil mengonfigurasi Geocoder gem untuk menggunakan Nominatim self-hosted sebagai geocoding service lookup. Selanjutnya, saya bisa menggunakan Geocoder gem untuk melakukan geocoding dan reverse geocoding pada aplikasi Ruby on Rails saya dengan menggunakan instance Nominatim yang saya jalankan sendiri.</p>

<h2 id="pengujian">Pengujian</h2>

<p>Untuk menguji apakah konfigurasi sudah benar, bisa dilakukan di Rails console.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ rails console
</code></pre></div></div>

<p>Setup logger agar menampilkan request dan response dari Geocoder gem untuk mempermudah proses debugging,</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">001</span><span class="o">&gt;</span> <span class="no">Geocoder</span><span class="p">.</span><span class="nf">configure</span><span class="p">(</span><span class="ss">logger: </span><span class="no">Logger</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">STDOUT</span><span class="p">))</span>
</code></pre></div></div>

<p>Outputnya,</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">=&gt;</span>
<span class="p">{</span><span class="ss">:timeout</span><span class="o">=&gt;</span><span class="mi">3</span><span class="p">,</span>
 <span class="ss">:lookup</span><span class="o">=&gt;</span><span class="ss">:nominatim</span><span class="p">,</span>
 <span class="ss">:ip_lookup</span><span class="o">=&gt;</span><span class="ss">:ipinfo_io</span><span class="p">,</span>
 <span class="ss">:language</span><span class="o">=&gt;</span><span class="ss">:en</span><span class="p">,</span>
 <span class="ss">:http_headers</span><span class="o">=&gt;</span><span class="p">{},</span>
 <span class="ss">:use_https</span><span class="o">=&gt;</span><span class="kp">true</span><span class="p">,</span>
 <span class="ss">:http_proxy</span><span class="o">=&gt;</span><span class="kp">nil</span><span class="p">,</span>
 <span class="ss">:https_proxy</span><span class="o">=&gt;</span><span class="kp">nil</span><span class="p">,</span>
 <span class="ss">:api_key</span><span class="o">=&gt;</span><span class="kp">nil</span><span class="p">,</span>
 <span class="ss">:basic_auth</span><span class="o">=&gt;</span><span class="p">{},</span>
 <span class="ss">:logger</span><span class="o">=&gt;</span>
  <span class="c1">#&lt;Logger:0x000000012837e6b8</span>
   <span class="vi">@default_formatter</span><span class="o">=</span><span class="c1">#&lt;Logger::Formatter:0x0000000124a709e8 @datetime_format=nil&gt;,</span>
   <span class="vi">@formatter</span><span class="o">=</span><span class="kp">nil</span><span class="p">,</span>
   <span class="vi">@level</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
   <span class="vi">@level_override</span><span class="o">=</span><span class="p">{},</span>
   <span class="vi">@logdev</span><span class="o">=</span>
    <span class="c1">#&lt;Logger::LogDevice:0x0000000128273980</span>
     <span class="vi">@binmode</span><span class="o">=</span><span class="kp">false</span><span class="p">,</span>
     <span class="vi">@dev</span><span class="o">=</span><span class="c1">#&lt;IO:&lt;STDOUT&gt;&gt;,</span>
     <span class="vi">@filename</span><span class="o">=</span><span class="kp">nil</span><span class="p">,</span>
     <span class="vi">@mon_data</span><span class="o">=</span><span class="c1">#&lt;Monitor:0x0000000124a70970&gt;,</span>
     <span class="vi">@mon_data_owner_object_id</span><span class="o">=</span><span class="mi">71700</span><span class="p">,</span>
     <span class="vi">@reraise_write_errors</span><span class="o">=</span><span class="p">[],</span>
     <span class="vi">@shift_age</span><span class="o">=</span><span class="kp">nil</span><span class="p">,</span>
     <span class="vi">@shift_period_suffix</span><span class="o">=</span><span class="kp">nil</span><span class="p">,</span>
     <span class="vi">@shift_size</span><span class="o">=</span><span class="kp">nil</span><span class="p">,</span>
     <span class="vi">@skip_header</span><span class="o">=</span><span class="kp">false</span><span class="o">&gt;</span><span class="p">,</span>
   <span class="vi">@progname</span><span class="o">=</span><span class="kp">nil</span><span class="o">&gt;</span><span class="p">,</span>
 <span class="ss">:kernel_logger_level</span><span class="o">=&gt;</span><span class="mi">2</span><span class="p">,</span>
 <span class="ss">:always_raise</span><span class="o">=&gt;</span><span class="p">[],</span>
 <span class="ss">:units</span><span class="o">=&gt;</span><span class="ss">:km</span><span class="p">,</span>
 <span class="ss">:distances</span><span class="o">=&gt;</span><span class="ss">:linear</span><span class="p">,</span>
 <span class="ss">:cache</span><span class="o">=&gt;</span><span class="kp">nil</span><span class="p">,</span>
 <span class="ss">:cache_prefix</span><span class="o">=&gt;</span><span class="kp">nil</span><span class="p">,</span>
 <span class="ss">:cache_options</span><span class="o">=&gt;</span><span class="p">{</span><span class="ss">:prefix</span><span class="o">=&gt;</span><span class="s2">"geocoder:"</span><span class="p">,</span> <span class="ss">:expiration</span><span class="o">=&gt;</span><span class="kp">nil</span><span class="p">},</span>
 <span class="ss">:nominatim</span><span class="o">=&gt;</span><span class="p">{</span><span class="ss">:host</span><span class="o">=&gt;</span><span class="s2">"osm.bintangdigitalasia.com/nominatim"</span><span class="p">}}</span>
</code></pre></div></div>

<p>Dapat dilihat, bahwa konfigurasi <code class="language-plaintext highlighter-rouge">nominatim</code> untuk <code class="language-plaintext highlighter-rouge">host</code> sudah sesuai dengan yang diinginkan.</p>

<p>Lalu lakukan geocoding pada alamat tertentu,</p>

<h3 id="forward-search">Forward Search</h3>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">002</span><span class="o">&gt;</span> <span class="no">Geocoder</span><span class="p">.</span><span class="nf">search</span><span class="p">(</span><span class="s2">"Jakarta"</span><span class="p">)</span>
</code></pre></div></div>

<p>Outputnya,</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">D</span><span class="p">,</span> <span class="p">[</span><span class="mi">2026</span><span class="o">-</span><span class="mo">02</span><span class="o">-</span><span class="mi">09</span><span class="no">T00</span><span class="p">:</span><span class="mo">02</span><span class="p">:</span><span class="mf">12.686252</span> <span class="c1">#30316] DEBUG -- : Geocoder: HTTP request being made for http://localhost:8080/search?accept-language=en&amp;addressdetails=1&amp;format=json&amp;q=Jakarta</span>
<span class="o">=&gt;</span>
<span class="p">[</span><span class="c1">#&lt;Geocoder::Result::Nominatim:0x0000000127219df0</span>
  <span class="vi">@cache_hit</span><span class="o">=</span><span class="kp">nil</span><span class="p">,</span>
  <span class="vi">@data</span><span class="o">=</span>
   <span class="p">{</span><span class="s2">"place_id"</span><span class="o">=&gt;</span><span class="mi">3204450</span><span class="p">,</span>
    <span class="s2">"licence"</span><span class="o">=&gt;</span><span class="s2">"Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright"</span><span class="p">,</span>
    <span class="s2">"osm_type"</span><span class="o">=&gt;</span><span class="s2">"relation"</span><span class="p">,</span>
    <span class="s2">"osm_id"</span><span class="o">=&gt;</span><span class="mi">6362934</span><span class="p">,</span>
    <span class="s2">"lat"</span><span class="o">=&gt;</span><span class="s2">"-6.1754049"</span><span class="p">,</span>
    <span class="s2">"lon"</span><span class="o">=&gt;</span><span class="s2">"106.8271680"</span><span class="p">,</span>
    <span class="s2">"class"</span><span class="o">=&gt;</span><span class="s2">"boundary"</span><span class="p">,</span>
    <span class="s2">"type"</span><span class="o">=&gt;</span><span class="s2">"administrative"</span><span class="p">,</span>
    <span class="s2">"place_rank"</span><span class="o">=&gt;</span><span class="mi">8</span><span class="p">,</span>
    <span class="s2">"importance"</span><span class="o">=&gt;</span><span class="mf">0.2933433333333333</span><span class="p">,</span>
    <span class="s2">"addresstype"</span><span class="o">=&gt;</span><span class="s2">"city"</span><span class="p">,</span>
    <span class="s2">"name"</span><span class="o">=&gt;</span><span class="s2">"Special Capital Region of Jakarta"</span><span class="p">,</span>
    <span class="s2">"display_name"</span><span class="o">=&gt;</span><span class="s2">"Special Capital Region of Jakarta, Java, Indonesia"</span><span class="p">,</span>
    <span class="s2">"address"</span><span class="o">=&gt;</span>
     <span class="p">{</span><span class="s2">"city"</span><span class="o">=&gt;</span><span class="s2">"Special Capital Region of Jakarta"</span><span class="p">,</span>
      <span class="s2">"ISO3166-2-lvl4"</span><span class="o">=&gt;</span><span class="s2">"ID-JK"</span><span class="p">,</span>
      <span class="s2">"region"</span><span class="o">=&gt;</span><span class="s2">"Java"</span><span class="p">,</span>
      <span class="s2">"ISO3166-2-lvl3"</span><span class="o">=&gt;</span><span class="s2">"ID-JW"</span><span class="p">,</span>
      <span class="s2">"country"</span><span class="o">=&gt;</span><span class="s2">"Indonesia"</span><span class="p">,</span>
      <span class="s2">"country_code"</span><span class="o">=&gt;</span><span class="s2">"id"</span><span class="p">},</span>
    <span class="s2">"boundingbox"</span><span class="o">=&gt;</span><span class="p">[</span><span class="s2">"-6.3744575"</span><span class="p">,</span> <span class="s2">"-4.9993635"</span><span class="p">,</span> <span class="s2">"106.3146732"</span><span class="p">,</span> <span class="s2">"106.9739750"</span><span class="p">]}</span><span class="o">&gt;</span><span class="p">]</span>
</code></pre></div></div>

<h3 id="reverse-search">Reverse Search</h3>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">003</span><span class="o">&gt;</span> <span class="no">Geocoder</span><span class="p">.</span><span class="nf">search</span><span class="p">([</span><span class="o">-</span><span class="mf">1.2379</span><span class="p">,</span> <span class="mf">116.8529</span><span class="p">])</span>
</code></pre></div></div>

<p>Outputnya,</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">D</span><span class="p">,</span> <span class="p">[</span><span class="mi">2026</span><span class="o">-</span><span class="mo">02</span><span class="o">-</span><span class="mi">09</span><span class="no">T00</span><span class="p">:</span><span class="mo">04</span><span class="p">:</span><span class="mf">49.941967</span> <span class="c1">#30316] DEBUG -- : Geocoder: HTTP request being made for http://locahost:8080/reverse?accept-language=en&amp;addressdetails=1&amp;format=json&amp;lat=-1.2379&amp;lon=116.8529</span>
<span class="o">=&gt;</span>
<span class="p">[</span><span class="c1">#&lt;Geocoder::Result::Nominatim:0x0000000125da17b0</span>
  <span class="vi">@cache_hit</span><span class="o">=</span><span class="kp">nil</span><span class="p">,</span>
  <span class="vi">@data</span><span class="o">=</span>
   <span class="p">{</span><span class="s2">"place_id"</span><span class="o">=&gt;</span><span class="mi">119266</span><span class="p">,</span>
    <span class="s2">"licence"</span><span class="o">=&gt;</span><span class="s2">"Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright"</span><span class="p">,</span>
    <span class="s2">"osm_type"</span><span class="o">=&gt;</span><span class="s2">"way"</span><span class="p">,</span>
    <span class="s2">"osm_id"</span><span class="o">=&gt;</span><span class="mi">109864339</span><span class="p">,</span>
    <span class="s2">"lat"</span><span class="o">=&gt;</span><span class="s2">"-1.2378944"</span><span class="p">,</span>
    <span class="s2">"lon"</span><span class="o">=&gt;</span><span class="s2">"116.8529396"</span><span class="p">,</span>
    <span class="s2">"class"</span><span class="o">=&gt;</span><span class="s2">"highway"</span><span class="p">,</span>
    <span class="s2">"type"</span><span class="o">=&gt;</span><span class="s2">"residential"</span><span class="p">,</span>
    <span class="s2">"place_rank"</span><span class="o">=&gt;</span><span class="mi">26</span><span class="p">,</span>
    <span class="s2">"importance"</span><span class="o">=&gt;</span><span class="mf">0.0533433333333333</span><span class="p">,</span>
    <span class="s2">"addresstype"</span><span class="o">=&gt;</span><span class="s2">"road"</span><span class="p">,</span>
    <span class="s2">"name"</span><span class="o">=&gt;</span><span class="s2">"Jalan Bubutan"</span><span class="p">,</span>
    <span class="s2">"display_name"</span><span class="o">=&gt;</span><span class="s2">"Jalan Bubutan, Gunung Samarinda, Balikpapan Utara, Balikpapan, East Kalimantan, 76125, Indonesia"</span><span class="p">,</span>
    <span class="s2">"address"</span><span class="o">=&gt;</span>
     <span class="p">{</span><span class="s2">"road"</span><span class="o">=&gt;</span><span class="s2">"Jalan Bubutan"</span><span class="p">,</span>
      <span class="s2">"village"</span><span class="o">=&gt;</span><span class="s2">"Gunung Samarinda"</span><span class="p">,</span>
      <span class="s2">"city_district"</span><span class="o">=&gt;</span><span class="s2">"Balikpapan Utara"</span><span class="p">,</span>
      <span class="s2">"city"</span><span class="o">=&gt;</span><span class="s2">"Balikpapan"</span><span class="p">,</span>
      <span class="s2">"state"</span><span class="o">=&gt;</span><span class="s2">"East Kalimantan"</span><span class="p">,</span>
      <span class="s2">"ISO3166-2-lvl4"</span><span class="o">=&gt;</span><span class="s2">"ID-KI"</span><span class="p">,</span>
      <span class="s2">"postcode"</span><span class="o">=&gt;</span><span class="s2">"76125"</span><span class="p">,</span>
      <span class="s2">"country"</span><span class="o">=&gt;</span><span class="s2">"Indonesia"</span><span class="p">,</span>
      <span class="s2">"country_code"</span><span class="o">=&gt;</span><span class="s2">"id"</span><span class="p">},</span>
    <span class="s2">"boundingbox"</span><span class="o">=&gt;</span><span class="p">[</span><span class="s2">"-1.2383814"</span><span class="p">,</span> <span class="s2">"-1.2355025"</span><span class="p">,</span> <span class="s2">"116.8482510"</span><span class="p">,</span> <span class="s2">"116.8530576"</span><span class="p">]}</span><span class="o">&gt;</span><span class="p">]</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">003</span><span class="o">&gt;</span>
</code></pre></div></div>

<h2 id="kesimpulan">Kesimpulan</h2>

<p>Dengan mengikuti langkah-langkah di atas, saya berhasil mengonfigurasi Geocoder gem untuk menggunakan Nominatim self-hosted sebagai geocoding service lookup. Saya juga berhasil melakukan geocoding dan reverse geocoding menggunakan instance Nominatim yang saya jalankan sendiri. Dengan menggunakan Nominatim self-hosted, saya memiliki kontrol penuh atas data geocoding dan dapat menghindari batasan penggunaan yang mungkin diterapkan oleh layanan geocoding pihak ketiga.</p>

<h2 id="referensi">Referensi</h2>

<ol>
  <li><a href="https://github.com/alexreisner/geocoder">https://github.com/alexreisner/geocoder</a> <br />
  Diakses tanggal: 2026-02-08</li>
</ol>]]></content><author><name>BanditHijo</name></author><category term="blog" /><category term="openstreetmap" /><category term="nominatim" /><category term="geocoder" /><category term="geocoding" /><category term="rails" /><summary type="html"><![CDATA[Pada artikel ini, saya akan mencatat langkah-langkah untuk mengonfigurasi Geocoder gem di aplikasi Ruby on Rails agar menggunakan instance Nominatim self-hosted sebagai geocoding service lookup.]]></summary></entry><entry><title type="html">OpenStreetMap Nominatim (Geocoding Machine) dengan Docker</title><link href="https://bandithijo.dev/blog/openstreetmap-nominatim-dengan-docker" rel="alternate" type="text/html" title="OpenStreetMap Nominatim (Geocoding Machine) dengan Docker" /><published>2026-02-07T11:21:00+08:00</published><updated>2026-02-07T11:21:00+08:00</updated><id>https://bandithijo.dev/blog/openstreetmap-nominatim-dengan-docker</id><content type="html" xml:base="https://bandithijo.dev/blog/openstreetmap-nominatim-dengan-docker"><![CDATA[<p><img src="https://bandithijo.dev/assets/posts/blog/2026/2026-02-07-openstreetmap-nominatim-dengan-docker/gambar_01.png" alt="Gambar 1" /></p>

<h2 id="pendahuluan">Pendahuluan</h2>

<p>OpenStreetMap Nominatim adalah sebuah layanan geocoding yang memungkinkan pengguna untuk mencari lokasi berdasarkan nama tempat  atau alamat (forward search) atau geographic coordinate (reverse search). Dalam artikel ini, saya akan mendokumentasikan cara menjalankan OpenStreetMap Nominatim menggunakan Docker agar proses setup Nominatim menjadi lebih mudah dan cepat, tanpa perlu repot mengatur lingkungan dan dependensi secara manual.</p>

<h2 id="apa-itu-openstreetmap-nominatim">Apa itu OpenStreetMap Nominatim?</h2>

<p>OpenStreetMap Nominatim adalah sebuah layanan geocoding yang memungkinkan pengguna untuk mencari lokasi berdasarkan nama tempat atau alamat (<em>forward search</em>) atau koordinat geografis (<em>reverse search</em>). Nominatim menggunakan data dari OpenStreetMap untuk menyediakan informasi lokasi yang akurat. Tanpa OpenStreetMap, Nominatim tidak memiliki data apapun untuk digunakan dalam proses geocoding.</p>

<p><strong><em>Forward Geocodig</em></strong> adalah proses mengubah nama tempat atau alamat menjadi koordinat geografis (latitude dan longitude). Misalnya, jika mencari “Balikpapan”, Nominatim akan memberikan koordinat geografis dari Balikpapan.</p>

<p><strong><em>Reverse Geocoding</em></strong> adalah proses mengubah koordinat geografis (latitude &amp; longitude) menjadi nama tempat atau alamat. Misalnya, jika memiliki koordinat geografis dari Balikpapan (<code class="language-plaintext highlighter-rouge">-1.2398711,116.8593379</code>), Nominatim akan memberikan nama tempat atau alamat yang sesuai.</p>

<h3 id="nominatim-api">Nominatim API</h3>

<p>Nominatim menyediakan API yang dapat digunakan untuk melakukan forward, reverse geocoding dan beberapa hal lainnya.</p>

<p>Berikut adalah contoh penggunaan Nominatim API:</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">/search</code> <br />
  Digunakan untuk melakukan forward geocoding. Untuk mencari lokasi berdasarkan nama tempat atau alamat.</li>
  <li><code class="language-plaintext highlighter-rouge">/reverse</code> <br />
  Digunakan untuk melakukan reverse geocoding. Untuk mencari nama tempat atau alamat berdasarkan koordinat geografis (latitude &amp; longitude).</li>
  <li><code class="language-plaintext highlighter-rouge">/lookup</code> <br />
  Digunakan untuk mencari informasi lokasi berdasarkan OSM ID.</li>
  <li><code class="language-plaintext highlighter-rouge">/details</code> <br />
  Digunakan untuk mencari informasi lokasi berdasarkan OSM ID, dengan informasi yang lebih detail dibandingkan dengan <code class="language-plaintext highlighter-rouge">/lookup</code>.</li>
  <li><code class="language-plaintext highlighter-rouge">/status</code> <br />
  Digunakan untuk memeriksa status dari Nominatim service.</li>
  <li>dll.</li>
</ol>

<h2 id="openstreetmap-nominatim-dengan-docker">OpenStreetMap Nominatim dengan Docker</h2>

<p>Untuk menjalankan OpenStreetMap Nominatim dengan Docker, bisa menggunakan image yang sudah tersedia di Docker Hub. Agar prosesnya lebih mudah, saya prefer untuk membuat docker compose saja. Berikut adalah langkah-langkahnya:</p>

<h3 id="1-buat-docker-compose-untuk-nominatim-service">1. Buat Docker Compose untuk Nominatim Service</h3>

<p>Buat file <code class="language-plaintext highlighter-rouge">docker-compose.yml</code> dengan isi sebagai berikut:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">!filename:</span> <span class="s">docker-compose.yml</span>
<span class="na">services</span><span class="pi">:</span>
 <span class="na">nominatim</span><span class="pi">:</span>
   <span class="na">image</span><span class="pi">:</span> <span class="s">mediagis/nominatim:5.2</span>
   <span class="na">container_name</span><span class="pi">:</span> <span class="s">osm-nominatim</span>
   <span class="na">restart</span><span class="pi">:</span> <span class="s">unless-stopped</span>
   <span class="na">environment</span><span class="pi">:</span>
     <span class="na">PBF_PATH</span><span class="pi">:</span> <span class="s">/nominatim/data/kalimantan-latest.osm.pbf</span>
   <span class="na">volumes</span><span class="pi">:</span>
     <span class="pi">-</span> <span class="s">./geofabrik/kalimantan-latest.osm.pbf:/nominatim/data/kalimantan-latest.osm.pbf</span>
     <span class="pi">-</span> <span class="s">nominatim-data:/var/lib/postgresql</span>
   <span class="na">expose</span><span class="pi">:</span>
     <span class="pi">-</span> <span class="s2">"</span><span class="s">8080"</span>
   <span class="na">ports</span><span class="pi">:</span>
     <span class="pi">-</span> <span class="s2">"</span><span class="s">8080:8080"</span>

<span class="na">volumes</span><span class="pi">:</span>
 <span class="na">nominatim-data</span><span class="pi">:</span>
</code></pre></div></div>

<p>Saya menggunakan docker image <code class="language-plaintext highlighter-rouge">mediagis/nominatim:5.2</code> yang sudah tersedia di Docker Hub.</p>

<p>Pada <code class="language-plaintext highlighter-rouge">PBF_PATH</code> diisi dengan file <code class="language-plaintext highlighter-rouge">.osm.pbf</code>. PBF adalah format file yang digunakan untuk menyimpan data OpenStreetMap. File ini berisi informasi tentang jalan, bangunan, dan fitur geografis lainnya yang ada di wilayah tertentu. Dalam contoh ini, saya menggunakan file <code class="language-plaintext highlighter-rouge">kalimantan-latest.osm.pbf</code> yang berisi data OpenStreetMap untuk wilayah Kalimantan. Untuk mendapatkan file <code class="language-plaintext highlighter-rouge">.osm.pbf</code> untuk wilayah lain, bisa mengunduhnya dari situs <a href="https://download.geofabrik.de/">Geofabrik</a>.</p>

<p>Kisaran size file <code class="language-plaintext highlighter-rouge">.osm.pbf</code> untuk wilayah Indonesia dan beberapa wilayah lainnya adalah sebagai berikut:</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Region</th>
      <th style="text-align: right">Size</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">Indonesia (with East Timor)</td>
      <td style="text-align: right">1.6 GB</td>
    </tr>
    <tr>
      <td style="text-align: left">Java</td>
      <td style="text-align: right">845 MB</td>
    </tr>
    <tr>
      <td style="text-align: left">Kalimantan</td>
      <td style="text-align: right">138 MB</td>
    </tr>
    <tr>
      <td style="text-align: left">Maluku</td>
      <td style="text-align: right">25.1 MB</td>
    </tr>
    <tr>
      <td style="text-align: left">Nusa Tenggara</td>
      <td style="text-align: right">162 MB</td>
    </tr>
    <tr>
      <td style="text-align: left">Papua</td>
      <td style="text-align: right">31.0 MB</td>
    </tr>
    <tr>
      <td style="text-align: left">Sulawesi</td>
      <td style="text-align: right">149 MB</td>
    </tr>
    <tr>
      <td style="text-align: left">Sumatra</td>
      <td style="text-align: right">255 MB</td>
    </tr>
  </tbody>
</table>

<p>Saya menggunakan 2 values untuk <code class="language-plaintext highlighter-rouge">volumes</code>,</p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">.geofabrik/kalimantan-latest.osm.pbf:/nominatim/data/kalimantan-latest.osm.pbf</code> <br />
  Volume ini digunakan untuk menghubungkan file <code class="language-plaintext highlighter-rouge">.osm.pbf</code> yang ada di host dengan file <code class="language-plaintext highlighter-rouge">.osm.pbf</code> yang ada di dalam container. Dengan begitu, saya dapat menggunakannya di <code class="language-plaintext highlighter-rouge">PBF_PATH</code> untuk proses import data. Proses persiapan file <code class="language-plaintext highlighter-rouge">.osm.pbf</code> ini akan saya jelaskan di bagian selanjutnya.</li>
  <li><code class="language-plaintext highlighter-rouge">nominatim-data:/var/lib/postgresql</code> <br />
  Volume ini digunakan untuk menyimpan data yang dihasilkan oleh Nominatim. Data ini akan disimpan di dalam container, sehingga jika container dihapus, data ini tidak akan hilang. <code class="language-plaintext highlighter-rouge">nominatim-data</code> ini adalah nama volume yang dibuat dibagian <code class="language-plaintext highlighter-rouge">volumes</code> di bawah <code class="language-plaintext highlighter-rouge">nominatim-data:</code>. Volume ini akan dihubungkan dengan direktori <code class="language-plaintext highlighter-rouge">/var/lib/postgresql</code> di dalam container, yang merupakan direktori tempat Nominatim menyimpan data yang dihasilkan.</li>
</ol>

<p>Secara default nonimatin mengekspose port <code class="language-plaintext highlighter-rouge">8080</code> di dalam container, sehingga saya juga expose port <code class="language-plaintext highlighter-rouge">8080</code> di bagian <code class="language-plaintext highlighter-rouge">expose</code>. Agar bisa diakses dari luar container, saya juga memetakan port <code class="language-plaintext highlighter-rouge">8080</code> di host ke port <code class="language-plaintext highlighter-rouge">8080</code> di dalam container dengan menggunakan <code class="language-plaintext highlighter-rouge">ports</code>.</p>

<h3 id="2-persiapkan-data-osm-berupa-file-osmpbf">2. Persiapkan data OSM berupa file <code class="language-plaintext highlighter-rouge">.osm.pbf</code></h3>

<p>Sebelum menjalankan Docker Compose, pastikan sudah memiliki file <code class="language-plaintext highlighter-rouge">.osm.pbf</code> yang akan digunakan untuk proses import data. File <code class="language-plaintext highlighter-rouge">.osm.pbf</code> ini bisa didapatkan dari situs <a href="https://download.geofabrik.de/">Geofabrik</a>.</p>

<p>Setelah mengunduh file <code class="language-plaintext highlighter-rouge">.osm.pbf</code>, letakkan file tersebut di dalam direktori <code class="language-plaintext highlighter-rouge">geofabrik/</code> yang berada di root project. Buat direktori <code class="language-plaintext highlighter-rouge">geofabrik/</code> jika belum ada.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ mkdir geofabrik
$ cd geofabrik
$ wget -c https://download.geofabrik.de/asia/indonesia/kalimantan-latest.osm.pbf
</code></pre></div></div>

<p>Tunggu proses download selesai, setelah itu pastikan file <code class="language-plaintext highlighter-rouge">.osm.pbf</code> sudah berada di dalam direktori <code class="language-plaintext highlighter-rouge">geofabrik/</code>.</p>

<p>Berikut adalah struktur direktori yang diharapkan setelah menambahkan file <code class="language-plaintext highlighter-rouge">.osm.pbf</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>geofabrik/
└── kalimantan-latest.osm.pbf
docker-compose.yml
</code></pre></div></div>

<p>Sip, sekarang file <code class="language-plaintext highlighter-rouge">.osm.pbf</code> sudah siap untuk digunakan dalam proses import data oleh Nominatim.</p>

<h3 id="3-jalankan-docker-compose">3. Jalankan Docker Compose</h3>

<p>Setelah membuat file <code class="language-plaintext highlighter-rouge">docker-compose.yml</code>, jalankan perintah berikut untuk menjalankan Nominatim service:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker-compose up -d
</code></pre></div></div>

<blockquote>
  <p>PERHATIAN</p>

  <p>Untuk pertama kali menjalankan docker compose, Nominatim service akan melakukan proses import data dari file <code class="language-plaintext highlighter-rouge">.osm.pbf</code> ke dalam Nominatim, proses ini membutuhkan waktu yang cukup lama, tergantung pada ukuran file <code class="language-plaintext highlighter-rouge">.osm.pbf</code> yang digunakan. Untuk file <code class="language-plaintext highlighter-rouge">kalimantan-latest.osm.pbf</code> yang berukuran 138 MB, proses import data bisa memakan waktu sekitar 30 menit hingga 1 jam.</p>
</blockquote>

<p>Untuk melihat log dari container, bisa menggunakan perintah berikut:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker compose logs nominatim -f
</code></pre></div></div>

<p>Tunggu proses import data selesai. Biasanya akan muncul log seperti berikut ketika proses import data sudah selesai:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>--&gt; Nominatim is ready to accept requests
</code></pre></div></div>

<p>Setelah proses import data selesai, Nominatim service sudah siap untuk digunakan. Nominatim API bisa diakses melalui <code class="language-plaintext highlighter-rouge">http://localhost:8080/</code>.</p>

<h3 id="4-coba-nominatim-api">4. Coba Nominatim API</h3>

<p>Setelah Nominatim service sudah siap, coba akses Nominatim API untuk melakukan forward geocoding dan reverse geocoding.</p>

<h4 id="status">/status</h4>

<p>Pertama-tama coba cek statusnya dulu.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ curl http://localhost:8080/status
</code></pre></div></div>

<p>Outputnya,</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>OK
</code></pre></div></div>

<p>Atau kalau mau outputnya dalam JSON,</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ curl http://localhost:8080/status?format=json
</code></pre></div></div>

<p>Outputnya,</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"status"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
  </span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"OK"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"data_updated"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2026-01-21T12:30:08+00:00"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"software_version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"5.2.0"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"database_version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"5.2.0-0"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h4 id="search-forward-geocoding">/search (Forward Geocoding)</h4>

<p>Coba lakukan forward geocoding untuk mencari lokasi berdasarkan nama tempat atau alamat. Misalnya, mencari lokasi “jakarta”.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ curl "http://localhost:8080/search?q=jakarta&amp;format=json"
</code></pre></div></div>

<p>Outputnya,</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="w">
  </span><span class="p">{</span><span class="w">
    </span><span class="nl">"place_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">144282</span><span class="p">,</span><span class="w">
    </span><span class="nl">"licence"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"osm_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"way"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"osm_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">795600162</span><span class="p">,</span><span class="w">
    </span><span class="nl">"lat"</span><span class="p">:</span><span class="w"> </span><span class="s2">"-0.5354329"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"lon"</span><span class="p">:</span><span class="w"> </span><span class="s2">"117.0914415"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"category"</span><span class="p">:</span><span class="w"> </span><span class="s2">"highway"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"residential"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"place_rank"</span><span class="p">:</span><span class="w"> </span><span class="mi">26</span><span class="p">,</span><span class="w">
    </span><span class="nl">"importance"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.0533433333333333</span><span class="p">,</span><span class="w">
    </span><span class="nl">"addresstype"</span><span class="p">:</span><span class="w"> </span><span class="s2">"road"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Jakarta"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"display_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Jakarta, Loa Bakung, Sungai Kunjang, Samarinda, Kalimantan Timur, 75391, Indonesia"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"boundingbox"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
      </span><span class="s2">"-0.5355636"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"-0.5353021"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"117.0914346"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"117.0914483"</span><span class="w">
    </span><span class="p">]</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span></code></pre></div></div>

<p>Wah! Ternyata ada daerah beranama “Jakarta” di Kalimantan Timur.</p>

<h4 id="revers-reverse-geocoding">/revers (Reverse Geocoding)</h4>

<p>Coba lakukan reverse geocoding untuk mencari nama tempat atau alamat berdasarkan koordinat geografis (latitude &amp; longitude). Misalnya, mencari lokasi berdasarkan koordinat <code class="language-plaintext highlighter-rouge">-0.5354329,117.0914415</code> (koordinat Balikpapan).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ curl "http://localhost:8080/reverse?lat=-1.2398711&amp;lon=116.8593379&amp;format=json"
</code></pre></div></div>

<p>Outputnya,</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"place_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">144282</span><span class="p">,</span><span class="w">
  </span><span class="nl">"licence"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"osm_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"way"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"osm_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">795600162</span><span class="p">,</span><span class="w">
  </span><span class="nl">"lat"</span><span class="p">:</span><span class="w"> </span><span class="s2">"-0.5354329"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"lon"</span><span class="p">:</span><span class="w"> </span><span class="s2">"117.0914415"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"class"</span><span class="p">:</span><span class="w"> </span><span class="s2">"highway"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"residential"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"place_rank"</span><span class="p">:</span><span class="w"> </span><span class="mi">26</span><span class="p">,</span><span class="w">
  </span><span class="nl">"importance"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.0533433333333333</span><span class="p">,</span><span class="w">
  </span><span class="nl">"addresstype"</span><span class="p">:</span><span class="w"> </span><span class="s2">"road"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Jakarta"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"display_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Jakarta, Loa Bakung, Sungai Kunjang, Samarinda, Kalimantan Timur, 75391, Indonesia"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"address"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"road"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Jakarta"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"village"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Loa Bakung"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"city_district"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sungai Kunjang"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"city"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Samarinda"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"state"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Kalimantan Timur"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"ISO3166-2-lvl4"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ID-KI"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"postcode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"75391"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"country"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Indonesia"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"country_code"</span><span class="p">:</span><span class="w"> </span><span class="s2">"id"</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"boundingbox"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="s2">"-0.5355636"</span><span class="p">,</span><span class="w">
    </span><span class="s2">"-0.5353021"</span><span class="p">,</span><span class="w">
    </span><span class="s2">"117.0914346"</span><span class="p">,</span><span class="w">
    </span><span class="s2">"117.0914483"</span><span class="w">
  </span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h4 id="lookup">/lookup</h4>

<p>Coba lakukan lookup untuk mencari informasi lokasi berdasarkan OSM ID. Misalnya, mencari informasi lokasi berdasarkan OSM ID <code class="language-plaintext highlighter-rouge">795600162</code>. Ini adalah OSM ID dari hasil pencarian sebelumnya untuk lokasi “jakarta” di Kalimantan Timur.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ curl "http://localhost:8080/lookup?osm_ids=W795600162&amp;format=json"
</code></pre></div></div>

<p>Outputnya,</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="w">
  </span><span class="p">{</span><span class="w">
    </span><span class="nl">"place_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">144282</span><span class="p">,</span><span class="w">
    </span><span class="nl">"licence"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"osm_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"way"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"osm_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">795600162</span><span class="p">,</span><span class="w">
    </span><span class="nl">"lat"</span><span class="p">:</span><span class="w"> </span><span class="s2">"-0.5354329"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"lon"</span><span class="p">:</span><span class="w"> </span><span class="s2">"117.0914415"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"class"</span><span class="p">:</span><span class="w"> </span><span class="s2">"highway"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"residential"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"place_rank"</span><span class="p">:</span><span class="w"> </span><span class="mi">26</span><span class="p">,</span><span class="w">
    </span><span class="nl">"importance"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.0533433333333333</span><span class="p">,</span><span class="w">
    </span><span class="nl">"addresstype"</span><span class="p">:</span><span class="w"> </span><span class="s2">"road"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Jakarta"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"display_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Jakarta, Loa Bakung, Sungai Kunjang, Samarinda, Kalimantan Timur, 75391, Indonesia"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"address"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"road"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Jakarta"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"village"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Loa Bakung"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"city_district"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Sungai Kunjang"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"city"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Samarinda"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"state"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Kalimantan Timur"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"ISO3166-2-lvl4"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ID-KI"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"postcode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"75391"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"country"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Indonesia"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"country_code"</span><span class="p">:</span><span class="w"> </span><span class="s2">"id"</span><span class="w">
    </span><span class="p">},</span><span class="w">
    </span><span class="nl">"boundingbox"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
      </span><span class="s2">"-0.5355636"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"-0.5353021"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"117.0914346"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"117.0914483"</span><span class="w">
    </span><span class="p">]</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span></code></pre></div></div>

<h4 id="details">/details</h4>

<p>Coba lakukan details untuk mencari informasi lokasi berdasarkan OSM ID, dengan informasi yang lebih detail dibandingkan dengan <code class="language-plaintext highlighter-rouge">/lookup</code>. Misalnya, mencari informasi lokasi berdasarkan OSM ID <code class="language-plaintext highlighter-rouge">795600162</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ curl "http://localhost:8080/details?osmtype=W&amp;osmid=795600162&amp;format=json"
</code></pre></div></div>

<p>Outputnya,</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"place_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">144282</span><span class="p">,</span><span class="w">
  </span><span class="nl">"parent_place_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">142133</span><span class="p">,</span><span class="w">
  </span><span class="nl">"osm_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"W"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"osm_id"</span><span class="p">:</span><span class="w"> </span><span class="mi">795600162</span><span class="p">,</span><span class="w">
  </span><span class="nl">"category"</span><span class="p">:</span><span class="w"> </span><span class="s2">"highway"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"residential"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"admin_level"</span><span class="p">:</span><span class="w"> </span><span class="mi">15</span><span class="p">,</span><span class="w">
  </span><span class="nl">"localname"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Jakarta"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"names"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Jakarta"</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"addresstags"</span><span class="p">:</span><span class="w"> </span><span class="p">{},</span><span class="w">
  </span><span class="nl">"calculated_postcode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"75391"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"country_code"</span><span class="p">:</span><span class="w"> </span><span class="s2">"id"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"indexed_date"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2026-02-08T13:11:46.748639+00:00"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"importance"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.0533433333333333</span><span class="p">,</span><span class="w">
  </span><span class="nl">"calculated_importance"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.0533433333333333</span><span class="p">,</span><span class="w">
  </span><span class="nl">"extratags"</span><span class="p">:</span><span class="w"> </span><span class="p">{},</span><span class="w">
  </span><span class="nl">"rank_address"</span><span class="p">:</span><span class="w"> </span><span class="mi">26</span><span class="p">,</span><span class="w">
  </span><span class="nl">"rank_search"</span><span class="p">:</span><span class="w"> </span><span class="mi">26</span><span class="p">,</span><span class="w">
  </span><span class="nl">"isarea"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
  </span><span class="nl">"centroid"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Point"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"coordinates"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
      </span><span class="mf">117.0914415</span><span class="p">,</span><span class="w">
      </span><span class="mf">-0.5354329</span><span class="w">
    </span><span class="p">]</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"geometry"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Point"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"coordinates"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
      </span><span class="mf">117.0914415</span><span class="p">,</span><span class="w">
      </span><span class="mf">-0.5354329</span><span class="w">
    </span><span class="p">]</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h3 id="5-stop-docker-compose">5. Stop Docker Compose</h3>

<p>Jika sudah selesai menggunakan Nominatim service, bisa stop Docker Compose dengan perintah berikut:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ docker-compose down
</code></pre></div></div>

<h2 id="kesimpulan">Kesimpulan</h2>

<p>Dalam artikel ini, saya telah mendokumentasikan cara menjalankan OpenStreetMap Nominatim menggunakan Docker, mulai dari membuat Docker Compose, mempersiapkan file <code class="language-plaintext highlighter-rouge">.osm.pbf</code>, menjalankan Docker Compose, mencoba Nominatim API, hingga menghentikan Docker Compose. Dengan menggunakan Docker, proses setup Nominatim menjadi lebih mudah dan cepat, tanpa perlu repot mengatur lingkungan dan dependensi secara manual.</p>

<p>Pada artikel selanjutnya, saya akan mendokumentasikan cara menggunakan Nominatim self-hosted pada Geocoder gem untuk melakukan geocoding dan reverse geocoding di aplikasi Ruby on Rails, “<a href="https://bandithijo.dev/blog/menggunakan-nominatim-self-hosted-pada-geocoder-gem">Menggunakan Nominatim Self-Hosted pada Geocoder Gem</a>”</p>

<h2 id="referensi">Referensi</h2>

<ol>
  <li>
    <p><a href="https://nominatim.openstreetmap.org/ui/about.html">https://nominatim.openstreetmap.org/ui/about.html</a> <br />
  Diakses tanggal: 2026-02-07</p>
  </li>
  <li>
    <p><a href="https://nominatim.org/release-docs/develop/api/Overview/">https://nominatim.org/release-docs/develop/api/Overview/</a> <br />
  Diakses tanggal: 2026-02-07</p>
  </li>
</ol>]]></content><author><name>BanditHijo</name></author><category term="blog" /><category term="openstreetmap" /><category term="nominatim" /><summary type="html"><![CDATA[OpenStreetMap Nominatim adalah sebuah layanan geocoding yang memungkinkan pengguna untuk mencari lokasi berdasarkan nama tempat atau alamat (forward search) atau geographic coordinate (reverse search). Dalam artikel ini, saya akan mendokumentasikan cara menjalankan OpenStreetMap Nominatim menggunakan Docker agar proses setup Nominatim menjadi lebih mudah dan cepat, tanpa perlu repot mengatur lingkungan dan dependensi secara manual.]]></summary></entry><entry><title type="html">QnA: Fitur Apa yang Dimiliki Rails Sehingga Sulit untuk Pindah ke Framework Lain?</title><link href="https://bandithijo.dev/blog/qna-fitur-yang-dimiliki-rails-sehingga-sulit-pindah-ke-framework-lain" rel="alternate" type="text/html" title="QnA: Fitur Apa yang Dimiliki Rails Sehingga Sulit untuk Pindah ke Framework Lain?" /><published>2026-02-01T18:13:00+08:00</published><updated>2026-02-01T18:13:00+08:00</updated><id>https://bandithijo.dev/blog/qna-fitur-yang-dimiliki-rails-sehingga-sulit-pindah-ke-framework-lain</id><content type="html" xml:base="https://bandithijo.dev/blog/qna-fitur-yang-dimiliki-rails-sehingga-sulit-pindah-ke-framework-lain"><![CDATA[<h2 id="pendahuluan">Pendahuluan</h2>

<p>QnA ini di-request oleh mas Rizky Ramadhan via email. Pertanyaan ini diajukan sekitar tahun 2023. Ia bertanya sebagian besar terkait dengan Ruby on Rails. Saya merasa pertanyaan dan jawaban ini akan memberikan lebih banyak manfaat jika dipublikasikan. Semoga bermanfaat yaa.</p>

<blockquote>
  <p>PERHATIAN</p>

  <p>Saya kesulitan mencari alamat email dari mas Rizky Ramadhan, jika mas Rizky membaca ini dan tidak berkenan untuk mempublikasikan tulisan ini, boleh hubungi saya via email yaa.</p>
</blockquote>

<h2 id="question-from-rizky-ramadhan">Question: from Rizky Ramadhan</h2>

<p>Halo, mas. Perkenalkan, saya Rizky, baru lulus tahun ini, sekarang sudah bekerja, sekitar 1 bulan lebih dikit. Kalau di kantor biasa pakai Yii, untuk hobi saya suka Laravel. Mau tanya soal Ruby on Rails.</p>

<p>Kemarin saya sudah menonton tutorial Ruby on Rails dari Padang Tekno di YouTube, lumayan sulit juga nyari tutorial yang up to date, kebanyakan 3 tahun / 5 tahun yang lalu.</p>

<p>Kalau dari yang saya pahami, konsep Rails dan Laravel lumayan mirip. Apa yang bisa dilakukan Rails, bisa juga dilakukan Laravel. Meskipun, kalau soal syntax, Ruby lebih elegan.</p>

<p>Jadi, pertanyaannya:</p>

<ol>
  <li><a href="https://bandithijo.dev/blog/qna-fitur-yang-dimiliki-rails-sehingga-sulit-pindah-ke-framework-lain#q-apa-yang-bikin-bertahan-dengan-rails-sampai-hari-ini"><strong>Apa yang bikin bertahan dengan Rails sampai hari ini mas?</strong></a></li>
  <li><a href="https://bandithijo.dev/blog/qna-fitur-yang-dimiliki-rails-sehingga-sulit-pindah-ke-framework-lain#q-kelebihan-apa-yang-dimiliki-rails-sehingga-memudahkan-pada-saat-bekerja"><strong>Kelebihan apa yang dimiliki Rails sehingga memudahkan pada saat bekerja?</strong></a></li>
  <li><a href="https://bandithijo.dev/blog/qna-fitur-yang-dimiliki-rails-sehingga-sulit-pindah-ke-framework-lain#q-fitur-apa-yang-dimiliki-rails-sehingga-sulit-untuk-pindah-ke-framework-lain"><strong>Fitur apa yang dimiliki Rails sehingga sulit untuk pindah ke framework lain?</strong></a></li>
</ol>

<p>Saya tertarik buat nyoba Rails, mas. Cuman, belum click di mana “magic” nya, selain syntax yang elegan tadi.</p>

<p>Udah liat-liat comparison nya di internet, tapi sepertinya kebih baik bertanya langsung kepada sepuh. Makasih mas 🙏</p>

<h2 id="answer-from-bandithijo">Answer: from BanditHijo</h2>

<p>Halo halo Rizky.</p>

<p>Selamat atas kelulusan dan sudah keterima bekerja. Mudah-mudahan berkah ilmunya yaa.</p>

<p>Sebelumnya, terima kasih yaa sudah mengajukan pertanyaan terkait Rails. Sebenernya saya belum bisa disebut sepuh Rails, karena baru pakai Rails dari tahun 2019-2021 (FullStack), 2022-2023 (Backend). Wkwkwk.</p>

<h3 id="q-apa-yang-bikin-bertahan-dengan-rails-sampai-hari-ini">Q: Apa yang bikin bertahan dengan Rails sampai hari ini?</h3>

<p>Mungkin karena masih bekerja pakai Rails dan belum ketemu kesulitan dan jalan buntu ketika digunakan saat bekerja. Masih happy pakai Rails.</p>

<h3 id="q-kelebihan-apa-yang-dimiliki-rails-sehingga-memudahkan-pada-saat-bekerja">Q: Kelebihan apa yang dimiliki Rails sehingga memudahkan pada saat bekerja?</h3>

<p>Kelebihan-kelebihan yang saya rasakan ketika pakai Rails saat bekerja:</p>

<ol>
  <li>
    <p>Rails ini framework yang bersifat Opinionated. Artinya sudah ada aturan yang disepakati (secara umum) untuk melakukan suatu pekerjaan yang umum (biasa disebut Best Practice). Kalau bekerja dalam tim, sifat opinionated ini yang mempermudah dan mempercepat menyelesaikan suatu task. Karena kita tidak perlu lagi memperdebatkan mana cara penyelesaian masalah yang baik. Kecuali ada kondisi-kondisi tertentu yang disepakai oleh tim untuk tidak menggunakan “best practice” karena kebutuhan tertentu.</p>
  </li>
  <li>
    <p>Proses menyelesaikan task menjadi lebih cepat karena beberapa flow bisnis, sudah ada dan sudah dibuatkan best practicenya, jadi tidak perlu lagi memperdebatkan flow bisnis yang sudah umum. Tinggal pakai saja kalau memang tidak ada kebutuhan khusus.</p>

    <p>Dengan begini, perdebatan terkait hal-hal teknis, yang umumnya terjadi di tempat kami:</p>

    <ul>
      <li><strong>Nama tabel</strong> di Rails, sudah dikonvensikan kalau nama tabel harus kata benda yang plural</li>
      <li><strong>Penggunaan HTTP method</strong> harus mengikuti aturan RESTful API. Dimana ketika membuat endpoint harus menggunakan HTTP method yang sesuai untuk fungsi yang sesuai (GET/POST/PATCH/PUT/DELETE).</li>
    </ul>
  </li>
  <li>
    <p>Metaprogramming. Ruby memiliki kemampuan metaprogramming yang diadopsi oleh Rails untuk mempermudah proses pembuatan aplikasi.</p>

    <p>Terkait metraprogramming di Rails, ada banyak sekali, tapi yang baru-baru aja (inget) saya pakai yang seperti ini:</p>

    <ul>
      <li>
        <p><strong>Active Model Dirty</strong> <a href="https://api.rubyonrails.org/classes/ActiveModel/Dirty.html">https://api.rubyonrails.org/classes/ActiveModel/Dirty.html</a> <br />
Saya pakai untuk membuat callback, ketika suatu atribute (misal: name) berubah nilainya.</p>
      </li>
      <li>
        <p><strong>Active Record Nested Attributes</strong> <a href="https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html">https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html</a> <br />
Saya pakai untuk membuat data child yang berasosiasi dengan parent. Jadi ketika parentnya dibuat, child nya juga ikut terbut. Misal: membuat admin (parent) baru dengan beberapa admin_permission (child).</p>
      </li>
    </ul>

    <p>2 method di atas, terdengar biasa aja. Tapi kalau dilihat kodenya, hal-hal tersebut dapat dilakukan hanya dengan kode yang simple tanpa perlu banyak effort.</p>

    <p>Hal lain seperti migrasi dan relasi tabel juga pakai metaprogramming, sehingga ada method-method yang secara ajaib sudah ada dan tinggal dipakai.</p>

    <p>Kebetulan kemarin sempet lihat topik terkait “Powerful Rails Feature You Might Not Know” dari Chris Oliver di Rails World 2023, bisa coba tonton di sini yaa <a href="https://www.youtube.com/watch?v=iPCqwZ9Ouc4">https://www.youtube.com/watch?v=iPCqwZ9Ouc4</a></p>
  </li>
  <li>
    <p>Dokumentasi yang dimiliki Rails juga terbilang rapi dan deskriptif. Mulai dari dokumentasi Rails yang ada di <a href="https://guides.rubyonrails.org/">https://guides.rubyonrails.org/</a>, sampai dokumentasi Rails API yang ada di <a href="https://api.rubyonrails.org/">https://api.rubyonrails.org/</a></p>
  </li>
  <li>
    <p>Rails sebenarnya kumpulan dari beberapa module (library) yang modular yang didesain untuk memiliki intarface yang agnostic. Jadi bisa pakai engine (backend) apa saja. Misal, untuk Active Job kita bisa pakai Sidekiq, Resque, Sneakers, Delayed Job, Good Job, dll. <a href="https://edgeguides.rubyonrails.org/active_job_basics.html#starting-the-backend">https://edgeguides.rubyonrails.org/active_job_basics.html#starting-the-backend</a> Tapi dengan interface yang sama. Jadi meskipun backend job nya bisa berbeda, tapi interface nya tetep sama (nama pemanggilan method nya sama). Terkait Rails dan modularitynya, bisa tonton dari salah satu Rails Core, Eileen Uchitelle di Keynote RailsConf 2023 <a href="https://www.youtube.com/watch?v=TKulocPqV38">https://www.youtube.com/watch?v=TKulocPqV38</a>.</p>
  </li>
</ol>

<h3 id="q-fitur-apa-yang-dimiliki-rails-sehingga-sulit-untuk-pindah-ke-framework-lain">Q: Fitur apa yang dimiliki Rails sehingga sulit untuk pindah ke framework lain?</h3>

<p>Jujurly saya belum pernah coba framework lain selama Rails, jadi belum bisa kasih jawaban.</p>

<p>Rails ini framework yang sudah lama, sudah mature dalam artian sudah banyak digunakan untuk menyelesaikan beberapa bisnis flow. Yang kemudian flow tersebut dibakukan dalam bentuk method, sehingga tinggal kita pakai dan panggil saja. Tentunya ketersediaan built-in class dan method ini dan hal-hal yang berkaitan dengan jawaban sebelumnya juga yang membuat proses penyelesaian suatu problem menjadi lebih cepat.</p>

<p>Kira-kira ini sedikit yang bisa saya sharing terkait Rails dari pengalaman selama menggunakan Rails untuk kerjaan.</p>

<p>Untuk sekarang, dikerjaan, saya lebih banyak pakai Rails sebagai Backend saja. Jadi tidak menjadikan Rails sebagai FullStack. Maka dari itu, jawaban dan ilustrasi yang kuberikan, terbatas di Rails sebagai Backend (sudut pandang fitur-fitur yang memudahkan pekerjaan di Backend). Tentunya tidak sebanding dengan orang yang menjadikan Rails sebagai Fullstack. Karena di bagian Frontend juga terdapat method-method helper yang banyak memudahkan untuk mempercepat proses pembuatan tampilan web.</p>

<p>Untuk kedepannya, saya juga masih sambil belajar JavaScript. Pengetahuan JavaScript sebagai Rails Developer tentu akan sangat membantu, dibandingkan dengan Rails Developer yang tidak memiliki pengetahuan tentang JavaScript sama sekali.</p>

<p>Mudah-mudahan jawaban saya sudah menjawab 3 pertanyaan yang diajukan yaa.</p>]]></content><author><name>BanditHijo</name></author><category term="blog" /><category term="ruby" /><category term="rails" /><summary type="html"><![CDATA[QnA ini di-request oleh mas Rizky Ramadhan via email. Pertanyaan ini diajukan sekitar tahun 2023. Ia bertanya sebagian besar terkait dengan Ruby on Rails. Saya merasa pertanyaan dan jawaban ini akan memberikan lebih banyak manfaat jika dipublikasikan. Semoga bermanfaat yaa.]]></summary></entry><entry><title type="html">Berkenalan dengan AsciiDoc</title><link href="https://bandithijo.dev/blog/berkenalan-dengan-asciidoc" rel="alternate" type="text/html" title="Berkenalan dengan AsciiDoc" /><published>2026-01-18T12:37:00+08:00</published><updated>2026-01-18T12:37:00+08:00</updated><id>https://bandithijo.dev/blog/berkenalan-dengan-asciidoc</id><content type="html" xml:base="https://bandithijo.dev/blog/berkenalan-dengan-asciidoc"><![CDATA[<h2 id="apa-itu-asciidoc">Apa itu AsciiDoc?</h2>

<p>AsciiDoc adalah bahasa markup teks ringan yang digunakan untuk menulis dokumentasi, artikel, buku, dan konten lainnya. Mirip dengan Markdown, AsciiDoc memungkinkan penulis untuk membuat dokumen yang mudah dibaca dan ditulis dalam format teks biasa, yang kemudian dapat dikonversi ke berbagai format output seperti HTML, PDF, dan ePub.</p>

<blockquote>
  <p>INFO</p>

  <p>“<em>AsciiDoc is a plain text markup language for writing technical content. It’s packed with semantic elements and equipped with features to modularize and reuse content. AsciiDoc content can be composed using a text editor, managed in a version control system, and published to multiple output formats.</em>” - AsciiDoc.org</p>
</blockquote>

<h2 id="awal-mula-bertemu-asciidoc">Awal Mula Bertemu AsciiDoc</h2>

<p>Awal mula saya bertemu dengan Markup Language ini adalah ketika saya membeli sebuah ebook berjudul “Pemrogram Rp 100 Juta: Panduan Bagi Pemrogram Untuk Menggapai Harga, Tahta, dan Kemasyhuran” oleh Arjuna Sky Kok pada tahun 2020.</p>

<p>Saat itu kami diberikan akses ke private repositori GitHub tempat buku tersebut disimpan, dan saya menemukan bahwa buku tersebut ditulis menggunakan AsciiDoc. Saat itu saya berfikir, “Wah! Keren sekali bisa membuat sebuah dokumen atau buku menggunakan bahasa markup seperti ini.” – Saat itu saya belum mengenal LaTeX. Karena yang saya tahu, untuk membuat dokumen atau buku perlu menggunakan aplikasi pengolah kata seperti Microsoft Word atau LibreOffice Writer atau dengan aplikasi desktop publishing seperti Adobe InDesign atau Scribus.</p>

<p>Dikemudian hari, ternyata saya cukup sering menemukan proyek-proyek open source yang menggunakan AsciiDoc untuk dokumentasi mereka, seperti proyek-proyek yang menggunakan Asciidoctor sebagai tool untuk mengkonversi dokumen AsciiDoc ke format lain. Beberapa diantaranya seperti:</p>

<ol>
  <li><a href="https://github.com/madeindjs/api_on_rails">GitHub: Book: Api on Rails 6</a> (AsciiDoc + Asciidoctor)</li>
  <li><a href="https://gitlab.com/fedora/docs/fedora-linux-documentation/release-docs-home">FedoraProject Docs: GitLab: Fedora Linux Documentation Home</a> (AsciiDoc + Antora + Asciidoctor)</li>
</ol>

<blockquote>
  <p>PERTANYAAN</p>

  <p><strong>Apa perbedaan AsciiDoc dan Asciidoctor?</strong></p>

  <p>AsciiDoc adalah markup language yang digunakan untuk menulis dokumen, sedangkan Asciidoctor adalah tool atau perangkat lunak yang digunakan untuk mengkonversi dokumen AsciiDoc ke berbagai format output seperti HTML, PDF, ePub, dan lainnya.</p>
</blockquote>

<h2 id="apakah-tidak-cukup-dengan-markdown">Apakah tidak cukup dengan Markdown?</h2>

<p>Markdown memang sudah sangat populer dan banyak digunakan untuk menulis dokumentasi, artikel, dan konten lainnya. Namun, AsciiDoc menawarkan beberapa kelebihan dibandingkan Markdown, terutama untuk dokumentasi teknis yang kompleks. Beberapa kelebihan AsciiDoc dibandingkan Markdown antara lain:</p>

<ol>
  <li><strong>Fitur yang Lebih Lengkap</strong> <br />
  AsciiDoc memiliki fitur yang lebih lengkap dibandingkan Markdown, seperti dukungan untuk tabel, blok kode dengan penyorotan sintaks, catatan kaki, dan lainnya.</li>
  <li><strong>Mudah Dibaca dan Ditulis</strong> <br />
  AsciiDoc dirancang agar mudah dibaca dalam format teks biasa, sehingga penulis dapat fokus pada konten tanpa terganggu oleh format yang rumit.</li>
  <li><strong>Fleksibilitas Format Output</strong> <br />
  AsciiDoc dapat dikonversi ke berbagai format output seperti HTML, PDF, ePub, dan lainnya menggunakan tool seperti Asciidoctor.</li>
  <li><strong>Dukungan untuk Modularisasi Konten</strong> <br />
  AsciiDoc mendukung modularisasi konten, sehingga penulis dapat mengelola dokumen yang besar dengan lebih efisien.</li>
  <li><strong>Integrasi dengan Development Tool</strong> <br />
  AsciiDoc sering digunakan dalam proyek perangkat lunak untuk dokumentasi, dan dapat diintegrasikan dengan development tool seperti Git dan CI/CD.</li>
</ol>

<h2 id="contoh-dokumen-asciidoc">Contoh Dokumen AsciiDoc</h2>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>= Title of the document
Rizqi Nur Assyaufi <span class="nv">&lt;bandithijo@example.mail&gt;</span>
:source-highlighter: rouge
:icons: font
:toc: macro
:toc-title:

== Table of contents

toc::[]

</code></pre></div></div>

<p><img src="/assets/posts/blog/2026/2026-01-18-berkenalan-dengan-asciidoc/gambar_01.png" alt="Gambar 1" /></p>

<p>Gambar 1. Table of Contents dan Judul Dokumen</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>== Section

Hi, my name is {author}. I'm a Backend Software Engineer at Small Startup footnote:[Startup is a new company, often technology-focused, designed for rapid growth by validating a scalable business model, seeking external funding (like venture capital), and aiming to disrupt existing markets with innovative products or services — Wikipedia] in Jakarta that are working remotely from Balikpapan. Feel free to ask me anything about Software Develop-thing or Linux-thing on {email}.

<span class="ge">*This is bold text*</span>

<span class="ge">_This is cursive text_</span>

<span class="sb">`This is mono text`</span>

</code></pre></div></div>

<p><img src="/assets/posts/blog/2026/2026-01-18-berkenalan-dengan-asciidoc/gambar_02.png" alt="Gambar 2" /></p>

<p>Gambar 2. Paragraf dengan format teks</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>== List

Docker allows to package the full stack in a container:
<span class="p">
*</span> OS
<span class="ge">**</span> Windows
<span class="ge">**</span> Ubuntu
<span class="p">*</span> JVM,
<span class="p">*</span> App server
<span class="p">*</span> Application with its configuration
</code></pre></div></div>

<p><img src="/assets/posts/blog/2026/2026-01-18-berkenalan-dengan-asciidoc/gambar_03.png" alt="Gambar 3" /></p>

<p>Gambar 3. Nested list</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>== Block quotes

[quote, Ben Parker, Spiderman Movie]
<span class="gs">____</span>
With great power comes great responsibility.
<span class="gs">____</span>

</code></pre></div></div>

<p><img src="/assets/posts/blog/2026/2026-01-18-berkenalan-dengan-asciidoc/gambar_04.png" alt="Gambar 4" /></p>

<p>Gambar 4. Block quote</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
== Defining cross references

You can assign meta data to a block. Here’s an example of a quote block that includes all types of metadata:

<span class="gh">[source, ruby, linenums]
----
</span>class Cat <span class="nt">&lt;</span><span class="err">1</span><span class="nt">&gt;</span>
  def meow <span class="nt">&lt;</span><span class="err">2</span><span class="nt">&gt;</span>
    puts "Meow!" <span class="nt">&lt;</span><span class="err">3</span><span class="nt">&gt;</span>
  end
end

cat = Cat.new <span class="nt">&lt;</span><span class="err">4</span><span class="nt">&gt;</span>
<span class="gh">cat.meow &lt;5&gt;
----
</span><span class="nt">&lt;</span><span class="err">1</span><span class="nt">&gt;</span> class definition
<span class="nt">&lt;</span><span class="err">2</span><span class="nt">&gt;</span> method definition
<span class="nt">&lt;</span><span class="err">3</span><span class="nt">&gt;</span> output statement
<span class="nt">&lt;</span><span class="err">4</span><span class="nt">&gt;</span> creating an instance of the class
<span class="nt">&lt;</span><span class="err">5</span><span class="nt">&gt;</span> calling the method
</code></pre></div></div>

<p><img src="/assets/posts/blog/2026/2026-01-18-berkenalan-dengan-asciidoc/gambar_05.png" alt="Gambar 5" /></p>

<p>Gambar 5. Cross reference in code block</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>== Admonition paragraphs and blocks for warnings, notes and tips

An admonition paragraph draws the reader’s attention to certain information. It can be defined by a predefined label at the beginning of the paragraph or as a block.

Here are the other built-in admonition types:

NOTE: Some additional info...

TIP: Pro tip...

IMPORTANT: Don't forget...

WARNING: Watch out for...

CAUTION: Ensure that...

</code></pre></div></div>

<p><img src="/assets/posts/blog/2026/2026-01-18-berkenalan-dengan-asciidoc/gambar_06.png" alt="Gambar 6" /></p>

<p>Gambar 6. Admonition blocks</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Hi, my name is {author}. I'm a Backend Software Engineer at Small Startup footnote:[Startup is a new company, often technology-focused, designed for rapid growth by validating a scalable business model, seeking external funding (like venture capital), and aiming to disrupt existing markets with innovative products or services — Wikipedia] in Jakarta that are working remotely from Balikpapan. Feel free to ask me anything about Software Develop-thing or Linux-thing on {email}.
</code></pre></div></div>

<p><img src="/assets/posts/blog/2026/2026-01-18-berkenalan-dengan-asciidoc/gambar_07.png" alt="Gambar 7" /></p>

<p>Gambar 7. Footnote example</p>

<p>Lalu dengan menggunakan tool Asciidoctor, dokumen tersebut dapat dieksport ke dalam format PDF.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ asciidoctor-pdf sample_document.adoc
</code></pre></div></div>

<p>Maka akan menghasilkan file <code class="language-plaintext highlighter-rouge">sample_document.pdf</code> yang berisi dokumen yang sudah terformat dengan baik.</p>

<p><img src="/assets/posts/blog/2026/2026-01-18-berkenalan-dengan-asciidoc/gambar_08.png" alt="Gambar 8" /></p>

<p>Gambar 8. Hasil eksport dokumen ke format PDF halaman 1</p>

<p><img src="/assets/posts/blog/2026/2026-01-18-berkenalan-dengan-asciidoc/gambar_09.png" alt="Gambar 9" /></p>

<p>Gambar 9. Hasil eksport dokumen ke format PDF halaman 2</p>

<p>Dapat dilihat dari contoh-contoh di atas, dokumen yang dihasilkan memiliki format yang rapi dan terlihat profesional.</p>

<p>Sintaks AsciiDoc juga mendukung berbagai elemen seperti judul, paragraf, list, blok kode, quote, cross reference, footnote, table of contents, dan blok peringatan (admonition blocks) untuk menyoroti informasi penting.</p>

<p>Dokumen di atas hanyalah contoh sederhana dari apa yang dapat dilakukan dengan AsciiDoc. Untuk membuat menjadi layout buku juga tinggal menggunakan dokumen type book.</p>

<h2 id="komentar-penulis">Komentar Penulis</h2>

<p>Bukan saya alergi dengan WYSIWYG editor seperti Ms.Word atau LO Writer, tapi “menurut keyakinan saya”, menulis dokumen teknis lebih efisien dengan AsciiDoc. Kita tinggal mengisi konten saja dengan notasi-notasi (sintaks) yang sesuai, processor yang akan merender menjadi format yang sesuai. Tidak perlu formatting text manual.</p>

<p>Kalau membuat dokumen teknis itu 50% nya menulis konten dan 50% nya lagi formatting text. Maka dengan AsciiDoc, kita bisa 90% fokus menulis kontent dan 10% nya konfigurasi template awal.</p>

<p>Bahkan jika konfigurasi templatenya sudah jadi, “menurut keyakinan saya” malah bisa 100% tinggal menulis konten saja.</p>

<h2 id="penutup">Penutup</h2>

<p>Dengan fitur-fitur yang lengkap dan fleksibilitasnya, AsciiDoc menjadi pilihan yang menarik untuk menulis dokumentasi teknis.</p>

<p>Untuk informasi lebih lanjut tentang AsciiDoc, Anda dapat mengunjungi situs resminya atau dokumentasi Asciidoctor yang saya sertakan pada bagian referensi di bawah.</p>

<h2 id="referensi">Referensi</h2>

<ol>
  <li>
    <p><a href="https://asciidoc.org/">https://asciidoc.org/</a> <br />
  Tanggal diakses: 2026-01-18</p>
  </li>
  <li>
    <p><a href="https://docs.asciidoctor.org/asciidoc/latest/">https://docs.asciidoctor.org/asciidoc/latest/</a> <br />
  Tanggal diakses: 2026-01-18</p>
  </li>
  <li>
    <p><a href="https://asciidoctor.org/">https://asciidoctor.org/</a> <br />
  Tanggal diakses: 2026-01-18</p>
  </li>
</ol>]]></content><author><name>BanditHijo</name></author><category term="blog" /><category term="asciidoc" /><summary type="html"><![CDATA[AsciiDoc adalah bahasa markup teks ringan yang digunakan untuk menulis dokumentasi, artikel, buku, dan konten lainnya. Mirip dengan Markdown, AsciiDoc memungkinkan penulis untuk membuat dokumen yang mudah dibaca dan ditulis dalam format teks biasa, yang kemudian dapat dikonversi ke berbagai format output seperti HTML, PDF, dan ePub.]]></summary></entry><entry><title type="html">Apa yang Baru di Blog BanditHijo versi 3?</title><link href="https://bandithijo.dev/blog/apa-yang-baru-di-blog-bandithijo-versi-3" rel="alternate" type="text/html" title="Apa yang Baru di Blog BanditHijo versi 3?" /><published>2026-01-16T10:06:00+08:00</published><updated>2026-01-16T10:06:00+08:00</updated><id>https://bandithijo.dev/blog/apa-yang-baru-di-blog-bandithijo-versi-3</id><content type="html" xml:base="https://bandithijo.dev/blog/apa-yang-baru-di-blog-bandithijo-versi-3"><![CDATA[<h2 id="pendahuluan">Pendahuluan</h2>

<p>Di pertengahan tahun 2025, saya memutuskan untuk membuat perubahan besar pada cara saya menulis artikel di blog ini. Setelah beberapa tahun menggunakan berbagai notasi syntax, saya merasa perlu untuk menyederhanakan proses penulisan agar tetap mempertahankan mood dalam menulis. Oleh karena itu, pada BanditHijo Versi 3, saya berfokus pada penggunaan CommonMark specification sebagai standar penulisan artikel.</p>

<h2 id="format-penulisan-dari-versi-ke-versi">Format Penulisan dari Versi ke Versi</h2>

<p>Sedikit kilas balik, pada versi pertama blog ini [1], saya menggunakan modifikasi tag/notasi markdown yang cukup kompleks untuk menulis artikel. Hal ini membuat proses penulisan menjadi lebih rumit dan terkadang mengganggu alur kreatif saya.</p>

<h3 id="versi-pertama-markdown--jekyll-custom-tags">Versi Pertama (Markdown + Jekyll Custom Tags)</h3>

<p><img src="/assets/posts/blog/2026/2026-01-16-apa-yang-baru-di-blog-bandithijo-versi-3/gambar_01.png" alt="Gambar 1" /></p>

<p>Gambar 1. BanditHijo’s Blog versi pertama</p>

<p>Sebagai gambaran, seperti ini Jekyll custom tag yang saya gunakan pada versi pertama:</p>

<ol>
  <li>Jika ingin menuliskan shell dengan user prompt:
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{% shell_user %}
sudo pacman -Syu
{% endshell_user %}
</code></pre></div>    </div>
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo pacman -Syu
</code></pre></div>    </div>
  </li>
  <li>Jika ingin menuliskan shell dengan custom prompt:
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{% shell_term postgres&gt; %}
CONNECT my_database;
{% endshell_term %}
</code></pre></div>    </div>
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>postgres&gt; CONNECT my_database;
</code></pre></div>    </div>
  </li>
  <li>Jika ingin memasukkan gambar:
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{% image https://image.url/123/image_01.png | 1 %}
</code></pre></div>    </div>
  </li>
  <li>Jika ingin memasukkan gambar dengan caption:
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{% image https://image.url/123/image_01.png | 1 | Caption di sini %}
</code></pre></div>    </div>
  </li>
</ol>

<p>Dan masih banyak lagi notasi khusus yang saya pergunakan pada versi pertama. Artikel lengkapnya bisa di baca di sini: <a href="/blog/membuat-jekyll-custom-tags-dengan-liquid-tags">Membuat Jekyll Custom Tags dengan Liquid Tags</a>.</p>

<p>Pada mulanya, saya merasa bahwa dengan menggunakan custom tag/notasi markdown tersebut, saya dapat menulis artikel dengan lebih ekspresif. Namun, seiring berjalannya waktu, saya menyadari bahwa kompleksitas tersebut justru menghambat proses penulisan saya.</p>

<h3 id="versi-kedua-asciidoc">Versi Kedua (AsciiDoc)</h3>

<p>Saya juga sempat mencoba merubah format artikel di versi kedua [2], yang tadinya menggunakan Markdown pada versi pertama, saya ubah menjadi AsciiDoc. Pertimbangan saya menggunakan AsciiDoc, karena blog saya sebagian besar berisi hal-hal teknis. Sehingga cocok menggunakan notasi AsciiDoc yang luwes untuk dokumen teknis.</p>

<p><img src="/assets/posts/blog/2026/2026-01-16-apa-yang-baru-di-blog-bandithijo-versi-3/gambar_02.png" alt="Gambar 2" /></p>

<p>Gambar 2. BanditHijo’s Blog versi kedua</p>

<p>Namun, setelah mencoba beberapa waktu, dan memigrasikan beberapa artikel saya, proses build menjadi lebih lambat dan proses menulis menggunakan AsciiDoc ternyata tidak semudah yang saya bayangkan. Akhirnya, saya memutuskan untuk kembali lagi menggunakan versi pertama.</p>

<p>AsciiDoc memang memiliki kelebihan dalam hal penulisan dokumen teknis, namun untuk blog pribadi yang lebih banyak berisi artikel ringan dan tutorial, saya merasa bahwa Markdown lebih sesuai dengan kebutuhan saya. Tapi, saya masih tetap menggunakan AsciiDoc untuk membuat dokumentasi teknis yang saya berikan untuk pihak lain. Karena membuat dokumentasi teknis dengan AsciiDoc sangat efisien. Karena hanya cukup menyediakan template dokumen, kemudian tinggal menulis kontennya saya, lalu build menjadi dokumen.</p>

<p>Saya menggunakan AsciiDoctor sebagai tool untuk formatingnya, dan AsciiDoctor PDF untuk merubah menjadi format PDF. Keduanya adalah tool yang sangat powerful untuk membuat dokumentasi teknis.</p>

<p>AsciiDoc menurut saya levelnya berada di antara Markdown dan LaTeX. Jika Markdown terlalu sederhana, dan LaTeX terlalu kompleks, maka AsciiDoc adalah solusi di tengah-tengahnya.</p>

<h3 id="versi-ketiga-commonmark-specification">Versi Ketiga (CommonMark Specification)</h3>

<p>Seiring berjalannya waktu, saya menyadari bahwa semakin sederhana proses penulisan, semakin bersemangat saya untuk menulis. Karena custom tag/notasi markdown yang saya gunakan pada versi pertama justru membuat proses menulis menjadi lebih rumit dan mengganggu alur kreatif saya. Meskipun saya sudah menggunakan snippet code di Neovim untuk mempercepat penulisan, tetap saja prosesnya terasa kurang praktis buat saya.</p>

<p>Maka dari itu, di pertengahan tahun 2025, saya memutuskan untuk membuat perubahan besar pada cara saya menulis artikel di blog ini. Setelah beberapa tahun menggunakan berbagai notasi syntax, saya merasa perlu untuk menyederhanakan proses penulisan agar tetap mempertahankan mood dalam menulis. Oleh karena itu, pada BanditHijo Versi 3, saya berfokus pada penggunaan CommonMark specification sebagai standar penulisan artikel.</p>

<p>Ada beberapa keuntungan yang saya dapatkan dengan mengikuti CommonMark specification:</p>

<ol>
  <li><strong>Sederhana dan Efisien</strong>: Proses penulisan menjadi lebih cepat dan efisien karena saya tidak perlu mengingat berbagai custom tag/notasi markdown yang rumit.</li>
  <li><strong>Konsistensi</strong>: Artikel-artikel di blog ini menjadi lebih konsisten dalam formatnya, sehingga pembaca dapat dengan mudah memahami konten tanpa terganggu oleh variasi notasi.</li>
  <li><strong>Fokus pada Konten</strong>: Saya dapat lebih fokus pada isi artikel tanpa harus terganggu oleh aspek teknis penulisan.</li>
  <li><strong>Kompatibilitas</strong>: Dengan mengikuti standar yang umum digunakan, artikel-artikel di blog ini lebih mudah diakses dan dibaca di berbagai platform dan perangkat. Misalnya, jika saya ingin memigrasikan blog ini ke platform lain di masa depan, prosesnya akan lebih mudah karena artikel-artikel sudah mengikuti standar yang umum. Selain itu juga jadi lebih kompatibel dengan berbagai tool yang mendukung Markdown seperti saat dibaca oleh RSS reader, atau saat diimport ke aplikasi note-taking seperti Obsidian, Notion, dsb.</li>
</ol>

<p>Untuk menjaga konsistensi format penulisan, saya mendokumentasikan rules dalam menulis di sini “<a href="/writing-rules">Writing Rules</a>” yang berisi panduan menulis artikel di blog ini.</p>

<p>Saya berusaha semaksimal mungkin mengikuti CommonMark specification dan seminimal mungkin menggunakan modifikasi tag/notasi markdown dalam menulis artikel.</p>

<h2 id="thema-baru-di-blog-bandithijo-versi-3">Thema Baru di Blog BanditHijo versi 3</h2>

<p>Saya menggunakan thema baru yang lebih minimalis dan fokus pada konten artikel.</p>

<p>Kali ini saya tidak lagi menggunakan plain CSS yang dibuat sendiri seperti pada versi sebelumnya, melainkan menggunakan framework CSS bernama <a href="https://tailwindcss.com/">Tailwind CSS</a>. Framework ini memungkinkan saya untuk membuat desain yang responsif dan modern dengan lebih mudah.</p>

<p><img src="/assets/posts/blog/2026/2026-01-16-apa-yang-baru-di-blog-bandithijo-versi-3/gambar_03.png" alt="Gambar 3" /></p>

<p>Gambar 3. BanditHijo’s Blog versi ketiga</p>

<h2 id="assets-management">Assets Management</h2>

<p>Sebelumnya, pada versi pertama, saya menyimpan semua gambar di layanan pihak ketiga, seperti postimages.org. Pada mulanya, saya pikir gambar akan membuat repo blog ini menjadi gemuk dan sulit di-manage. Namun, setelah mempertimbangkan berbagai aspek, saya memutuskan untuk menyimpan semua gambar langsung di dalam repository blog ini. Ceritanya bisa dibaca di sini, <a href="/blog/preferensi-saya-dalam-menyimpan-assets-gambar-di-jekyll">Preferensi Saya dalam Menyimpan Assets Gambar di Jekyll</a>.</p>

<p>Untuk manajemen assets seperti gambar, saya membuat struktur direktori yang lebih terorganisir di dalam repository blog ini. Setiap artikel memiliki direktori khusus untuk menyimpan gambar dan file terkait lainnya. Hal ini memudahkan saya dalam mengelola assets baik berupa gambar maupun file lainnya.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>📂 _posts/
└ 📂 blog/
  └ 📂 2025/
    └ 📄 2025-12-29-ruby-programmers-best-friend.md 👈 artikel
📂 assets/
│ 📁 css/
│ 📂 images/
└ 📂 posts/
  └ 📂 blog/
    └ 📂 2025/
      └ 📂 2025-12-29-ruby-programmers-best-friend/ 👈 direktori assets
        │ 📄 file-01.pdf
        │ 📄 gambar-01.png
        └ 📄 gambar-02.png
⚙️ _config.yml
📄 index.markdown
📄 README.md
</code></pre></div></div>

<p>Kemudian pada front matter artikel, saya menambahkan variabel <code class="language-plaintext highlighter-rouge">assets</code> yang berisi path ke direktori assets artikel tersebut. Sehingga saat menulis artikel, saya hanya perlu merujuk ke variabel <code class="language-plaintext highlighter-rouge">assets</code> untuk menyisipkan gambar atau file lainnya.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span>
<span class="na">layout</span><span class="pi">:</span> <span class="s2">"</span><span class="s">post"</span>
<span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Ruby,</span><span class="nv"> </span><span class="s">Programmer's</span><span class="nv"> </span><span class="s">Best</span><span class="nv"> </span><span class="s">Friend"</span>
<span class="na">date</span><span class="pi">:</span> <span class="s2">"</span><span class="s">2025-12-29</span><span class="nv"> </span><span class="s">08:00"</span>
<span class="na">permalink</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/blog/:title"</span>
<span class="na">assets</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/assets/posts/blog/2025/2025-12-29-ruby-programmers-best-friend"</span> <span class="c1"># 👈 direktori assets</span>
<span class="na">author</span><span class="pi">:</span> <span class="s2">"</span><span class="s">BanditHijo"</span>
<span class="na">category</span><span class="pi">:</span> <span class="s2">"</span><span class="s">blog"</span>
<span class="na">tags</span><span class="pi">:</span> <span class="pi">[</span><span class="s2">"</span><span class="s">ruby"</span><span class="pi">]</span>
<span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Ruby</span><span class="nv"> </span><span class="s">adalah</span><span class="nv"> </span><span class="s">bahasa</span><span class="nv"> </span><span class="s">pemrograman</span><span class="nv"> </span><span class="s">yang</span><span class="nv"> </span><span class="s">dirancang</span><span class="nv"> </span><span class="s">untuk</span><span class="nv"> </span><span class="s">kemudahan</span><span class="nv"> </span><span class="s">dan</span><span class="nv"> </span><span class="s">produktivitas."</span>
<span class="nn">---</span>
</code></pre></div></div>

<p>Kemudian pada artikel, saya dapat mengakses variabel <code class="language-plaintext highlighter-rouge">assets</code> dengan <code class="language-plaintext highlighter-rouge">{{ page.assets }}</code>.</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Lorem ipsum dolor sit amet, consectetur adipiscing elit.

<span class="p">![</span><span class="nv">Gambar 1</span><span class="p">](</span><span class="sx">{{</span> page.assets }}/gambar-01.png)

<span class="p">![</span><span class="nv">Gambar 2</span><span class="p">](</span><span class="sx">{{</span> page.assets }}/gambar-02.png)

Lorem ipsum dolor sit amet, consectetur adipiscing elit, <span class="p">[</span><span class="nv">Download File 1</span><span class="p">](</span><span class="sx">{{</span> page.assets }}/file-01.pdf).
</code></pre></div></div>

<p>Dengan pendekatan ini, saya mendapatkan beberapa keuntungan, di antaranya:</p>
<ol>
  <li><strong>Terstruktur dengan baik</strong> <br />
  Setiap artikel memiliki direktori gambar sendiri yang terorganisir berdasarkan kategori dan tanggal postingan.</li>
  <li><strong>Mudah untuk dikelola</strong> <br />
  Jika saya perlu mengubah nama file gambar atau menghapus gambar tertentu, saya hanya perlu mengakses direktori gambar yang sesuai dengan artikel tersebut tanpa harus mencari di seluruh project.</li>
  <li><strong>Fleksibel untuk berbagai jenis file</strong> <br />
  Saya dapat menyimpan berbagai jenis file (gambar, PDF, dokumen, dll) di dalam direktori yang sama tanpa harus bergantung pada layanan pihak ketiga.</li>
</ol>

<h2 id="penutup">Penutup</h2>

<p>Tak terasa sudah sejak 2018 saya menulis di blog ini dengan berbagai format penulisan. Dari mulai menggunakan custom tag/notasi markdown di versi pertama, mencoba AsciiDoc di versi kedua, hingga akhirnya kembali ke Markdown dengan mengikuti CommonMark specification di versi ketiga ini.</p>

<p>Dengan perubahan ini, saya berharap dapat lebih fokus pada konten artikel tanpa terganggu oleh aspek teknis penulisan.</p>

<p>Terima kasih saya ucapkan untuk teman-teman yang telah mengikuti perjalanan blog ini hingga versi ketiga. Terima kasih karena telah memberikan testimonial dan feedback dalam beberapa kesempatan ketika berinteraksi dengan saya, baik secara langsung maupun tidak langsung melalui media sosial dan juga email. Saya senang jika blog ini dapat memberikan manfaat dan inspirasi buat teman-teman yang membacanya.</p>

<p>Mumpung masih awal tahun, saya mengajak teman-teman, “Ayo nulis blog juga yaa!”</p>

<h2 id="referensi">Referensi</h2>

<ol>
  <li>
    <p><a href="https://github.com/bandithijo/bandithijo.github.io_v1">https://github.com/bandithijo/bandithijo.github.io_v1</a> <br />
  Tanggal diakses: 2026-01-16</p>
  </li>
  <li>
    <p><a href="https://github.com/bandithijo/bandithijo.github.io_v2">https://github.com/bandithijo/bandithijo.github.io_v2</a> <br />
  Tanggal diakses: 2026-01-16</p>
  </li>
  <li>
    <p><a href="https://github.com/bandithijo/bandithijo.github.io_v3">https://github.com/bandithijo/bandithijo.github.io_v3</a> <br />
  Tanggal diakses: 2026-01-16</p>
  </li>
</ol>]]></content><author><name>BanditHijo</name></author><category term="blog" /><category term="blog" /><summary type="html"><![CDATA[Di pertengahan tahun 2025, saya memutuskan untuk membuat perubahan besar pada cara saya menulis artikel di blog ini. Setelah beberapa tahun menggunakan berbagai notasi syntax, saya merasa perlu untuk menyederhanakan proses penulisan agar tetap mempertahankan mood dalam menulis. Oleh karena itu, pada BanditHijo Versi 3, saya berfokus pada penggunaan CommonMark specification sebagai standar penulisan artikel.]]></summary></entry></feed>