SSD Nodes Learn
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-07-24

วิธีใช้ Traefik v3 จัดการ 5 แอปด้วย Compose

เรียนรู้วิธีใช้ Traefik v3 บน Docker Compose เพื่อทำ Reverse Proxy สำหรับ 5 แอปพลิเคชัน พร้อมวิธีแก้ปัญหา acme.json ที่ทำให้ระบบไม่สามารถเริ่มต้นทำงานได้

หนึ่ง IP, ห้าแอปพลิเคชัน, หนึ่งพอร์ต 443

VPS ของคุณมี public IPv4 เพียงหนึ่งหมายเลข และมี TCP port 443 เพียงพอร์ตเดียว คุณต้องการรัน Gitea, staging copy ของแอปพลิเคชัน, internal dashboard, status page และ webhook receiver บนเครื่องนี้ ซึ่งรวมเป็นห้า hostname บนเครื่องเดียว Reverse proxy คือกระบวนการที่ทำหน้าที่จัดการ port :80 และ :443 โดยจะอ่าน header Host ในทุก request เพื่อส่งข้อมูลไปยัง container ที่ถูกต้อง Traefik สามารถทำหน้าที่นี้ได้ และจะดำเนินการขอและต่ออายุ certificate สำหรับแต่ละ hostname โดยที่คุณไม่ต้องรัน certbot ด้วยตนเอง

สิ่งที่ทำให้ Traefik ต่างจาก nginx server {} block คือแหล่งที่มาของการตั้งค่า ใน nginx คุณต้องแก้ไขไฟล์และสั่ง reload ซึ่งการจัดการ lifecycle ของ certificate จะเป็นงานที่แยกต่างหาก เป็นขั้นตอนเดียวกับที่คุณใช้เมื่อ issue Let's Encrypt certificates with certbot on nginx โดยที่ตัวตั้งเวลาการต่ออายุ (renewal timer) จะทำงานแยกจาก web server โดยสิ้นเชิง ส่วน Docker provider ของ Traefik จะเฝ้าติดตาม Docker event stream และอ่าน labels จาก container ของคุณ เพียงแค่เริ่มทำงาน container ที่มี label กฎ Host() ระบบก็จะสามารถกำหนดเส้นทาง (route) ได้ภายในหนึ่งวินาที และเมื่อหยุดการทำงาน เส้นทางนั้นจะหายไปทันที นี่คือข้อควรระวังเช่นกัน เนื่องจากการตั้งค่าที่อยู่ใน labels จะกระจายอยู่ตามที่ต่าง ๆ การใช้ label ที่ผิดพลาดจะไม่มีการแจ้งเตือนใด ๆ เพียงแต่ container นั้นจะไม่ถูกกำหนดเส้นทาง และ Traefik จะไม่แจ้งข้อผิดพลาดใด ๆ ออกมา

คำนามทั้งสี่

  • Entrypoints คือ listening sockets คุณต้องกำหนดค่าสองรายการ ได้แก่ web บน :80 และ websecure บน :443
  • Routers ทำหน้าที่จับคู่ request (Host(...)) และส่งต่อไปยัง service การขอใบรับรอง (Certificates) จะเกิดขึ้นต่อหนึ่ง router ผ่านทาง tls.certresolver
  • Services คือ backend ซึ่งประกอบด้วย container และ port ที่ใช้รับข้อมูล ภายใน Docker network
  • Middlewares ทำหน้าที่คั่นกลางระหว่าง router และ service เช่น basic auth, IP allow-lists, การแก้ไข header หรือการทำ redirects

การตั้งค่าแบบ Static (entrypoints, providers, ACME) จะถูกส่งผ่าน command line ของ Traefik หรือใน traefik.yml ซึ่งการเปลี่ยนแปลงค่าเหล่านี้จำเป็นต้อง restart Traefik ส่วนการตั้งค่าแบบ Dynamic (routers, services, middlewares) จะมาจาก container labels และสามารถ hot-reload ได้ การสับสนระหว่างการตั้งค่าทั้งสองแบบนี้เป็นสาเหตุหลักที่ทำให้เกิดปัญหา "flag ที่ตั้งค่าไว้ไม่มีผล"

