NGINX স্ট্রিম রিলে দিয়ে SSH — না ভেঙে
PROXY হেডার এমন এক প্রাপকের জন্য বার্তা যে এটি আশা করে, আর প্রক্সি করা DNS রেকর্ড কোনো TCP রিলে নয়। প্রান্ত ও আপস্ট্রিম আলাদাভাবে ঠিক করুন।
রিলের মাধ্যমে পাবলিক SSH দুটি সম্পর্কহীন সীমায় ব্যর্থ হয়, আর একটি ঠিক করলে সাধারণত অন্যটি প্রকাশ পায়। হয় প্রান্ত স্ট্রিম বহনের বদলে একটি HTTP প্রতিক্রিয়া ফেরত দেয়, নয়তো রিলে এমন একটি হেডার সামনে বসায় যা ব্যাকএন্ড কখনো পড়তে রাজি হয়নি। তিনটি শর্ত ঠিক করে আপনি কোনটি দেখছেন: পাবলিক রেকর্ড আসলে কীসের দিকে ইঙ্গিত করে, স্ট্রিম ব্লক আপস্ট্রিমে কী পাঠায়, এবং SSH ক্লায়েন্ট কোন নাম যাচাই করে। এই ক্রমেই সেগুলো দেখুন।
দুটি সীমা, দুটি লক্ষণ
প্রান্তের ব্যর্থতা দেখতে এমনভাবে লাগে যেন SSH ব্যানারের জায়গায় একটি HTTP স্ট্যাটাস পৃষ্ঠা আসছে। সংযোগ TCP স্তরে সম্পন্ন হয় এবং প্রথম বাইটগুলো ওয়েব সার্ভারের টেক্সট। এটি প্রোটোকল অসঙ্গতি, হারানো প্যাকেট নয়। এটি আরও বলে যে প্রান্ত ওই নামের জন্য সচেতনভাবেই অন্য কিছু পরিবেশন করছে।
আপস্ট্রিমের ব্যর্থতা ভিন্ন দেখায়। সংযোগ sshd-তে পৌঁছায়, sshd এমন বাইট পড়ে যা তার প্রত্যাশিত পরিচয় বিনিময় নয়, এবং সেশনটি কোনো কী না দিয়েই মরে যায় বা আটকে থাকে।
এই দুটিকে গুলিয়ে ফেলা সহজ, কারণ দুটিই এমন ক্লায়েন্ট দেয় যা সংযোগ করে তারপর ব্যর্থ হয়। আপনি যে প্রথম প্রোটোকল প্রতিক্রিয়া পান সেটিই তাদের আলাদা করে, তাই এটিই টিকিটে থাকা উচিত।
PROXY হেডার একটি বার্তা, কোনো টগল নয়
স্ট্রিম মডিউলে proxy_protocol on NGINX-কে নির্দেশ দেয় পেলোডের আগে আপস্ট্রিমের দিকে একটি PROXY প্রোটোকল হেডার লেখার জন্য। এটি TCP প্রক্সিং চালু করে না, এবং SSH এনক্রিপশনের সঙ্গে এর কোনো সম্পর্ক নেই। এটি প্রাপকের উদ্দেশে একটি নোট। প্রাপক যদি এটি পড়তে না পারে, তবে তা স্ট্রিমের শুরুতে আবর্জনা হয়ে যায়।
গ্রহণকারী সেবাকে সেই হেডার সচেতনভাবেই গ্রহণ করতে হবে। সাধারণ sshd সংযোগের প্রথম বাইট হিসেবে SSH পরিচয় বিনিময় আশা করে, তাই অপ্রত্যাশিত প্রস্তাবনা হ্যান্ডশেক ভেঙে দেয় এমনভাবে যা নষ্ট সার্ভারের মতো দেখায়।
stream {
server {
listen 2222;
proxy_pass 10.77.0.20:22;
}
}
VPN জুড়ে পৌঁছানো ব্যাকএন্ডের জন্য ওই টুকরোটিই সম্পূর্ণ কার্যকর রিলে। কোনো PROXY নির্দেশনা দেখা যায় না কারণ প্রাপক প্রোটোকলটি বোঝে না, আর এই অনুপস্থিতি বাদ দেওয়া নয়, একটি সিদ্ধান্ত।
দুই দিকও আলাদা করুন। listen লাইনে proxy_protocol সেট করা মানে NGINX আশা করে তার নিজের ক্লায়েন্ট আগে হেডার পাঠাবে; সাধারণ SSH ক্লায়েন্টের জন্য এটি চালু করা ঠিক তার উল্টোটা ঘটায় যা মানুষ সাধারণত সমাধান করতে চায়।
পাবলিক হোস্টনেম আসলে কী পর্যন্ত পৌঁছায়
SSH সেশনে একটি HTTP 400 পৃষ্ঠা প্রান্ত সম্পর্কে প্রমাণ। পথের মধ্যে কিছু HTTP বলে, এবং ব্যাকএন্ডে কী বা অ্যাকাউন্ট নিয়ে যতই কাজ করুন তা বদলাবে না। প্রান্ত নিষ্পত্তি না হওয়া পর্যন্ত ব্যাকএন্ড বদলানো বন্ধ করুন।
Cloudflare-এর সাধারণ প্রক্সি করা রেকর্ড নির্দিষ্ট পোর্টে তার সমর্থিত HTTP ও HTTPS ট্রাফিক বহন করে। একটি হোস্টনেমের জন্য প্রক্সি চালু করা সাধারণ TCP রিলে তৈরি করে না, আর SSH-কে 443 পোর্টে সরানো তা HTTPS করে না।
দুটি কার্যকর দিক আছে। শুধু DNS রেকর্ড আপনার নিজের TCP রিলের দিকে ইঙ্গিত করতে পারে, যা প্রকাশের সিদ্ধান্ত আপনার হাতে রাখে। বিকল্পভাবে, এমন পণ্য ব্যবহার করুন যা SSH বহন স্পষ্টভাবে নথিভুক্ত করে, নিজস্ব অরিজিন, ক্লায়েন্ট ও অ্যাক্সেস কনফিগারেশনসহ।
যেটিই বেছে নিন, রিলের তবুও ব্যাকএন্ডে একটি VPN রুট, অনুমোদিত সংযোগ এবং ফেরত পথ দরকার। রুটটি ঐচ্ছিক নয়, কারণ পাবলিক দিকটি কাজ করে।
অ্যালিয়াসের মাধ্যমে SSH পরিচয় স্থিত রাখুন
ব্যবহারকারীরা সাধারণত তাদের বিদ্যমান হোস্টনেম টাইপ করতে চান। একটি SSH কনফিগ অ্যালিয়াস রিলে সম্পর্কে কিছু না বদলেই তা করতে পারে, এবং পরিবর্তনটি ক্লায়েন্টের দিকে রাখে যেখানে তা থাকা উচিত।
Host git.example.com
HostName ssh-entry.example.net
Port 2222
User git
HostKeyAlias git.example.com
HostKeyAlias ছাড়া OpenSSH যে নামে সংযোগ করে সেই নামেই হোস্ট কী খোঁজে, তাই এন্ট্রিটি সরে যায় এবং প্রত্যেক ব্যবহারকারী প্রথম ব্যবহারেই কী-পরিবর্তনের সতর্কতা দেখেন। অ্যালিয়াস সেট করলে known-hosts এন্ট্রি স্থিত থাকে, আর সংযোগ তবুও রিলেতে যায়।
এই অ্যালিয়াস কেবল SSH-ভিত্তিক রিমোটের ক্ষেত্রে প্রযোজ্য। একটি HTTPS Git URL এটি দেখে না, এবং সাধারণ রিমোট URL আপনার প্রকৃতপক্ষে প্রস্তুত করা ট্রান্সপোর্টের সঙ্গে মিলতে হবে।
যা করা উচিত নয় তা হলো সতর্কতাটি সরাতে হোস্ট কী যাচাই বন্ধ করা। এতে এমন একটি সুরক্ষা সরে যায় যা ফরওয়ার্ডিং মেরামত কখনো স্পর্শ করতে বলেনি, এবং এটি একটি চেহারার অসুবিধাকে সত্যিকারের ঝুঁকিতে পরিণত করে।
প্রতিটি হপ আলাদাভাবে যাচাই করুন
পাবলিক লিসেনার একা পরীক্ষা করুন, তারপর রিলে হোস্ট থেকে রিলে-থেকে-ব্যাকএন্ড সংযোগ, এবং কেবল তারপর ক্লায়েন্টকে শুরু থেকে শেষ পর্যন্ত। ওই তিনটি পরীক্ষার প্রতিটি ভিন্ন স্তর বাদ দেয়। একটি বাদ দিলে বাকি দুটি ফলাফল ব্যাখ্যা করা যায় না। তিনটি পর্যবেক্ষণ, ব্যর্থতা থাকতে পারে এমন তিনটি জায়গা।
প্রতিটি ফলাফলের সঙ্গে গন্তব্য ঠিকানা, পোর্ট এবং প্রথম প্রোটোকল বাইট রাখুন। এই ত্রয়ী প্রান্তের ত্রুটিকে VPN রাউটিং সমস্যা ও SSH প্রমাণীকরণ ব্যর্থতা থেকে আলাদা করে, এবং এটিই মেরামত ও অনুমানের মধ্যে পার্থক্য।
সবশেষে, অভিপ্রেত প্রকাশ নথিভুক্ত করুন। একটি TCP রিলে যা ব্যক্তিগত ব্যাকএন্ডে SSH বহন করে তা পাবলিক পরিধিতে সচেতন একটি দ্বার, এবং এটি অন্য যেকোনো আগমনকারী সেবার মতোই পর্যালোচনার যোগ্য।