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

علت سرعت پایین WireGuard و روش رفع مشکل MTU

سرعت پایین WireGuard معمولاً به دلیل تنظیمات نادرست MTU است. با استفاده از روش bisection مسیر MTU را پیدا کنید، TCP MSS را clamp کنید و steal time را بررسی کنید.

منشأ واقعی سرعت پایین در WireGuard

سرعت پایین در WireGuard به یکی از چهار عامل زیر بازمی‌گردد که احتمال بروز هرکدام یکسان نیست. نخست، MTU (واحد انتقال حداکثر) است: تونل بسته‌هایی می‌سازد که برای یکی از لینک‌های موجود در مسیر بیش از حد بزرگ هستند، بنابراین انتقال‌های حجیم متوقف می‌شوند در حالی که انتقال‌های کوچک سالم به نظر می‌رسند. دوم، خودِ مسیر شبکه است که پیش از ایجاد تونل نیز محدودیت داشته است. سوم، پردازنده (CPU) در یک VPS اشتراکی کوچک است که در آن عملیات رمزنگاری با سایر مهمانان روی همان میزبان رقابت می‌کند. چهارم، اتصال خودِ همتا (peer) است.

این موارد را به همین ترتیب بررسی کنید. MTU در اولویت است زیرا تنها عاملی در این فهرست است که خودِ WireGuard آن را ایجاد می‌کند و علائم آن اصلاً شبیه کندی نیست. MTU نادرست معمولاً به شکل تونلی ظاهر می‌شود که فوراً متصل می‌شود، به ping پاسخ می‌دهد، ورود SSH را می‌پذیرد و سپس در اولین باری که فایلی را کپی می‌کنید، فریز می‌شود.

یک علامت وجود دارد که پیش از هر اقدامی باید آن را رد کنید. اگر بارگذاری هر سایت جدید چندین ثانیه طول می‌کشد و سپس با سرعت کامل منتقل می‌شود، مشکل از وضوح نام (name resolution) است نه توان عملیاتی (throughput). DNS over WireGuard حالت‌های خرابی خاص خود را دارد و هیچ تغییر MTU آن‌ها را برطرف نمی‌کند.

چرا MTU در WireGuard برابر با 1420 است؟

هر بسته‌ای که به داخل تونل می‌فرستید، رمزنگاری شده و درون یک بسته جدید بسته‌بندی می‌شود. این بسته‌بندی هزینه‌ای به بایت دارد و این بایت‌ها از ظرفیت بار مفید (payload) شما کسر می‌شوند.

هدر داده‌های WireGuard برابر با 32 بایت است: یک فیلد نوع 4 بایتی، یک ایندکس گیرنده 4 بایتی، یک شمارنده 8 بایتی و یک تگ احراز هویت 16 بایتی Poly1305. در اطراف آن، یک هدر UDP با 8 بایت قرار دارد. در اطراف آن نیز هدر IP خارجی قرار می‌گیرد که برای IPv4 برابر با 20 بایت و برای IPv6 برابر با 40 بایت است. بنابراین، مجموع کپسوله‌سازی (encapsulation) زمانی که Endpoint شما یک آدرس IPv4 باشد، 60 بایت و زمانی که IPv6 باشد، 80 بایت است. صفحه پروتکل WireGuard ساختار پیام‌هایی که این اعداد از آن‌ها استخراج شده‌اند را مستند کرده است.

wg-quick در این مورد حدس نمی‌زند. این ابزار MTU اینترفیسی که به Endpoint شما مسیردهی می‌کند را می‌خواند و سپس 80 بایت از آن کسر می‌کند. در یک مسیر اترنت معمولی 1500 بایتی، این محاسبه عدد 1420 را نتیجه می‌دهد که همان مقداری است که ip link show wg0 نمایش می‌دهد. دلیل کسر 80 بایت به جای 60 بایت این است که اگر آن نقطه پایانی (endpoint) روزی از طریق IPv6 در دسترس قرار گیرد، همان مقدار ایمن باقی بماند؛ چرا که هدر خارجی در IPv6، 20 بایت بزرگ‌تر است.

