همه سامانه‌ها عملیاتی هستند 6 منطقه آفشور پرداخت بدون KYC
Hands-on راهنمای میدانی

پنهان نگه داشتن IP مبدأ: یک reverse proxy آفشور که دوام می‌آورد

همه یک نصیحت را تکرار می‌کنند — یک CDN جلویش بگذارید و سرور واقعی ناپدید می‌شود. اما این‌طور نیست. آدرس مبدأ (origin) در بایگانی‌های DNS منفعل، در لاگ‌های شفافیت گواهی (certificate transparency)، در هدرهای همان ایمیل خروجیِ خودتان، و در هر درخواستی که اپلیکیشن‌تان به دنیای بیرون می‌فرستد، زنده می‌ماند. این راهنما نسخه‌ای می‌سازد که واقعاً دوام می‌آورد: یک گرهٔ لبه (edge) از $8.00 در ماه در منطقه‌ای متفاوت، یک تونل WireGuard، یک مبدأ بدون هیچ شنوندهٔ عمومی — و جست‌وجوهایی که بعدتر برای پیداکردنِ باکس‌های خودمان اجرا می‌کنیم.

به‌روزرسانی‌شده در 2026-09-02 · 15 دقیقه مطالعه · عملیات ناوگان
در این صفحه
  1. پنهان کردن مبدأ واقعاً چه چیزی نصیبتان می‌کند
  2. هر راهی که IP مبدأ از آن نشت می‌کند
  3. دو شکل از لبه: یک CDN، یا باکسی که خودتان مالکش هستید
  4. تونل همان بخشی است که مردم اشتباه می‌گیرند
  5. گواهی‌ها، و لاگی که نام‌های میزبان شما را منتشر می‌کند
  6. ایمیل، و بقیهٔ سرویس‌هایی که روی آدرس اشتباه پاسخ می‌دهند
  7. Egress: اتصال‌هایی که مبدأ شما آغاز می‌کند
  8. چقدر هزینه دارد، و چطور ثابت کنید که کار می‌کند
  9. گام‌به‌گام
SP·01

پنهان کردن مبدأ واقعاً چه چیزی نصیبتان می‌کند

سه چیز، و ارزش دارد دربارهٔ آن‌ها دقیق بود. اول، سیل حملات دیگر به ماشینی نمی‌رسد که توان جذبش را ندارد: یک VPS تنها یک آپلینک (uplink) با ظرفیت محدود دارد، و وقتی آدرسی که بسته‌ها را می‌بلعد یک لبهٔ ساخته‌شده برای همین کار باشد نه همان باکسی که پایگاه‌دادهٔ شما را نگه می‌دارد، یک حملهٔ حجمی به مسئلهٔ مهندسیِ یک نفر دیگر تبدیل می‌شود. دوم، اپلیکیشن دیگر با دورزدنِ دفاع‌های خودش قابل‌دسترس نیست — محدودیت‌های نرخ، قوانین ضدربات، یک WAF و مسدودسازی جغرافیایی، همه را هرکسی که بتواند مستقیماً به مبدأ متصل شود به‌سادگی دور می‌زند، و بیشتر کسانی که این‌ها را مستقر می‌کنند هرگز بررسی نمی‌کنند که آیا این کار هنوز ممکن است یا نه. سوم، آدرسی که محتوای شما را سرویس می‌دهد دیگر همان آدرسی نیست که داده‌های شما را نگه می‌دارد، و همین جدایی است که باعث می‌شود یک شکایت سوءاستفاده، یک اسکن یا یک کاوش هدفمند، جایی ارزان و قابل‌جایگزین فرود بیاید.

و حالا نیمهٔ صادقانه‌اش. پنهان‌کردن یک مبدأ ناشناسی نیست — یک آدرس را پنهان می‌کند، نه یک شخص را، و ردِ پرداخت، ثبت دامنه و حسابِ پشتِ این‌ها، مسئله‌ای جداست که راهنمای مخصوص خودش را دارد. اپلیکیشن شما را وصله نمی‌زند: یک مبدأ که هیچ‌کس نمی‌تواند پیدایش کند، به‌محض اینکه کسی پیدایش کند همچنان قابل‌اکسپلویت است، و مبدأها واقعاً پیدا می‌شوند. هیچ‌چیزی را از ارائه‌دهندهٔ شما پنهان نمی‌کند، که طبق تعریف می‌داند کدام ماشین روی کدام آدرس پاسخ می‌دهد. با آن مثل یک لایه رفتار کنید که هزینهٔ یک حمله را بالا می‌برد، لایه‌ای روی باکسی که از قبل درست‌وحسابی سخت‌سازی شده — نه جایگزینی برای هیچ‌کدام.

SP·02

هر راهی که IP مبدأ از آن نشت می‌کند

