wg-easy di Docker: WireGuard dengan Antarmuka Web
Jalankan WireGuard dengan UI wg-easy melalui Docker Compose. Pelajari port, NET_ADMIN, sysctl penting, serta cara onboarding ponsel memakai kode QR.
Yang Anda bangun
wg-easy adalah WireGuard dengan antarmuka web yang berjalan sebagai satu container Docker. Aplikasi ini mengelola antarmuka WireGuard untuk Anda dan menambahkan UI browser untuk membuat client. Setiap client yang Anda buat memperoleh file konfigurasi dan kode QR. Dengan demikian, ponsel dapat bergabung ke VPN dengan mengarahkan kameranya ke layar.
Tunnel itu sendiri adalah WireGuard biasa. Modul kernel memindahkan paket, sehingga throughput sama seperti pada konfigurasi yang ditulis secara manual. Keuntungannya adalah pengelolaan siklus hidup client: menambahkan, menonaktifkan, dan menghapus peer tanpa mengedit file konfigurasi melalui SSH. Kekurangannya adalah Anda tidak memiliki kendali langsung atas konfigurasi tersebut. Hal ini dibahas dalam konfigurasi WireGuard manual di VPS.
Anda memerlukan VPS KVM dengan alamat IPv4 publik, Docker Engine dengan plugin Compose, dan akses root. Virtualisasi container yang menggunakan kernel host secara bersama, seperti OpenVZ atau LXC, biasanya tidak dapat memuat modul WireGuard. Akibatnya, container gagal mengaktifkan antarmuka tersebut.
Versi 15 memindahkan pengaturan dari environment
Sebagian besar panduan yang Anda temukan ditulis untuk wg-easy 14. Pada versi tersebut, Anda menetapkan WG_HOST ke alamat server dan PASSWORD_HASH ke hash bcrypt kata sandi admin, keduanya sebagai variabel environment. Versi 15 merupakan penulisan ulang. Catatan migrasi resmi menyatakan dengan jelas bahwa v15 tidak menggunakan variabel environment yang sama seperti v14, dan sebagian besar pengaturan tersebut dipindahkan ke panel admin di web UI.
Jadi, WG_HOST dan PASSWORD_HASH tidak lagi berfungsi. Jika Anda menyalin file compose lama, container akan berjalan, mengabaikan baris tersebut, lalu meminta Anda membuat akun admin melalui browser. Ini bukan bug. Ini adalah alur penyiapan yang baru.
Per Juli 2026, tag major yang harus dipin adalah 15. Gunakan pin versi major, bukan latest, karena peningkatan versi major mengubah format konfigurasi pada disk dan tidak dapat dikembalikan dengan baik.
File compose
Buat direktori untuk stack tersebut, lalu tulis file compose resmi ke dalamnya. Ini adalah file upstream tanpa perubahan.
sudo mkdir -p /etc/docker/containers/wg-easy
sudo curl -o /etc/docker/containers/wg-easy/docker-compose.yml \
https://raw.githubusercontent.com/wg-easy/wg-easy/master/docker-compose.ymlIsinya seperti berikut:
volumes:
etc_wireguard:
services:
wg-easy:
image: ghcr.io/wg-easy/wg-easy:15
container_name: wg-easy
networks:
wg:
ipv4_address: 10.42.42.42
ipv6_address: fdcc:ad94:bacf:61a3::2a
volumes:
- etc_wireguard:/etc/wireguard
- /lib/modules:/lib/modules:ro
ports:
- "51820:51820/udp"
- "51821:51821/tcp"
restart: unless-stopped
cap_add:
- NET_ADMIN
- SYS_MODULE
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv6.conf.all.disable_ipv6=0
- net.ipv6.conf.all.forwarding=1
- net.ipv6.conf.default.forwarding=1
networks:
wg:
driver: bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 10.42.42.0/24
- subnet: fdcc:ad94:bacf:61a3::/64etc_wireguard adalah volume bernama yang menyimpan kunci server dan setiap klien yang Anda buat. Cadangkan volume tersebut. Jika tidak, proses build ulang akan menghapus semua peer Anda. Jika Anda ingin melihat file tersebut di sistem file host, ganti volume itu dengan bind mount. Baca perbedaan antara bind mount dan volume bernama terlebih dahulu karena izin aksesnya berperilaku berbeda.
Alasan Memerlukan NET_ADMIN, SYS_MODULE, dan sysctl
Kontainer tidak diizinkan mengakses tumpukan jaringan secara default, dan setiap baris ini menghapus satu pembatas tertentu.
NET_ADMIN memungkinkan kontainer membuat antarmuka wg0, menetapkan alamat padanya, dan menulis rute. Tanpanya, kontainer berjalan lalu berhenti saat mengaktifkan antarmuka karena ip link add wg0 type wireguard mengembalikan Operation not permitted.
SYS_MODULE bersama mount /lib/modules hanya-baca memungkinkan kontainer memuat modul kernel WireGuard jika host belum memuatnya. Modul tersebut berada pada kernel host, bukan di dalam image. Karena itu, direktori host harus terlihat oleh kontainer. Pada kernel modern, modul biasanya sudah terintegrasi. Anda dapat memastikannya dengan sudo modprobe wireguard && echo ok pada host.
net.ipv4.ip_forward=1 membuat kernel meneruskan paket yang tidak ditujukan ke host itu sendiri. Tanpanya, klien terhubung dan handshake berhasil, tetapi setiap paket ke internet dibuang. Akibatnya, ping 1.1.1.1 mengalami timeout meskipun VPN tampak terhubung.
net.ipv4.conf.all.src_valid_mark=1 adalah bagian yang sering mengejutkan pengguna. WireGuard menandai paket keluar yang dibuatnya sendiri agar paket tersebut tidak dirutekan kembali ke dalam tunnel. Reverse path filtering yang ketat melihat paket dengan alamat sumber yang tidak sesuai dengan rute yang diharapkan, lalu membuangnya. sysctl ini memberi tahu kernel untuk menerima paket yang ditandai. Dengan demikian, full tunnel tidak memutus koneksinya sendiri.
Jalankan dan buat akun admin
cd /etc/docker/containers/wg-easy
sudo docker compose up -d
sudo docker compose logs -fGunakan docker compose up dan docker compose down, bukan start dan stop. Upstream memperingatkan bahwa start pada container yang dibuat dengan pengaturan berbeda akan membuat jaringan berada dalam keadaan tidak konsisten. Jika Anda ingin stack aktif kembali setelah reboot, restart: unless-stopped sudah menanganinya, dan perilaku boot layanan compose menjelaskan hal-hal yang dijamin dan tidak dijamin oleh kebijakan tersebut.
Antarmuka web mendengarkan pada TCP 51821. Saat pertama kali dibuka, antarmuka ini menampilkan halaman penyiapan untuk membuat akun admin dan mengonfirmasi alamat host yang akan digunakan klien untuk menjangkau server. Alamat host tersebut dicantumkan pada baris Endpoint di setiap konfigurasi klien. Karena itu, alamat tersebut harus berupa IP publik atau nama DNS VPS. Jika alamatnya salah, kode QR yang Anda berikan kepada ponsel akan mengarah ke lokasi yang tidak dapat dijangkau, dan handshake tidak akan pernah selesai.
Ada satu hal lagi tentang port tersebut: wg-easy 15 menolak HTTP biasa kecuali Anda menetapkan INSECURE=true. Mengaksesnya melalui HTTPS dengan sertifikat yang tidak tepercaya, atau mengakhiri TLS pada reverse proxy di depannya, sama-sama dapat dilakukan. Mengaksesnya melalui http:// dengan pengaturan default tidak dapat dilakukan.
Jangan publikasikan port UI ke internet
File compose memublikasikan port 51821 pada setiap antarmuka. Port tersebut adalah halaman login untuk sistem yang dapat merutekan traffic Anda, sehingga tidak boleh terbuka untuk umum. Publikasi port di Docker menulis aturan ke dalam rantai DOCKER, yang dievaluasi sebelum ufw. Karena itu, aturan penolakan ufw tidak menutup port tersebut. Perangkap ini perlu dipahami secara khusus, dan alasan port yang dipublikasikan Docker mengabaikan ufw membahasnya secara lengkap.
Perbaikan sederhananya adalah mengikat UI ke loopback dan mengaksesnya melalui tunnel SSH:
ports:
- "51820:51820/udp"
- "127.0.0.1:51821:51821/tcp"
environment:
- INSECURE=trueKemudian, dari laptop Anda:
ssh -L 51821:127.0.0.1:51821 youruser@your.server.addressBuka http://127.0.0.1:51821 di browser pada laptop Anda. Traffic dienkripsi oleh SSH, port tersebut tidak dapat diakses oleh pihak lain, dan INSECURE=true aman digunakan di sini karena koneksi HTTP biasa tidak pernah meninggalkan antarmuka loopback.
Buka UDP 51820 dan periksa kedua firewall
WireGuard memerlukan UDP 51820 agar dapat dijangkau dari internet. Docker memublikasikan port tersebut, tetapi banyak penyedia layanan menempatkan firewall jaringan terpisah di depan VPS yang tidak diketahui Docker. Buka port tersebut di kedua tempat. Jika Anda mengelola firewall host dengan ufw, aturan dasar ufw untuk VPS merupakan cara yang lebih singkat daripada menulis nftables secara manual.
Periksa apakah container benar-benar sedang mendengarkan:
sudo ss -ulnp | grep 51820Anda akan melihat soket UDP yang sedang mendengarkan. Jika tidak ada apa pun pada baris tersebut, berarti container tidak pernah mengaktifkan antarmuka, dan sudo docker compose logs wg-easy akan menyebutkan penyebabnya.
Buat klien dan pindai di ponsel
Di UI, buat klien dan beri nama yang akan Anda kenali nanti, misalnya nama perangkat yang menggunakannya. wg-easy mengalokasikan alamat tunnel berikutnya yang tersedia dan membuat pasangan kunci untuk Anda. Setiap baris klien menyediakan kode QR dan file .conf yang dapat diunduh.
Instal aplikasi WireGuard resmi di ponsel, pilih opsi untuk menambahkan tunnel dari kode QR, lalu arahkan kamera ke kode di layar. Tunnel muncul dengan nama yang Anda masukkan. Aktifkan tunnel tersebut. Baris klien di UI akan mulai menampilkan penghitung transfer dan waktu handshake terakhir.
Klien yang tidak menampilkan handshake setelah diaktifkan sama sekali tidak dapat menjangkau server. Ini menunjukkan masalah pada UDP 51820, baik di firewall provider maupun pada alamat endpoint yang tertanam dalam konfigurasi. Klien yang menampilkan handshake tetapi tidak dapat mengakses internet menunjukkan masalah pada penerusan atau DNS.
Di desktop, unduh file .conf dan impor file tersebut ke klien WireGuard, bukan mengetiknya kembali. Private key dalam file tersebut dibuat satu kali dan hanya ditampilkan satu kali. Perlakukan file tersebut seperti Anda memperlakukan private key SSH.
Kapan harus beralih dari UI
wg-easy adalah pilihan yang tepat selama peer Anda berupa orang dan ponsel. UI lebih cepat daripada mengedit file konfigurasi, dan mencabut akses ponsel yang hilang hanya memerlukan satu klik.
Anda akan mencapai batasnya ketika menginginkan sesuatu yang tidak dimodelkan oleh UI. Perutean site-to-site, ketika AllowedIPs milik peer mencakup seluruh subnet jarak jauh, bukan hanya satu alamat, biasanya menjadi kendala pertama. Tunnel terpisah dengan aturan perutean per peer, atau konfigurasi yang dibuat oleh alat penyediaan Anda, adalah kendala berikutnya. Pada tahap itu, penyiapan manual tidak lebih sulit, tetapi pendekatannya berbeda, dan panduan WireGuard biasa menunjukkan tunnel yang sama yang dibuat dari wg0.conf. Jika Anda lebih memilih untuk tidak menjalankan bidang kontrol sama sekali, perbandingan WireGuard dengan Tailscale membahas opsi terkelola.
Jika sintaks compose di atas yang terasa asing, bukan bagian WireGuard-nya, dasar-dasar Docker Compose di VPS menjelaskan format file dan perintah sehari-hari.
FAQ
Mengapa wg-easy mengabaikan WG_HOST dan PASSWORD_HASH saya?
Variabel tersebut digunakan oleh wg-easy 14. Versi 15 ditulis ulang, dan upstream memindahkan hampir seluruh konfigurasi ke panel admin di antarmuka web. Container tidak membaca kedua variabel tersebut, sehingga container berjalan normal lalu meminta Anda membuat akun admin saat pertama kali diakses. Tetapkan alamat host yang digunakan klien pada halaman penyiapan tersebut.
Apakah saya memerlukan SYS_MODULE jika kernel saya sudah memiliki WireGuard?
Tidak. SYS_MODULE dan mount /lib/modules ada agar container dapat memuat modul jika host belum memilikinya. Pada host yang sudo modprobe wireguard sudah berhasil dijalankan, capability tersebut tidak digunakan. Menghapusnya merupakan langkah hardening yang wajar, dan NET_ADMIN tetap diperlukan.
Klien terhubung, tetapi tidak ada internet. Apa masalahnya?
Handshake tanpa traffic hampir selalu menunjukkan masalah forwarding. Pastikan net.ipv4.ip_forward=1 dan net.ipv4.conf.all.src_valid_mark=1 masih ada di file compose, karena salinan yang diedit secara manual sering kehilangan keduanya. Jika forwarding aktif, periksa server DNS yang diterima klien. Tunnel yang mengirim semua traffic melalui VPN tetapi menunjuk ke server DNS yang tidak lagi dapat dijangkaunya akan terlihat seperti koneksi yang mati di browser.
Bagaimana cara mencadangkan klien saya?
Semua data berada di named volume etc_wireguard, dalam file wg0.json. UI juga memiliki tombol backup yang mengekspor data yang sama. Salin file tersebut ke lokasi di luar server sebelum melakukan upgrade. Pemulihan dilakukan dengan mengunggah file tersebut selama langkah penyiapan pada container baru.
Apakah saya dapat menjalankan wg-easy di balik reverse proxy?
Ya. Tempatkan proxy di depan TCP 51821, lakukan terminasi TLS di sana, dan tetapkan INSECURE=true pada container agar container menerima hop HTTP biasa dari proxy. Tetap publikasikan UDP 51820 secara langsung, karena traffic VPN menggunakan UDP dan tidak melewati proxy HTTP.