SSD Nodes Learn Hosting plans →
راهنماها Matt Connorتوسط Matt Connor · به‌روزرسانی شده 2026-08-27

مقایسه Nginx و Caddy و Traefik برای انتخاب Reverse Proxy

برای انتخاب بین Nginx، Caddy و Traefik در یک VPS با IP عمومی، این راهنما تفاوت مدیریت گواهی TLS، تنظیمات Docker و عملکرد WebSocket را برای هر سرویس بررسی می‌کند.

مقایسه Nginx، Caddy و Traefik: پاسخ کوتاه

Nginx، Caddy و Traefik همگی وظیفه یکسانی را به عنوان reverse proxy انجام می‌دهند: گوش دادن روی پورت 443، خواندن نام دامنه در هر درخواست و هدایت آن به سرویس صحیح روی VPS شما. هر سه گزینه می‌توانند چهار برنامه self-hosted را پشت یک آدرس IP عمومی قرار دهند و همگی به اندازه‌ای سریع هستند که گلوگاه عملکرد، برنامه‌های شما خواهد بود، نه این ابزارها. تفاوت در نحوه دریافت گواهی TLS (امنیت لایه انتقال) توسط هر کدام و میزان پیکربندی مورد نیاز برای هر سرویس اضافی است. تفاوت دیگر زمانی آشکار می‌شود که به قابلیتی نیاز پیدا کنید که در آموزش‌های معمول نادیده گرفته شده است.

اگر می‌خواهید مدیریت HTTPS به‌طور خودکار انجام شود و سرویس‌های شما برنامه‌های وب معمولی هستند، Caddy را انتخاب کنید. اگر همه چیز در Docker Compose اجرا می‌شود و هر چند هفته یک سرویس جدید اضافه می‌کنید، Traefik را انتخاب کنید. اگر از قبل با Nginx کار می‌کنید، یا به قابلیت‌هایی مانند response caching، گواهی‌های کلاینت، raw TCP forwarding یا یک پیکربندی حجیم موجود نیاز دارید که نمی‌خواهید آن را بازنویسی کنید، Nginx را انتخاب کنید.

هر کدام چگونه گواهی TLS دریافت می‌کنند؟

این محور برای اکثر افراد تعیین‌کننده است، پس از اینجا شروع کنید. هر سه در نهایت گواهی یکسانی را از همان مرجع صدور دریافت می‌کنند. کاری که برای رسیدن به آن انجام می‌دهید یکسان نیست.

Caddy به دلیل نام‌گذاری hostname، درخواست گواهی می‌دهد. کافی است app.example.com را به عنوان آدرس سایت بنویسید تا Caddy از طریق ACME (محیط مدیریت خودکار گواهی) از Let's Encrypt درخواست گواهی کند، در صورت شکست به ZeroSSL متوسل شود، تغییر مسیر HTTP به HTTPS را روی پورت 80 انجام دهد و به‌طور خودکار آن را تمدید کند. هیچ ابزار دومی وجود ندارد و نیازی به بررسی تایمر نیست. گواهی‌ها در دایرکتوری داده کاربر caddy، یعنی /var/lib/caddy/.local/share/caddy در نصب بسته‌ای، قرار می‌گیرند؛ بنابراین آن مسیر را به بک‌آپ‌های خود اضافه کنید یا پس از بازسازی سرور، صدور مجدد آن را بپذیرید. برای hostnameهایی که عمومی نیستند، tls internal با استفاده از مرجع صدور گواهی محلی خودِ Caddy، گواهی را امضا می‌کند. این کار نتیجه‌ای مشابه ایجاد گواهی خود-امضا در Ubuntu به شما می‌دهد، با این تفاوت که تمدید آن برای شما مدیریت می‌شود.

