Traefik v3 Docker Compose Guide
Traefik v3 का उपयोग करके एक ही IP पर 5 apps कैसे चलाएं। Docker Compose के साथ Host rule और Let's Encrypt TLS सेटअप करें और acme.json की गलतियों से बचें।
एक IP, पांच apps, एक port 443
आपके VPS में एक single public IPv4 address और एक single TCP port 443 है। आप इस पर Gitea, अपने app की एक staging copy, एक internal dashboard, एक status page और एक webhook receiver चलाना चाहते हैं — यानी एक ही box पर पांच hostnames। Reverse proxy वह process है जो :80 और :443 को handle करता है, हर request पर Host header पढ़ता है और उसे सही container को भेज देता है। Traefik यही काम करता है, और यह बिना किसी manual certbot command के, प्रत्येक hostname के लिए certificate प्राप्त और renew कर लेता है।
Traefik को nginx server {} block से जो चीज़ अलग बनाती है, वह है इसके configuration का source। nginx में आपको एक file edit करके reload करनी पड़ती है, और certificate lifecycle एक अलग task बना रहता है — जैसा कि आप तब करते हैं जब आप nginx पर certbot के साथ Let's Encrypt certificates issue करते हैं, जहाँ renewal timer पूरी तरह से web server से बाहर होता है। Traefik का Docker provider Docker event stream को monitor करता है और आपके containers से labels पढ़ता है: यदि आप एक Host() rule label वाला container start करते हैं, तो वह एक second के भीतर routable हो जाता है; यदि आप उसे stop करते हैं, तो route गायब हो जाता है। यही एक जोखिम भी है। Labels में रहने वाला configuration एक साथ पांच जगहों पर होता है, और गलत label होने पर कोई error नहीं मिलता — container बस route नहीं होता, और Traefik कुछ नहीं कहता।
चार मुख्य संज्ञाएँ (Nouns)
- Entrypoints listening sockets होते हैं। आप दो define करेंगे:
:80परwebऔर:443परwebsecure। - Routers एक request (
Host(...)) को match करते हैं और उसे एक service से जोड़ते हैं। Certificates प्रत्येक router के लिएtls.certresolverके माध्यम से request किए जाते हैं। - Services backend होते हैं — एक container और Docker network के अंदर वह port जिस पर वह listen करता है।
- Middlewares router और service के बीच काम करते हैं: basic auth, IP allow-lists, header rewrites, और redirects।
Static configuration (entrypoints, providers, ACME) Traefik की command line या traefik.yml में दी जाती है, और इसे बदलने के लिए Traefik को restart करना पड़ता है। Dynamic configuration (routers, services, middlewares) container labels से आती है और इसे hot-reload किया जा सकता है। इन दोनों के बीच भ्रम होना ही अक्सर "my flag does nothing" वाली समस्या का कारण बनता है।
The compose file
proxy नाम का एक shared Docker network मुख्य आधार है। Traefik किसी container तक तभी पहुँच पाता है जब दोनों उसी network पर हों।
name: edge
networks:
proxy:
name: proxy
services:
traefik:
image: traefik:v3.5
restart: unless-stopped
command:
- --providers.docker=true
- --providers.docker.exposedByDefault=false
- --providers.docker.network=proxy
- --entryPoints.web.address=:80
- --entryPoints.websecure.address=:443
- --entryPoints.web.http.redirections.entryPoint.to=websecure
- --entryPoints.web.http.redirections.entryPoint.scheme=https
- --certificatesresolvers.le.acme.email=you@example.com
- --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
- --certificatesresolvers.le.acme.tlschallenge=true
# while you iterate, point at staging so a mistake costs nothing:
# - --certificatesresolvers.le.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
- --api.dashboard=true
- --log.level=INFO
- --accesslog=true
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
networks:
- proxy
labels:
- traefik.enable=true
- traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)
- traefik.http.routers.dashboard.entrypoints=websecure
- traefik.http.routers.dashboard.tls.certresolver=le
- traefik.http.routers.dashboard.service=api@internal
- traefik.http.routers.dashboard.middlewares=dashboard-auth
- traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$apr1$$REPLACE$$THIS
gitea:
image: gitea/gitea:1 # major-only pin keeps this demo copy-pasteable; pin an exact release in production
restart: unless-stopped
volumes:
- ./gitea:/data
networks:
- proxy
labels:
- traefik.enable=true
- traefik.http.routers.gitea.rule=Host(`git.example.com`)
- traefik.http.routers.gitea.entrypoints=websecure
- traefik.http.routers.gitea.tls.certresolver=le
- traefik.http.services.gitea.loadbalancer.server.port=3000पहले docker compose up -d, फिर docker compose logs -f traefik। प्रत्येक अतिरिक्त app, gitea block की एक copy है जिसमें अपना router name, अपना Host() और अपना internal port होता है। Nextcloud install running in Docker with TLS and backups भी इसी तरह काम करता है — इसके published ports हटा दें, इसे proxy से जोड़ें, और hostname तथा certificate के लिए router labels का उपयोग करें।
यहाँ पाँच महत्वपूर्ण विवरण दिए गए हैं।
exposedByDefault=false container को Traefik के लिए तब तक invisible रखता है जब तक उसमें traefik.enable=true न हो। यदि आप इसे हटा देते हैं, तो आपके द्वारा शुरू किया गया हर container — जिसमें जांच के लिए चलाया गया postgres भी शामिल है — उसके लिए एक route generate हो जाएगा।
providers.docker.network=proxy Traefik को बताता है कि जब कोई container कई networks से जुड़ा हो, तो उसे किस network का उपयोग करना चाहिए। यदि इसे नहीं लिखा गया, तो Traefik गलत container IP चुन सकता है, जिससे 502 error आता है जो application fault जैसा दिखता है।
loadbalancer.server.port=3000 container के अंदर का port है; Gitea वहाँ 3000 पर listen करता है। ध्यान दें कि कोई भी app container port publish नहीं करता है — केवल Traefik करता है।
web entrypoint पर redirect, plaintext requests को HTTPS के लिए 308 में बदल देता है। Port 80 फिर भी खुला रहता है: ACME HTTP challenge को इसकी आवश्यकता होती है, और उन users को भी जो केवल hostname टाइप करते हैं।
basic-auth hash में doubled $$ Compose escaping है, कोई typo नहीं। इसे htpasswd -nbB admin 'your-password' (package apache2-utils) से generate करें, फिर हर $ को double कर दें।
Certificate, aur acme.json ki samasya
tlschallenge=true TLS-ALPN-01 chunta hai: Let's Encrypt aapke box se 443 par connect karta hai aur Traefik TLS handshake ke andar challenge ka jawab deta hai. Iska vikalp HTTP-01 hai, jo port 80 par chalta hai — iske liye Traefik ki command: list mein tlschallenge line ko in do lines se badal dein:
- --certificatesresolvers.le.acme.httpchallenge=true
- --certificatesresolvers.le.acme.httpchallenge.entrypoint=webDono kaam karte hain. Dono ke liye hostname ka public DNS pehle se hi aapke VPS par point karna chahiye — certificate authority naam ko resolve karti hai aur bahar se connect karti hai. Pehle A (aur AAAA) record banayein, dig +short git.example.com se confirm karein, phir Traefik shuru karein.
Ab woh samasya jiske karan log apna pura shaam barbaad kar dete hain. Traefik apni ACME account key aur har issue kiya gaya certificate ek acme.json mein rakhta hai. Agar woh file group- ya world-readable hai, to Traefik aisa message dikhayega aur ruk jayega:
error: unable to get ACME account: permissions 644 for /letsencrypt/acme.json are too open, please use 600Iska sahi samadhan upar wala hai: directory ko bind-mount karein aur Traefik ko sahi mode ke saath file khud banane dein. Agar aapne acme.json ko touch ke saath banaya hai, to aapke umask ne ise 644 bana diya hoga. Host par ise repair karein:
chmod 600 ./letsencrypt/acme.json
docker compose restart traefikIs directory ka backup apne app volumes ke saath lein. Iska khona nuksan-dayak hai — certificates phir se issue ho sakte hain — lekin ek saath paanch hostnames ko re-issue karne se aap rate limits mein phans sakte hain.
Iteration ke dauran staging CA ka upyog karein. caserver line ko uncomment karein, har route ko sahi se chalayein, phir ise comment kar dein aur acme.json ko delete kar dein taaki production certificates naye sire se request kiye ja sakein. Production Let's Encrypt ek hi set of hostnames ke liye har hafte paanch duplicate certificates ki anumati deta hai, aur ek hi naam ke liye baar-baar failed validations ko throttle karta hai. Staging untrusted certificates issue karta hai — aapka browser warning dega, aur woh warning hi iska sanket hai ki kaam ho gaya hai — iske limits bahut zyada loose hote hain.
Dashboard एक control surface है, demo नहीं
ज़्यादातर quickstarts --api.insecure=true सेट करते हैं, जो बिना किसी authentication के port 8080 पर dashboard सर्व करता है। यदि आपके पास public IP वाला server है, तो यह किसी भी scanner को आपकी routing topology, hostnames, middleware names और backend ports की जानकारी दे सकता है।
ऊपर दिए गए traefik service के labels एक विकल्प प्रदान करते हैं: dashboard को किसी अन्य app की तरह route करें, एक real hostname पर, TLS के माध्यम से, और basicauth के पीछे। service=api@internal router को Traefik के built-in API से जोड़ता है। इसे और सुरक्षित बनाने के लिए IP allow-list का उपयोग करें, जिसे left से right क्रम में लागू किया जाता है। यदि आपका office address dynamic है, तो range को उसी VPS पर self-host किए गए WireGuard VPN द्वारा दिए गए subnet पर सेट करें और dashboard को केवल tunnel के माध्यम से एक्सेस करें:
- traefik.http.middlewares.office.ipallowlist.sourcerange=10.0.0.7/32
- traefik.http.routers.dashboard.middlewares=office,dashboard-authDocker socket root के समान है
/var/run/docker.sock एक API है जो ऐसा container बना सकता है जो host से / को mount करता है। इसका access machine पर root के बराबर है, और Traefik को labels पढ़ने के लिए इसकी आवश्यकता होती है।
Mount में :ro का उपयोग करें, लेकिन इसके लाभ को समझें: यह socket file को read-only बना देता है। यह Docker API के लिए POST requests को नहीं रोकता है। वास्तविक समाधान यह है कि Traefik को socket न दें, और बीच में एक filtering proxy का उपयोग करें:
dockerproxy:
image: tecnativa/docker-socket-proxy # pin the current tag
restart: unless-stopped
environment:
CONTAINERS: 1
NETWORKS: 1
POST: 0
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- proxyTraefik से socket volume हटा दें और provider को proxy पर point करें:
--providers.docker.endpoint=tcp://dockerproxy:2375Traefik के पास containers और networks के लिए read access रहेगा, और इसके पास कुछ भी create करने की क्षमता नहीं रहेगी।
Firewall, ports, aur woh rule jo sab galat samajhte hain
Do ports open hain, plus SSH:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enableDocker ke published ports ufw ko bypass kar dete hain. Docker apne khud ke iptables rules insert karta hai, jo ufw ke chains se pehle evaluate hote hain. Iska matlab hai ki agar ports: ["3000:3000"] ke saath koi container start kiya gaya hai, toh ufw deny hone ke bawajood woh internet se reachable hoga. Yeh samasya firewall configuration ki nahi, balki structural hai: sirf Traefik se ports publish karein, aur baaki sabhi containers ko networks: [proxy] dein aur kuch nahi. Agar kisi cheez ko host tak pahunchna hi hai, toh use loopback par bind karein — "127.0.0.1:3000:3000".
Troubleshooting: आपको मिलने वाली वास्तविक त्रुटियाँ
404 page not found, Traefik द्वारा। कोई router मैच नहीं हुआ। होने की संभावना के क्रम में: container में traefik.enable=true (exposedByDefault=false सेट होने के साथ) नहीं है; Host() rule आपके द्वारा टाइप किए गए नाम से मैच नहीं करता है; एक label में router का नाम दूसरे label के router name से अलग है (routers.gitea.rule और routers.gitea.entrypoints एक ही शब्द होने चाहिए); या आपने hostname को backticks के बजाय quotes में लिखा है। Traefik v3 के matchers में backticks का उपयोग आवश्यक है।
502 Bad Gateway. Router मैच हो गया लेकिन backend तक पहुँचा नहीं जा सका। लगभग हमेशा container proxy network पर नहीं होता है — docker inspect -f '{{json .NetworkSettings.Networks}}' gitea चेक करें। दूसरा कारण गलत loadbalancer.server.port हो सकता है: आपने published port दिया है, या app कहीं और listen कर रहा है। Log में प्रयास का विवरण है: dial tcp 172.18.0.5:8080: connect: connection refused।
Browser चेतावनी देता है, और certificate TRAEFIK DEFAULT CERT को जारी किया जाता है। उस hostname के लिए कोई certificate मौजूद नहीं है और Traefik ने अपना self-signed placeholder सर्व किया है। ACME lines पढ़ें:
unable to obtain ACME certificate for domains "git.example.com" ...
acme: error: 400 ... DNS problem: NXDOMAIN looking up A for git.example.comDNS अभी box की ओर point नहीं कर रहा है। Record को ठीक करें, TTL समाप्त होने का इंतज़ार करें, और Traefik को restart करें।
HTTP challenge पर Invalid response from http://git.example.com/.well-known/acme-challenge/...: बाहर से port 80 Traefik तक नहीं पहुँच पा रहा है — आमतौर पर यह VPS के सामने provider-level firewall होता है, ufw नहीं।
Certificates जारी नहीं हो रहे हैं, और आपका DNS Cloudflare पर है जिसमें orange cloud चालू है। Cloudflare अपने edge पर TLS को terminate कर देता है, जिससे TLS-ALPN-01 पूरा नहीं हो पाता। Issuing के दौरान record को DNS-only पर सेट करें, या API token के साथ DNS-01 challenge का उपयोग करें। DNS-01 ही एकमात्र ऐसा challenge है जो wildcards जारी करता है।
Redirect loop. Traefik के सामने कोई चीज़ पहले ही TLS को terminate कर रही है और :80 पर plaintext भेज रही है; entrypoint redirect इसे वापस HTTPS पर भेज देता है। इन दोनों redirects में से किसी एक को हटा दें।
इसे चालू रखना
Docker unit को boot-enabled (systemctl is-enabled docker) होना चाहिए, और restart: unless-stopped reboot के बाद stack को वापस लाता है। सटीक नियंत्रण के लिए, RemainAfterExit=yes के साथ docker compose -f /srv/edge/compose.yml up -d चलाने वाला एक छोटा systemd unit आपको systemctl status edge और ordering control प्रदान करता है।
Traefik tag को pin करें (traefik:v3.5, कभी भी latest नहीं)। v2-to-v3 upgrade ने rule syntax और provider names को बदल दिया है, और एक unattended latest उस config को reload कर देगा जिसे वह अब समझ नहीं सकता। जानबूझकर upgrade करें: migration notes पढ़ें, tag बदलें, docker compose up -d traefik करें, और log देखें। यदि आप अभी भी v2 tag पर हैं, तो the Traefik v2 to v3 migration guide हर rename, compatibility mode, और certificates को सुरक्षित रखने वाले rollback के बारे में विस्तार से बताता है।
./letsencrypt और प्रत्येक app के data volume का backup लें। Traefik में ऐसी कोई अन्य state नहीं होती जिसे आप compose file से दोबारा न बना सकें।
Scaling के दौरान क्या समस्याएँ आती हैं
पहली सीमा throughput नहीं, बल्कि single box है: एक VPS पर एक Traefik instance पांच apps के लिए single point of failure है, और acme.json एक flat-file storage है — यदि दो Traefik instances इसमें write करेंगे, तो data corrupt हो जाएगा। Scaling out करने का अर्थ है certificate storage को file से हटाना, या TLS को कहीं और terminate करना।
दूसरी समस्या long-lived connections है। Server-sent events, बड़े uploads और slow clients entrypoint के responding timeouts से टकराते हैं; --entryPoints.websecure.transport.respondingTimeouts.readTimeout और इसके writeTimeout तथा idleTimeout siblings ही इसके controls हैं। WebSockets बिना किसी extra configuration के pass through हो जाते हैं।
तीसरी समस्या disk है। --accesslog=true stdout पर write करता है, और Docker का json-file driver इसे तब तक सुरक्षित रखता है जब तक इसे cap न किया जाए। Traefik service पर logging.options.max-size सेट करें, या access log को एक file में write करके उसे rotate करें।
इनमें से किसी के लिए भी orchestrator की आवश्यकता नहीं है। आपको केवल एक server चाहिए जिसका control आपके पास हो, जिसमें real IP हो और ports 80 और 443 दुनिया के लिए open हों — एक single छोटा VPS ही आपकी पूरी dependency list है।
FAQ
क्या मुझे Certbot की आवश्यकता है यदि मैं Traefik चला रहा हूँ?
नहीं। Traefik का ACME resolver हर उस hostname के लिए certificate request और renew करता है जिसे वह route करता है, और इन्हें acme.json में store करता है। यदि nginx या कोई अन्य server स्वयं TLS terminate करता है, तो Certbot सही tool है; एक ही hostname के लिए दोनों का उपयोग करने से Let's Encrypt की rate limits समाप्त हो जाती हैं।
Traefik के माध्यम से मेरा container 404 क्यों return कर रहा है?
Traefik द्वारा दिया गया 404 का अर्थ है कि कोई भी router उस request से match नहीं हुआ। Check करें कि container में traefik.enable=true है (एक बार exposedByDefault=false set होने के बाद यह अनिवार्य है), Host() value आपके द्वारा टाइप किए गए name से मेल खाती है, और उस app के हर label के लिए router name identical है। Traefik v3 में matcher के अंदर quotes के बजाय backticks का उपयोग करना आवश्यक है।
यहाँ 404 और 502 के बीच क्या अंतर है?
404 का अर्थ है कि routing कभी हुई ही नहीं; 502 का अर्थ है कि router match हुआ लेकिन backend ने connection refuse कर दिया। 502 के सामान्य कारण एक container है जो proxy network से attached नहीं है, और एक loadbalancer.server.port जो app के container के अंदर listen करने वाले port के बजाय published port को point कर रहा है। Access log उस exact address को दर्शाता है जिसे Traefik ने dial किया था।
क्या Docker socket को read-only mount करना पर्याप्त है?
:ro flag socket file को read-only बनाता है, उसके पीछे के API को नहीं — POST requests अभी भी इसके माध्यम से जाती हैं, और Docker API access host पर root के समान है। अधिक सुरक्षित व्यवस्था ऊपर दिखाया गया docker-socket-proxy container है, जो Traefik को केवल container और network reads प्रदान करता है और writes को पूरी तरह से block करता है।
क्या Traefik wildcard certificate issue कर सकता है?
केवल DNS-01 challenge के माध्यम से, आपके DNS provider के API token के साथ। TLS-ALPN-01 और HTTP-01 प्रत्येक एक single hostname को validate करते हैं और wildcard produce नहीं कर सकते। DNS-01 तब भी सही विकल्प है जब Cloudflare जैसा CDN आपके VPS के सामने TLS terminate करता है और अन्य दो challenges पूरे नहीं हो पाते।