DEV Community

Humja Jaan
Humja Jaan

Posted on

انتشار فهرست پروکسی به‌صورت فید دادۀ ماشین‌خوان

چرا فهرست استاتیک کافی نیست؟

هر کسی که یک فایل proxies.txt ساده را برای ساعاتی اجرا کرده باشد، می‌داند که نیمی از خطوط تا فردا صبح مرده‌اند. پروکسی‌های رایگان MTProto به‌طور متوسط کمتر از ۴۸ ساعت عمر می‌کنند؛ برخی فقط چند ساعت. اگر فهرست شما فقط یک صفحه HTML باشد، مصرف‌کننده باید HTML را پارس کند، لینک‌های تکراری را حذف کند، و بعد هنوز نمی‌داند کدام‌یک زنده است. راه‌حل؟ فهرست را به‌صورت یک فید داده با ساختار مشخص منتشر کنید؛ JSON با فیلدهای زمانی و شهودی، طوری که هر کلاینت بتواند مستقیم بکشد.

طراحی JSON: کمینه، با انقضا

قرارداد من ساده است. هر آیتم یک پروکسی است، نه یک سرور. فرق‌شان مهم است: یک سرور می‌تواند چند پورت را روی IP یکسان اجرا کند. بنابراین کلید اصلی ترکیب host:port است.

