SSD Nodes Learn Hosting plans →
गाइड Matt Connorलेखक: Matt Connor

Traefik v3 के साथ एक Docker Compose में 5 ऐप्स कैसे चलाएं

Traefik v3 का उपयोग करके एक ही IP और पोर्ट पर पांच ऐप्स होस्ट करें। Host rule और automatic TLS कॉन्फ़िगरेशन सीखें और acme.json की उस गलती से बचें जो SSL जारी होने से रोकती है।

एक IP, पाँच ऐप्स, एक पोर्ट 443

आपके VPS पर एक ही public IPv4 address और एक ही TCP port 443 है। आप उस पर Gitea, अपने ऐप की एक staging copy, एक internal dashboard, एक status page और एक webhook receiver चलाना चाहते हैं—पाँच hostnames, एक ही सर्वर। एक reverse proxy वह process है जो :80 और :443 को control करती है, हर request पर Host header को पढ़ती है और उसे सही container तक पहुँचाती है। Traefik यह काम करता है, और यह आपके द्वारा हाथ से certbot चलाए बिना ही हर hostname के लिए certificate प्राप्त और renew करता है। Nginx और Caddy भी इन्हीं पाँच hostnames को कुशलतापूर्वक handle कर सकते हैं, इसलिए यदि चुनाव अभी बाकी है, तो certificate handling और प्रति ऐप configuration लागत के आधार पर तीनों proxies की तुलना करना फायदेमंद होगा, इससे पहले कि आप सब कुछ किसी एक के साथ जोड़ें।

Traefik को nginx के server {} block से जो चीज़ अलग करती है, वह है इसकी configuration का स्रोत। Nginx के साथ आप एक file edit करते हैं और reload करते हैं, और certificate का lifecycle एक अलग काम बना रहता है, जो कि वह workflow है जिसका आप तब पालन करते हैं जब आप nginx पर certbot के साथ Let's Encrypt certificates जारी करते हैं, जहाँ renewal timer web server से पूरी तरह बाहर होता है। Traefik का Docker provider Docker event stream को monitor करता है और आपके containers से labels पढ़ता है: एक ऐसा container start करें जिसमें Host() rule label हो और वह एक सेकंड के भीतर routable हो जाता है; उसे stop करें और route गायब हो जाता है। यही इसमें एक जोखिम भी है। Labels में मौजूद configuration एक साथ पाँच जगहों पर होती है, और यदि कोई label गलत हो, तो कोई error नहीं आता; container बस route नहीं होता और Traefik कुछ नहीं कहता।

चार संज्ञाएं

  • Entrypoints listening sockets हैं। आप दो परिभाषित करेंगे: web, :80 पर और websecure, :443 पर।
  • Routers एक request (Host(...)) का मिलान करते हैं और उसे एक service से जोड़ते हैं। Certificates का अनुरोध प्रति router, tls.certresolver के माध्यम से किया जाता है।
  • Services backend हैं, यानी एक container और वह port जिस पर वह Docker network के अंदर listen करता है।
  • Middlewares router और service के बीच स्थित होते हैं: basic auth, IP allow-lists, header rewrites, redirects।

ये चार संज्ञाएं Traefik द्वारा उन कार्यों के लिए दिए गए नाम हैं जिन्हें आप अन्यथा मैन्युअल रूप से लिखते: router एक server_name है, service एक proxy_pass target है, और middlewares वे header और auth directives हैं जिन्हें आप तब सेट करते हैं जब आप nginx reverse proxy server block को पंक्ति-दर-पंक्ति बनाते हैं।

Static configuration (entrypoints, providers, ACME) को Traefik की command line पर या traefik.yml में पास किया जाता है, और इसे बदलने का अर्थ है Traefik को restart करना। Dynamic configuration (routers, services, middlewares) container labels से प्राप्त होती है और hot-reload होती है। इन दोनों के बीच भ्रम होना ही "मेरी flag काम नहीं कर रही है" का सामान्य कारण है।

Compose फ़ाइल

