Docker में wg-easy के साथ WireGuard कैसे सेटअप करें
Docker Compose का उपयोग करके wg-easy इंस्टॉल करें। NET_ADMIN और sysctls सेटिंग्स के साथ VPN कॉन्फ़िगर करें। फोन पर QR कोड से कनेक्ट करने का आसान तरीका यहाँ जानें।
आप क्या बना रहे हैं
wg-easy एक वेब इंटरफेस के साथ WireGuard है, जो एक Docker container के रूप में चलता है। यह आपके लिए WireGuard इंटरफेस को मैनेज करता है और क्लाइंट बनाने के लिए एक ब्राउज़र UI जोड़ता है। आपके द्वारा बनाए गए प्रत्येक क्लाइंट को एक कॉन्फ़िगरेशन फ़ाइल और एक QR कोड मिलता है, इसलिए फोन स्क्रीन पर कैमरा पॉइंट करके VPN से जुड़ जाता है।
टनल स्वयं सामान्य WireGuard है। कर्नल मॉड्यूल पैकेट को मूव करता है, इसलिए थ्रूपुट हाथ से लिखे गए सेटअप के समान ही होता है। आप जो हासिल करते हैं वह क्लाइंट लाइफसाइकिल है: SSH पर कॉन्फ़िगरेशन फ़ाइल को एडिट किए बिना पीयर्स को जोड़ना, अक्षम करना और हटाना। आप जो छोड़ते हैं वह उस कॉन्फ़िगरेशन का सीधा नियंत्रण है, जो VPS पर मैन्युअल WireGuard सेटअप का विषय है।
आपको एक ऐसे Linux होस्ट की आवश्यकता है जिसे आप मैनेज कर सकें, जैसे कि KVM VPS, जिसमें एक पब्लिक IP एड्रेस या डोमेन नाम हो जो उस पर पॉइंट करता हो, एक x86_64 या arm64 CPU, Compose प्लगइन के साथ Docker Engine, और root एक्सेस हो। कंटेनर वर्चुअलाइजेशन जो होस्ट कर्नल को साझा करता है, जैसे कि OpenVZ या LXC, आमतौर पर WireGuard मॉड्यूल को लोड नहीं कर सकता है, और कंटेनर इंटरफेस को चालू करने में विफल रहेगा।
Version 15 में सेटिंग्स को environment से हटा दिया गया है
आपको मिलने वाली अधिकांश गाइड wg-easy 14 के लिए लिखी गई हैं, जहाँ आप WG_HOST को अपने सर्वर पते पर और PASSWORD_HASH को एडमिन पासवर्ड के bcrypt हैश पर सेट करते थे, ये दोनों environment variables के रूप में होते थे। Version 15 एक पूरी तरह से नया rewrite है। आधिकारिक माइग्रेशन नोट्स स्पष्ट रूप से कहते हैं कि v15, v14 वाले environment variables का उपयोग नहीं करता है, और उनमें से अधिकांश को वेब UI में एडमिन पैनल में स्थानांतरित कर दिया गया है।
इसलिए WG_HOST और PASSWORD_HASH अब कोई कार्य नहीं करते हैं। यदि आप पुरानी compose file को कॉपी करते हैं, तो कंटेनर शुरू हो जाता है, उन लाइनों को अनदेखा कर देता है, और फिर आपसे ब्राउज़र में एक एडमिन अकाउंट बनाने के लिए कहता है। यह कोई बग नहीं है। यह नया सेटअप फ्लो है।
अक्टूबर 2026 तक, पिन करने के लिए प्रमुख टैग 15 है। latest का उपयोग करने के बजाय प्रमुख version को पिन करें, क्योंकि एक प्रमुख अपग्रेड डिस्क पर मौजूद कॉन्फ़िगरेशन फॉर्मेट को बदल देता है और इसे आसानी से रोल बैक नहीं किया जा सकेगा। 15 पर जाने के साथ v14 की JSON फ़ाइल को एक SQLite डेटाबेस से बदल दिया गया है।
Compose file
Stack के लिए एक directory बनाएँ और उसमें official compose file लिखें। यह upstream file है, जिसमें optional lines को हटा दिया गया है।
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.ymlइसका content इस प्रकार है:
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 एक named volume है जिसमें server key और आपके द्वारा बनाए गए सभी clients होते हैं, जो SQLite database wg-easy.db में store रहते हैं। इस volume का backup लें, अन्यथा rebuild करने पर आपके सभी peers हट जाएंगे। यदि आप उन files को host filesystem पर देखना चाहते हैं, तो इसे bind mount से बदलें। ऐसा करने से पहले bind mounts और named volumes के बीच का अंतर पढ़ें, क्योंकि permissions अलग तरह से काम करती हैं।
NET_ADMIN, SYS_MODULE और sysctls की आवश्यकता क्यों है
डिफ़ॉल्ट रूप से किसी container को network stack में बदलाव करने की अनुमति नहीं होती है, और इनमें से प्रत्येक लाइन एक विशिष्ट प्रतिबंध को हटाती है।
NET_ADMIN container को wg0 interface बनाने, उसे एक address असाइन करने और routes लिखने की अनुमति देता है। इसके बिना container start तो होता है, लेकिन interface को up करते समय बंद हो जाता है, क्योंकि ip link add wg0 type wireguard, Operation not permitted return करता है।
SYS_MODULE और read-only /lib/modules mount container को WireGuard kernel module लोड करने की अनुमति देते हैं, यदि host ने इसे पहले से लोड नहीं किया है। Module host kernel पर स्थित होता है, न कि image के अंदर, इसीलिए host directory का दिखाई देना आवश्यक है। आधुनिक kernel पर module आमतौर पर पहले से ही built-in होता है, जिसे आप host पर sudo modprobe wireguard && echo ok के साथ confirm कर सकते हैं।
net.ipv4.ip_forward=1 kernel को उन packets को forward करने के लिए कहता है जो स्वयं उस box के लिए नहीं हैं। इसके बिना client connect होता है, handshake सफल होता है, लेकिन internet के लिए भेजा गया हर packet drop हो जाता है, जिससे VPN connected दिखने के बावजूद ping 1.1.1.1 time out हो जाता है।
net.ipv4.conf.all.src_valid_mark=1 वह सेटिंग है जो लोगों को हैरान करती है। WireGuard अपने outgoing packets को mark करता है ताकि उन्हें वापस tunnel में route न किया जाए। Strict reverse path filtering ऐसे packet को देखती है जिसका source address अपेक्षित route से मेल नहीं खाता और उसे drop कर देती है। यह sysctl kernel को marked packets को स्वीकार करने का निर्देश देता है, जो एक full tunnel को स्वयं को तोड़ने से रोकता है।
इसे start करें और admin account बनाएँ
cd /etc/docker/containers/wg-easy
sudo docker compose up -d
sudo docker compose logs -fdocker compose up और docker compose down का उपयोग करें, न कि start और stop का। start केवल उन containers को restart करता है जो पहले से मौजूद हैं, इसलिए compose file में किए गए आपके किसी भी बदलाव (network और sysctl settings सहित) को लागू नहीं किया जाता है, जबकि up जो कुछ भी बदला है उसे फिर से बनाता है। यदि आप reboot के बाद stack को वापस चाहते हैं, तो restart: unless-stopped इसे पहले ही कवर कर लेता है, और compose services के boot व्यवहार में बताया गया है कि वह policy क्या वादा करती है और क्या नहीं।
Web UI TCP 51821 पर listen करता है। पहली बार visit करने पर यह एक setup page दिखाता है जहाँ आप admin account बनाते हैं और उस host address की पुष्टि करते हैं जिसका उपयोग clients सर्वर तक पहुँचने के लिए करेंगे। वह host address हर client config की Endpoint line में चला जाता है, इसलिए यह VPS का public IP या DNS name होना चाहिए। यदि यह गलत है, तो आपके द्वारा phone को दिया गया QR code किसी ऐसी जगह point करेगा जहाँ तक पहुँचा नहीं जा सकता और handshake कभी पूरा नहीं होगा।
उस port के बारे में एक और बात: wg-easy कभी भी स्वयं TLS serve नहीं करता है, और यह plain HTTP को मना भी नहीं करता है। http:// पर UI अभी भी load होता है और एक warning banner दिखाता है। default बदलाव session cookie का है, जिसमें Secure flag होता है, इसलिए public address पर plain HTTP के माध्यम से UI तक पहुँचने वाला browser इसे discard कर देता है और login काम नहीं करता है। INSECURE=true उस flag को हटा देता है और इसके अलावा कुछ नहीं करता है। सामने एक reverse proxy लगाने से जो TLS terminate करता है, self-signed certificate के साथ भी, wg-easy में किसी बदलाव की आवश्यकता नहीं होती है।
UI port को इंटरनेट पर पब्लिश न करें
Compose file 51821 port को हर interface पर पब्लिश कर देती है। यह एक ऐसे बॉक्स का login page है जो आपके traffic को route कर सकता है, इसलिए इसे दुनिया के लिए खुला नहीं होना चाहिए। Docker में port पब्लिश करने पर DOCKER chain में rules लिख दिए जाते हैं, जिन्हें ufw से पहले evaluate किया जाता है, इसलिए ufw deny rule इसे बंद नहीं कर पाता। यह एक ऐसी समस्या है जिसे समझना जरूरी है, और Docker द्वारा पब्लिश किए गए ports ufw को क्यों नजरअंदाज करते हैं में इसका पूरा विवरण दिया गया है।
इसका सरल समाधान UI को loopback पर bind करना और इसे SSH tunnel के जरिए एक्सेस करना है:
ports:
- "51820:51820/udp"
- "127.0.0.1:51821:51821/tcp"
environment:
- INSECURE=trueइसके बाद अपने laptop से यह चलाएं:
ssh -L 51821:127.0.0.1:51821 youruser@your.server.addressअपने laptop के browser में http://127.0.0.1:51821 खोलें। Traffic SSH द्वारा encrypted होता है और यह port किसी और को जवाब नहीं देता। INSECURE=true केवल session cookie से Secure flag को हटाता है ताकि browser इस plain HTTP address पर आपके login को बनाए रखे, और यह यहाँ सुरक्षित है क्योंकि plain HTTP hop कभी भी loopback interface से बाहर नहीं जाता।
UDP 51820 को खोलें और दोनों firewalls की जाँच करें
WireGuard को इंटरनेट से UDP 51820 तक पहुँच की आवश्यकता होती है। Docker इसे publish तो करता है, लेकिन कई providers VPS के सामने एक अलग network firewall रखते हैं जिसके बारे में Docker को जानकारी नहीं होती। दोनों स्थानों पर port खोलें। यदि आप ufw के साथ host firewall manage करते हैं, तो VPS के लिए बुनियादी ufw नियम हाथ से nftables लिखने की तुलना में आसान विकल्प है।
जाँचें कि container वास्तव में listening स्थिति में है या नहीं:
sudo ss -ulnp | grep 51820आपको एक listening UDP socket दिखाई देना चाहिए। उस line पर कुछ भी न दिखने का अर्थ है कि container ने interface को start नहीं किया है, और sudo docker compose logs wg-easy में इसका कारण लिखा होगा।
एक क्लाइंट बनाएँ और उसे फोन पर स्कैन करें
UI में, एक क्लाइंट बनाएँ और उसे ऐसा नाम दें जिसे आप बाद में पहचान सकें, जैसे कि वह डिवाइस जिससे वह संबंधित है। wg-easy अगला खाली tunnel पता आवंटित करता है और आपके लिए key pair जनरेट करता है। प्रत्येक क्लाइंट पंक्ति एक QR कोड और एक डाउनलोड करने योग्य .conf फ़ाइल प्रदान करती है।
फोन पर आधिकारिक WireGuard ऐप इंस्टॉल करें, QR कोड से tunnel जोड़ने का विकल्प चुनें, और कैमरे को अपनी स्क्रीन पर मौजूद कोड की ओर करें। tunnel आपके द्वारा टाइप किए गए नाम के साथ दिखाई देता है। इसे चालू करें, और UI में क्लाइंट पंक्ति transfer counters और हालिया handshake समय दिखाना शुरू कर देती है। एक बार जब फोन tunnel पर आ जाता है, तो वह उन सेवाओं तक पहुँच सकता है जिन्हें आपने कभी इंटरनेट पर पब्लिश नहीं किया था। इसी तरह एक फोन कहीं से भी self-hosted photo server पर फोटो अपलोड करता रहता है, बिना उस सर्वर का एक भी port दुनिया के लिए खोले। यही तरीका मीडिया पर भी लागू होता है, और 90 के दशक के वीडियो स्टोर के रूप में फिर से बनाई गई Jellyfin library को होटल के कमरे से ब्राउज़ करना एक सुखद अनुभव है, जबकि यह उतना ही निजी रहता है जितना कि आपके LAN पर था। अलर्ट उसी tunnel पर विपरीत दिशा में काम करते हैं, क्योंकि self-hosted ntfy server उस फोन पर संदेश भेज सकता है जैसे ही कोई बैकअप जॉब विफल होती है, बिना सार्वजनिक इंटरनेट से किसी अनुरोध का उत्तर दिए।
यदि कोई क्लाइंट उसे सक्षम करने के बाद handshake नहीं दिखाता है, तो वह सर्वर तक नहीं पहुँच पा रहा है। यह UDP 51820 की ओर इशारा करता है, जो या तो provider firewall पर है या कॉन्फ़िगरेशन में डाले गए endpoint पते पर है। यदि कोई क्लाइंट handshake दिखाता है लेकिन इंटरनेट काम नहीं कर रहा है, तो यह forwarding या DNS की समस्या है।
डेस्कटॉप पर, .conf फ़ाइल डाउनलोड करें और इसे फिर से टाइप करने के बजाय WireGuard क्लाइंट में import करें। उस फ़ाइल में मौजूद private key एक बार जनरेट होती है और एक बार दिखाई जाती है। इस फ़ाइल के साथ वैसा ही व्यवहार करें जैसा आप SSH private key के साथ करते हैं।
UI से आगे कब बढ़ें
जब आपके peers केवल लोग और उनके phones हों, तब wg-easy एक सही tool है। UI का उपयोग config files को edit करने से तेज है, और खोए हुए phone का access एक click में revoke किया जा सकता है।
जब आप कुछ ऐसा करना चाहते हैं जो UI में उपलब्ध नहीं है, तब आप इसकी सीमाओं तक पहुँच जाते हैं। Site-to-site routing, जहाँ किसी peer का AllowedIPs एक single address के बजाय पूरे remote subnet को cover करता है, आमतौर पर पहली बाधा होती है। इसके बाद per-peer routing rules के साथ split tunnels, या आपके provisioning tool द्वारा generate की गई config आती है। उस स्थिति में, हाथ से setup करना कठिन नहीं होता, बस तरीका अलग होता है, और the plain WireGuard guide वही tunnel दिखाती है जिसे wg0.conf से बनाया गया है। यदि आप control plane को चलाना पूरी तरह बंद करना चाहते हैं, तो WireGuard compared with Tailscale managed विकल्प को कवर करता है। क्या यह एक उचित सौदा है, यह इस पर निर्भर करता है कि coordination server वास्तव में कहाँ तक पहुँच सकता है, और Tailscale's trust model को पढ़ना तब जरूरी है जब आप इसे अपना network सौंपने वाले हों। लागत आमतौर पर अगला सवाल होता है, और what the Tailscale free plan actually covers के अनुसार यह केवल गैर-व्यावसायिक उपयोग के लिए छह users तक मुफ्त है, इसलिए एक घर के लिए यह मुफ्त है जबकि एक छोटी व्यावसायिक टीम चाहे कितनी भी छोटी क्यों न हो, इसके लिए योग्य नहीं है। उस बिंदु के बाद, billing devices के बजाय users की गिनती करती है, जो उस VPS से अलग तरह का बिल है जिसके लिए आप पहले से भुगतान कर रहे हैं, इसलिए what Tailscale costs once you outgrow the free plan वह संख्या है जिसे आपको टीम को migrate करने से पहले देखना चाहिए। आपके द्वारा अभी बनाई गई full tunnel का वहाँ सीधा विकल्प मौजूद है, क्योंकि advertising the VPS as a Tailscale exit node आपको सर्वर के माध्यम से वही route प्रदान करता है, जिसे प्रत्येक client config में लिखने के बजाय admin console में approve किया जाता है। Subnet की बाधा का भी एक विकल्प है, क्योंकि advertising a whole private network from the VPS उस network को tailnet के प्रत्येक device को सौंप देता है, बिना उस per-peer AllowedIPs editing के जिसने आपको UI से दूर किया था। यदि आप वह dashboard और automatic mesh routing चाहते हैं लेकिन किसी और का coordination server नहीं, तो running your own NetBird server on a VPS control plane को आपके अपने hardware पर रखता है, जिसकी कीमत DNS और TLS setup है जिसे wg-easy ने आपसे कभी नहीं माँगा था।
यदि ऊपर दिया गया compose syntax WireGuard के बजाय आपके लिए अपरिचित हिस्सा था, तो Docker Compose basics on a VPS file format और दैनिक commands की व्याख्या करता है।
FAQ
wg-easy मेरे WG_HOST और PASSWORD_HASH को अनदेखा क्यों करता है?
ये variables wg-easy 14 से संबंधित हैं। Version 15 एक पूर्ण पुनर्लेखन (rewrite) है, और upstream ने लगभग सभी कॉन्फ़िगरेशन को वेब UI के एडमिन पैनल में स्थानांतरित कर दिया है। कंटेनर इन variables को नहीं पढ़ता है, इसलिए यह सामान्य रूप से शुरू होता है और पहली बार खोलने पर आपसे एक एडमिन अकाउंट बनाने के लिए कहता है। उस सेटअप पेज पर ही client-facing host address सेट करें।
यदि मेरे kernel में पहले से ही WireGuard है, तो क्या मुझे SYS_MODULE की आवश्यकता है?
नहीं। SYS_MODULE और /lib/modules माउंट इसलिए मौजूद हैं ताकि यदि होस्ट में मॉड्यूल न हो, तो कंटेनर उसे लोड कर सके। ऐसे होस्ट पर जहाँ sudo modprobe wireguard पहले से ही सफल है, यह capability उपयोग में नहीं आती है। इसे हटाना एक उचित सुरक्षा उपाय (hardening step) है, और NET_ADMIN की आवश्यकता दोनों ही स्थितियों में बनी रहती है।
क्लाइंट कनेक्ट हो जाता है लेकिन इंटरनेट नहीं चलता। क्या समस्या है?
बिना ट्रैफ़िक के हैंडशेक का मतलब लगभग हमेशा IP forwarding होता है। पुष्टि करें कि net.ipv4.ip_forward=1 और net.ipv4.conf.all.src_valid_mark=1 अभी भी compose फ़ाइल में मौजूद हैं, क्योंकि हाथ से संपादित (hand-edited) कॉपी में अक्सर ये छूट जाते हैं। यदि forwarding चालू है, तो क्लाइंट को मिले DNS सर्वर की जाँच करें। एक ऐसा टनल जो सारा ट्रैफ़िक VPN के माध्यम से भेजता है लेकिन ऐसे DNS सर्वर की ओर इशारा करता है जिस तक वह अब नहीं पहुँच सकता, ब्राउज़र में मृत कनेक्शन जैसा ही दिखता है।
मैं अपने क्लाइंट्स का बैकअप कैसे लूँ?
सब कुछ etc_wireguard नामक वॉल्यूम में रहता है। Version 15 में इसका मतलब है कि कंटेनर के अंदर /etc/wireguard/wg-easy.db पर एक SQLite डेटाबेस है। v15 के दस्तावेज़ों में कोई बैकअप या एक्सपोर्ट सुविधा वर्णित नहीं है, इसलिए वॉल्यूम का ही बैकअप लें: docker compose down चलाएँ, वॉल्यूम की सामग्री को सर्वर से बाहर कहीं कॉपी करें, और फिर docker compose up -d के साथ स्टैक को वापस चालू करें। किसी भी अपग्रेड से पहले ऐसा करें। पुराने गाइडों में उल्लिखित wg0.json फ़ाइल wg-easy 14 से संबंधित है। यह वही है जिसे v14 का बैकअप बटन एक्सपोर्ट करता है, और v15 में इसका एकमात्र उपयोग वह फ़ाइल है जिसे आप पुराने इंस्टॉलेशन को माइग्रेट करते समय सेटअप विज़ार्ड में अपलोड करते हैं।
क्या मैं wg-easy को reverse proxy के पीछे चला सकता हूँ?
हाँ। प्रॉक्सी को वेब UI पोर्ट के सामने रखें, वहाँ TLS terminate करें, और INSECURE को unset छोड़ दें। कंटेनर प्रॉक्सी से आने वाले सादे HTTP हॉप को स्वीकार कर लेता है, और आधिकारिक Caddy और Traefik उदाहरणों में कोई INSECURE variable सेट नहीं होता है। चूँकि ब्राउज़र प्रॉक्सी से HTTPS के माध्यम से बात करता है, आप चाहेंगे कि session cookie अपना Secure flag बनाए रखे, जिसे INSECURE=true हटा देता है। UDP 51820 को सीधे पब्लिश रखें, क्योंकि VPN ट्रैफ़िक UDP है और यह HTTP प्रॉक्सी से होकर नहीं गुजरता है।