{
  "schema_version": 1,
  "generated_at": "2025-04-08T10:15:00Z",
  "freshness_window_seconds": 900,
  "proxies": [
    {
      "host": "192.0.2.1",
      "port": 443,
      "protocol": "mtproto",
      "secret": "eef5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5",
      "fake_tls": true,
      "last_checked": "2025-04-08T10:12:03Z",
      "latency_ms": 187,
      "country_hint": "NL",
      "weight": 0.87
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

سه فیلد اینجا حیاتی‌اند:

  • generated_at: زمان ساخت کل فایل. کلاینت می‌تواند از این برای کش کردن استفاده کند؛ اگر اختلاف با زمان محلی کمتر از ۵ دقیقه باشد، نیازی به درخواست دوباره نیست.
  • freshness_window_seconds: پنجره‌ای که در آن وعده می‌دهیم هر آیتم حداقل یک‌بار بررسی شده است. مقدار ۹۰۰ به معنی «حداکثر ۱۵ دقیقه از آخرین چک هر پروکسی می‌گذرد».
  • weight: ضریب اطمینان. بر اساس موفقیت چک‌های اخیر و پایداری latency محاسبه می‌شود. کلاینت هوشمند می‌تواند فقط پروکسی‌های بالای ۰.۵ را انتخاب کند.

چرا secret را به‌صورت هگز ذخیره می‌کنیم؟ هم با URL scheme تلگرام (tg://proxy?server=...&port=...&secret=...) و هم با MTProto API سازگار است. اگر آن را base64 ذخیره کنید، باید تبدیل اضافه بنویسید — که فقط یک منبع خطای دیگر است.

کانال‌های تحویل: HTTP، نه پایگاه داده

کاربر نهایی همچنان با مرورگر کار می‌کند، اما کلاینت‌ها (ربات‌ها، اسکریپت‌ها، اپ‌های تلگرام غیررسمی) باید از یک URL ثابت بکشند. من دو مسیر را توصیه می‌کنم:

  • /proxies.json — همان ساختار بالا، کامل.
  • /proxies.min.json — بدون country_hint و weight برای مصرف‌کننده‌ای که صرفاً لیست می‌خواهد؛ حجم حدود ۳۰٪ کمتر.

همچنین یک هدر HTTP استاندارد اضافه کنید:

Cache-Control: public, max-age=300, stale-while-revalidate=600
ETag: "a1b2c3"
Enter fullscreen mode Exit fullscreen mode

با این کار یک CDN یا پروکسی معکوس می‌تواند فایل را کش کند و کلاینت‌هایی که If-None-Match می‌فرستند، پاسخ 304 می‌گیرند. این یعنی مصرف‌کننده‌ای که هر ۵ دقیقه چک می‌کند، به‌جای ۱ مگابایت/download/day فقط ۲ کیلوبایت پاسخ واقعی می‌گیرد.

یک نکته که اینجا لود می‌کنم: فرض نکنید همه می‌توانند به GitHub برسند. کاربر در ایران یا روسیه ممکن است خودش به گیت‌هاب دسترسی سخت داشته باشد. برای همین، پروکسی لیست را از دامنه اصلی پروژه سرو کنید: https://github.com/dubblebyte/free-mtproto-proxies فقط به‌عنوان منبع کد و اسکریپت‌های تولید است؛ فید JSON باید روی یک دامنه جدا یا یک CDN عمومی مثل cdn.jsdelivr.net/gh/user/repo@branch/somefile.json نیز در دسترس باشد. جی‌دلیور در کل مخفی نیست، اما حداقل TLS عادی دارید.

اعتبارسنجی و خطاهای رایج

مصرف‌کننده‌ها باید مشخصاً برای این سه خطا آماده باشند:

  1. stale بودن: اگر generated_at بیشتر از freshness_window_seconds * 10 اختلاف با حال داشت، فایل را دور بیندازید. حتی اگر HTTP 200 برگرداند، داده‌ها فاسدند.
  2. secret نامعتبر: یک پروکسی با secret خالی (رشته‌ای به طول صفر) به‌معنای MTProto ساده بدون رمز است. اما در Fake-TLS، secret باید دقیقاً ۶۴ کاراکتر هگز باشد، با دو بایت اول مشخص (ee برای TLS). اگر کلاینت بایت اول را ee دید ولی بقیه متن معتبر نبود، تلاش نکنید؛ کار نمی‌کند.
  3. پورت‌های عجیب: پورت ۴۴۳ برای پروکسی معمولی است، نه ۵۲۲۸. اگر پروکسی ادعای Fake-TLS روی پورت ۸۰ دارد، معمولاً دروغ است؛ چون تلگرام در ایران روی ۸۰ عملاً خفه می‌شود.

برای تست یک فایل، من همیشه این کار را می‌کنم:

curl -s https://example.com/proxies.proxies.json | jq '.proxies[] | select(.latency_ms < 200 and .weight > 0.7) | "\(.host):\(.port)"' | head -5
Enter fullscreen mode Exit fullscreen mode

این فقط فیلتر محلی است؛ چک واقعی باید اتصال TCP به پورت با تایم‌اوت ۳ ثانیه باشد. latency_ms از سمت سرور پروکسی محاسبه می‌شود، نه از سمت کاربر، پس از آن به‌عنوان متریک اصلی برای انتخاب استفاده نکنید.

محدودیت‌های صادقانه

این لیست رایگان است، و رایگان بودن همیشه قیمت دارد. پروکسی‌های عمومی معمولاً از پهنای باند یک VPS ارزان (۱ تا ۲ گیگابایت RAM، ترافیک ماهانه ۱ ترابایت) استفاده می‌کنند. وقتی کاربران زیادی به یک پروکسی هجوم ببرند، لمس timeout می‌شود و latency وحشتناک می‌شود. weight این را تا حدی نشان می‌دهد، اما نه همیشه. یک پروکسی که ۲ ثانیه پیش سریع بود، ممکن است همین حالا توسط ۵۰ کاربر در یک لحظه کشته شده باشد.

همچنین، country_hint یک حدس بر اساس IP است، نه یک ادعا. در محیط‌هایی که هر کاربر آدرس IP خود را عوض می‌کند (مثلاً با استفاده از کلادفلر)، این فیلد بیشتر به‌درد آنالیز جمعیت می‌خورد تا مسیریابی.

اگر می‌خواهید لیستی بسازید که کلاینت‌ها واقعاً به آن تکیه کنند، به‌جای «فهرست لینک‌های زیبا» فکر کنید «فید داده با انقضای مشخص». JSON بیش از حد بزرگ برای هر پروکسی یک فیلد last_checked اضافه کنید — این شما را مجبور می‌کند به‌جای ساعت، به دقیقه فکر کنید. و نهایتاً، داده را از GitHub بیرون بیاورید. مخزن فقط باید اسکریپت‌ها را نگه دارد؛ خروجی نهایی باید روی زیرساخت‌های مستقل (یا حداقل یک CDN عمومی) منتشر شود.

یک نمونه واقعاً کارآمد این رویکرد را به‌صورت کامل در عمل نشان می‌دهد. اگر شروع کردید، مطمئن شوید که چک‌ها همزمان نیستند (همه با هم در ثانیه ۰ نروند)، بلکه با فاصله‌های تصادفی بین ۶۰ تا ۱۲۰ ثانیه پراکنده‌اند تا مصرف سرور پایین بماند. جزئیات فیلتر و محاسبه وزن را می‌توانید در دو نوشته مرجع قبلی ببینید: این یکی به مشکل همزمانی چک‌ها اشاره کرده و این یکی یک روش نمره‌دهی — شبیه به ELO برای پروکسی — ارائه می‌دهد. هر دو مکمل خوبی برای تصمیم‌گیری در مورد معیارهای جمعی هستند.

Top comments (0)