دلیل اینکه این‌همه مبدأِ «پنهان‌شده» واقعاً پنهان نیستند این است که آدم‌ها یک کانال را می‌بندند و فرض می‌کنند بقیه هم به همان راه رفته‌اند. این‌طور نیست. این فهرستی است که ما مرور می‌کنیم، تقریباً به ترتیب اینکه هرکدام چند بار واقعاً کار دست کسی داده‌اند:

  • DNS تاریخی. جمع‌آورهای DNS منفعل مدت‌ها پیش از آنکه پشت یک پروکسی بروید، رکورد A شما را ثبت می‌کرده‌اند. آدرسی که سال گذشته استفاده می‌کردید، یک جست‌وجوی دائمی، قابل‌جست‌وجو و رایگان است.
  • شفافیت گواهی. هر گواهیِ عمومیِ مورد‌اعتماد در لاگ‌های عمومیِ append-only منتشر می‌شود، همراه با هر نام میزبانی که پوشش می‌دهد. گواهی‌ای که برای origin.example.com صادر شده، این نام را به دنیا اعلام می‌کند، و رکورد A آن بقیهٔ کار را انجام می‌دهد.
  • ساب‌دامین‌هایی که هرگز جابه‌جا نشدند. mail، ftp، webmail، cpanel، dev، staging، vpn، monitor — دامنهٔ اصلی پشت CDN رفت و این‌ها همچنان به سمت همان باکس اشاره می‌کردند.
  • ایمیل. یک رکورد MX روی مبدأ، آدرس را مستقیماً لو می‌دهد؛ یک هدر Received: در ایمیلی که اپلیکیشن شما فرستاده هم همین کار را می‌کند، و هرکسی می‌تواند آن را با یک فرم بازنشانیِ رمز عبور فعال کند.
  • درخواست‌های خروجی. webhookها، دریافت آواتار، خواندن RSS، پیش‌نمایش لینک، بررسی به‌روزرسانی، callbackهای OAuth. هرکدام آدرس مبدأ را به هرکس که سرِ دیگر را اداره می‌کند لو می‌دهد — و یک قابلیتِ پیش‌نمایش URL به یک مهاجم اجازه می‌دهد آن سرِ دیگر را خودش انتخاب کند.
  • پاسخ‌دادن روی آدرس لخت. اگر مبدأ همچنان به درخواستی بدون هدر Host مطابق، سایت شما را سرویس بدهد، اسکنرهای سراسر اینترنت از قبل آن را ایندکس کرده‌اند: هش favicon، عنوان صفحه، اثر انگشت گواهی و ترتیب هدرهای HTTP، همه قابل‌جست‌وجو هستند.
  • رکورد IPv6ای که فراموشش کردید. رکورد A به سمت پروکسی رفت؛ رکورد AAAA همچنان به خانه اشاره می‌کند.
  • اپلیکیشنی که دربارهٔ خودش حرف می‌زند. URLهای absolute در تنظیمات یک CMS، ریدایرکت به یک نام میزبانِ داخلی، stack traceها، بنرهای Server، source mapها، یک نقطهٔ پایانیِ وضعیت بدون احراز هویت.

توجه کنید بیشتر این‌ها چه وجه مشترکی دارند: آن‌ها دائمی هستند. لاگ‌های گواهی append-only هستند و DNS منفعل یک بایگانی است. شما نمی‌توانید آدرسی را که یک‌بار منتشر شده پس بگیرید — تنها می‌توانید دیگر از آن استفاده نکنید، و دقیقاً به همین دلیل است که ترتیب کارها در ادامه اهمیت دارد.

SP·03

دو شکل از لبه: یک CDN، یا باکسی که خودتان مالکش هستید

یک CDN تجاری ظرفیت anycastی به شما می‌دهد که هیچ سرور تکی نمی‌تواند با آن برابری کند، در ده‌ها شهر، اغلب حتی روی یک پلن رایگان. بهایش این است که TLS روی زیرساختی terminate می‌شود که شما کنترلش نمی‌کنید: اپراتور متنِ سادهٔ (plaintext) شما را می‌بیند، می‌داند متعلق به کدام حساب است، و می‌تواند بر اساس همین دانش مجبور به اقدام شود یا صرفاً یک روز صبح تصمیم بگیرد که محتوای شما خوش‌آمد نیست. یک مشکل ظریف‌تر هم هست که مخصوص جلوبندهای مشترک است — اگر فایروال مبدأ شما بازهٔ آدرس‌های منتشرشدهٔ آن CDN را مجاز کند، آنگاه هرکس دیگری که روی همان CDN حساب داشته باشد داخل allowlist شما قرار می‌گیرد و می‌تواند نام میزبان خودش را به سمت مبدأ شما نشانه بگیرد. این یک دورزدنِ واقعی است، نه نظری، و دقیقاً به همین دلیل است که origin pull با احراز هویت وجود دارد.

لبه‌ای که خودتان اجرایش می‌کنید، بهای معکوس را دارد. هیچ‌کس جز شما کلید خصوصی را در دست ندارد، باکس در حوزهٔ قضایی‌ای می‌نشیند که خودتان عامدانه انتخابش کرده‌اید، و برای کوچک‌ترین پلن $8.00 در ماه هزینه دارد — واقعاً یک خطای گرد‌کردن است در برابر چیزی که از آن محافظت می‌کند. چیزی که به دست نمی‌آورید anycast است: یک سیل 200 Gbpsی، فارغ از اینکه پیکربندی nginx شما چقدر شیک باشد، آپلینک لبه را اشباع می‌کند، پس جذب در سطح شبکه باید از جایی دیگر بیاید. در مورد ما، آن جای دیگر 1.5 Tbps کاهش حملهٔ بالادست است که جلوی تک‌تک ماشین‌های ناوگان قرار دارد، و همین است که یک لبهٔ خوداجراشونده را به‌جای یک نقطهٔ شکستِ واحد، عملی می‌کند. این دو شکل با هم هم ترکیب می‌شوند: CDN جلو برای دسترسی و حجم، گرهٔ خودتان پشت آن برای همان بخشی که حاضر نیستید تحویل بدهید. بر اساس اینکه کدام شکست را ترجیح می‌دهید توضیح دهید، انتخاب کنید.