एक साझा Docker network जिसका नाम proxy है, इसकी रीढ़ है। Traefik किसी container तक तभी पहुँच सकता है जब दोनों उस पर मौजूद हों।

name: edge

networks:
  proxy:
    name: proxy

services:
  traefik:
    image: traefik:v3.7
    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 ब्लॉक की एक प्रति है जिसमें उसका अपना router नाम, अपना Host() और अपना आंतरिक port होता है। एक TLS और बैकअप के साथ Docker में Nextcloud इंस्टॉलेशन भी इसी तरह फिट हो जाता है; इसके published ports हटा दें, इसे proxy से जोड़ें, और router labels को hostname और certificate संभालने दें।

यहाँ पाँच विवरण महत्वपूर्ण हैं।

exposedByDefault=false एक container को तब तक Traefik के लिए अदृश्य रखता है जब तक कि उसमें traefik.enable=true न हो। इसे हटा देने पर, आपके द्वारा शुरू किया गया हर container, जिसमें कुछ जाँचने के लिए चलाया गया अस्थायी postgres भी शामिल है, उसके लिए एक route बन जाएगा।

providers.docker.network=proxy Traefik को बताता है कि जब कोई container कई networks से जुड़ा हो, तो किस network का उपयोग करना है। इसे न लिखने पर Traefik गलत container IP चुन सकता है, जो 502 error के रूप में सामने आता है और ऐसा लगता है जैसे application में कोई खराबी है।

loadbalancer.server.port=3000 container के अंदर का port है; Gitea वहाँ 3000 पर listen करता है। ध्यान दें कि कोई भी app container port publish नहीं करता, केवल Traefik ऐसा करता है।

web entrypoint पर redirect डिफ़ॉल्ट रूप से permanent होता है, इसलिए plaintext GET (जो browser भेजता है) को HTTPS पर 301 redirect मिलता है; Traefik अन्य methods, जैसे POST, के लिए केवल 308 का उत्तर देता है, ताकि method hop के बाद भी सुरक्षित रहे। Port 80 वैसे भी खुला रहता है: ACME HTTP challenge को इसकी आवश्यकता होती है, और उन लोगों को भी जो केवल hostname टाइप करते हैं।

basic-auth hash में दोहराया गया $$, Compose का escaping है, न कि कोई टाइपिंग की गलती। इसे htpasswd -nbB admin 'your-password' (package apache2-utils) के साथ generate करें, फिर हर $ को दोगुना कर दें।

Certificate और acme.json का जाल

tlschallenge=true TLS-ALPN-01 को चुनता है: Let's Encrypt आपके सर्वर से 443 port पर जुड़ता है और Traefik TLS handshake के भीतर challenge का उत्तर देता है। दूसरा विकल्प HTTP-01 है, जो port 80 पर काम करता है। Traefik की command: सूची में tlschallenge लाइन को इन दो लाइनों से बदलें:

      - --certificatesresolvers.le.acme.httpchallenge=true
      - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web

दोनों में से कोई भी तरीका काम करता है। दोनों के लिए यह आवश्यक है कि hostname का public DNS पहले से ही आपके VPS पर point कर रहा हो, ताकि certificate authority नाम को resolve कर सके और बाहर से जुड़ सके। पहले A (और AAAA) record बनाएँ, dig +short git.example.com के साथ पुष्टि करें, और फिर Traefik शुरू करें।

अब वह जाल जिससे लोगों का काफी समय बर्बाद होता है। Traefik अपनी ACME account key और जारी किए गए सभी certificates को एक acme.json में रखता है। यदि वह file group-readable या world-readable है, तो Traefik इस तरह की एक log line दर्ज करेगा और resolver को बंद कर देगा। यह चलता रहेगा और traffic route करता रहेगा, लेकिन कोई certificate request नहीं किया जाएगा, इसलिए हर hostname TRAEFIK DEFAULT CERT पर serve होगा:

ERR The ACME resolve is skipped from the resolvers list error="unable to get ACME account: permissions 644 for /letsencrypt/acme.json are too open, please use 600" resolver=le