The compose file

เครือข่าย Docker ที่ใช้ร่วมกันชื่อ proxy คือส่วนประกอบหลัก Traefik จะเชื่อมต่อกับ container ได้ก็ต่อเมื่อทั้งสองอยู่ในเครือข่ายเดียวกันเท่านั้น

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 แอปพลิเคชันที่เพิ่มเข้ามาแต่ละตัวจะเป็นการคัดลอก block gitea โดยเปลี่ยนชื่อ router, Host() และ internal port ของตนเอง การติดตั้ง Nextcloud install running in Docker with TLS and backups ใช้วิธีเดียวกัน คือไม่ต้องระบุ published ports ให้เชื่อมต่อกับ proxy และใช้ router labels ในการจัดการ hostname และ certificate

รายละเอียด 5 ประการมีดังนี้

exposedByDefault=false ทำให้ container ไม่ปรากฏใน Traefik จนกว่าจะมี label traefik.enable=true หากไม่ใส่ label นี้ container ทุกตัวที่รัน รวมถึง postgres ที่ใช้ทดสอบชั่วคราว จะถูกสร้าง route ให้โดยอัตโนมัติ

providers.docker.network=proxy ระบุเครือข่ายที่ Traefik ต้องใช้ในกรณีที่ container เชื่อมต่ออยู่หลายเครือข่าย หากไม่ระบุ Traefik อาจเลือก IP ของ container ผิดพลาด ซึ่งจะส่งผลให้เกิด error 502 ที่ดูเหมือนเป็นข้อผิดพลาดจากแอปพลิเคชัน

loadbalancer.server.port=3000 คือ port ภายใน container โดย Gitea จะ listen ที่ port 3000 สังเกตว่าไม่มี container ของแอปพลิเคชันตัวใดที่ publish port เลย มีเพียง Traefik เท่านั้นที่ทำหน้าที่นี้

การ redirect บน entrypoint web จะเปลี่ยน request แบบ plaintext เป็น 308 ไปยัง HTTPS อย่างไรก็ตาม port 80 ยังคงต้องเปิดไว้ เนื่องจากจำเป็นสำหรับการทำ ACME HTTP challenge และสำหรับผู้ใช้งานที่พิมพ์ hostname โดยตรง

การใช้ $$ ซ้ำกันสองครั้งใน basic-auth hash คือการ escape ของ Compose ไม่ใช่การพิมพ์ผิด สามารถสร้างค่านี้ได้ด้วย htpasswd -nbB admin 'your-password' (package apache2-utils) จากนั้นให้ใส่ $ ซ้ำกันสองครั้ง

ใบรับรอง และปัญหาของ acme.json

tlschallenge=true เลือกใช้ TLS-ALPN-01: Let's Encrypt จะเชื่อมต่อมายังเครื่องของคุณผ่านพอร์ต 443 และ Traefik จะตอบรับการตรวจสอบภายใน TLS handshake อีกทางเลือกหนึ่งคือ HTTP-01 ผ่านพอร์ต 80 โดยให้เปลี่ยนบรรทัด tlschallenge ในรายการ command: ของ Traefik เป็นสองบรรทัดนี้:

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

สามารถใช้แบบใดก็ได้ ทั้งสองวิธีต้องการให้ Public DNS ของ hostname ชี้มาที่ VPS ของคุณแล้ว เนื่องจาก Certificate Authority จะทำการตรวจสอบชื่อและเชื่อมต่อมาจากภายนอก ให้สร้าง A (และ AAAA) record ก่อน จากนั้นตรวจสอบด้วย dig +short git.example.com แล้วจึงเริ่มการทำงานของ Traefik

ปัญหาที่ทำให้ผู้ใช้เสียเวลาไปทั้งคืนคือเรื่องนี้ Traefik เก็บ ACME account key และใบรับรองที่ออกทั้งหมดไว้ใน acme.json เพียงไฟล์เดียว หากไฟล์นี้สามารถอ่านได้โดย group หรือ world Traefik จะแสดงข้อความลักษณะนี้และหยุดทำงาน:

error: unable to get ACME account: permissions 644 for /letsencrypt/acme.json are too open, please use 600