SP·04

تونل همان بخشی است که مردم اشتباه می‌گیرند

راه‌اندازی رایج این است که مبدأ روی 0.0.0.0:443 گوش می‌دهد و یک فایروال آدرس‌های پروکسی را در allowlist می‌گذارد. کار می‌کند، و همین ضعیف‌ترین حلقهٔ کل طراحی است. Allowlistها دستخوش drift می‌شوند — بازه‌های منتشرشده تغییر می‌کنند و به‌روزرسانی هیچ‌وقت اعمال نمی‌شود؛ مشترک‌اند، پس روی یک CDN عمومی هر مشتری دیگری را هم می‌پذیرند؛ و درست از همان جهتی شکست می‌خورند که اهمیت دارد، چون مبدأ در تمام این مدت همچنان یک شنوندهٔ عمومیِ زنده است، منتظر یک پیکربندی غلط یا یک ufw disable در میانهٔ یک نشستِ عیب‌یابی.

نسخه‌ای که دوام می‌آورد، دقیقاً برعکس این است: مبدأ اصلاً هیچ شنوندهٔ عمومی‌ای ندارد. یک تونل WireGuard میان لبه و مبدأ برقرار می‌شود، وب‌سرور فقط به آدرس تونل بایند می‌شود، و رابط عمومی روی هر دو خانوادهٔ IP یک سیاست default-deny دارد، بدون هیچ استثنایی برای 80 یا 443. آنگاه دسترس‌پذیری دیگر قانونی نیست که کسی ممکن است فراموش کند تمدیدش کند — بلکه نبودِ یک مسیر است. WireGuard ابزار درستی برای این کار است چون یک ماژول کرنل با سطح حملهٔ بسیار کوچک است، در برابر اسکنرهای بدون‌احراز‌هویت ساکت می‌ماند (یک بستهٔ بدون‌احراز‌هویت اصلاً هیچ پاسخی نمی‌گیرد، پس پورت UDP حتی به‌نظر هم نمی‌رسد وجود داشته باشد)، و هزینه‌اش چند میکروثانیهٔ تک‌رقمی به‌ازای هر بسته است. اگر پیش از این یکی را راه‌اندازی نکرده‌اید، راهنمای WireGuard مبانی را پوشش می‌دهد؛ اینجا فقط به یک پیوند نقطه‌به‌نقطه با دو همتا نیاز داریم.

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

SP·05

گواهی‌ها، و لاگی که نام‌های میزبان شما را منتشر می‌کند

شفافیت گواهی واقعاً چیز خوبی است که با کمال میل هفتهٔ شما را خراب می‌کند. هر گواهی‌ای که یک CA عمومی صادر می‌کند به لاگ‌های append-onlyای فرستاده می‌شود که هرکسی می‌تواند در آن‌ها جست‌وجو کند، و آن ورودی شامل تک‌تک نام‌های درون گواهی است. برای origin.example.com یا direct.example.com یکی صادر کنید و همین نام میزبانی را که سعی داشتید تبلیغ نکنید، به‌شکلی دائمی و ساختاریافته منتشر کرده‌اید. بدتر اینکه، عادتِ گذاشتنِ نام‌های میزبانِ staging و مدیریتی در همان یک لیست SAN، یک تمدیدِ بی‌دقت را به یک نقشه از زیرساخت شما تبدیل می‌کند.

نظم لازم ساده است. گواهی‌های عمومی فقط روی لبه زندگی می‌کنند، و فقط همان نام‌هایی را پوشش می‌دهند که عموم واقعاً استفاده می‌کند. مبدأ یک گواهی خودامضا می‌گیرد یا یکی از یک CA خصوصیِ کوچک، که با proxy_ssl_trusted_certificate در پیکربندی پروکسی پین شده — چیزی روی پیوندی که فقط پروکسیِ خودتان با آن حرف می‌زند، نیازی به مورد‌اعتماد‌عمومی‌بودن ندارد، و صدور یک گواهی عمومی برایش چیزی جز یک ورودی در یک لاگ نصیبتان نمی‌کند. اگر به ساب‌دامین‌های عمومیِ زیادی نیاز دارید، یک گواهی wildcard به‌جای سی نام، یک نام منتشر می‌کند. و ACME را روی چالش DNS-01 تنظیم کنید: چالش HTTP-01 نیاز دارد چیزی روی پورت 80 برای همان نام میزبانی که در حال اعتبارسنجی است پاسخ بدهد، که دقیقاً همان شنوندهٔ عمومی‌ای است که همین الان حذفش کردید. در آخر، این عدمِ تقارن را بپذیرید — لاگ‌ها append-only هستند، پس نام میزبانی که یک‌بار منتشرش کرده‌اید دیگر قابل‌پس‌گرفتن نیست. اگر به مبدأ resolve می‌شده، مبدأ به یک آدرس تازه نیاز دارد.

