---
title: "Cara Mengamankan Docker di VPS agar Port Tidak Bocor"
description: "Port container Docker bisa terbuka ke internet walau UFW aktif. Ini penyebabnya dan cara menguncinya dengan bind 127.0.0.1 dan DOCKER-USER."
url: "https://nivelva.com/insight/cara-mengamankan-docker-vps-port-tidak-bocor"
category: "Keamanan/Cyber Security"
tags: ["docker","firewall","ufw","iptables","keamanan vps"]
author: "Theresia Candiawan"
published: "2026-11-07T04:34:00+07:00"
updated: "2026-11-07T04:34:00+07:00"
language: "id"
publisher: "Nivelva (https://nivelva.com)"
---

# Cara Mengamankan Docker di VPS agar Port Tidak Bocor

> **Jawaban singkat:** Port yang dipublikasikan Docker melewati aturan UFW karena Docker mengatur iptables sendiri. Solusinya, petakan port ke 127.0.0.1, buka ke publik hanya lewat reverse proxy, dan pakai rantai DOCKER-USER bila perlu membatasi IP.

Sudah mengaktifkan UFW, menolak semua koneksi masuk kecuali SSH dan HTTPS, lalu kaget karena port database di container tetap bisa dibuka dari luar? Kamu tidak salah ketik aturan. Begitulah cara Docker bekerja secara bawaan.

Dokumentasi resmi Docker menjelaskan bahwa lalu lintas ke port yang dipublikasikan (`-p` atau `ports:` di Compose) dialihkan di tabel `nat` sebelum sampai ke rantai `INPUT` yang dipakai UFW. Akibatnya aturan UFW dilewati. Jadi pengamanannya harus dilakukan di sisi Docker: tentukan port mana yang boleh publik, ikat sisanya ke localhost, dan saring sisanya di rantai `DOCKER-USER`.

## Kenapa UFW tidak melindungi container?

Saat kamu menjalankan `docker run -p 8080:80 nginx`, Docker menambahkan aturan iptables yang meneruskan paket dari port 8080 di host ke container. Pengalihan ini terjadi di awal, lalu paket berjalan di rantai `FORWARD`, bukan `INPUT`. UFW memasang aturannya terutama di `INPUT`, sehingga tidak pernah "melihat" paket itu.

Kalau kamu memakai firewalld (umum di AlmaLinux atau Rocky), Docker membuat zona bernama `docker` dengan target `ACCEPT` dan kebijakan forwarding ke zona itu. Efeknya mirip: port yang dipublikasikan terbuka.

Docker juga memperingatkan agar kamu tidak mematikan pengelolaan iptables (`"iptables": false`) karena hampir pasti merusak jaringan container. Jadi jalan yang benar bukan melawan Docker, tetapi mengatur publikasi port dengan sadar.

## Langkah mengunci port Docker

### Langkah 1: Inventaris port yang sedang terbuka

```
docker ps --format 'table {{.Names}}\t{{.Ports}}'
sudo ss -tlnp
```

Perhatikan kolom Ports. Tulisan `0.0.0.0:5432->5432/tcp` atau `[::]:6379->6379/tcp` berarti port itu terbuka ke semua alamat, termasuk internet. Yang aman terlihat seperti `127.0.0.1:5432->5432/tcp`.

### Langkah 2: Ikat port internal ke 127.0.0.1

Untuk layanan yang hanya dipakai di server itu sendiri (database, Redis, panel admin, API internal), tulis alamatnya secara eksplisit. Di Docker Compose:

```
services:
  db:
    image: postgres:16
    ports:
      - "127.0.0.1:5432:5432"
```

Lebih baik lagi, hapus `ports:` sama sekali bila hanya container lain yang butuh akses. Container di jaringan Compose yang sama bisa saling memanggil lewat nama layanan (`db:5432`) tanpa port dipublikasikan ke host.

Terapkan dengan `docker compose up -d`, lalu cek lagi `docker ps`.

### Langkah 3: Jadikan 127.0.0.1 sebagai bawaan

Supaya port baru tidak terbuka tanpa sengaja, setel alamat bawaan di `/etc/docker/daemon.json`:

```
{
  "ip": "127.0.0.1"
}
```

Lalu `sudo systemctl restart docker`. Opsi `ip` membuat `-p 8080:80` otomatis terikat ke 127.0.0.1. Port yang memang harus publik ditulis eksplisit, misalnya `"0.0.0.0:443:443"`. Perhatikan bahwa restart Docker ikut menghentikan container sementara, jadi lakukan di jam sepi.

### Langkah 4: Buka ke publik hanya lewat reverse proxy

