ট্রেনে থাকা ফোন থেকে একটি অনুরোধকে এমন ব্যাকএন্ড পর্যন্ত অনুসরণ করুন যা কেবল ব্যক্তিগত নেটওয়ার্কের ভেতরে বিদ্যমান। ফোন একটি প্রকাশ্য নাম সমাধান করে, পোর্ট 443-এ একটি প্রকাশ্য ঠিকানার সঙ্গে সংযুক্ত হয় এবং সাধারণ TLS হ্যান্ডশেক সম্পন্ন করে। Nginx সেই সংযোগ গ্রহণ করে আর তারপর দ্বিতীয়, সম্পূর্ণ আলাদা সংযোগ খোলে এমন ঠিকানার দিকে যেখানে সে কেবল VPN ইন্টারফেস দিয়ে পৌঁছায়। ফোনে কিছুই বদলায় না, এবং ফোন কখনও জানে না যে একটি টানেল জড়িত ছিল।

একটি অনুরোধকে দুটি সংযোগ দিয়ে অনুসরণ করা

আসা অংশটি একটি প্রকাশ্য HTTP লেনদেন। এর একটি প্রকাশ্য নাম, একটি প্রকাশ্য সার্টিফিকেট এবং একটি প্রতিক্রিয়া পথ আছে যা সেই মুহূর্তে দর্শকের যে কোনো ঠিকানার জন্য কাজ করতে হবে। সেই পথ নষ্ট করে এমন যেকোনো পরিবর্তন একসঙ্গে সব দর্শককে ভেঙে দেয়। এজন্য প্রকাশ্য অংশটিই সেই অংশ যেখানে আপনি সবচেয়ে কম পরীক্ষা করতে চান।

যাওয়া অংশটি ব্যক্তিগত। Nginx ক্লায়েন্ট হয়ে ওঠে, একটি অভ্যন্তরীণ নাম সমাধান করে বা নির্দিষ্ট ঠিকানা ব্যবহার করে, এবং এমন সেবায় পৌঁছায় যা ইন্টারনেট থেকে আসা সংযোগ প্রত্যাখ্যান করত।

Public client  -> frontend public address:443   (TLS, public name)
Frontend       -> VPN private backend 10.40.0.20:8443  (TLS, private name)

এগুলো মনের মধ্যে আলাদা রাখুন আর কনফিগারেশন স্বতঃস্পষ্ট হয়ে যায়। এগুলো মিলিয়ে দিলে শেষে আপনি একটি প্রকাশ্য ক্লায়েন্টকে টানেলে অংশগ্রহণ করানোর চেষ্টা করবেন, এবং এই নকশার বেশিরভাগ বিভ্রান্তি সেখান থেকেই আসে। ব্যক্তিগত অংশটি ভঙ্গুর হতে পারে। প্রকাশ্য অংশটি নয়।

এর কিছু বানানোর আগে নিশ্চিত করুন যে অ্যাপ্লিকেশন প্রকাশ করা ইচ্ছাকৃত। কাজ করা প্রক্সি একটি কাজ করা প্রকাশও, এবং প্রমাণীকরণ মডেলকে সিদ্ধান্ত হতে হবে, পার্শ্বপ্রতিক্রিয়া নয়।

গেটওয়ের নামকে টানেল থেকে বেঁচে থাকতে হবে

নাম সমাধানে একটি সূক্ষ্ম ফাঁদ আছে। যদি ব্যক্তিগত DNS সেই একই নাম পরিবর্তন করে যা VPN প্রোফাইল নিজের গেটওয়ের জন্য ব্যবহার করে, তাহলে পুনরায় সংযোগ শেষে সেই গেটওয়ে পর্যন্ত সেই টানেল দিয়েই পৌঁছানোর চেষ্টা করতে পারে যা তাকে নিজেই তৈরি করতে হবে। ক্লায়েন্টের এই নাম টানেল অস্তিত্বে আসার আগেই সমাধান হওয়া দরকার। একবার এটি টানেলের ভেতরে সমাধান হলে সংযোগ আর কখনও তৈরি করা যায় না।

গেটওয়ে ও ব্যাকএন্ডের জন্য আলাদা অনুমোদিত নাম ব্যবহার করুন, এবং সমাধানকারীর নীতি এমনভাবে সীমিত করুন যাতে প্রতিটি নাম তার গ্রাহকের প্রয়োজনীয় ঠিকানায় সমাধান হয়। কোনো অ্যাপ্লিকেশনের Host হেডার বদলালে এখানে কিছুই হয় না, কারণ অনুসন্ধানটি VPN ক্লায়েন্ট করে।

তারপর পরিধি নিয়ে ভাবুন। ফ্রন্টএন্ডের ব্যাকএন্ডের ঠিকানা পর্যন্ত একটি পথ দরকার, এবং তাকে প্রকাশ্য ক্লায়েন্টদের উত্তর দিতে থাকতেও হবে। ওই হোস্টে সম্পূর্ণ টানেল প্রথম শর্ত পূরণ করে দ্বিতীয়টি ভেঙে দিতে পারে।

যেখানে নীতি অনুমতি দেয়, সেখানে নির্দিষ্ট গন্তব্যের টানেল বেশি পরিষ্কার নকশা। যেখানে নীতি সম্পূর্ণ টানেল বাধ্যতামূলক করে, সেখানে ফ্রন্টএন্ড আলাদা নেটওয়ার্ক প্রসঙ্গে থাকে, পরিচিত দর্শকদের জন্য অস্থায়ী পথ দিয়ে তালি দেওয়া হয় না।

সার্ভার ব্লকটি এমনভাবে লিখুন যাতে দুই অংশই যাচাই করে