SP·06

ایمیل، و بقیهٔ سرویس‌هایی که روی آدرس اشتباه پاسخ می‌دهند

ایمیل کلاسیک‌ترین راه دور زدن است، چون طبق تعریف باید در دسترس باشد. اگر رکورد MX دامنهٔ شما به مبدأ اشاره کند، بازی پیش از شروع تمام شده — آن رکورد عمومی است و یک dig به کل شکار پایان می‌دهد. حتی با MXای در جای دیگر، اپلیکیشنی که مستقیماً از مبدأ ایمیل می‌فرستد، آدرس میزبانِ فرستنده را در زنجیرهٔ Received: هر پیام مهر می‌زند، و هر فرمی که به تقاضا برای یک کاربر ایمیل بفرستد، همین را به یک جست‌وجوی خودسرویس تبدیل می‌کند. راه‌حل این است که مبدأ را یک کلاینت کنید و هرگز یک سرور: ایمیل خروجی را از طریق یک سرویس submission یا یک باکسِ جدا relay کنید، MX را روی ماشینی نگه دارید که اجازه دارد پیدا شود، و پیش از آنکه کارش را تمام‌شده اعلام کنید، هدرهای کامل یک پیام آزمایشی را بخوانید. اجرای ایمیل خودتان در مقیاس، خودش یک پروژهٔ جداست، و جایش روی ماشینی که در حال پنهان‌کردنش هستید نیست.

سپس یک جست‌وجوی کامل برای هر چیز دیگری انجام دهید که بی‌سروصدا در حال گوش‌دادن است. عامل‌های مانیتورینگ، داشبوردهای کانتینر، پورت‌های پایگاه‌داده‌ای که "موقتاً" باز شده‌اند، یک نقطهٔ پایانی متریک روی 9100، یک پنل کنترل روی یک پورت بالا، یک دیمن SSH روی رابط عمومی. هرکدام از این‌ها یک سرویس است که روی همان آدرسی پاسخ می‌دهد که سعی دارید خصوصی نگهش دارید، و اسکنرها پورت‌های بالا را به همان راحتیِ پورت‌های پایین پیدا می‌کنند. ممیزی‌اش یک دستور است — ss -tulpn — و خروجیِ درست فهرستی است که در آن هیچ‌چیز به یک آدرس عمومی بایند نیست. مرحلهٔ سومِ زیر همان چیزی است که این را درست می‌کند و درست نگهش می‌دارد.

SP·07

Egress: اتصال‌هایی که مبدأ شما آغاز می‌کند

یک مبدأ که هیچ‌چیز را نمی‌پذیرد، همچنان می‌تواند خودش را لو بدهد، چون فقط اتصال دریافت نمی‌کند — اتصال هم باز می‌کند. Mirrorهای پکیج، NTP، یک webhook به یک پردازشگر پرداخت، یک API ربات، تصویری که برای پیش‌نمایش لینک گرفته می‌شود، یک بررسیِ مجوز، یک نشستِ SMTP خروجی، یک Git remote، یک گزارش‌دهندهٔ خطا. برای سرِ دیگرِ هرکدام از این‌ها، آدرس عمومیِ مبدأ چیزی نیست جز آدرس فرستندهٔ آن اتصال. بیشتر اوقات این بی‌ضرر است، چون خودتان سرِ دیگر را انتخاب کرده‌اید و به آن اعتماد دارید. مشکل، همان تعداد اندکی نقطهٔ پایانی است که یک مهاجم انتخاب می‌کند: یک لینک را در هر چیزی که پیش‌نمایش رندر می‌کند بچسبانید، یک webhook ثبت کنید، یا یک server-side request forgery در یک واردکنندهٔ تصویر پیدا کنید، آنگاه مبدأ resolve می‌شود و به میزبانی متصل می‌شود که مهاجم زیر نظر دارد. این یک ناشناسی‌زدایی دو‌دقیقه‌ای است، بدون آنکه هیچ اکسپلویتی درکار باشد.

دو پاسخ قابل‌دفاع وجود دارد. پاسخ سخت‌گیرانه، تمام egress را از روی تونل عبور می‌دهد و می‌گذارد لبه آن را NAT کند، پس آدرس فرستندهٔ خروجیِ مبدأ همان آدرس لبه می‌شود — یک تنظیم در پیکربندی peer، به‌علاوهٔ forwarding و یک قاعدهٔ masquerade در سرِ دیگر. wg-quick حلقهٔ مسیریابی را خودش برایتان مدیریت می‌کند: با یک مسیر 0.0.0.0/0، یک قاعدهٔ fwmark نصب می‌کند تا بسته‌های خودِ تونل همچنان مستقیم به نقطهٔ پایانی برسند، که دقیقاً همان بخشی است که آدم‌ها وقتی مسیرها را دستی می‌نویسند خرابش می‌کنند. پاسخ عمل‌گرایانه، egress مستقیم را برای ترافیکی که خودتان کنترلش می‌کنید نگه می‌دارد و جلوی هر چیزی که یک URLِ ارائه‌شده از سمت کاربر را می‌گیرد، یک پروکسی می‌گذارد. آنچه قابل‌دفاع نیست، ندانستنِ این است که کدام‌یک از این دو را دارید. عامدانه تصمیم بگیرید، سپس آن را با یک درخواست به میزبانی که خودتان مالکش هستید و نگاهی به آدرس فرستنده در لاگ‌های آن تأیید کنید.