Nginx کلاینت ACME ندارد. Certbot گواهی را دریافت می‌کند و پلاگین --nginx آن، بلوک سرور شما را بازنویسی می‌کند تا listener پورت 443 و تغییر مسیر (redirect) را اضافه کند. تمدید از طریق یک تایمر systemd که توسط بسته نصب می‌شود اجرا می‌گردد، بنابراین دو بخش متحرک و دو مورد برای بررسی وجود دارد: systemctl list-timers | grep certbot نشان می‌دهد که تایمر وجود دارد و sudo certbot renew --dry-run ثابت می‌کند که مسیر تمدید همچنان کار می‌کند. مراحل گام‌به‌گام در استفاده از Certbot روی Ubuntu 24.04 با Nginx آمده است و همین ابزار گواهی wildcard از طریق چالش DNS-01 را زمانی که تعداد زیردامنه‌های شما بیش از حد لیست‌کردن است، پوشش می‌دهد.

Traefik کلاینت ACME مخصوص خود را دارد. شما یک certificate resolver را در پیکربندی ایستا (static configuration) تنظیم می‌کنید و هر router می‌تواند از آن استفاده کند. تمام وضعیت، شامل کلید حساب و گواهی‌ها، در یک فایل واحد acme.json قرار می‌گیرد. Traefik اگر این فایل توسط هر کسی غیر از مالک آن قابل خواندن باشد، از استفاده از آن خودداری می‌کند و پیش از غیرفعال‌کردن resolver، این موضوع را به شما اطلاع می‌دهد:

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

یک دایرکتوری mount کنید و اجازه دهید Traefik خودش فایل را ایجاد کند. اگر آن را ابتدا با touch ایجاد کنید، umask شما را به ارث می‌برد که این همان دلیلی است که اکثر افراد با آن خطا مواجه می‌شوند.

یک نکته برای هر سه صادق است. چالش HTTP-01 نیاز دارد که پورت 80 از اینترنت در دسترس باشد، زیرا مرجع صدور گواهی برای تأیید به آن متصل می‌شود. اگر فقط پورت 443 را باز کنید، صدور گواهی با خطایی مواجه می‌شود که شبیه به خطای DNS به نظر می‌رسد.

همان وظیفه مسیریابی دو برنامه در سه پیکربندی

وظیفه: app.example.com به سرویسی در 127.0.0.1:8080 هدایت شود، files.example.com به سرویسی در 127.0.0.1:8081، هر دو از طریق HTTPS. در اینجا کل فرآیند برای هر پروکسی آورده شده است تا تفاوت در حجم پیکربندی به‌جای ادعا، به‌وضوح قابل مشاهده باشد.

Nginx

# /etc/nginx/sites-available/app.example.com
server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

سپس آن را لینک کنید، تست کنید، reload کنید و گواهی را اضافه نمایید.

sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d app.example.com

nginx -t با چاپ syntax is ok و test is successful همان بررسی است که باید پیش از هر reload اجرا شود. برنامه دوم همان بلوک با تغییر نام میزبان و پورت است. خطوط proxy_set_header تزئینی نیستند: وقتی proxy_pass یک آدرس را نام می‌برد، Nginx به‌صورت پیش‌فرض Host: 127.0.0.1:8080 را به سمت upstream می‌فرستد؛ بنابراین برنامه‌ای که URLهای مطلق را از هدر Host می‌سازد، کاربران شما را به localhost هدایت می‌کند. اینکه هر یک از آن چهار هدر برای چیست و چرا یک اسلش انتهایی در proxy_pass به‌طور نامحسوس مسیری را که برنامه شما دریافت می‌کند تغییر می‌دهد، در این راهنمای گام‌به‌گام بلوک سرور Nginx به صورت دستور به دستور بررسی شده است.

Caddy

app.example.com {
	reverse_proxy 127.0.0.1:8080
}

files.example.com {
	reverse_proxy 127.0.0.1:8081
}
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy

این کل فایل است. reverse_proxy به‌طور خودکار X-Forwarded-For، X-Forwarded-Proto و X-Forwarded-Host را تنظیم می‌کند و به‌صورت پیش‌فرض هر آنچه کلاینت در آن هدرها ارسال کرده است را نادیده می‌گیرد، بنابراین یک درخواست نمی‌تواند به backend شما درباره مبدأ خود دروغ بگوید. گواهی‌ها، تغییر مسیر پورت 80 و تمدید، همگی از همان دو آدرس سایت پیروی می‌کنند. هیچ چیز دیگری در فایل برای آن‌ها درخواست نمی‌شود.

Traefik

Traefik پیش از مسیریابی هر چیزی به یک پیکربندی ایستا نیاز دارد. به‌عنوان یک سرویس Compose، با تگ image که تا اوت 2026 به‌روز است:

services:
  traefik:
    image: traefik:v3.7
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.le.acme.email=you@example.com"
      - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
      - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt

سپس هر برنامه مسیریابی خاص خود را از طریق labelها در فایل compose اختصاصی خود حمل می‌کند:

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app.rule=Host(`app.example.com`)"
      - "traefik.http.routers.app.entrypoints=websecure"
      - "traefik.http.routers.app.tls.certresolver=le"
      - "traefik.http.services.app.loadbalancer.server.port=8080"

loadbalancer.server.port پورت داخل کانتینر است، نه یک پورت منتشر شده (published)، زیرا Traefik از طریق یک شبکه مشترک Docker به کانتینر دسترسی پیدا می‌کند. برنامه اصلاً به خط ports: نیاز ندارد و این مزیت اصلی است: فقط Traefik منتشر می‌شود. ساختار کامل، شامل شبکه مشترک و میان‌افزار تغییر مسیر، در مسیریابی چندین برنامه با Traefik و Docker Compose آمده است.

هزینه پیکربندی برای هر برنامه اضافی چقدر است؟

ChartNon-blank config lines for the same two-app routing job
The data behind this chart
[
  {
    "tool": "Nginx",
    "proxy_setup_lines": 0,
    "lines_per_app": 11
  },
  {
    "tool": "Caddy",
    "proxy_setup_lines": 0,
    "lines_per_app": 3
  },
  {
    "tool": "Traefik",
    "proxy_setup_lines": 17,
    "lines_per_app": 5
  }
]

این تعداد بر اساس بلوک‌های بالا محاسبه شده است. بلوک سرور Nginx شامل 11 خط غیرخالی است که باید برای هر نام دامنه دوباره نوشته شود. بلوک سایت Caddy شامل 3 خط است. Traefik پیش از پاسخ‌دهی به اولین درخواست، به 17 خط پیکربندی ایستا نیاز دارد و پس از آن برای هر برنامه، 5 خط برچسب (label) لازم است.

به جای تعیین برنده، به موازنه هزینه‌ها توجه کنید. Traefik بیشترین هزینه را پیش از راه‌اندازی اولین برنامه و کمترین هزینه را برای هر برنامه بعدی دارد؛ این دو مقدار در حدود سومین سایت با هم برابر می‌شوند. در تعداد کمتر از آن، پیکربندی ایستا سرباری است که به آن نیاز نداشتید. در تعداد بیشتر، برچسب‌ها پیش می‌افتند و این برتری را حفظ می‌کنند، زیرا تنظیمات مسیریابی در کنار سرویسی قرار دارد که آن را هدایت می‌کند. با حذف سرویس، مسیر آن نیز حذف می‌شود؛ این همان نقطه‌ضعفی است که فایل‌های پیکربندی متمرکز دارند: باقی ماندن بلوک‌های سرورِ بلااستفاده برای برنامه‌هایی که ماه‌هاست دیگر وجود ندارند.

تعداد خطوط، Nginx را در موقعیت بهتری نشان می‌دهد. هر یک از آن بلوک‌ها به یک symlink، یک nginx -t، یک reload و اجرای certbot نیاز دارد، در حالی که ویرایش Caddy تنها به یک reload و ویرایش Traefik به هیچ دستوری نیاز ندارد. هر سه ابزار بدون قطع اتصالات فعال، reload می‌شوند. تفاوت اصلی در تعداد مراحل مجزایی است که باید در ساعت یک بامداد به خاطر داشته باشید.