วิธีแก้ไขที่ถูกต้องคือวิธีที่ระบุไว้ด้านบน: ให้ใช้การ bind-mount ไปที่ directory เพื่อให้ Traefik สร้างไฟล์ขึ้นมาเองพร้อมกำหนด mode ที่ถูกต้อง หากคุณสร้าง acme.json ด้วย touch ค่า umask อาจทำให้ไฟล์มีสิทธิ์เป็น 644 ให้แก้ไขที่เครื่อง host ดังนี้:

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

ควรทำการสำรองข้อมูล (backup) directory นี้ไว้พร้อมกับ app volumes การสูญเสียไฟล์นี้สามารถแก้ไขได้โดยการออกใบรับรองใหม่ แต่การออกใบรับรองใหม่สำหรับ 5 hostnames พร้อมกันจะทำให้คุณติดข้อจำกัดด้าน rate limits

ควรใช้ staging CA ในขณะที่กำลังทดสอบ ให้เอาเครื่องหมาย comment ออกจากบรรทัด caserver เพื่อทดสอบให้ทุก route ใช้งานได้ จากนั้นจึงใส่เครื่องหมาย comment กลับคืนและลบ acme.json ทิ้ง เพื่อให้ระบบขอใบรับรองจริงใหม่ Let's Encrypt (production) อนุญาตให้ขอใบรับรองที่ ซ้ำกัน ได้เพียง 5 ชุดต่อสัปดาห์สำหรับ hostname ชุดเดิม และมีการจำกัดจำนวนหากมีการตรวจสอบที่ล้มเหลวซ้ำๆ สำหรับชื่อเดิม ส่วน staging จะออกใบรับรองที่ไม่ได้รับความเชื่อถือ (untrusted) ซึ่งเบราว์เซอร์จะแจ้งเตือน และการแจ้งเตือนนั้นคือสัญญาณว่าระบบทำงานถูกต้องแล้ว โดยมีข้อจำกัดที่ยืดหยุ่นกว่ามาก

Dashboard คือส่วนควบคุม ไม่ใช่ตัวอย่างสำหรับการสาธิต

คู่มือเริ่มต้นใช้งานส่วนใหญ่จะตั้งค่า --api.insecure=true ซึ่งจะให้บริการ dashboard ผ่าน port 8080 โดยไม่มีการยืนยันตัวตน หากใช้งานบนเครื่องที่มี public IP จะทำให้ข้อมูล routing topology, hostname, ชื่อ middleware และ backend ports ถูกเปิดเผยต่อผู้ที่ทำการสแกนระบบ

ทางเลือกอื่นคือการใช้ label บน service traefik ด้านบน โดย dashboard จะถูกกำหนดเส้นทางเหมือนแอปพลิเคชันทั่วไป ผ่าน hostname จริง ใช้งานผ่าน TLS และอยู่หลัง basicauth โดยมี service=api@internal ทำหน้าที่เชื่อมต่อ router เข้ากับ API ในตัวของ Traefik คุณสามารถเพิ่มความปลอดภัยได้มากขึ้นโดยการใช้ IP allow-list ซึ่งจะถูกนำมาใช้จากซ้ายไปขวา หากที่อยู่ IP ของสำนักงานของคุณเป็นแบบ dynamic ให้กำหนดช่วง IP เป็น subnet ที่ได้รับจาก WireGuard VPN ที่คุณติดตั้งเองบน VPS เครื่องเดียวกัน เพื่อให้เข้าถึง dashboard ได้ผ่านทาง tunnel เท่านั้น:

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

The Docker socket is root

/var/run/docker.sock คือ API ที่สามารถสร้าง container ซึ่งทำการ mount / จาก host ได้ การเข้าถึง API นี้มีสิทธิ์เทียบเท่า root บนเครื่อง และ Traefik จำเป็นต้องใช้เพื่ออ่าน labels

หากต้องการคง :ro ไว้ใน mount ให้พิจารณาข้อจำกัดดังนี้: วิธีนี้จะทำให้ socket file เป็นแบบ read-only เท่านั้น แต่ไม่ได้ป้องกันการส่งคำขอ POST ไปยัง Docker API ผ่าน socket ดังกล่าว วิธีการป้องกันที่มีประสิทธิภาพคือการไม่ให้ 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