Pola yang rapi: hanya satu container (Nginx, Caddy, atau Traefik) yang mempublikasikan port 80 dan 443. Aplikasi lain berada di jaringan internal dan diakses lewat proxy itu. Keuntungannya, HTTPS, pembatasan laju, dan log akses terpusat di satu tempat. Contoh pengaturan pembatasan laju ada di artikel [rate limiting di Nginx](https://nivelva.com/insight/rate-limiting-nginx).

### Langkah 5: Batasi sumber IP dengan DOCKER-USER

Kadang port memang harus publik tapi hanya untuk alamat tertentu, misalnya panel monitoring untuk IP kantor. Docker menyediakan rantai `DOCKER-USER` yang diproses sebelum aturan Docker sendiri. Contoh dari dokumentasi resmi, disesuaikan:

```
sudo iptables -I DOCKER-USER -i eth0 ! -s 203.0.113.10 -j DROP
sudo iptables -I DOCKER-USER -m state --state RELATED,ESTABLISHED -j ACCEPT
```

Baris pertama menolak semua koneksi dari antarmuka publik `eth0` kecuali dari IP kantor (ganti dengan IP dan nama antarmukamu). Baris kedua disisipkan paling atas agar balasan untuk koneksi keluar dari container tetap lolos. Aturan ini berlaku untuk semua port container, jadi uji dengan hati-hati. Aturan iptables manual hilang saat reboot kecuali disimpan, misalnya dengan paket `iptables-persistent`.

### Langkah 6: Lindungi Docker socket

Port bukan satu-satunya kebocoran. File `/var/run/docker.sock` setara akses root ke host. Jangan memasangnya ke container kecuali benar-benar perlu (misalnya alat manajemen), dan jangan pernah membuka API Docker lewat TCP tanpa TLS. Tambahkan pengguna ke grup `docker` hanya bila kamu sadar itu sama dengan memberi akses root.

### Langkah 7: Uji dari luar

Dari komputer lain:

```
nc -zv IP_PUBLIK_SERVER 5432
nc -zv IP_PUBLIK_SERVER 443
```

Port internal harus gagal tersambung, port publik (443) harus terbuka. Ulangi setiap kali menambah layanan baru.

## Ringkasan pilihan publikasi port

| Penulisan di Compose | Bisa diakses dari | Cocok untuk |
|:--|:--|:--|
| Tanpa `ports:` | Hanya container di jaringan yang sama | Database, cache, worker |
| `"127.0.0.1:5432:5432"` | Hanya host itu sendiri | Alat admin lewat SSH tunnel |
| `"10.0.0.2:5432:5432"` (IP privat) | Jaringan privat | Server aplikasi terpisah |
| `"443:443"` atau `"0.0.0.0:443:443"` | Seluruh internet | Reverse proxy saja |

Kalau butuh membuka panel admin dari laptop, gunakan SSH tunnel: `ssh -L 5432:127.0.0.1:5432 user@server`, lalu sambungkan alatmu ke `localhost:5432`. Port tidak perlu dibuka ke internet sama sekali.

Untuk pemahaman kesalahan lain yang sering terjadi, baca juga [kesalahan umum Docker di produksi](https://nivelva.com/insight/kesalahan-docker-di-produksi). Contoh nyata untuk database ada di [cara mengunci Redis dan MongoDB](https://nivelva.com/insight/cara-mengunci-redis-mongodb-tidak-terbuka-publik).

## Pertanyaan yang sering diajukan

### Apakah benar UFW tidak berpengaruh sama sekali pada Docker?

UFW tetap melindungi layanan yang berjalan langsung di host, seperti SSH. Yang dilewati adalah port yang dipublikasikan Docker ke container, karena paketnya diteruskan lewat rantai FORWARD.

### Bolehkah saya menyetel "iptables": false di daemon.json?

Docker tidak menyarankannya karena jaringan container kemungkinan besar rusak. Lebih aman memakai bind 127.0.0.1, reverse proxy, dan rantai DOCKER-USER.

### Apakah Docker rootless atau Podman menyelesaikan masalah ini?

Mode rootless mengurangi dampak bila container dibobol, tapi port yang dipublikasikan ke 0.0.0.0 tetap terbuka. Prinsip memilih alamat bind tetap berlaku.

### Bagaimana mengecek port dari luar tanpa komputer kedua?

Kamu bisa memakai VPS lain, koneksi HP dengan aplikasi terminal, atau layanan pengecek port daring. Yang penting pengujian dilakukan dari luar server.

Checklist singkat:

- Tidak ada `0.0.0.0` atau `[::]` di `docker ps` selain reverse proxy.
- `daemon.json` berisi `"ip": "127.0.0.1"`.
- Database dan cache tanpa `ports:` atau terikat ke 127.0.0.1.
- Docker socket tidak dipasang ke container sembarangan.
- Uji `nc` dari luar sesuai harapan.

## Sumber

- <https://docs.docker.com/engine/network/packet-filtering-firewalls/>
- <https://docs.docker.com/engine/network/firewall-iptables/>
- <https://docs.docker.com/reference/cli/dockerd/>

---

Diterbitkan oleh Nivelva Insight (https://nivelva.com/insight/). Artikel ini: https://nivelva.com/insight/cara-mengamankan-docker-vps-port-tidak-bocor
Kontak Nivelva: WhatsApp https://wa.me/6285111245007, email hello@nivelva.com