इसका सही समाधान ऊपर दिया गया है: directory को bind-mount करें और Traefik को सही mode के साथ file खुद बनाने दें। यदि आपने touch के साथ acme.json बनाया है, तो आपके umask ने इसे 644 बना दिया होगा। इसे host पर ठीक करें:

chmod 600 ./letsencrypt/acme.json
docker compose restart traefik

उस directory का backup अपने app volumes के साथ रखें। इसे एक बार खोना तो ठीक है, certificates फिर से जारी हो जाते हैं, लेकिन हर redeploy पर इसे मिटाने से आप हर 7 दिनों में एक ही hostname set के लिए पाँच certificates की limit तक पहुँच सकते हैं।

प्रयोग करते समय staging CA का उपयोग करें। caserver लाइन से comment हटाएँ, हर route को काम करने दें, फिर उसे वापस comment कर दें और acme.json को delete कर दें ताकि production certificates नए सिरे से request किए जाएँ। Production Let's Encrypt एक ही hostname set के लिए प्रति सप्ताह पाँच duplicate certificates की अनुमति देता है, और एक ही नाम के लिए बार-बार विफल validation को रोकता है। Staging untrusted certificates जारी करता है, आपका browser चेतावनी देता है, और वह चेतावनी ही इस बात का संकेत है कि सब कुछ सही काम कर रहा है, साथ ही इसमें limits भी काफी उदार हैं।

Dashboard एक control surface है, न कि कोई demo

अधिकांश quickstarts --api.insecure=true सेट करते हैं, जो बिना किसी authentication के port 8080 पर dashboard को serve करता है। एक public IP वाले box पर, यह आपकी routing topology, hostnames, middleware names और backend ports को किसी भी ऐसे व्यक्ति को सौंप देता है जो इसे scan करता है।

ऊपर दिए गए traefik service पर लगे labels इसका विकल्प हैं: dashboard को किसी अन्य app की तरह, एक वास्तविक hostname पर, TLS के माध्यम से, basicauth के पीछे route किया जाता है। service=api@internal वह है जो router को Traefik के built-in API से जोड़ता है। इसे और अधिक सुरक्षित बनाने के लिए एक IP allow-list को chain करें, जिसे बाएं से दाएं लागू किया जाता है। यदि आपका office address dynamic है, तो range को उस subnet पर सेट करें जो उसी VPS पर आपके द्वारा self-host किए गए WireGuard VPN द्वारा दिया गया है और dashboard तक केवल tunnel के माध्यम से पहुँचें:

- traefik.http.middlewares.office.ipallowlist.sourcerange=10.0.0.7/32
- traefik.http.routers.dashboard.middlewares=office,dashboard-auth

एक साझा basicauth पासवर्ड तब defensible नहीं रहता जब पांच apps को अपने स्वयं के accounts की आवश्यकता होती है, और वही middleware slot एक forwardauth लेता है जो निर्णय को Authentik, एक self-hosted single sign-on server को सौंप देता है, ताकि dashboard और इसके बगल का प्रत्येक route एक ऐसे login के पीछे हो जिसे आप एक ही स्थान पर revoke कर सकें।

Docker socket root है

/var/run/docker.sock एक API है जो ऐसा container बना सकता है जो host से / को mount करता है। इस तक पहुँच का मतलब मशीन पर root access होना है, और Traefik को labels पढ़ने के लिए इसकी आवश्यकता होती है।

mount पर :ro बनाए रखें, लेकिन यह स्पष्ट रहें कि इससे क्या लाभ मिलता है: यह socket file को केवल-पठनीय (read-only) बनाता है। यह Docker API पर आने वाले POST अनुरोधों को नहीं रोकता है। वास्तविक सुरक्षा उपाय यह है कि 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:
      - proxy

Traefik से socket volume हटा दें और provider को proxy की ओर निर्देशित करें:

--providers.docker.endpoint=tcp://dockerproxy:2375

Traefik के पास containers और networks का read access बना रहता है, और वह कुछ भी नया बनाने की क्षमता खो देता है।

Firewall, ports, और वह नियम जिसे हर कोई गलत समझता है