ChartMTU arithmetic for common underlays
The data behind this chart
[
  {
    "label": "Ethernet, IPv4 endpoint",
    "path_mtu": 1500,
    "encap_overhead": 60,
    "usable_wg0_mtu": 1440
  },
  {
    "label": "Ethernet, IPv6 endpoint",
    "path_mtu": 1500,
    "encap_overhead": 80,
    "usable_wg0_mtu": 1420
  },
  {
    "label": "PPPoE DSL, IPv4 endpoint",
    "path_mtu": 1492,
    "encap_overhead": 60,
    "usable_wg0_mtu": 1432
  },
  {
    "label": "Extra tunnel in the path",
    "path_mtu": 1400,
    "encap_overhead": 80,
    "usable_wg0_mtu": 1320
  }
]

آن 4 ردیف، محاسبات ریاضی هستند، نه اندازه‌گیری. در یک مسیر 1500 بایتی استاندارد با یک نقطه پایانی IPv4، مقدار 1440 جا می‌شود، بنابراین مقدار پیش‌فرض 1420 باعث می‌شود 20 بایت بدون استفاده باقی بماند. این حاشیه امن، عمدی است و مشکلی برای شما ایجاد نمی‌کند.

ردیف آخر همان جایی است که مشکل ایجاد می‌شود. وقتی یک لینک در مسیر، تنها 1400 بایت را حمل می‌کند، تونلی که همچنان روی 1420 تنظیم شده باشد، برای هر سگمنت با اندازه کامل، یک بسته خارجی 1500 بایتی تولید می‌کند که 100 بایت بیشتر از ظرفیت پذیرش آن لینک است. مقداری که در اینجا مناسب است، 1320 می‌باشد.

مقدار 1320 را نیز کپی نکنید. MTU مسیر شما، ویژگیِ همان مسیر است و تنها راه دانستن آن، اندازه‌گیری است.

نشانه‌های تنظیم نادرست MTU

این خطا تدریجی نیست. شکافی کاملاً مشخص بین بسته‌های کوچک و بزرگ وجود دارد.

  • دستور ping از طریق تونل با هر اندازه معمولی کار می‌کند.
  • ورود به SSH انجام می‌شود و تایپ کردن پاسخگو است.
  • دستور curl -I https://example.com بلافاصله هدرها را برمی‌گرداند.
  • دستور curl https://example.com روی یک صفحه بزرگ، پس از چند کیلوبایت اول متوقف (hang) می‌شود.
  • دستور scp برای یک فایل بزرگ شروع شده و سپس در درصدی خاص متوقف می‌شود.
  • یک نشست SSH در لحظه‌ای که دستوری با خروجی زیاد اجرا می‌کنید، فریز می‌شود.

همه این موارد به این دلیل رخ می‌دهد که یک اتصال TCP تنها زمانی سگمنت‌هایی با اندازه کامل می‌سازد که داده‌های حجیم برای انتقال داشته باشد. دست‌دادن (handshake) و اولین درخواست در هر MTU موجود در مسیر جای می‌گیرند. توقف در اولین سگمنت با اندازه کامل آغاز می‌شود؛ به همین دلیل است که اتصال تا لحظه‌ای که کاملاً غیرقابل استفاده شود، سالم به نظر می‌رسد.

یک بسته خارجی که بزرگ‌تر از MTU لینک بعدی باشد، با یکی از دو سرنوشت زیر روبرو می‌شود:

قطعه‌قطعه (Fragment) می‌شود. یک روتر آن را تقسیم می‌کند و سمت مقصد قطعات را دوباره کنار هم می‌چیند. انتقال کار می‌کند اما کندتر است، زیرا اکنون برای یک بسته، هزینه دو بسته را می‌پردازید و گیرنده تا زمان رسیدن هر دو قطعه، وضعیت را در حافظه نگه می‌دارد. از دست رفتن یک قطعه باعث از دست رفتن کل بسته اصلی می‌شود، بنابراین مسیری با 1% خطا، بسیار بدتر عمل می‌کند. بسیاری از فایروال‌ها نیز طبق سیاست‌های امنیتی، قطعات IP را مسدود می‌کنند که این نتیجه را به مورد بعدی تبدیل می‌کند.

دور انداخته (Drop) می‌شود و ممکن است به شما اطلاع داده شود یا نشود. روتری که قطعه‌قطعه نمی‌کند، یک پیام ICMP (پروتکل پیام کنترل اینترنت) با عنوان "fragmentation needed" به فرستنده می‌فرستد و MTU قابل پذیرش خود را اعلام می‌کند. اگر آن پیام برسد، کشف مسیر MTU (Path MTU Discovery) کار می‌کند و فرستنده اندازه سگمنت خود را به‌طور خودکار کاهش می‌دهد. بسیاری از شبکه‌ها ICMP را فیلتر می‌کنند، بنابراین اغلب این پیام نمی‌رسد. هیچ چیز دیگری این فقدان را گزارش نمی‌کند. این همان "سیاه‌چاله" (black hole) است: بسته خارج می‌شود، هیچ پاسخی برنمی‌گردد، هیچ خطایی در لاگ‌های هیچ‌کدام از دو طرف ظاهر نمی‌شود و انتقال تا زمان timeout شدن متوقف می‌ماند.