ধরে নিন ব্যাকএন্ড এই নামের জন্য সার্টিফিকেট উপস্থাপন করে: backend.corp.example এবং ব্যক্তিগত ঠিকানায় উত্তর দেয়। নাম যাচাই করতে করতে কোনো ঠিকানায় সংযুক্ত হওয়াই ঠিক সেই কাজ যার জন্য প্রক্সি মডিউলের SNI ও নামের অপশনগুলি আছে।

upstream private_app {
    server 10.40.0.20:8443;
}

server {
    listen 443 ssl;
    server_name app.example.com;

    ssl_certificate     /etc/nginx/tls/app-fullchain.pem;
    ssl_certificate_key /etc/nginx/tls/app-key.pem;

    location / {
        proxy_pass https://private_app;
        proxy_ssl_server_name on;
        proxy_ssl_name backend.corp.example;
        proxy_ssl_trusted_certificate /etc/nginx/trust/backend-ca.pem;
        proxy_ssl_verify on;
        proxy_ssl_verify_depth 3;

        proxy_set_header Host app.example.com;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-For $remote_addr;
    }
}

উপরের প্রতিটি পথ ও ঠিকানা একটি প্লেসহোল্ডার। গুরুত্বপূর্ণ সেই অংশগুলি যা যাচাই চালু রাখে: যাচাই করার একটি নাম, তার বিরুদ্ধে যাচাই করার একটি ট্রাস্ট বান্ডল, এবং অনুমোদিত চেইনের সঙ্গে মেলানো গভীরতা।

proxy_set_header Host app.example.com ইচ্ছাকৃত। ব্যাকএন্ডকে এই প্রকাশ্য উৎস গ্রহণ করার জন্য কনফিগার করা উচিত, এবং তাকে কেবল এই ফ্রন্টএন্ড থেকে পাঠানো হেডারেই বিশ্বাস করা উচিত। এর ওপরে লেখা X-Forwarded-For ক্লায়েন্ট ঠিকানা দিয়ে একটি প্রক্সির জন্য সঠিক এবং চেইনের জন্য ভুল, তাই বহু-প্রক্সি স্থাপনার নিজস্ব বিশ্বস্ত ঠিকানা ব্যবস্থা দরকার।

প্রকাশ্য উৎসকে প্রকাশ্য উৎসের মতো আচরণ করানো

অ্যাপ্লিকেশনকে প্রকাশ্য উৎসের জন্য পরম URL, রিডাইরেক্ট ও কুকি তৈরি করতে হবে। যদি সে কোনো দর্শককে এখানে পাঠায়: backend.corp.example, তবে সেই দর্শক এমন নামে পাঠানো হয় যা সে সমাধান করতে পারে না।

এটি অ্যাপ্লিকেশনের সমর্থিত বাহ্যিক URL সেটিং এবং পর্যালোচিত রিডাইরেক্ট নীতি দিয়ে ঠিক করুন, প্রতিক্রিয়া বডিতে হোস্ট নাম আবার লিখে নয়। নির্বিচার কনটেন্টে স্ট্রিং প্রতিস্থাপন স্বাক্ষরিত পেলোড ভাঙে এবং খুঁজে পাওয়া কঠিন বাগ তৈরি করে।

কুকিও একই যত্নের যোগ্য। ব্যক্তিগত নামে সীমিত কুকি কেবল প্রকাশ্য নাম জানে এমন ব্রাউজার কখনও পাঠাবে না।

এটাও নিশ্চিত করুন যে Nginx সত্যিই প্রকাশ্য সকেটের মালিক হতে পারে। 443-এ থাকা বিদ্যমান ওয়েব সেবাকে সরতে হবে বা ফ্রন্টএন্ডকে অন্য জায়গায় থাকতে হবে, কারণ দুটি প্রক্রিয়া একই ঠিকানা ও পোর্ট বাঁধতে পারে না।

প্রতিটি অংশ সেখানেই যাচাই করুন যেখানে সে সত্যিই চলে

যেকোনো পুনঃলোডের আগে কনফিগারেশনটি স্থাপিত পার্সার দিয়ে বৈধ করুন, যাতে টাইপিংয়ের ভুল এখন সেবা দিচ্ছে এমন শ্রোতাকে ফেলে না দেয়।

তারপর ব্যাকএন্ডের অংশটি ফ্রন্টএন্ড হোস্ট থেকেই, Nginx যে একই নেটওয়ার্ক প্রসঙ্গে ব্যবহার করে সেখানেই পরীক্ষা করুন। টানেল দিয়ে ping পৌঁছানো প্রমাণ করে আর TLS, অনুমোদন বা অ্যাপ্লিকেশন সম্পর্কে কিছুই নয়।

শেষে আসল হোস্ট নামে সাধারণ সার্টিফিকেট যাচাই নিয়ে নতুন প্রকাশ্য অনুরোধ করুন, এবং কেবল প্রতিক্রিয়া বডি নয় প্রতিক্রিয়া পথ লক্ষ্য করুন।

দুটি পর্যবেক্ষণই স্থাপিত কনফিগারেশনের সঙ্গে রাখুন এবং লিখে রাখুন টানেল অনুপলব্ধ হলে কী হয়। ফ্রন্টএন্ডকে নিয়ন্ত্রিত upstream ত্রুটি ফেরানো উচিত, নয়তো কেউ নথিভুক্ত করেনি এমন অন্য ব্যাকএন্ডে চুপচাপ পড়ে যাওয়া উচিত নয়। স্পষ্ট লগ লাইনসহ 502 ভালো ফলাফল। অনিচ্ছাকৃত উৎস থেকে ক্যাশ করা পৃষ্ঠা তা নয়।

সম্পর্কিত নিবন্ধ