<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.haidhi.my.id/wiki/index.php?action=history&amp;feed=atom&amp;title=Hairpin_NAT</id>
	<title>Hairpin NAT - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.haidhi.my.id/wiki/index.php?action=history&amp;feed=atom&amp;title=Hairpin_NAT"/>
	<link rel="alternate" type="text/html" href="https://wiki.haidhi.my.id/wiki/index.php?title=Hairpin_NAT&amp;action=history"/>
	<updated>2026-11-02T09:35:40Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://wiki.haidhi.my.id/wiki/index.php?title=Hairpin_NAT&amp;diff=891&amp;oldid=prev</id>
		<title>SanzSkuy: Created page with &quot;&#039;&#039;&#039;Hairpin NAT&#039;&#039;&#039; (disebut juga &#039;&#039;NAT loopback&#039;&#039; atau &#039;&#039;NAT reflection&#039;&#039;) adalah masalah klasik ketika perangkat di dalam LAN mencoba mengakses server internal &#039;&#039;&#039;lewat IP publik&#039;&#039;&#039; (atau domain yang menunjuk ke IP publik), padahal server itu berada di jaringan yang sama. Dari internet berjalan normal, dari dalam LAN koneksi menggantung.  Halaman ini memakai kasus nyata: node OKD (&lt;code&gt;192.168.90.30&lt;/code&gt;) gagal mengakses &lt;code&gt;registry.example.com&lt;/code&gt;. Lihat juga [...&quot;</title>
		<link rel="alternate" type="text/html" href="https://wiki.haidhi.my.id/wiki/index.php?title=Hairpin_NAT&amp;diff=891&amp;oldid=prev"/>
		<updated>2026-11-02T06:42:16Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;&amp;#039;&amp;#039;&amp;#039;Hairpin NAT&amp;#039;&amp;#039;&amp;#039; (disebut juga &amp;#039;&amp;#039;NAT loopback&amp;#039;&amp;#039; atau &amp;#039;&amp;#039;NAT reflection&amp;#039;&amp;#039;) adalah masalah klasik ketika perangkat di dalam LAN mencoba mengakses server internal &amp;#039;&amp;#039;&amp;#039;lewat IP publik&amp;#039;&amp;#039;&amp;#039; (atau domain yang menunjuk ke IP publik), padahal server itu berada di jaringan yang sama. Dari internet berjalan normal, dari dalam LAN koneksi menggantung.  Halaman ini memakai kasus nyata: node OKD (&amp;lt;code&amp;gt;192.168.90.30&amp;lt;/code&amp;gt;) gagal mengakses &amp;lt;code&amp;gt;registry.example.com&amp;lt;/code&amp;gt;. Lihat juga [...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;#039;&amp;#039;&amp;#039;Hairpin NAT&amp;#039;&amp;#039;&amp;#039; (disebut juga &amp;#039;&amp;#039;NAT loopback&amp;#039;&amp;#039; atau &amp;#039;&amp;#039;NAT reflection&amp;#039;&amp;#039;) adalah masalah klasik ketika perangkat di dalam LAN mencoba mengakses server internal &amp;#039;&amp;#039;&amp;#039;lewat IP publik&amp;#039;&amp;#039;&amp;#039; (atau domain yang menunjuk ke IP publik), padahal server itu berada di jaringan yang sama. Dari internet berjalan normal, dari dalam LAN koneksi menggantung.&lt;br /&gt;