چگونه MTU مناسب را پیدا کنم؟

مسیر را اندازه‌گیری کنید و سپس تفریق را انجام دهید. لایه زیرین (underlay) را به جای تونل تست کنید؛ بنابراین آدرس عمومی سرور را از سمت کلاینت ping کنید و از قطعه‌قطعه شدن (fragmentation) بسته‌ها جلوگیری کنید.

ping -M do -s 1472 -c 3 203.0.113.10

-M do بیت DF (don't fragment) را تنظیم می‌کند، بنابراین هیچ مسیریابی در طول راه اجازه ندارد بسته را خرد کند. -s اندازه payload پروتکل ICMP است. یک بسته کامل IPv4 شامل این payload به اضافه 8 بایت هدر ICMP و 20 بایت هدر IP است، بنابراین -s 1472 دقیقاً 1500 بایت را روی شبکه قرار می‌دهد.

سه نتیجه اهمیت دارند. پاسخ‌های سالم به این معنی است که 1500 بایت جا می‌شود و MTU مشکل شما نیست. خطای محلی به این معنی است که اینترفیس خودتان از مقداری که درخواست کرده‌اید کوچک‌تر است:

ping: local error: message too long, mtu=1500

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

From 203.0.113.1 icmp_seq=1 Frag needed and DF set (mtu = 1492)

از دست رفتن 100 درصد بسته‌ها در اندازه 1472، در حالی که در اندازه‌های کوچک‌تر پاسخ‌های سالم دریافت می‌کنید، نشان‌دهنده وضعیت "سیاه‌چاله" (black hole) است. هیچ مسیریابی به شما اطلاع نمی‌دهد، بنابراین با روش نصف کردن (halving) مرز را پیدا کنید. یک اندازه که می‌دانید کار می‌کند و یک اندازه که می‌دانید شکست می‌خورد را نگه دارید، نقطه میانی را تست کنید و بسته به نتیجه، یکی از مرزها را جابه‌جا کنید. هر دور، محدوده باقی‌مانده را نصف می‌کند، بنابراین پنج یا شش دور کافی است.

یک نمونه عملی از روش دو نیم کردن، مرحله به مرحله

هر خط دستوری است که روی کلاینت به مقصد آدرس عمومی سرور اجرا می‌کنید. بخش توضیحات، نتیجه دریافتی را ثبت می‌کند.

ping -M do -s 1472 -c 3 203.0.113.10   # 100% loss, so 1500 is too big
ping -M do -s 1272 -c 3 203.0.113.10   # replies, so 1300 fits
ping -M do -s 1372 -c 3 203.0.113.10   # replies, so 1400 fits
ping -M do -s 1422 -c 3 203.0.113.10   # 100% loss, so 1450 is too big
ping -M do -s 1397 -c 3 203.0.113.10   # 100% loss, so 1425 is too big
ping -M do -s 1384 -c 3 203.0.113.10   # 100% loss, so 1412 is too big

بزرگ‌ترین payload که عبور کرد 1372 است، بنابراین این مسیر حداقل 1400 بایت و کمتر از 1412 بایت را حمل می‌کند. سمت امن را انتخاب کنید. MTU مسیر برابر 1400 است که با کسر 80 بایت برای کپسوله‌سازی، MTU برای wg0 برابر 1320 می‌شود.

tracepath همین جستجو را به‌صورت خودکار انجام می‌دهد و ارزش دارد پیش از شروع دستی، یک بار آن را اجرا کنید:

tracepath -n 203.0.113.10

آخرین خط آن، مقدار یافته شده را گزارش می‌دهد:

     Resume: pmtu 1492 hops 12 back 12

هر دو ابزار را به عنوان نقطه شروع در نظر بگیرید، نه به عنوان مدرک قطعی. برخی میزبان‌ها نرخ ICMP را محدود کرده یا آن را کاملاً مسدود می‌کنند، بنابراین روش دو نیم کردن ممکن است MTU کوچک‌تری نسبت به ظرفیت واقعی مسیر گزارش دهد. انتقالی که با شکست مواجه می‌شد، تست واقعی است.

ابتدا مقدار را به‌صورت زنده اعمال کنید، زیرا اگر حدس شما اشتباه باشد، تنها با یک دستور قابل بازگشت است:

sudo ip link set mtu 1320 dev wg0

انتقالی که متوقف می‌شد را دوباره امتحان کنید. اگر کامل شد، مقدار را در بلاک [Interface] کلاینت دائمی کنید:

[Interface]
PrivateKey = <client private key>
Address = 10.8.0.2/32
MTU = 1320
sudo wg-quick down wg0 && sudo wg-quick up wg0
ip link show wg0

ip link show wg0 اکنون باید mtu 1320 را چاپ کند. اگر هنوز مقدار قدیمی را چاپ می‌کند، wg-quick فایلی که ویرایش کرده‌اید را نخوانده است. بررسی کنید که /etc/wireguard/wg0.conf را ویرایش کرده‌اید و MTU زیر [Interface] قرار دارد، نه زیر [Peer] که در آنجا نادیده گرفته می‌شود.

MTU ویژگی یک اینترفیس است و هرگز بین همتایان (peers) مذاکره نمی‌شود. تنظیم آن فقط روی کلاینت، بسته‌های ارسالی کلاینت را کوچک می‌کند. سرور همچنان بسته‌ها را با MTU مخصوص wg0 خودش می‌سازد، بنابراین دانلودها ممکن است پس از درست شدن آپلودها، همچنان دچار سیاه‌چاله شوند. مقدار را در هر دو سمت تنظیم کنید یا MSS را روی سرور clamp کنید.

چرا MSS clamping فقط مشکلات TCP را حل می‌کند و نه چیز دیگر

اگر سرور ترافیک همتایان (peers) خود را هدایت (forward) می‌کند، که در هر تنظیمات استاندارد WireGuard روی VPS با استفاده از NAT (ترجمه آدرس شبکه) انجام می‌شود، یک قانون واحد مشکلات TCP را برای همه همتایان حل می‌کند و شما را از جستجوی یک مقدار خاص برای هر کلاینتی که کنترلش در دست شما نیست، بی‌نیاز می‌سازد.

مقدار MSS (حداکثر اندازه سگمنت) یک گزینه در پروتکل TCP است که هر طرف در بسته SYN خود قرار می‌دهد تا اعلام کند مایل به دریافت سگمنتی با چه اندازه‌ای است. عملیات Clamping این گزینه را در حین انتقال بازنویسی می‌کند تا با MTU واقعی مسیر مطابقت داشته باشد؛ بنابراین هر دو طرف پیش از جابه‌جایی داده‌ها، بر سر یک سگمنت کوچک‌تر توافق می‌کنند. این روش به این دلیل کار می‌کند که در حین دست‌دادن (handshake) انجام می‌شود و به پیام‌های ICMP که احتمالاً توسط مسیر فیلتر می‌شوند، وابسته نیست.

با استفاده از nftables، این جدول را در /etc/nftables.conf زیر جدول‌های موجود خود اضافه کنید:

table inet mangle {
  chain forward {
    type filter hook forward priority mangle; policy accept;
    tcp flags syn tcp option maxseg size set rt mtu
  }
}

با sudo systemctl reload nftables تنظیمات را دوباره بارگذاری کنید. در سیستمی که از iptables استفاده می‌کند، معادل آن یک خط دستور است:

sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

تأیید کنید که این قانون در مسیری قرار دارد که بسته‌ها از آن عبور می‌کنند. در حالی که کلاینت اتصالات جدیدی برقرار می‌کند، sudo nft list table inet mangle یا sudo iptables -t mangle -L FORWARD -n -v را اجرا کنید و افزایش شمارنده را مشاهده کنید. اگر شمارنده روی صفر باقی بماند، یعنی بسته‌ها از آن hook عبور نمی‌کنند و قانون عملاً هیچ کاری انجام نمی‌دهد.

و حالا محدودیت‌های واقعی: Clamping فقط TCP را پوشش می‌دهد و نه هیچ پروتکل دیگری؛ همچنین فقط ترافیک هدایت‌شده (forwarded) را شامل می‌شود، بنابراین سرویسی که مستقیماً روی خود سرور WireGuard اجرا می‌شود، هرگز از hook مربوط به forward عبور نمی‌کند و تحت تأثیر clamping قرار نمی‌گیرد. این قانون همچنین فقط بر اتصالاتی که پس از بارگذاری آن برقرار می‌شوند اثر می‌گذارد: نشست‌های موجود، همان MSS که قبلاً بر سر آن توافق کرده‌اند را حفظ می‌کنند.

ترافیک UDP دست‌نخورده باقی می‌ماند، زیرا UDP هیچ دست‌دادنی برای بازنویسی ندارد. اکثر ترافیک‌های UDP به‌هرحال بدون مشکل عبور می‌کنند. پروتکل QUIC که لایه انتقال HTTP/3 است، اندازه بسته قابل‌استفاده خود را بررسی می‌کند و عمداً با اندازه کوچک شروع می‌کند. آنچه عبور نمی‌کند، ترافیک UDP است که یک دیتاگرام بزرگ ارسال می‌کند و انتظار دارد از مسیر عبور کند، مانند پاسخ‌های DNSSEC (افزونه‌های امنیتی DNS) که بیش از 1400 بایت هستند. این پرس‌وجوها با اتمام زمان (timeout) مواجه شده و دوباره از طریق TCP تلاش می‌کنند، که در نهایت برای کاربر به شکل یک سایت کند ظاهر می‌شود تا یک سایت از کار افتاده.

آیا CPU سرور مجازی (VPS) من محدودکننده است؟

پروتکل WireGuard برای رمزنگاری از ChaCha20-Poly1305 و برای تبادل کلید از Curve25519 استفاده می‌کند. در مسیر داده هیچ اثری از AES وجود ندارد و این موضوع یک نتیجهٔ مهم دارد که اغلب اشتباه برداشت می‌شود: دستورالعمل‌های AES-NI در CPU شما هیچ تأثیری بر عملکرد WireGuard ندارند. میزبانی که از AES-NI پشتیبانی می‌کند، قابلیت ویژه‌ای برای افزایش سرعت WireGuard به شما ارائه نمی‌دهد. انتخاب ChaCha20 به این دلیل بوده که در نرم‌افزارهای معمولی، حتی روی CPUهایی که هیچ شتاب‌دهندهٔ رمزنگاری ندارند، بسیار سریع عمل می‌کند.

البته این به معنای رایگان بودن هزینهٔ پردازشی WireGuard نیست. در یک VPS با 1 هستهٔ مجازی (vCPU)، همان یک هسته باید هم‌زمان رمزنگاری و وقایع شبکه (network interrupts) را مدیریت کند، علاوه بر اینکه بار پردازشی برنامه‌های شما نیز روی آن است.

در حین انجام انتقال داده، این موارد را اندازه‌گیری کنید:

sudo apt install -y sysstat
mpstat -P ALL 1

سه ستون را بررسی کنید. %soft زمان softirq است که پردازش بسته‌های شبکه در سطح هسته (kernel) در آنجا انجام می‌شود. %steal زمانی است که هایپروایزر (hypervisor) آن را به پردازش‌های دیگر اختصاص داده است. %idle مقدار باقی‌مانده از توان پردازشی است.

اگر %soft در تنها هستهٔ شما به نزدیک 100 برسد، یعنی سرور به سقف توان پردازش بسته‌های شبکه رسیده است؛ این یک محدودیت واقعی است که با افزایش تعداد هسته‌ها برطرف می‌شود. top در همان لحظه، ksoftirqd/0 را در صدر لیست پردازش‌ها نشان می‌دهد که تأییدکنندهٔ همان یافته از دیدگاهی دیگر است.

اگر %steal بیش از چند درصد باشد، یعنی این محدودیت از دست شما خارج است؛ زیرا میزبان بیش از حد ظرفیت (oversubscribed) فروخته شده و vCPU شما منتظر دریافت زمان از یک هستهٔ فیزیکی است. این وضعیت در ارزان‌ترین پلن‌های اشتراکی رایج است و در طول روز نوسان دارد. Steal time از همسایه‌های پرمصرف (noisy neighbour) نیاز به بررسی جداگانه دارد و هیچ مقدار MTU نمی‌تواند آن را بهبود بخشد.

عامل دیگر، پیاده‌سازی مورد استفاده در کلاینت است. ماژول هستهٔ لینوکس (Linux kernel module) سریع‌ترین مسیر است و رمزنگاری هر peer را بین هسته‌ها توزیع می‌کند. wireguard-go که پیاده‌سازی در فضای کاربری (userspace) است، سرعت کمتری دارد و همان چیزی است که کلاینت‌های macOS و iOS استفاده می‌کنند، زیرا این پلتفرم‌ها اجازه نمی‌دهند یک برنامه، ماژول هسته بارگذاری کند.

آیا مشکل از مسیر است یا لینک خودِ همتا؟

پیش از هرگونه تغییر در تنظیمات، دو عدد را از یک کلاینت با فاصله چند دقیقه یادداشت کنید: نرخ انتقال (throughput) بدون تونل و نرخ انتقال با تونل. بدون این جفت عدد، شما فقط در حال حدس زدن هستید.

دستور iperf3 -s را روی سرور اجرا کنید. تست مستقیم نیازمند دسترسی به پورت TCP 5201 روی آدرس عمومی است؛ بنابراین آن را برای مدت تست باز کنید و پس از پایان، قانون فایروال را حذف کنید. به جای فرض کردن، بسته بودن مجدد پورت را تایید کنید.

# on the client, outside the tunnel
iperf3 -c 203.0.113.10
# then through the tunnel
iperf3 -c 10.8.0.1

اگر این دو عدد به هم نزدیک هستند، WireGuard هزینه ناچیزی برای شما دارد و محدودیت از سمت مسیر شبکه است. اگر عدد مربوط به تونل بسیار کمتر از عدد تست مستقیم است و در عین حال %soft پایین باقی مانده، به سراغ MTU بروید. قطعه‌قطعه شدن بسته‌ها (Fragmentation) بدون اینکه چیزی را از کار بیندازد، نرخ انتقال را کاهش می‌دهد؛ بنابراین در اینجا به صورت افت درصدی ظاهر می‌شود، نه به شکل توقف کامل.

هر دو جهت را تست کنید، زیرا اتصالات خانگی معمولاً نامتقارن هستند. iperf3 -c 10.8.0.1 -R جهت جریان را معکوس می‌کند تا سرور ارسال‌کننده باشد. کلاینتی که روی یک خط 500/20 قرار دارد، هرگز نمی‌تواند بیش از 20 Mbit آپلود خود را به داخل تونل بفرستد و هیچ تغییری در سمت سرور این محدودیت را تغییر نخواهد داد.

سپس با استفاده از جریان‌های موازی (parallel streams) تست کنید:

iperf3 -c 10.8.0.1 -P 4

اگر چهار جریان در کنار هم بسیار بیشتر از یک جریان داده جابه‌جا می‌کنند، یک اتصال TCP واحد در پر کردن مسیر ناتوان است. نرخ انتقال یک جریان توسط پنجره دریافت (receive window) تقسیم بر زمان رفت و برگشت (RTT) محدود می‌شود؛ بنابراین یک مسیر 150 میلی‌ثانیه‌ای برای انتقال داده زیاد، به یک پنجره بزرگ نیاز دارد. محدودیت‌های خود را بخوانید:

sysctl net.ipv4.tcp_rmem net.ipv4.tcp_wmem

مقدار سوم در هر خروجی، حداکثری است که لینوکس به صورت خودکار (autotune) تنظیم می‌کند. از دست رفتن بسته‌ها (Packet loss) نیز یک جریان واحد را به شدت محدود می‌کند، زیرا TCP به از دست رفتن بسته‌ها واکنش نشان می‌دهد و در یک مسیر طولانی، بازیابی داده‌ها پرهزینه است. دستور mtr -rwc 100 203.0.113.10 را از سمت کلاینت برای صد چرخه اجرا کنید تا ببینید افت بسته‌ها در کجای مسیر رخ می‌دهد. افت بسته‌ای که از یک گره (hop) شروع شده و تا گره نهایی ادامه می‌یابد، واقعی است. افت بسته‌ای که فقط در یک گره میانی دیده می‌شود و بعد از آن ناپدید می‌گردد، به این معناست که آن روتر اولویت ICMP را کاهش داده و اهمیت خاصی ندارد.

برای داشتن تصویری قابل تکرار از وضعیت خودِ سرور، مستقل از شبکه، سرور مجازی (VPS) را با یک روش مستند بنچمارک کنید تا بتوانید پس از هر تغییر، همان تست را دوباره اجرا کرده و نتایج را با هم مقایسه کنید.

مواردی که WireGuard قادر به حل آن‌ها نیست

WireGuard یک تونل است. این پروتکل نمی‌تواند سریع‌تر از کندترین لینک در مسیر مورد استفاده‌اش باشد و افزودن آن همیشه مسیر را کمی کندتر می‌کند.

این پروتکل فشرده‌سازی انجام نمی‌دهد. هیچ معادلی برای comp-lzo در OpenVPN وجود ندارد و برنامه‌ای هم برای آن در نظر گرفته نشده است، زیرا فشرده‌سازی پیش از رمزنگاری، اطلاعاتی درباره متن اصلی (plaintext) نشت می‌دهد. اکثر داده‌های حجیم از قبل فشرده شده‌اند، بنابراین در عمل این موضوع هزینه‌ای برای شما ندارد. این یکی از تفاوت‌های واقعی است که هنگام مقایسه WireGuard با OpenVPN باید در نظر بگیرید و یک انتخاب طراحی آگاهانه است.

یک تونل کامل (full tunnel)، مسیری را که هر بسته طی می‌کند تغییر می‌دهد. ترافیکی که قبلاً از شما به یک CDN (شبکه توزیع محتوا) نزدیک می‌رسید، اکنون از شما به VPS و سپس به CDN می‌رود. اگر VPS در قاره دیگری باشد، هر درخواست هزینه این مسیر انحرافی را می‌پردازد و زمان رفت و برگشت (RTT) به همان نسبت افزایش می‌یابد. هیچ مقدار پیکربندی نمی‌تواند این زمان را کوتاه کند. VPS را به خود نزدیک‌تر کنید یا از یک تونل تفکیک‌شده (split tunnel) استفاده کنید تا فقط ترافیکی که به VPN نیاز دارد، مسیر طولانی را طی کند. اینکه کدام ترافیک به کجا برود، کاملاً توسط AllowedIPs تعیین می‌شود و مسیریابی کلید رمزنگاری (cryptokey routing) توضیح می‌دهد که این تصمیم چگونه اتخاذ می‌شود.

محدودیت‌های ارائه‌دهنده سرویس خارج از تونل قرار دارند و فراموش کردن آن‌ها آسان است. طرحی که دارای سقف پهنای باند ماهانه است، اغلب پس از اتمام سقف مجاز، سرعت پورت را به میزان قابل‌توجهی کاهش می‌دهد و در نتیجه تونل قطع به‌نظر می‌رسد. پیش از آنکه یک شب را صرف بررسی MTU کنید، پنل کاربری خود را چک کنید.

PersistentKeepalive بر توان عملیاتی (throughput) تأثیری ندارد. این پارامتر برای باز نگه داشتن نگاشت NAT وجود دارد تا سرور همچنان بتواند به کلاینتی که پشت یک روتر خانگی قرار دارد، دسترسی داشته باشد. کاهش آن به کمتر از 25 ثانیه فقط باعث ارسال بسته‌های اضافی می‌شود و هیچ مشکلی را حل نمی‌کند.

اندازه‌گیری به این ترتیب

  1. مشکل را بازتولید کنید و یادداشت کنید که آیا با یک توقف (hang) مواجه هستید یا یک کندی یکنواخت. توقف معمولاً به MTU اشاره دارد، اما کندی یکنواخت خیر.
  2. با استفاده از ping -M do از کلاینت به آدرس عمومی سرور، عملیات bisect را انجام دهید و Path MTU را یادداشت کنید.
  3. عدد 80 را از آن کم کنید، MTU حاصل را روی wg0 در هر دو سمت تنظیم کنید و انتقال فایلی که با شکست مواجه می‌شد را دوباره تست کنید.
  4. اگر سرور ترافیک را برای peerها فوروارد می‌کند، MSS clamping را روی آن فعال کنید.
  5. در حین انتقال فایل، mpstat -P ALL 1 را اجرا کنید و مقادیر %soft و %steal را بخوانید.
  6. دستور iperf3 را هم خارج از تونل و هم داخل آن، در هر دو جهت، به صورت تک‌جریان (single stream) و با استفاده از -P 4 اجرا کنید.
  7. دستور mtr -rwc 100 را به سمت سرور اجرا کنید و به دنبال افت بسته‌ای (loss) باشید که تا آخرین hop ادامه دارد.

تنها زمانی طرح (plan) سرور را تغییر دهید که مرحله 5 نشان دهد CPU به سقف توان خود رسیده است. مراحل 1 تا 4 هزینه‌ای ندارند و اکثر گزارش‌های مربوط به کندی تونل را برطرف می‌کنند.

FAQ

چرا تونل WireGuard من برای ping سریع است اما برای دانلود کند؟

این تفاوت، نشانهٔ وجود مشکل در MTU است. بسته‌های کوچک در تمام لینک‌های مسیر جا می‌شوند، بنابراین ping و ورود SSH به‌خوبی کار می‌کنند. انتقال‌های حجیم، سگمنت‌هایی با اندازهٔ کامل ارسال می‌کنند؛ نسخهٔ کپسوله‌شدهٔ این سگمنت‌ها از ظرفیت برخی لینک‌ها بزرگ‌تر است. اگر روتر آن بسته‌ها را بدون بازگرداندن پیام ICMP حذف کند، هیچ‌چیز گزارش خطا نمی‌دهد و انتقال متوقف می‌شود. MTU مسیر را با یک جستجوی دودویی (bisection) توسط ping -M do به آدرس عمومی سرور پیدا کنید، 80 بایت برای کپسوله‌سازی از آن کم کنید و نتیجه را به‌عنوان MTU در رابط wg0 در هر دو سمت تنظیم کنید.

چه مقدار MTU باید برای WireGuard تنظیم کنم؟

عدد ثابتی وجود ندارد و دقیقاً به همین دلیل است که مقدار پیش‌فرض 1420 برای برخی افراد کار نمی‌کند. عدد 1420 حاصل تفریق 80 بایت (شامل هدر WireGuard، هدر UDP و هدر خارجی IPv6) از 1500 است. اگر مسیر شما کمتر از 1500 بایت را پشتیبانی می‌کند—که در اتصالات PPPoE DSL و هر جایی که ترافیک شما از تونل دیگری عبور می‌کند رایج است—باید از مقدار کوچک‌تری استفاده کنید. ابتدا MTU مسیر خود را اندازه بگیرید و سپس 80 بایت از آن کم کنید.

آیا MSS clamping جایگزین تنظیم MTU می‌شود؟

خیر. Clamping گزینهٔ MSS را در دست‌دادن (handshake) پروتکل TCP بازنویسی می‌کند تا هر دو سمت سگمنت‌های کوچک‌تری ارسال کنند؛ این کار مشکل TCP را بدون دست‌کاری رابط شبکه حل می‌کند. پروتکل UDP دست‌دادنی برای بازنویسی ندارد، بنابراین تحت تأثیر قرار نمی‌گیرد. همچنین Clamping فقط برای ترافیکی اعمال می‌شود که سرور آن را هدایت (forward) می‌کند، بنابراین سرویسی که مستقیماً روی خودِ سرور WireGuard اجرا می‌شود از آن بهره‌ای نمی‌برد. از هر دو روش استفاده کنید: یک MTU صحیح روی رابط شبکه، و Clamping برای پوشش دادن کلاینت‌هایی که پیکربندی آن‌ها در کنترل شما نیست.

آیا پلن VPS سریع‌تر، WireGuard را سریع‌تر می‌کند؟

فقط اگر محدودیت از سمت CPU باشد، و یک دستور این موضوع را به شما می‌گوید. در حین انجام انتقال داده، mpstat -P ALL 1 را اجرا کنید. اگر %soft در تنها هستهٔ پردازندهٔ شما نزدیک به 100 باشد، یعنی پردازش بسته‌ها گلوگاه است و هسته‌های بیشتر مشکل را حل می‌کند. مقدار بالای %steal نشان می‌دهد که میزبان (host) بیش از حد ظرفیت خود سرویس‌دهی می‌کند (oversubscribed)، بنابراین تغییر پلن یا تغییر میزبان راه‌حل است. اگر در حین کندی تونل، هر دو عدد پایین باشند، CPU بیکار است و ارتقای پلن هیچ تغییری ایجاد نخواهد کرد.

چرا مک من نسبت به کلاینت لینوکسی در همان شبکه کندتر است؟

کلاینت لینوکس از ماژول WireGuard در سطح هسته (kernel) استفاده می‌کند که بسته‌ها را در فضای هسته پردازش کرده و رمزنگاری هر peer را بین هسته‌های CPU پخش می‌کند. برنامه‌های macOS و iOS از wireguard-go استفاده می‌کنند که یک پیاده‌سازی در فضای کاربری (userspace) است، زیرا این پلتفرم‌ها اجازه نمی‌دهند یک برنامه ماژول هسته بارگذاری کند. فضای کاربری هر بسته را بین هسته و برنامه کپی می‌کند و این کپی‌کردن باعث کاهش نرخ انتقال (throughput) می‌شود. این اختلاف مورد انتظار است و هیچ تنظیماتی در کلاینت نمی‌تواند آن را برطرف کند.