SSD Nodes Learn 🎉 VPS از $5.50/ماه
راهنماها Matt Connorتوسط Matt Connor · به‌روزرسانی شده 2026-08-13

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

انتخاب بهترین Reverse Proxy برای VPS. تفاوت Nginx، Caddy و Traefik در مدیریت خودکار گواهی TLS، پیکربندی Docker Compose، پشتیبانی از Websockets و هزینه نگهداری هر سرویس.

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

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

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

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

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

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

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 است. برنامه دوم همان بلوک با تغییر نام میزبان (hostname) و پورت است. خطوط proxy_set_header تزئینی نیستند: وقتی proxy_pass یک آدرس را نام می‌برد، Nginx به‌طور پیش‌فرض Host: 127.0.0.1:8080 را به سمت upstream می‌فرستد؛ بنابراین برنامه‌ای که URLهای مطلق را از هدر Host می‌سازد، کاربران شما را به localhost هدایت خواهد کرد.

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 منتشر می‌شود. ساختار کامل، شامل شبکه مشترک و middleware تغییر مسیر، در مسیریابی چندین برنامه با 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) آن‌ها، مسیرها (routers) را می‌سازد. هیچ ابزار دیگری در اینجا این کار را انجام نمی‌دهد. Nginx و Caddy هر دو هنگام ظاهر شدن یک کانتینر جدید، نیاز به ویرایش فایل پیکربندی و reload دارند؛ همچنین آن‌ها به آدرسی نیاز دارند که بتوانند به آن دسترسی داشته باشند: یا پورتی که روی loopback منتشر شده باشد، یا یک شبکه Docker مشترک که proxy به آن متصل است.

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

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

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

Nginx تنها موردی است که به کمک نیاز دارد. اتصال وب‌سوکت به‌عنوان یک درخواست 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 را چاپ می‌کند، در حالی که لاگ backend شما یک درخواست GET معمولی را نشان می‌دهد. متغیر map به این دلیل وجود دارد که یک مقدار ثابت Connection: upgrade در هر درخواست ارسال می‌شود، از جمله درخواست‌های ساده‌ای که باید مقدار close را داشته باشند.

دو مورد پیش‌فرض دیگر در Nginx نیز مشکل‌ساز می‌شوند. مقدار proxy_read_timeout برابر با 60 ثانیه است و پس از ارتقای اتصال (upgrade) روی تونل اعمال می‌شود؛ بنابراین یک وب‌سوکت که به مدت یک دقیقه ترافیکی نداشته باشد، توسط پروکسی بسته می‌شود. همچنین، رویدادهای ارسالی از سمت سرور (SSE) با تأخیر یا به‌صورت دسته‌ای می‌رسند، مگر اینکه 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 باید در context مربوط به http قرار گیرد، نه داخل server، بنابراین آن را در فایل مخصوص خود در مسیر /etc/nginx/conf.d/ نگه دارید. گزینه proxy_buffering را فقط در locationهایی که استریم می‌کنند غیرفعال (off) کنید، زیرا بافرینگ همان چیزی است که به Nginx اجازه می‌دهد worker مربوط به backend را در پاسخ‌های معمولی زودتر آزاد کند. 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 ندارد، که این موضوع برای کسانی که تصور می‌کنند هر پروکسی قابلیت کش کردن دارد، تعجب‌آور است.
  • TCP یا UDP خام، برای پورت دیتابیس یا سرور بازی. Nginx دارای ماژول stream است. Traefik دارای روترهای TCP و UDP روی entrypointهای اختصاصی خود است. Caddy به یک پلاگین دیگر نیاز دارد که مستلزم یک build سفارشی است.
  • یک وب‌سرور که از قبل پشت پروکسی است. اگر سرویس مورد نظر یک برنامه کلاسیک PHP باشد، آنگاه یک LAMP stack روی Ubuntu 24.04 از قبل شامل Apache است و قرار دادن یک پروکسی در مقابل آن، دو نقطه برای تنظیم هدرها و دو نقطه برای بازنویسی URL ایجاد می‌کند. تصمیم بگیرید کدام‌یک TLS termination را انجام می‌دهد، سپس دیگری را روی 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 به کانتینر دسترسی پیدا کند؛ این همان کاری است که در مثال Traefik در بالا انجام شد. مکانیزم و راه‌حل این مشکل در چرا پورت‌های منتشرشده توسط Docker از ufw عبور می‌کنند آمده است.

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

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

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

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

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

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

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

صرف‌نظر از انتخابتان، یک قانون کلی وجود دارد: دقیقاً یک پردازش باید روی رابط عمومی (public interface) گوش دهد و سایر موارد باید روی 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 ناپایدار به نظر می‌رسد.