ลบ volume ของ socket ออกจาก Traefik และกำหนดค่า provider ให้ชี้ไปยัง proxy:

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

Traefik จะยังคงสามารถอ่านข้อมูล container และ networks ได้ แต่จะไม่สามารถสร้างทรัพยากรใดๆ ได้อีกต่อไป

Firewall, ports, และกฎที่ทุกคนมักเข้าใจผิด

พอร์ตที่เปิดอยู่ 2 พอร์ต พร้อมกับ SSH:

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

Docker's published ports bypass ufw. Docker จะแทรก iptables rules ของตนเอง ซึ่งจะถูกประเมินก่อน ufw chains ดังนั้น container ที่เริ่มทำงานด้วย ports: ["3000:3000"] จะสามารถเข้าถึงได้จากอินเทอร์เน็ต แม้จะมีการตั้งค่า ufw deny ไว้ก็ตาม ปัญหานี้เกิดจากโครงสร้างระบบ ไม่ใช่การตั้งค่า firewall: ควร publish ports จาก Traefik เท่านั้น และกำหนดให้ container อื่นๆ ใช้เพียง networks: [proxy] เท่านั้น หากจำเป็นต้องมีการเชื่อมต่อมายัง host จริงๆ ให้ bind ไว้ที่ loopback — "127.0.0.1:3000:3000"

Troubleshooting: errors you will actually see

404 page not found ถูกส่งโดย Traefik เนื่องจากไม่มี router ที่ตรงกับเงื่อนไข สาเหตุที่เป็นไปได้เรียงตามลำดับความน่าจะเป็น: container ขาด traefik.enable=true (โดยมีการตั้งค่า exposedByDefault=false ไว้); กฎ Host() ไม่ตรงกับชื่อที่คุณพิมพ์; ชื่อ router ใน label หนึ่งไม่ตรงกับชื่อ router ในอีก label หนึ่ง (routers.gitea.rule และ routers.gitea.entrypoints ต้องเป็นคำเดียวกัน); หรือคุณใช้เครื่องหมายอัญประกาศ (quotes) แทนที่จะใช้ backticks สำหรับ hostname เนื่องจาก Traefik v3 กำหนดให้ใช้ backticks ภายใน matcher

502 Bad Gateway. router ทำงานได้แต่ไม่สามารถเชื่อมต่อกับ backend ได้ สาเหตุส่วนใหญ่เกิดจาก container ไม่ได้อยู่ใน network proxy — โปรดตรวจสอบ docker inspect -f '{{json .NetworkSettings.Networks}}' gitea สาเหตุอื่นที่เป็นไปได้คือ loadbalancer.server.port ไม่ถูกต้อง: คุณระบุ port ที่ถูก publish ไว้ หรือแอปพลิเคชันรับคำสั่งจาก port อื่น รายละเอียดการเชื่อมต่อระบุไว้ใน log: dial tcp 172.18.0.5:8080: connect: connection refused

Browser แจ้งเตือน และ certificate ถูกออกให้แก่ TRAEFIK DEFAULT CERT. ไม่มี certificate สำหรับ hostname นั้น และ 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 ยังไม่ได้ชี้มาที่เครื่องนี้ ให้แก้ไข record รอจนกว่า TTL จะหมดอายุ แล้วจึง restart Traefik

Invalid response from http://git.example.com/.well-known/acme-challenge/... ใน HTTP challenge: port 80 ไม่สามารถเชื่อมต่อกับ Traefik จากภายนอกได้ — มักเกิดจาก firewall ในระดับผู้ให้บริการที่อยู่หน้า VPS ไม่ใช่ ufw

Certificate ไม่ถูกออกให้ และ DNS ของคุณใช้ Cloudflare โดยเปิด orange cloud ไว้ Cloudflare ทำการ terminate TLS ที่ edge ของระบบ ทำให้ไม่สามารถทำ TLS-ALPN-01 ให้เสร็จสมบูรณ์ได้ ให้ตั้งค่า record เป็น DNS-only ในขณะที่กำลังออก certificate หรือเปลี่ยนไปใช้ DNS-01 challenge ด้วย API token ทั้งนี้ DNS-01 เป็น challenge เพียงวิธีเดียวที่สามารถออก wildcard certificate ได้