दो ports खुले हैं, साथ में SSH:

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

Docker के published ports ufw को bypass कर देते हैं। Docker अपने स्वयं के iptables rules डालता है, जिनका मूल्यांकन ufw की chains से पहले किया जाता है। इसलिए, ports: ["3000:3000"] के साथ शुरू किया गया container इंटरनेट से तब भी पहुँच योग्य होता है, भले ही ufw में deny rule लगा हो। इसका बचाव संरचनात्मक है, न कि firewall configuration: केवल Traefik से ports publish करें, और बाकी हर container को networks: [proxy] दें, इसके अलावा कुछ नहीं। यदि किसी चीज़ को वास्तव में host तक पहुँचना ही है, तो उसे loopback, "127.0.0.1:3000:3000" पर bind करें।

समस्या निवारण: वे त्रुटियाँ जो आपको वास्तव में दिखाई देंगी

404 page not found, जिसे Traefik द्वारा सर्व किया गया है। कोई router मैच नहीं हुआ। संभावना के क्रम में: container में traefik.enable=true की कमी है (जिसमें exposedByDefault=false सेट है); Host() नियम आपके द्वारा टाइप किए गए नाम से मेल नहीं खाता है; एक label में router का नाम दूसरे से अलग है (routers.gitea.rule और routers.gitea.entrypoints एक ही शब्द होने चाहिए); या आपने hostname को single quotes में लपेटा है। Traefik v3 matchers के अंदर backticks या escaped double quotes (\") लेता है और single quotes को अस्वीकार कर देता है।

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 लाइनों को पढ़ें:

unable to obtain ACME certificate for domains "git.example.com" ...
acme: error: 400 ... DNS problem: NXDOMAIN looking up A for git.example.com

DNS अभी तक box की ओर इशारा नहीं कर रहा है। record को ठीक करें, TTL समाप्त होने की प्रतीक्षा करें, Traefik को restart करें।

Invalid response from http://git.example.com/.well-known/acme-challenge/... HTTP challenge पर: port 80 बाहर से Traefik तक नहीं पहुँच रहा है, आमतौर पर यह VPS के सामने provider-level का firewall होता है, न कि ufw।

Certificates कभी जारी नहीं होते, और आपका DNS Cloudflare पर है और orange cloud चालू है। Cloudflare अपने edge पर TLS को terminate करता है और TLS-ALPN-01 इसके माध्यम से पूरा नहीं हो सकता है। जारी करते समय record को DNS-only पर सेट करें, या API token के साथ DNS-01 challenge पर स्विच करें। DNS-01 ही एकमात्र challenge है जो wildcards जारी करता है।

Redirect loop. Traefik के सामने पहले से ही कुछ TLS को terminate कर रहा है और plaintext को :80 पर forward कर रहा है; 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 पर नियंत्रण देती है।

Traefik tag को पिन करें (traefik:v3.7, कभी भी latest न करें), और उस branch को पिन करें जो अभी भी releases जारी करती है। 2026-10-12 तक Traefik केवल v3.7 को ही समर्थित v3 branch के रूप में सूचीबद्ध करता है। v3.5 ने अपना अंतिम release, v3.5.6, 7 November 2025 को जारी किया था, और इसका Docker provider API version 1.24 पर hardcoded है, जिसे Docker Engine 29 और उसके बाद के संस्करण client version 1.24 is too old के साथ अस्वीकार कर देते हैं, इसलिए किसी भी container को route नहीं किया जाता है। Traefik 3.6.1 ने Docker API version negotiation को जोड़ा, यही कारण है कि ऊपर दी गई compose file v3.7 का उपयोग करती है। v2-से-v3 upgrade ने rule syntax और provider names को बदल दिया है, और एक unattended latest खुशी-खुशी उस config को reload कर देगा जिसे वह अब समझ नहीं पाता है। सोच-समझकर upgrade करें: migration notes पढ़ें, tag को bump करें, docker compose up -d traefik करें, और log पर नज़र रखें। यदि आप अभी भी v2 tag पर हैं, तो Traefik v2 से v3 migration guide हर rename, compatibility mode, और एक ऐसे rollback के बारे में बताता है जो आपके certificates को सुरक्षित रखता है।

./letsencrypt और प्रत्येक app के data volume का backup लें। Traefik में ऐसी कोई अन्य स्थिति (state) नहीं होती जिसे आप compose file से फिर से न बना सकें।

स्केल करने पर क्या समस्याएं आती हैं

पहली सीमा throughput नहीं, बल्कि एक सिंगल सर्वर है: एक VPS पर एक Traefik पांच apps के लिए single point of failure है, और acme.json flat-file storage है, जिसे दो Traefik instances द्वारा एक साथ लिखने पर वह corrupt हो जाएगा। स्केल करने का अर्थ है certificate storage को फाइल से बाहर ले जाना, या TLS termination कहीं और करना।

दूसरी समस्या long-lived connections की है। Server-sent events, बड़ी uploads और slow clients entrypoint के response timeouts का सामना करते हैं; --entryPoints.websecure.transport.respondingTimeouts.readTimeout और इसके writeTimeout तथा idleTimeout भाई-बहन इसके लिए मुख्य knobs हैं। WebSockets बिना किसी अतिरिक्त configuration के काम करते हैं।

तीसरी समस्या डिस्क की है। --accesslog=true stdout पर लिखता है, और Docker का json-file driver इसे तब तक सुरक्षित रखता है जब तक कि इसकी सीमा तय न की जाए। Traefik service पर logging.options.max-size सेट करें, या access log को एक फाइल में लिखें और उसे rotate करें।

इसके लिए किसी orchestrator की आवश्यकता नहीं है। आपको बस एक ऐसे सर्वर की जरूरत है जिसे आप नियंत्रित करते हों, जिसका एक वास्तविक IP हो और जिस पर 80 तथा 443 ports दुनिया के लिए खुले हों; एक छोटा सा VPS ही पूरी dependency list है।

FAQ

क्या Traefik चलाने पर भी मुझे certbot की आवश्यकता है?

नहीं। Traefik का ACME resolver प्रत्येक hostname के लिए certificate request और renew करता है और उन्हें acme.json में सुरक्षित रखता है। Certbot तब सही टूल है जब nginx या कोई अन्य सर्वर स्वयं TLS terminate करता है; एक ही hostname के लिए दोनों का उपयोग करने से Let's Encrypt की rate limits समाप्त हो जाती हैं।

मेरा container Traefik के माध्यम से 404 क्यों दे रहा है?

Traefik द्वारा 404 का मतलब है कि request के लिए कोई router match नहीं हुआ। जाँचें कि container में traefik.enable=true मौजूद है (एक बार exposedByDefault=false सेट होने पर यह अनिवार्य है), कि Host() का मान आपके द्वारा टाइप किए गए नाम से मेल खाता है, और router का नाम उस app के प्रत्येक label के लिए समान है। Traefik v3 में matcher के अंदर backticks या escaped double quotes की आवश्यकता होती है; single quotes को reject कर दिया जाता है।

यहाँ 404 और 502 के बीच क्या अंतर है?

404 का मतलब है कि routing कभी हुई ही नहीं; 502 का मतलब है कि एक router match हुआ लेकिन backend ने connection स्वीकार नहीं किया। 502 के सामान्य कारण हैं: container का proxy network से न जुड़ा होना, और loadbalancer.server.port का container के अंदर app द्वारा listen किए जा रहे port के बजाय किसी published port की ओर इशारा करना। Access log उस सटीक 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 को expose करता है और writes को पूरी तरह से block कर देता है।

क्या Traefik wildcard certificate जारी कर सकता है?

केवल DNS-01 challenge के माध्यम से, आपके DNS provider के लिए API token के साथ। TLS-ALPN-01 और HTTP-01 प्रत्येक एक single hostname को validate करते हैं और wildcard certificate नहीं बना सकते। जब Cloudflare जैसा कोई CDN आपके VPS के सामने TLS terminate करता है और अन्य दो challenges पूरी नहीं हो पातीं, तब भी DNS-01 ही समाधान है।