کدام‌یک از کانتینرهای شما آگاه است؟

Traefik سوکت Docker را پایش می‌کند و با شروع و توقف کانتینرها، روترها را بر اساس برچسب‌های (labels) کانتینر می‌سازد. هیچ ابزار دیگری در اینجا این کار را انجام نمی‌دهد. Nginx و Caddy هر دو هنگام ظاهر شدن یک کانتینر جدید، نیاز به ویرایش فایل پیکربندی و reload دارند؛ همچنین آن‌ها به آدرسی نیاز دارند که بتوانند به آن دسترسی داشته باشند: یا پورتی که روی loopback منتشر شده باشد، یا یک شبکه Docker مشترک که پروکسی به آن متصل است.

این قابلیت هزینه‌ای دارد که باید به‌صراحت بیان شود. Traefik فایل /var/run/docker.sock را می‌خواند. هر کسی که بتواند با آن سوکت ارتباط برقرار کند، می‌تواند کانتینری را با mount کردن فایل‌سیستم میزبان در داخل آن اجرا کند که به معنای دسترسی root روی میزبان است. mount کردن آن به صورت read-only ریسک را کاهش می‌دهد اما آن را از بین نمی‌برد. اگر این موضوع در مدل تهدید شما اهمیت دارد، یک socket proxy در میان قرار دهید که فقط endpointهای لیست کانتینر مورد نیاز Traefik را در دسترس قرار دهد.

Caddy می‌تواند از طریق یک پلاگین اجتماعی، کشف مبتنی بر برچسب را انجام دهد، اما پلاگین‌های Caddy در زمان کامپایل اضافه می‌شوند؛ بنابراین شما باید یک باینری سفارشی یا یک image سفارشی با xcaddy بسازید و سپس مسئولیت آن build و به‌روزرسانی‌هایش با شما خواهد بود. برای سه یا چهار سرویس، ویرایش یک Caddyfile زحمت کمتری دارد.

وب‌سوکت‌ها و استریمینگ: چه چیزی از کار می‌افتد و چرا

Nginx تنها موردی است که به کمک نیاز دارد. اتصال وب‌سوکت (WebSocket) به عنوان یک درخواست HTTP حاوی Upgrade: websocket شروع می‌شود و Nginx هدرهای hop-by-hop را به سمت upstream ارسال نمی‌کند، مگر اینکه صراحتاً به آن دستور دهید.

# /etc/nginx/conf.d/upgrade-map.conf
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

سپس، در داخل بلاک location، سه خط وجود دارد که همگی باید حضور داشته باشند:

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

اگر آن‌ها را حذف کنید، کنسول مرورگر خطای WebSocket connection to 'wss://app.example.com/ws' failed را چاپ می‌کند، در حالی که لاگ بک‌اند شما یک درخواست GET معمولی را نشان می‌دهد. دلیل وجود map این است که یک Connection: upgrade ثابت در هر درخواست ارسال می‌شود، از جمله درخواست‌های ساده‌ای که باید close را اعلام کنند.

دو پیش‌فرض دیگر Nginx نیز مشکل‌ساز می‌شوند. proxy_read_timeout برابر با 60 ثانیه است و پس از ارتقای اتصال (upgrade) روی تونل اعمال می‌شود؛ بنابراین یک وب‌سوکت که به مدت یک دقیقه ترافیکی نداشته باشد، توسط پروکسی بسته می‌شود. همچنین، رویدادهای ارسالی از سمت سرور (Server-Sent Events) با تأخیر یا به‌صورت انفجاری (burst) می‌رسند، مگر اینکه proxy_buffering off; را در آن location تنظیم کنید؛ زیرا Nginx تا زمانی که صفحه شما منتظر پاسخ است، آن را در بافر خود نگه می‌دارد.