Redirect loop. มีบริการบางอย่างอยู่หน้า Traefik ที่ทำการ terminate TLS และส่งต่อข้อมูลแบบ plaintext ไปยัง port :80 ทำให้การ redirect ของ entrypoint ส่งข้อมูลกลับไปยัง HTTPS อีกครั้ง ให้ลบการ redirect ออกหนึ่งอย่าง

Keeping it running

Docker unit ต้องตั้งค่าให้ boot-enabled (systemctl is-enabled docker) และ restart: unless-stopped จะช่วยให้ stack กลับมาทำงานใหม่หลังการ reboot หากต้องการควบคุมอย่างละเอียด ให้ใช้ systemd unit ขนาดเล็กที่รัน docker compose -f /srv/edge/compose.yml up -d พร้อมกับ RemainAfterExit=yes เพื่อให้ได้ systemctl status edge และการควบคุมลำดับการทำงาน (ordering control)

ควรระบุ Traefik tag ให้ชัดเจน (traefik:v3.5 ห้ามใช้ latest) การอัปเกรดจาก v2 เป็น v3 มีการเปลี่ยนไวยากรณ์ของ rule และชื่อของ provider หากใช้ latest แบบอัตโนมัติ ระบบอาจพยายาม reload config ที่ไม่รองรับอีกต่อไป การอัปเกรดควรทำอย่างระมัดระวัง: อ่านบันทึกการ migration, เปลี่ยน tag เป็น docker compose up -d traefik, และตรวจสอบ log หากคุณยังใช้ tag v2 อยู่ คู่มือการ migration Traefik v2 ไป v3 จะอธิบายรายละเอียดเกี่ยวกับการเปลี่ยนชื่อทั้งหมด, compatibility mode, และวิธีการ rollback โดยที่ยังรักษา certificate ไว้ได้

สำรองข้อมูล ./letsencrypt และ data volume ของแต่ละแอปพลิเคชัน Traefik ไม่มีการเก็บ state อื่นใดที่ไม่อาจสร้างขึ้นใหม่ได้จาก compose file

ปัญหาเมื่อต้องขยายระบบ (Scaling)

ข้อจำกัดแรกไม่ใช่ throughput แต่คือข้อจำกัดของเครื่องเซิร์ฟเวอร์เพียงเครื่องเดียว การใช้ Traefik หนึ่งตัวบน VPS หนึ่งเครื่อง ถือเป็นจุดอ่อนที่ทำให้ระบบล่มได้ (single point of failure) หากต้องรัน 5 แอปพลิเคชัน และเนื่องจาก acme.json ใช้การเก็บข้อมูลแบบ flat-file หากมี Traefik 2 instance เขียนข้อมูลพร้อมกันจะทำให้ไฟล์เสียหาย การขยายระบบ (Scaling out) จึงต้องเปลี่ยนจากการเก็บ certificate ไว้ในไฟล์ หรือเปลี่ยนไปใช้การจัดการ TLS ที่จุดอื่นแทน

ข้อจำกัดที่สองคือการเชื่อมต่อที่มีระยะเวลานาน (long-lived connections) เช่น Server-sent events, การอัปโหลดไฟล์ขนาดใหญ่ และ client ที่ตอบสนองช้า จะไปติดปัญหาเรื่อง timeout ของ entrypoint โดยมี --entryPoints.websecure.transport.respondingTimeouts.readTimeout รวมถึง writeTimeout และ idleTimeout เป็นตัวปรับตั้งค่า (knobs) สำหรับเรื่องนี้ ส่วน WebSockets สามารถใช้งานผ่านได้ทันทีโดยไม่ต้องตั้งค่าเพิ่มเติม

ข้อจำกัดที่สามคือพื้นที่ดิสก์ --accesslog=true จะเขียนข้อมูลลง stdout และ Docker json-file driver จะเก็บข้อมูลนั้นไว้ตลอดไปหากไม่มีการจำกัดขนาด ให้ตั้งค่า logging.options.max-size ใน Traefik service หรือเขียน access log ลงไฟล์แล้วทำการ rotate ไฟล์แทน