SP·08

چقدر هزینه دارد، و چطور ثابت کنید که کار می‌کند

ردیف بودجه، یک VPS اضافه است. کوچک‌ترین پلن با $8.00 در ماه، TLS را terminate می‌کند و برای یک سایت کوچک پروکسی می‌کند بدون آنکه اصلاً بار را حس کند — یک reverse proxy در اصل چیزی نیست جز کپی‌کردنِ یک سوکت، و 2 vCPU با 4 گیگابایت RAM، راحت خیلی جلوتر از نقطه‌ای است که مبدأِ پشتش تبدیل به گلوگاه شود. آن را در منطقه‌ای متفاوت از مبدأ قرار دهید تا یک سند حقوقیِ واحد یا یک مشکل در یک تأسیساتِ واحد، به هر دو نرسد، و تأخیر را هم فراموش نکنید: یک پرشِ اضافه، میلی‌ثانیه‌های واقعی اضافه می‌کند، پس یک لبه در آمستردام جلوی یک مبدأ در کوالالامپور، یک تصمیم طراحی است، نه یک تصادف. جفت‌های داخل یک قاره معمولاً چند میلی‌ثانیهٔ تک‌رقمی هزینه دارند، و استفادهٔ مجددِ نشستِ TLS که روی لبه به دست می‌آورید، اغلب همان را در یک بارگذاریِ واقعیِ صفحه پس می‌دهد.

ثابت‌کردنِ اینکه کار می‌کند، همان بخشی است که یک پیکربندی را از یک کنترل جدا می‌کند، و این یک کارِ تکرارشونده است نه یک‌بارمصرف — هر ساب‌دامین تازه، هر گواهی تازه، هر یکپارچه‌سازیِ تازه، یک فرصت تازه برای بازمنتشرکردنِ آن آدرس است. مجموعه‌آزمون‌های مرحلهٔ هفت حدود ده دقیقه طول می‌کشد: سعی کنید مستقیماً روی آدرس مبدأ به سایت خودتان برسید، هر نام میزبانی را که تابه‌حال گواهی گرفته‌اید فهرست کنید، نام‌های بدیهیِ ساب‌دامین را پیمایش کنید، رکورد AAAAای را که فراموش کرده بودید بررسی کنید، و برای خودتان یک ایمیل بفرستید. آن را بعد از هر تغییر زیرساختی اجرا کنید. و همین‌طور که این کار را می‌کنید، نتیجه را هم به‌خاطر داشته باشید: اگر مبدأ پاسخ بدهد، راه‌حل درست یک قانون فایروال دیگر نیست — یک آدرس تازه است، چون آدرس قدیمی از قبل در بایگانیِ یک نفر هست. در این پشته، این لایه بعد از سخت‌سازی و در کنار بک‌آپ‌های خارج از سایت می‌نشیند: سخت‌سازی تعیین می‌کند شکستنِ باکس چقدر سخت است، بک‌آپ‌ها تعیین می‌کنند چقدر سریع بازیابی می‌کنید، و این یکی از همان اول تعیین می‌کند پیداکردنِ باکس چقدر سخت است.

SP·09