Caddy ارتقای اتصال را انجام داده و بدون نیاز به هیچ دستورالعملی، اتصال را به یک تونل دوطرفه تبدیل می‌کند. همچنین، زمانی که پاسخ text/event-stream باشد یا طول مشخصی نداشته باشد، بلافاصله آن را تخلیه (flush) می‌کند، بنابراین استریمینگ بدون تغییر کار می‌کند. Traefik نیز ارتقاها را عبور می‌دهد و تا زمانی که خودتان middleware مربوط به buffering را اضافه نکنید، پاسخ‌ها را بافر نمی‌کند. اگر سرویس‌های شما شامل چت، ترمینال وب، مشاهده لاگ‌ها (log tails) یا داشبوردهای زنده باشد، این تفاوت بزرگی در میزان پیکربندی و عیب‌یابی است که باید انجام دهید.

بلاک کامل سرور Nginx، شامل وب‌سوکت‌ها و SSE
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    server_name app.example.com;
    client_max_body_size 64m;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_read_timeout 3600s;
        proxy_buffering off;
    }
}

دستور map باید در کانتکست http قرار گیرد، نه داخل server؛ بنابراین آن را در فایل جداگانه خود در مسیر /etc/nginx/conf.d/ نگه دارید. proxy_buffering را فقط در locationهایی که استریم می‌کنند غیرفعال (off) کنید، زیرا بافرینگ همان چیزی است که به Nginx اجازه می‌دهد worker بک‌اند را در پاسخ‌های معمولی زودتر آزاد کند. Certbot هنگام اجرا، این بلاک را بازنویسی می‌کند، بنابراین پس از آن، فایل را دوباره بررسی کنید.

وقتی به چیزی غیرمعمول نیاز دارید چه اتفاقی می‌افتد؟

اینجاست که Nginx ارزش خطوط اضافهٔ پیکربندی خود را نشان می‌دهد.

  • گواهی‌های کلاینت، که با نام mTLS (mutual TLS) نیز شناخته می‌شوند؛ در این حالت کلاینت نیز باید گواهی ارائه دهد. Nginx به ssl_client_certificate /etc/ssl/ca.pem; و ssl_verify_client on; در بلوک server نیاز دارد. Caddy به یک بلوک client_auth در داخل tls نیاز دارد. برچسب‌های Traefik اصلاً قادر به بیان این مورد نیستند: شما باید یک گزینه TLS در یک file provider تعریف کنید و با استفاده از traefik.http.routers.app.tls.options=mtls@file به آن اشاره کنید. مدلِ «همه چیز در برچسب‌ها» اولین باری که به این قابلیت نیاز پیدا کنید، با استثنا مواجه می‌شود.
  • آپلودهای حجیم. Nginx به‌طور پیش‌فرض بدنهٔ درخواست‌ها را به 1 MB محدود می‌کند. آپلودهای بزرگ‌تر منجر به بازگشت خطای 413 Request Entity Too Large می‌شوند و در لاگ خطا، عبارت client intended to send too large body ثبت می‌شود. برای رفع این مشکل، client_max_body_size را افزایش دهید. Caddy و Traefik به‌طور پیش‌فرض محدودیتی برای بدنه درخواست ندارند، بنابراین درخواست به برنامه شما می‌رسد و محدودیت خودِ برنامه تعیین‌کننده خواهد بود.
  • کش کردن پاسخ‌ها. Nginx دارای proxy_cache است که بسیار پخته و کامل است. Caddy برای این کار به یک پلاگین نیاز دارد که باید کامپایل شود. نسخه متن‌باز Traefik اصلاً قابلیت HTTP cache ندارد؛ موضوعی که برای کسانی که تصور می‌کنند هر پروکسی قابلیت کش کردن دارد، تعجب‌آور است.
  • TCP یا UDP خام، برای پورت دیتابیس یا سرور بازی. Nginx دارای ماژول stream است. Traefik دارای روترهای TCP و UDP روی entrypointهای اختصاصی خود است. Caddy برای این کار به پلاگین دیگری نیاز دارد که مستلزم یک build سفارشی است.
  • یک وب‌سرور که از قبل پشت پروکسی قرار دارد. اگر سرویس مورد نظر یک برنامه کلاسیک PHP باشد، آنگاه یک LAMP stack روی Ubuntu 24.04 از قبل شامل Apache است. قرار دادن یک پروکسی در مقابل آن، باعث می‌شود دو نقطه برای تنظیم هدرها و دو نقطه برای بازنویسی (rewrite) URL داشته باشید. تصمیم بگیرید کدام‌یک TLS را خاتمه می‌دهد (terminate)، سپس دیگری را روی HTTP ساده و متصل به loopback نگه دارید.