&lt;br /&gt;
Halaman ini memakai kasus nyata: node OKD (&amp;lt;code&amp;gt;192.168.90.30&amp;lt;/code&amp;gt;) gagal mengakses &amp;lt;code&amp;gt;registry.example.com&amp;lt;/code&amp;gt;. Lihat juga [[Install OKD Single Node (SNO) di Proxmox]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Topologi ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Komponen !! Alamat !! Peran&lt;br /&gt;
|-&lt;br /&gt;
| MikroTik (WAN) || &amp;lt;code&amp;gt;203.0.113.10&amp;lt;/code&amp;gt; || IP publik, NAT 80/443 ke proxy&lt;br /&gt;
|-&lt;br /&gt;
| MikroTik (LAN) || &amp;lt;code&amp;gt;192.168.90.1&amp;lt;/code&amp;gt; || Gateway subnet LAB&lt;br /&gt;
|-&lt;br /&gt;
| nginx proxy || &amp;lt;code&amp;gt;192.168.90.100&amp;lt;/code&amp;gt; || Terminasi HTTPS (Let&amp;#039;s Encrypt), reverse proxy berdasarkan nama domain&lt;br /&gt;
|-&lt;br /&gt;
| Registry backend || &amp;lt;code&amp;gt;192.168.90.25:5001&amp;lt;/code&amp;gt; || Docker Distribution (HTTP, auth)&lt;br /&gt;
|-&lt;br /&gt;
| Klien (node OKD) || &amp;lt;code&amp;gt;192.168.90.30&amp;lt;/code&amp;gt; || Ingin menarik image dari registry&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
DNS publik (Cloudflare, DNS only): &amp;lt;code&amp;gt;registry.example.com → 203.0.113.10&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Gejala ==&lt;br /&gt;
* Dari internet: &amp;lt;code&amp;gt;https://registry.example.com&amp;lt;/code&amp;gt; normal.&lt;br /&gt;
* Dari dalam LAN: koneksi menggantung tanpa error yang jelas.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ getent hosts registry.example.com&lt;br /&gt;
203.0.113.10    registry.example.com&lt;br /&gt;
&lt;br /&gt;
$ curl -sI -v https://registry.example.com/v2/&lt;br /&gt;
* Host registry.example.com:443 was resolved.&lt;br /&gt;
* IPv4: 203.0.113.10&lt;br /&gt;
*   Trying 203.0.113.10:443...&lt;br /&gt;
(menggantung)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Tidak ada &amp;#039;&amp;#039;connection refused&amp;#039;&amp;#039;, tidak ada error sertifikat; hanya diam. Ini ciri khas hairpin NAT.&lt;br /&gt;
&lt;br /&gt;
== Penyebab ==&lt;br /&gt;
=== Alur paket yang gagal ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. Klien 192.168.90.30 ingin ke 203.0.113.10:443&lt;br /&gt;
   &amp;quot;203.0.113.10 bukan subnet-ku&amp;quot; → kirim ke gateway MikroTik&lt;br /&gt;
      SYN  src 192.168.90.30  → dst 203.0.113.10&lt;br /&gt;
&lt;br /&gt;
2. MikroTik: aturan dst-nat 443 → proxy&lt;br /&gt;
      SYN  src 192.168.90.30  → dst 192.168.90.100     (alamat tujuan diganti)&lt;br /&gt;
&lt;br /&gt;
3. Proxy melihat pengirim 192.168.90.30, satu subnet dengannya&lt;br /&gt;
   → balas LANGSUNG ke klien lewat switch, TIDAK lewat MikroTik&lt;br /&gt;
      SYN-ACK  src 192.168.90.100 → dst 192.168.90.30&lt;br /&gt;
&lt;br /&gt;
4. Klien: &amp;quot;Aku mengirim SYN ke 203.0.113.10, kenapa yang membalas 192.168.90.100?&amp;quot;&lt;br /&gt;
   → balasan tidak cocok dengan koneksi mana pun, dibuang&lt;br /&gt;
   → klien terus menunggu → koneksi menggantung&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Inti masalah ===&lt;br /&gt;
NAT hanya berfungsi bila &amp;#039;&amp;#039;&amp;#039;paket pergi dan paket pulang melewati router yang sama&amp;#039;&amp;#039;&amp;#039;, supaya router bisa menerjemahkan alamat balik. Pada langkah 3, balasan mengambil jalan pintas di dalam subnet, sehingga MikroTik tidak sempat mengubah alamat sumber balasan dari &amp;lt;code&amp;gt;192.168.90.100&amp;lt;/code&amp;gt; kembali menjadi &amp;lt;code&amp;gt;203.0.113.10&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Kenapa dari internet tidak bermasalah? ===&lt;br /&gt;
Klien di internet tidak satu subnet dengan proxy. Balasan proxy pasti dikirim ke gateway (MikroTik), sehingga MikroTik menerjemahkan alamatnya dengan benar.&lt;br /&gt;
&lt;br /&gt;
== Cara membuktikan ==&lt;br /&gt;
Di server tujuan (proxy), tangkap paket dari klien:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo tcpdump -ni any host 192.168.90.30 and port 443&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Saat klien menjalankan &amp;lt;code&amp;gt;curl&amp;lt;/code&amp;gt;, terlihat SYN masuk dari &amp;lt;code&amp;gt;192.168.90.30&amp;lt;/code&amp;gt; dan proxy membalas SYN-ACK langsung ke &amp;lt;code&amp;gt;192.168.90.30&amp;lt;/code&amp;gt;, tetapi ACK dari klien tidak pernah datang.&lt;br /&gt;
&lt;br /&gt;
Uji jalur langsung tanpa NAT dengan &amp;lt;code&amp;gt;--resolve&amp;lt;/code&amp;gt; (memaksa nama domain ke IP tertentu):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
curl -sI --max-time 5 --resolve registry.example.com:443:192.168.90.100 \&lt;br /&gt;
  https://registry.example.com/v2/ | head -3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Bila ini menjawab (misalnya &amp;lt;code&amp;gt;HTTP/1.1 401 Unauthorized&amp;lt;/code&amp;gt; dari nginx), server sehat dan masalahnya memang hairpin NAT.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Catatan:&amp;#039;&amp;#039;&amp;#039; pastikan IP yang dipakai adalah server yang benar-benar melayani HTTPS. Pada kasus ini, &amp;lt;code&amp;gt;192.168.90.25&amp;lt;/code&amp;gt; (backend registry) menolak port 443 karena hanya melayani HTTP di port 5001; HTTPS dilayani oleh proxy &amp;lt;code&amp;gt;192.168.90.100&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
curl -sI --max-time 5 http://192.168.90.25:5001/v2/ | head -3   # backend, HTTP&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Solusi 1: Split DNS (dipakai) ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Ide:&amp;#039;&amp;#039;&amp;#039; perangkat di dalam LAN diberi jawaban DNS berbeda, yaitu langsung IP internal server. Disebut juga &amp;#039;&amp;#039;split-horizon DNS&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Klien 192.168.90.30 ──(langsung, satu subnet, tanpa NAT)──► Proxy 192.168.90.100&lt;br /&gt;
                    ◄──────────────── balasan ─────────────&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Di dnsmasq bastion (&amp;lt;code&amp;gt;/etc/dnsmasq.d/okd.conf&amp;lt;/code&amp;gt;):&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
address=/registry.example.com/192.168.90.100&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo systemctl restart dnsmasq&lt;br /&gt;
getent hosts registry.example.com        # → 192.168.90.100&lt;br /&gt;
curl -sI https://registry.example.com/v2/ | head -3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Kenapa HTTPS tetap valid?&amp;#039;&amp;#039;&amp;#039; Sertifikat dicocokkan dengan &amp;#039;&amp;#039;&amp;#039;nama&amp;#039;&amp;#039;&amp;#039;, bukan IP. Klien tetap meminta &amp;lt;code&amp;gt;registry.example.com&amp;lt;/code&amp;gt; (lewat SNI dan header Host), sehingga nginx menyajikan sertifikat Let&amp;#039;s Encrypt untuk nama itu lalu meneruskan ke backend &amp;lt;code&amp;gt;192.168.90.25:5001&amp;lt;/code&amp;gt;. Yang berubah hanya jalur jaringannya.&lt;br /&gt;
&lt;br /&gt;
Kelebihan:&lt;br /&gt;
* Tidak mengubah konfigurasi router.&lt;br /&gt;
* Trafik langsung di dalam subnet (lebih efisien).&lt;br /&gt;
* Proxy melihat IP asli klien di log.&lt;br /&gt;
&lt;br /&gt;
Kekurangan:&lt;br /&gt;
* Hanya berlaku untuk perangkat yang memakai DNS tersebut (di sini: node OKD, bastion, VM yang DNS-nya diarahkan ke bastion, dan klien WireGuard dengan &amp;lt;code&amp;gt;DNS = 192.168.90.29&amp;lt;/code&amp;gt;).&lt;br /&gt;
* Setiap subdomain yang perlu diakses dari dalam harus ditambahkan (atau pakai wildcard &amp;lt;code&amp;gt;address=/example.com/192.168.90.100&amp;lt;/code&amp;gt; bila semua subdomain memang dilayani proxy yang sama).&lt;br /&gt;
&lt;br /&gt;
== Solusi 2: Hairpin NAT di MikroTik ==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Ide:&amp;#039;&amp;#039;&amp;#039; untuk trafik LAN yang di-NAT balik ke LAN, MikroTik juga mengganti &amp;#039;&amp;#039;&amp;#039;alamat sumber&amp;#039;&amp;#039;&amp;#039; menjadi IP router sendiri. Akibatnya server terpaksa membalas ke MikroTik, sehingga terjemahan alamat bisa dibalik dengan benar.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. Klien  → MikroTik : src 192.168.90.30 → dst 203.0.113.10&lt;br /&gt;
2. MikroTik → Proxy  : src 192.168.90.1  → dst 192.168.90.100   (dst-nat + masquerade)&lt;br /&gt;
3. Proxy  → MikroTik : src 192.168.90.100 → dst 192.168.90.1     (balas ke router)&lt;br /&gt;
4. MikroTik → Klien  : src 203.0.113.10  → dst 192.168.90.30     (diterjemahkan balik)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Syarat 1: aturan dst-nat harus cocok untuk trafik dari LAN ===&lt;br /&gt;
Banyak aturan port forward ditulis dengan &amp;lt;code&amp;gt;in-interface=&amp;amp;lt;WAN&amp;amp;gt;&amp;lt;/code&amp;gt;, sehingga hanya berlaku untuk trafik dari internet. Untuk hairpin, aturan perlu mencocokkan alamat tujuan IP publik:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/ip firewall nat&lt;br /&gt;
add chain=dstnat dst-address=203.0.113.10 protocol=tcp dst-port=80,443 \&lt;br /&gt;
    action=dst-nat to-addresses=192.168.90.100 comment=&amp;quot;port forward web&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Bila IP publik dinamis, pilihan umum adalah &amp;lt;code&amp;gt;dst-address-type=local&amp;lt;/code&amp;gt; dikombinasikan dengan pembatas lain (misalnya &amp;lt;code&amp;gt;dst-address-list&amp;lt;/code&amp;gt; berisi IP publik yang diperbarui skrip), agar tidak ikut menangkap trafik ke IP router lainnya.&lt;br /&gt;
&lt;br /&gt;
=== Syarat 2: masquerade untuk trafik hairpin ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/ip firewall nat&lt;br /&gt;
add chain=srcnat src-address=192.168.90.0/24 dst-address=192.168.90.100 \&lt;br /&gt;
    protocol=tcp dst-port=80,443 out-interface=&amp;lt;interface-LAN&amp;gt; \&lt;br /&gt;
    action=masquerade comment=&amp;quot;hairpin NAT&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Aturan ini harus berada &amp;#039;&amp;#039;&amp;#039;di atas&amp;#039;&amp;#039;&amp;#039; aturan masquerade umum ke internet (urutan aturan NAT dievaluasi dari atas).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Sesuaikan&amp;#039;&amp;#039;&amp;#039; nama interface, subnet, dan alamat dengan konfigurasi sebenarnya sebelum dipakai. Cek aturan yang ada (hanya membaca):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/ip firewall nat print&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Kelebihan:&lt;br /&gt;
* Berlaku untuk semua perangkat di LAN, tanpa mengubah DNS mereka.&lt;br /&gt;
* Satu aturan mencakup semua subdomain yang diteruskan ke proxy.&lt;br /&gt;
&lt;br /&gt;
Kekurangan:&lt;br /&gt;
* Mengubah konfigurasi router.&lt;br /&gt;
* Trafik internal bolak-balik melewati router (beban tambahan, terutama untuk transfer besar seperti push image).&lt;br /&gt;
* Proxy melihat IP router sebagai pengirim, sehingga log dan pembatasan berbasis IP klien kurang berguna.&lt;br /&gt;
&lt;br /&gt;
== Perbandingan ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! !! Split DNS !! Hairpin NAT&lt;br /&gt;
|-&lt;br /&gt;
| Ubah router || Tidak || Ya&lt;br /&gt;
|-&lt;br /&gt;
| Cakupan || Perangkat yang memakai DNS internal || Semua perangkat LAN&lt;br /&gt;
|-&lt;br /&gt;
| Jalur trafik || Langsung (efisien) || Lewat router&lt;br /&gt;
|-&lt;br /&gt;
| IP klien di log server || Asli || IP router&lt;br /&gt;
|-&lt;br /&gt;
| Cocok untuk || Lab, server, klien VPN || LAN umum dengan banyak perangkat&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Catatan: jangan pakai Cloudflare proxy (awan oranye) untuk registry ==&lt;br /&gt;
Mengaktifkan proxy Cloudflare juga &amp;quot;menghindari&amp;quot; hairpin NAT, karena trafik keluar ke Cloudflare lalu masuk kembali dari IP Cloudflare. Namun untuk container registry ini tidak disarankan: trafik internal jadi keluar-masuk internet, dan batas ukuran body request pada paket gratis Cloudflare dapat membuat push layer image yang besar gagal.&lt;br /&gt;
&lt;br /&gt;
== Ringkasan ==&lt;br /&gt;
* Hairpin NAT terjadi saat klien dan server berada di subnet yang sama, tetapi klien mengakses server lewat IP publik.&lt;br /&gt;
* Gejala: koneksi menggantung tanpa error; &amp;lt;code&amp;gt;curl&amp;lt;/code&amp;gt; berhenti di &amp;#039;&amp;#039;Trying &amp;amp;lt;IP publik&amp;amp;gt;&amp;#039;&amp;#039;.&lt;br /&gt;
* Bukti: &amp;lt;code&amp;gt;curl --resolve&amp;lt;/code&amp;gt; ke IP internal berhasil; &amp;lt;code&amp;gt;tcpdump&amp;lt;/code&amp;gt; menunjukkan server membalas langsung ke klien.&lt;br /&gt;
* Solusi: &amp;#039;&amp;#039;&amp;#039;split DNS&amp;#039;&amp;#039;&amp;#039; (jawab nama dengan IP internal) atau &amp;#039;&amp;#039;&amp;#039;hairpin NAT&amp;#039;&amp;#039;&amp;#039; di router (masquerade agar balasan lewat router).&lt;/div&gt;</summary>
		<author><name>SanzSkuy</name></author>
	</entry>
</feed>