گام‌به‌گام

  1. 01

    لبه را مستقر کنید و دقیقاً یک کار به آن بدهید

    یک VPS دوم را در منطقه‌ای مستقر کنید که مبدأ در آن زندگی نمی‌کند، و با آن مثل یک دستگاه تک‌منظوره رفتار کنید: کاری که TLS را terminate می‌کند، یک reverse proxy، و نه چیز دیگری. نه پایگاه‌داده‌ای، نه کد اپلیکیشنی، نه اسکریپت‌های شلی که دلتنگشان شوید. چک‌لیست اولین ساعت را روی آن اجرا کنید — SSH فقط‌با‌کلید، فایروال default-deny روی هر دو خانوادهٔ IP، به‌روزرسانی‌های امنیتیِ بدون‌دخالت — سپس دقیقاً سه پورت باز کنید.

    ssh root@198.51.100.20
    apt update && apt full-upgrade -y
    hostnamectl set-hostname edge-01
    apt install -y nginx wireguard-tools ufw unattended-upgrades
    
    ufw default deny incoming && ufw default allow outgoing
    ufw limit 22/tcp
    ufw allow 80,443/tcp
    ufw allow 51820/udp
    ufw --force enable
  2. 02

    پیش از دست‌زدن به DNS، تونل را بالا بیاورید

    دو همتا، یک پیوند. روی هر ماشین یک جفت‌کلید تولید کنید و به تونل زیرشبکهٔ کوچک خودش را بدهید — مبدأ در نهایت فقط روی 10.66.0.2 در دسترس خواهد بود و هیچ‌جای دیگر. مبدأ به سمت لبه dial out می‌کند (همان طرفی است که هیچ پورت بازی نخواهد داشت)، پس Endpoint و یک keepalive را حمل می‌کند؛ لبه فقط گوش می‌دهد.

    # on both machines
    umask 077; wg genkey | tee privkey | wg pubkey > pubkey
    
    # edge-01 — /etc/wireguard/wg0.conf
    [Interface]
    Address = 10.66.0.1/24
    ListenPort = 51820
    PrivateKey = <edge-privkey>
    
    [Peer]
    PublicKey = <origin-pubkey>
    AllowedIPs = 10.66.0.2/32
    
    # origin-01 — /etc/wireguard/wg0.conf
    [Interface]
    Address = 10.66.0.2/24
    PrivateKey = <origin-privkey>
    
    [Peer]
    PublicKey = <edge-pubkey>
    Endpoint = 198.51.100.20:51820
    AllowedIPs = 10.66.0.1/32
    PersistentKeepalive = 25

    آن را در هر دو سر فعال کنید و پیش از هر کار دیگری دست‌دادن را تأیید کنید — تونلی که فقط تا ری‌بوتِ بعدی کار می‌کند، بدتر از نداشتنِ هیچ تونلی است.

    systemctl enable --now wg-quick@wg0
    wg show          # expect a recent handshake and non-zero transfer
    ping -c3 10.66.0.1   # from the origin
  3. 03

    مبدأ را از اینترنت عمومی غیرقابل‌دسترس کنید

    این همان مرحله‌ای است که کار واقعی را انجام می‌دهد، و همان مرحله‌ای که آدم‌ها در آن خودشان را بیرون قفل می‌کنند. یک نشست دومِ SSH باز کنید و پیش از اجرای هر چیزی در ادامه، آن را متصل نگه دارید — اینجا هیچ کنسول پشتیبانی‌ای نیست که بتوانید به آن پناه ببرید. سپس وب‌سرور را به آدرس تونل bind کنید، هر چیزی روی رابط عمومی را رها کنید، و فقط تونل به‌علاوهٔ خودِ نقطهٔ پایانیِ WireGuard را مجاز کنید.

    # /etc/nginx/sites-available/app  — listen on the tunnel only
    listen 10.66.0.2:8080;
    
    ufw --force reset
    ufw default deny incoming
    ufw default allow outgoing
    ufw allow in on wg0 to any port 8080 proto tcp
    ufw allow in on wg0 to any port 22 proto tcp
    ufw allow from 198.51.100.20 to any port 51820 proto udp
    ufw --force enable
    
    # the audit: nothing may be bound to a public address
    ss -tulpn | grep -Ev '10\.66\.0\.2|127\.0\.0|\[::1\]'

    اگر آن دستور آخر یک سرویس را چاپ کند، یعنی یک نشتی دارید — آدرس bind را درست کنید، نه اینکه دور آن یک قانون فایروال اضافه کنید. دو شنونده اجازه دارند دوام بیاورند: WireGuard روی 51820، و sshd اگر هنوز آن را به داخل تونل منتقل نکرده‌اید.

  4. 04

    TLS را روی لبه terminate کنید و از روی تونل proxy کنید

    گواهیِ عمومی را روی لبه صادر کنید، برای همان نام‌هایی که عموم واقعاً استفاده می‌کند، و به سمت آدرس تونل، upstream proxy کنید. بلوکِ سرورِ دوم یک تزیینِ اختیاری نیست: همان چیزی است که جلوی لبه را می‌گیرد از اینکه سایت شما را به اسکنری سرویس بدهد که با IP و بدون هدر Host متصل می‌شود، که دقیقاً همین‌طوری درِ ورودی اثرانگشت‌گیری می‌شود.

    # edge-01 — /etc/nginx/sites-available/example.com
    server {
        listen 443 ssl;
        http2 on;
        server_name example.com www.example.com;
    
        ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
        add_header Strict-Transport-Security "max-age=63072000" always;
    
        location / {
            proxy_pass http://10.66.0.2: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;
            proxy_http_version 1.1;
        }
    }
    
    # anything that is not a known hostname gets nothing at all
    server {
        listen 80 default_server;
        listen 443 ssl default_server;
        ssl_reject_handshake on;
        return 444;
    }
  5. 05

    IP واقعیِ کلاینت را به مبدأ برگردانید

    پشتِ یک پروکسی، هر درخواست از 10.66.0.1 می‌رسد. اگر دست‌نخورده رهایش کنید، لاگ‌های access شما بی‌فایده می‌شوند، محدودیت نرخِ به‌ازای هر IP به‌جای مهاجم، تونل را خفه می‌کند، و fail2ban دیر یا زود لبه را بن می‌کند و سایت را می‌خواباند — یک راهِ واقعاً محبوب برای ایجاد یک outage درست وسط سخت‌سازی. به هدرِ forward شده اعتماد کنید، اما فقط از آدرس تونل، هرگز از باقیِ دنیا.

    # origin-01 — /etc/nginx/conf.d/realip.conf
    set_real_ip_from 10.66.0.1;
    real_ip_header   X-Forwarded-For;
    real_ip_recursive off;

    معادلش را در اپلیکیشن هم انجام دهید — ProxyFix در Flask، TRUSTED_PROXIES در Laravel، set_real_ip_from به‌علاوهٔ فهرستِ trusted-proxy خودِ فریم‌ورک — و محدودیت نرخ را روی لبه بگذارید، همان‌جایی که آدرس واقعیِ کلاینت به‌شکل native وجود دارد:

    # edge-01 — /etc/nginx/nginx.conf (http block)
    limit_req_zone $binary_remote_addr zone=front:10m rate=20r/s;
    # then, inside the location block
    limit_req zone=front burst=40 nodelay;
  6. 06

    ایمیل و egress را از روی آدرس مبدأ جابه‌جا کنید

    MX را به‌سمت ماشینی نشانه بگیرید که اجازه دارد پیدا شود، ایمیل خروجی را از طریق یک relay بفرستید نه مستقیماً از مبدأ، و تمدید گواهی را روی چالش DNS-01 تنظیم کنید تا چیزی مجبور نباشد روی پورت 80 پاسخ بدهد. سپس تصمیم بگیرید با باقیِ ترافیک خروجی چه می‌کنید. برای عبوردادنِ همهٔ آن از میان لبه، AllowedIPs مبدأ را گسترده‌تر کنید و بگذارید لبه masquerade کند — wg-quick همان قاعدهٔ fwmark را نصب می‌کند که خودِ تونل را قابل‌دسترس نگه می‌دارد، پس لازم نیست خودتان دستی برای نقطهٔ پایانی یک مسیر بنویسید.

    # origin-01 — /etc/wireguard/wg0.conf, in [Peer]
    AllowedIPs = 0.0.0.0/0, ::/0
    
    # edge-01 — forward and NAT the tunnel
    echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/99-fwd.conf && sysctl --system
    ufw route allow in on wg0 out on eth0
    # in /etc/ufw/before.rules, above the *filter block:
    # *nat
    # :POSTROUTING ACCEPT [0:0]
    # -A POSTROUTING -s 10.66.0.0/24 -o eth0 -j MASQUERADE
    # COMMIT
    systemctl restart ufw && wg-quick down wg0 && wg-quick up wg0

    سپس آن را از روی مبدأ بررسی کنید: curl -s https://ifconfig.co باید آدرس لبه را برگرداند، نه آدرس خودش را.

  7. 07

    به‌دنبال مبدأ خودتان بگردید، سپس runbook را بنویسید

    همان‌طور به آن حمله کنید که یک نفر دیگر می‌کرد. اولین دستور همان دستورِ مهم است — اگر مبدأ وقتی مستقیماً آدرس‌دهی شود همچنان سایت شما را سرویس بدهد، هیچ‌کدام از موارد بالا هنوز کار نمی‌کند.

    # does the origin answer for your hostname?
    curl -sk --resolve example.com:443:203.0.113.10 https://example.com/ \
         -o /dev/null -w '%{http_code}\n'      # want: a timeout, not 200
    
    # every hostname you have ever certified, from the public logs
    curl -s 'https://crt.sh/?q=%25.example.com&output=json' \
      | grep -o '"name_value":"[^"]*"' | sort -u
    
    # records that never moved
    dig +short example.com A; dig +short example.com AAAA; dig +short example.com MX
    for h in www mail ftp webmail cpanel dev staging vpn monitor origin direct; do
      printf '%-9s %s\n' "$h" "$(dig +short $h.example.com | tr '\n' ' ')"
    done

    سپس از طریق اپلیکیشن برای خودتان یک ایمیل بفرستید و زنجیرهٔ کاملِ Received: را بخوانید، و یک لینک به میزبانی که خودتان کنترلش می‌کنید در هر قابلیتی که پیش‌نمایش رندر می‌کند بچسبانید و ببینید کدام آدرس آن را گرفته است. برای هر بررسی، بنویسید یک نتیجهٔ درست چه شکلی است، و کل مجموعه را بعد از هر تغییرِ DNS، هر گواهیِ تازه و هر یکپارچه‌سازیِ تازه دوباره اجرا کنید. اگر هرکدام از آن‌ها مبدأ را نشان داد، آن را روی یک آدرس تازه از نو بسازید — آدرسِ منتشرشده از قبل بایگانی شده، و هیچ قانونِ فایروالی آن را پس نمی‌گیرد.