تله فایروال در این انتخاب

هدف از استفاده از reverse proxy این است که فقط پورت‌های 80 و 443 باز باشند. Docker این وضعیت را به‌طور بی‌سروصدا تغییر می‌دهد. انتشار یک پورت با -p 8080:80 یک قانون DNAT در جدول nat می‌نویسد و این قانون پیش از قوانین INPUT که توسط ufw مدیریت می‌شوند ارزیابی می‌گردد. بنابراین ufw deny 8080 مانع آن نمی‌شود و برنامهٔ شما در کنار پروکسی که با دقت پیکربندی کرده‌اید، مستقیماً روی اینترنت عمومی قرار می‌گیرد. پورت‌های منتشرشده را با 127.0.0.1:8080:80 به loopback محدود کنید یا ports: را به‌طور کامل کنار بگذارید و اجازه دهید پروکسی از طریق یک شبکه Docker به container دسترسی پیدا کند؛ همان کاری که در مثال Traefik در بالا انجام شد. مکانیزم و راه‌حل این مشکل در چرا پورت‌های منتشرشده توسط Docker از ufw عبور می‌کنند آمده است.

این مورد را از ماشینی غیر از VPS تست کنید، زیرا بررسی انجام‌شده روی خود سرور همیشه موفقیت‌آمیز است:

curl --max-time 5 http://your.server.address:8080

Connection refused یا یک timeout نتیجه‌ای است که به دنبال آن هستید. دریافت پاسخ HTTP به این معنی است که برنامه بدون عبور از پروکسی شما در دسترس است و تمام تنظیماتی که در بالا انجام دادید، عملاً بی‌اثر هستند.

کدام پروکسی را انتخاب کنید؟

سایت‌های عمدتاً ایستا، به همراه یکی دو برنامه: Caddy. قابلیت HTTPS خودکار، بزرگ‌ترین وظیفهٔ تکراری شما را حذف می‌کند. پیکربندی آن به‌قدری کوتاه است که در یک صفحه نمایش جا می‌شود و یک سایت ایستا تنها به یک خط root و یک خط file_server در همان بلوک سایت نیاز دارد. هزینهٔ آن، دسترسی به منابع کمتر برای کپی-پیست کردن راه‌حل‌ها در صورت بروز مشکلات خاص است.

یک هوم‌لب مبتنی بر docker-compose که مدام به آن سرویس اضافه می‌کنید: Traefik. پس از سرویس سوم، استفاده از labelها نسبت به ویرایش یک فایل مرکزی، زحمت کمتری دارد و با حذف یک سرویس، مسیر (route) آن نیز حذف می‌شود. برای راه‌اندازی اولیه یک بعدازظهر وقت بگذارید، زیرا مفاهیم entrypoints، routers، services و middlewares برای شما جدید خواهند بود. یک غلط تایپی در label معمولاً به‌صورت خطای 404 از سمت Traefik ظاهر می‌شود تا اینکه باعث عدم اجرای سرویس شود؛ بنابراین پیش از آنکه تصور کنید برنامه خراب شده است، docker logs traefik را برای یافتن خطای تجزیه (parse error) بررسی کنید.