กระบวนการทั้งหมดนี้ไม่จำเป็นต้องใช้ orchestrator สิ่งที่จำเป็นคือเซิร์ฟเวอร์ที่คุณควบคุมได้ มี IP จริง และเปิดพอร์ต 80 และ 443 ไว้สู่สาธารณะ โดยใช้เพียง VPS ขนาดเล็กเพียงเครื่องเดียวเท่านั้น

FAQ

ฉันยังจำเป็นต้องใช้ certbot หรือไม่หากฉันรัน Traefik?

ไม่จำเป็น เนื่องจาก ACME resolver ของ Traefik จะทำหน้าที่ร้องขอและต่ออายุใบรับรองสำหรับทุก hostname ที่ทำ routing และจัดเก็บข้อมูลทั้งหมดไว้ใน acme.json การใช้ Certbot จะเหมาะสมเมื่อ nginx หรือ server อื่นทำหน้าที่ terminate TLS ด้วยตนเอง การรันทั้งสองระบบพร้อมกันบน hostname เดียวกันจะทำให้โควตา rate limits ของ Let's Encrypt หมดไปโดยไม่จำเป็น

ทำไม container ของฉันถึงส่งคืนค่า 404 ผ่าน Traefik?

ค่า 404 ที่ส่งมาจาก Traefik หมายถึงไม่มี router ใดที่จับคู่กับ request ได้เลย โปรดตรวจสอบว่า container มีการตั้งค่า traefik.enable=true (จำเป็นต้องมีเมื่อตั้งค่า exposedByDefault=false แล้ว) ตรวจสอบว่าค่า Host() ตรงกับชื่อที่คุณพิมพ์ และชื่อ router ต้องเหมือนกันในทุก label ของแอปพลิเคชันนั้น นอกจากนี้ Traefik v3 กำหนดให้ใช้ backticks ภายใน matcher แทนการใช้เครื่องหมายคำพูด

ความแตกต่างระหว่าง 404 และ 502 ในกรณีนี้คืออะไร?

404 หมายถึงไม่มีการทำ routing เกิดขึ้น ส่วน 502 หมายถึง router จับคู่สำเร็จแต่ backend ปฏิเสธการเชื่อมต่อ สาเหตุทั่วไปของ 502 คือ container ไม่ได้เชื่อมต่อกับ network proxy หรือมีการตั้งค่า loadbalancer.server.port ไปยัง port ที่ถูก publish แทนที่จะเป็น port ที่แอปพลิเคชันใช้งานอยู่ภายใน container ทั้งนี้ access log จะระบุที่อยู่ (address) ที่ Traefik พยายามเชื่อมต่อไว้

การ mount Docker socket แบบ read-only เพียงพอหรือไม่?

flag :ro ทำให้ไฟล์ socket เป็นแบบ read-only แต่ไม่ได้จำกัดการทำงานของ API ที่อยู่เบื้องหลัง ดังนั้น POST ยังคงส่งคำขอผ่าน socket นี้ได้ และการเข้าถึง Docker API นั้นมีสิทธิ์เทียบเท่า root บน host วิธีที่ปลอดภัยกว่าคือการใช้ container docker-socket-proxy ตามตัวอย่างด้านบน ซึ่งจะอนุญาตให้ Traefik อ่านข้อมูลเฉพาะส่วน container และ network เท่านั้น และบล็อกการเขียนข้อมูลทั้งหมด

Traefik สามารถออก wildcard certificate ได้หรือไม่?

ทำได้เฉพาะผ่าน DNS-01 challenge โดยต้องใช้ API token ของผู้ให้บริการ DNS เท่านั้น ส่วน TLS-ALPN-01 และ HTTP-01 จะตรวจสอบได้เพียง hostname เดียวและไม่สามารถออก wildcard ได้ นอกจากนี้ DNS-01 ยังเป็นวิธีแก้ปัญหาในกรณีที่ใช้ CDN เช่น Cloudflare ทำหน้าที่ terminate TLS หน้า VPS ของคุณ และวิธี challenge อีกสองวิธีไม่สามารถทำงานได้สำเร็จ