SP·10 — پرسش‌های متداول

پاسخ‌های سریع

آیا خودِ یک CDN به‌تنهایی کافی نیست؟

فقط اگر مبدأ واقعاً بدون آن قابل‌دسترسی نباشد، و به‌صورت پیش‌فرض هست. یک CDN فقط جای اشارهٔ DNS شما را عوض می‌کند؛ شنوندهٔ عمومیِ مبدأ را حذف نمی‌کند، آدرس را از بایگانی‌های DNS منفعل پس نمی‌گیرد، رکورد MX شما را جابه‌جا نمی‌کند، و اپلیکیشن شما را از فرستادنِ درخواست‌های خروجی باز نمی‌دارد. نتیجهٔ معمول، سایتی است که پروکسی شده و همچنان به‌سادگی resolve می‌شود. یک CDN جلوبندِ خوبی است — اگر ظرفیتش را می‌خواهید یکی جلوی لبه بگذارید — اما ویژگی‌ای که واقعاً می‌خواهید همان چیزی است که در مرحلهٔ سه آمد: مبدأ اصلاً هیچ مسیری از اینترنت عمومی ندارد، پس چیزی برای دور زدن وجود ندارد.

آیا پنهان‌کردنِ IP مبدأ من را ناشناس می‌کند؟