یک پیکربندی موجود Nginx، یا هر نیازمندی دیگری از لیست بالا: Nginx. این ابزار برای کش کردن پاسخ‌ها و گواهی‌های کلاینت (client certificates) از قبل راه‌حل دارد و تقریباً تمام راهنماهای شخص ثالث بر اساس آن نوشته شده‌اند. هزینهٔ آن این است که گواهی‌ها و پشتیبانی از websocket مواردی هستند که باید خودتان پیکربندی کنید، نه اینکه به‌صورت پیش‌فرض دریافت کنید.

صرف‌نظر از انتخابتان، یک قانون کلی وجود دارد: دقیقاً یک پردازش باید روی اینترفیس عمومی گوش دهد و سایر موارد باید روی loopback یا یک شبکهٔ خصوصی Docker فعال باشند.

FAQ

کدام reverse proxy برای چند برنامه Docker روی یک VPS مناسب‌تر است؟

برای سه یا چهار سرویسی که گهگاه اضافه می‌کنید، Traefik انتخاب به‌صرفه‌ای است؛ زیرا هر برنامه برچسب‌های مسیریابی (routing labels) مخصوص به خود را دارد و نیازی به ویرایش یک فایل مرکزی نیست. اگر سرویس‌ها پایدار هستند و هدف اصلی شما صرفاً خلاص شدن از دردسرهای HTTPS است، یادگیری و نگهداری Caddy ساده‌تر است. اگر از قبل با Nginx آشنایی دارید یا به قابلیتی نیاز دارید که دو مورد دیگر فاقد آن هستند (مانند response caching یا یک listener ساده TCP)، از Nginx استفاده کنید.

آیا Caddy واقعاً به هیچ پیکربندی گواهی نیاز ندارد؟

در حالت عادی، بله. کافی است نام دامنه عمومی را به عنوان آدرس سایت در پیکربندی وارد کنید: Caddy گواهی را از طریق ACME درخواست می‌کند، تغییر مسیر (redirect) از پورت 80 را انجام می‌دهد و پیش از انقضا، گواهی را تمدید می‌کند. البته دو شرط باید برقرار باشد: پورت 80 برای چالش HTTP-01 باید از اینترنت در دسترس باشد و رکورد DNS A یا AAAA دامنه باید به VPS اشاره کند، زیرا مرجع صدور گواهی (CA) نام را resolve کرده و به آن متصل می‌شود.

آیا می‌توانم Nginx و Traefik را همزمان روی یک VPS اجرا کنم؟

خیر، نمی‌توانند از پورت‌های یکسان استفاده کنند. هر کدام که دوم اجرا شود در bind کردن پورت شکست می‌خورد؛ Nginx خطای bind() to 0.0.0.0:443 failed (98: Address already in use) را نمایش می‌دهد و Traefik نیز با خطای مشابهی در bind کردن، متوقف می‌شود. تنها یک proxy را روی پورت‌های 80 و 443 اجرا کنید و بقیه سرویس‌ها را پشت آن قرار دهید. اگر در حال مهاجرت هستید، دامنه‌ها را یکی‌یکی منتقل کنید: اجازه دهید proxy جلویی درخواست‌ها را به proxy قدیمی روی یک پورت loopback هدایت کند تا زمانی که آخرین سایت منتقل شود.

چرا اتصال‌های websocket من پس از 60 ثانیه پشت Nginx قطع می‌شوند؟

مقدار پیش‌فرض proxy_read_timeout برابر با 60 ثانیه است و پس از تکمیل upgrade، روی تونل اعمال می‌شود. بنابراین اگر اتصالی به مدت یک دقیقه ترافیکی نداشته باشد، توسط proxy بسته می‌شود، نه توسط برنامه شما. این مقدار را در آن location با استفاده از proxy_read_timeout 3600s; افزایش دهید، یا کاری کنید که برنامه هر 30 ثانیه یک ping frame ارسال کند. Caddy و Traefik اتصال‌های ارتقایافته (upgraded) را با تایمر یک‌دقیقه‌ای نمی‌بندند؛ به همین دلیل است که یک برنامه مشابه ممکن است پشت آن‌ها پایدار و پشت Nginx ناپایدار باشد.