نه، و یکی‌گرفتنِ این دو، دقیقاً همان چیزی است که آدم‌ها را به یک حسِ امنیتِ کاذب می‌رساند. این کار یک آدرس را پنهان می‌کند. هویت شما از کانال‌هایی کاملاً متفاوت نشت می‌کند: ثبت دامنه، روش پرداخت، حسابی که با آن ثبت‌نام کرده‌اید، و عادت‌های عملیاتی‌ای که این‌ها را به هم پیوند می‌دهند. میزبانی نزد ما برخی از این‌ها را ذاتاً می‌بندد — ثبت‌نام یعنی یک هندل و یک رمز عبور، تأمین مالی یعنی یک موجودیِ رمزارزیِ پیش‌پرداخت، و هیچ مدرک هویتی در هیچ‌جای این چرخه نیست — اما ردِ دامنه و ردِ پرداخت را خودتان باید مدیریت کنید. دور نگه داشتن نامتان از یک سرور آن سمت قضیه را درست‌وحسابی پوشش می‌دهد.

پرشِ اضافه چقدر تأخیر اضافه می‌کند؟

دقیقاً همان رفت‌وبرگشتِ میان لبه و مبدأ، پس این یک تصمیمِ محل‌قرارگیری است، نه یک مالیاتِ ثابت. دو منطقهٔ اروپایی معمولاً در حدِ چند میلی‌ثانیهٔ تک‌رقمیِ پایین هستند؛ آمستردام تا کوالالامپور این‌طور نیست، و نباید آن جفت را تصادفی طراحی کنید. بخشی از آن هم برمی‌گردد: لبه، TLS را نزدیکِ بازدیدکننده terminate می‌کند و یک اتصالِ گرم به مبدأ نگه می‌دارد، پس بارگذاری‌های اولی که پر از دست‌دادن‌اند اغلب بهتر می‌شوند. اگر به تأخیر حساس هستید، لبه را نزدیکِ بازدیدکنندگان‌تان بگذارید و مبدأ را نزدیکِ لبه، و با بارگذاری‌های واقعیِ صفحه اندازه بگیرید، نه با پینگ.

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

سایت از کار می‌افتد، چون مبدأ عامدانه هیچ راه ورودِ دیگری ندارد — این طراحی است، نه یک باگ. با آن مثل هر نقطهٔ شکستِ واحدِ دیگری رفتار کنید: دو لبه در مناطق متفاوت اجرا کنید با هر دو آدرس در DNS، و فهرست peer مبدأ را طوری نگه دارید که هر دو را در خودش داشته باشد. اگر wg-quick@wg0 را فعال کرده باشید، تونل بعد از یک ری‌بوت خودش برمی‌گردد، پس شکستِ معمولی خودش را حل می‌کند. کاری که هرگز نباید بکنید این است که در طول یک incident یک شنوندهٔ عمومیِ موقت روی مبدأ اضافه کنید؛ شش ماه دیگر هم همان‌جا خواهد بود، و تا آن موقع آن آدرس اسکن و بایگانی شده خواهد بود.

آیا می‌توانم این کار را با یک سرور انجام دهم؟

نه به‌شکلی که واقعاً معنا داشته باشد. یک reverse proxy روی همان ماشین هیچ‌چیز را پنهان نمی‌کند — آدرسی که پاسخ می‌دهد همان آدرسی است که سعی داشتید پنهانش کنید. صادقانه‌ترین نسخهٔ ارزان، یک VPS دومِ $8.00 در ماه است که کاری جز terminate کردنِ TLS نمی‌کند، و همان نسخه‌ای هم هست که در آن یک سیل یا یک شکایت سوءاستفاده روی باکسی فرود می‌آید که می‌توانید در 15 min بدون دست‌زدن به داده‌هایتان جایگزینش کنید. تنها جایگزینِ واقعیِ تک‌ماشینه، منتشرکردن به‌شکل یک سرویس پیازیِ Tor است، که اصلاً به هیچ آدرس عمومی‌ای نیاز ندارد؛ این یک محصولِ متفاوت برای مخاطبی متفاوت است، نه یک جایگزینِ آماده برای یک وب‌سایتِ عمومی.

IP مبدأ من از قبل عمومی است. آیا دیگر دیر شده؟

برای همان آدرس، بله — بایگانی‌های DNS منفعل و لاگ‌های گواهی دائمی‌اند و هیچ سازوکارِ پس‌گرفتنی وجود ندارد. اما راه‌حلش ارزان است: اول لبه و تونل را بسازید، یک مبدأِ تازه روی یک آدرسِ نو مستقر کنید، به آن مهاجرت کنید، و ماشینِ قدیمی را نابود کنید. هر چیزی که منتشر شده به آدرسی اشاره می‌کند که دیگر هیچ‌چیز روی آن اجرا نمی‌شود. آن را دقیقاً به همین ترتیب انجام دهید، چون برپاکردنِ یک مبدأ تازه پیش از آنکه تونل وجود داشته باشد، صرفاً یک آدرس دوم را منتشر می‌کند. و از این فرصت استفاده کنید تا همان نشتی‌ای را که اولی را لو داد هم برطرف کنید — وگرنه سال دیگر دوباره همین کار را می‌کنید.

آن را به عمل درآورید

VPS ظرف 15 min آنلاین، اختصاصی ظرف 2–12 h تحویل داده می‌شود. از $30.00 با کریپتو شارژ کنید — بدون هویت پیوست‌شده.

استقرار یک VPS