CGNAT এড়াতে VPS reverse tunnel কীভাবে সেটআপ করবেন
CGNAT-এর কারণে port forwarding কাজ না করলে frp দিয়ে home box থেকে সস্তা VPS-এ outbound tunnel বানান, public প্রান্তে HTTPS ও আসল certificate চালানোর ধাপ দেখুন।
CGNAT-এর পেছনে port forwarding কেন কাজ করে না
CGNAT (carrier-grade network address translation)-এর পেছনে আপনার router-এর WAN address অন্য গ্রাহকদের সঙ্গে ভাগ করা থাকে। তাই কোনো public IP আপনার জন্য নির্দিষ্ট থাকে না এবং forward করার মতো কোনো port-ও থাকে না। একটি reverse tunnel এই সমস্যা সমাধান করে: একটি কম খরচের VPS public IP ধরে রাখে, আপনার home box VPS-এ outbound connection স্থাপন করে, এবং inbound request home box আগে থেকে খোলা সেই connection দিয়েই ফিরে আসে। আপনি আগে থেকেই থাকা hardware ব্যবহার করতে পারেন। ISP যে একমাত্র জিনিসটি আপনাকে দেবে না, সেটি ভাড়া নেন: একটি routable address।
নিচের প্রতিটি command কোন machine-এ চালাতে হবে তা উল্লেখ করা আছে। এর জন্য দুটি machine প্রয়োজন: public IP-সহ VPS এবং আপনি যে service-এ পৌঁছাতে চান সেটি চালানো home box।
CGNAT-এর পেছনে আছেন কি না তা কীভাবে বুঝবেন
আপনার router-এর admin page খুলে সেখানে দেখানো WAN address দেখুন। এরপর Internet-কে জিজ্ঞাসা করুন, সেটি কোন address দেখতে পাচ্ছে।
# on the home box
curl -4 -s https://ifconfig.me; echoদুটি address মিললে আপনার একটি public IP আছে এবং এর কোনোটিই আপনার প্রয়োজন নেই। Port forward করে পড়া বন্ধ করুন। router-এর WAN address যদি 100.64.0.0/10-এর মধ্যে থাকে, তাহলে আপনি CGNAT-এর পেছনে আছেন। এটি RFC 6598-এর shared address space, যা ঠিক এই ব্যবহারের জন্য সংরক্ষিত। কিছু ISP এর পরিবর্তে WAN পাশে 10.0.0.0/8 দেয়। Label ভিন্ন হলেও পরিস্থিতি একই।
কোনো কিছু rent করার আগে একটি বিষয় পরীক্ষা করুন। অনেক CGNAT ISP একটি বাস্তব IPv6 prefix দেয়। আপনার home box-এ global IPv6 address থাকলে সেই address-এর জন্য firewall খুলে সম্পূর্ণ tunnel এড়িয়ে যেতে পারেন। কোনো visitor IPv4-only network-এ থাকলেই এটি কাজ করা বন্ধ করে। তাই শেষ পর্যন্ত বেশিরভাগ মানুষ এখানেই আসে।
VPS reverse tunnel কীভাবে কাজ করে, ভেতর থেকে বাইরে সংযোগ শুরু করে
CGNAT এবং সাধারণ home router উভয়ই অননুমোদিত inbound connection আটকে দেয়। Corporate firewall-ও একই কাজ করে। তবে এগুলোর কোনোটিই outbound connection আটকায় না, কারণ প্রতিটি browser এবং update client সারা দিন outbound connection ব্যবহার করে। কোনো NAT device একটি outbound TCP connection শনাক্ত করলে সেটির জন্য একটি mapping তৈরি করে এবং সেই connection-এর return traffic অনুমোদন করে। বাইরের কোনো সিস্টেম আপনার home box-এ connection শুরু করতে পারে না। তাই home box-ই connection শুরু করে, এবং tunnel সেই একই connection-এর বিপরীত দিকে traffic ফিরিয়ে আনে।
এটাই পুরো প্রক্রিয়া। home box একটি port ব্যবহার করে VPS-এ outbound connection তৈরি করে এবং connection-টি খোলা রাখে। VPS public request গ্রহণ করে এবং বিদ্যমান connection ব্যবহার করে সেগুলো home box-এ পাঠায়। কেউ কখনো আপনার home IP address-এ সরাসরি পৌঁছানোর চেষ্টা করে না। তাই সেটির প্রয়োজনও হয় না।
এর ফলে দুটি বিষয় ঘটে, এবং দুটিই উপকারী। আপনার DNS record VPS-এর address-এ নির্দেশ করে, আপনার বাড়ির address-এ নয়। আপনার public address-ও এখন VPS-এর address। তাই কোনো observer IP lookup থেকে যা জানতে পারে, তা আপনার home line-এর বদলে একটি rented server সম্পর্কে জানতে পারে।
এটি তৈরির তিনটি উপায়
ssh -R: উভয় প্রান্তে আগে থেকেই ইনস্টল করা থাকে এবং একটি service বা অস্থায়ী demo-এর জন্য উপযুক্ত। এতে কোনো dashboard নেই এবং কার্যকর reconnection logic-ও নেই।- frp: একটি ছোট Go server (
frps) এবং এর সঙ্গে সামঞ্জস্যপূর্ণ client (frpc)। একটি hostname-এর পেছনে একাধিক service রেখে স্থায়ী setup-এর জন্য উপযুক্ত। এই গাইডের মূল অংশ এতে নিবেদিত। - একটি mesh VPN: Tailscale অথবা নিজে চালানো একটি WireGuard server। আপনার নিজস্ব device-গুলোকে public internet-এ কিছু প্রকাশ না করে ব্যক্তিগতভাবে একে অন্যের সঙ্গে যুক্ত করতে চাইলে এটি উপযুক্ত।
আপনার লক্ষ্য যদি নিয়ন্ত্রণাধীন device থেকে private access হয়, তাহলে mesh বেছে নিন। tailnet-এর বাইরে প্রকাশনা-এ tailnet-এর বাইরে কীভাবে কিছু publish করতে হয় তা ব্যাখ্যা করা হয়েছে, আর একই VPS-এ self-hosted WireGuard VPN তৃতীয় পক্ষের coordination server ছাড়াই একই ধরনের ব্যবস্থা দেয়। এই দুটির যেকোনো একটি পড়ে এই পৃষ্ঠার বাকি অংশ বাদ দিন। নিচের সবকিছু ধরে নেয় যে আপনি এমন একটি public HTTPS hostname চান, যা যে কেউ load করতে পারে।
সংক্ষিপ্ত সংস্করণ: একটি service-এর জন্য ssh -R
ধরা যাক, home box-এ একটি app 127.0.0.1:3000-এ চলছে এবং VPS-এ আপনার SSH access ইতিমধ্যে আছে।
# on the home box
ssh -N \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-R 127.0.0.1:8080:127.0.0.1:3000 \
tunnel@vps.example.com-R 127.0.0.1:8080:127.0.0.1:3000 VPS-এর sshd-কে নিজের 127.0.0.1:8080-এ listen করতে এবং সেখানে আসা সবকিছু home box-এর 127.0.0.1:3000-এ পাঠাতে বলে। -N-এর অর্থ হলো shell চালু না করা। ServerAlive-এর দুটি option থাকলে SSH প্রায় ninety seconds-এর মধ্যে dead link শনাক্ত করে; আর অস্তিত্বহীন connection-এর জন্য আটকে থাকে না।
এখন যে অংশটি সবাইকে বিভ্রান্ত করে। ওই listener loopback-এ রয়েছে, তাই অন্য যেকোনো স্থান থেকে curl http://vps.example.com:8080 ব্যর্থ হবে। sshd ডিফল্টভাবে GatewayPorts no ব্যবহার করে। এর অর্থ, remote forward শুধু loopback interface-এ bind হয়। GatewayPorts yes সেট করে এটি ঠিক করার চেষ্টা করবেন না। Forward-টি loopback-এই রাখুন এবং এর সামনে nginx ব্যবহার করুন, যেমন নিচের frp setup-এ করা হয়েছে। এতে public port হবে 443, certificate ব্যবহার করা যাবে, এবং tunnel port Internet-এর সামনে প্রকাশিত হবে না। বর্তমানে কোন port কোন interface-এ listen করছে তা নিশ্চিত না হলে, Linux-এ port ও listener সম্পর্কে সংক্ষিপ্ত নির্দেশিকা পড়তে দশ মিনিট সময় দেওয়া সার্থক।
VPS-এ port-টি আগে থেকেই ব্যবহৃত হলে SSH এই বার্তাটি দেখায়। তখন ExitOnForwardFailure=yes কাজের tunnel ছাড়া connection করার পরিবর্তে SSH-কে বন্ধ হতে বলে:
Warning: remote port forwarding failed for listen port 8080সাধারণত এর কারণ হলো আগের একটি session মারা গেছে, কিন্তু sshd তা শনাক্ত করতে পারেনি। VPS-এর /etc/ssh/sshd_config-এ ClientAliveInterval 30 এবং ClientAliveCountMax 3 সেট করুন, যাতে মৃত session সরিয়ে port মুক্ত করা হয়। পুরো command-টি Restart=always সহ একটি systemd unit এবং একটি dedicated key-এর মধ্যে রাখুন, অথবা autossh ব্যবহার করুন। একটির বেশি service থাকলে এখানে থামুন এবং frp ব্যবহার করুন।
VPS-এ frp ইনস্টল করুন এবং একটি tag-এ version pin করুন
frp একটি static Go binary হিসেবে release হয় এবং এটি Ubuntu বা Debian archive-এ নেই। তাই একটি release download করে নিজেই তার verification করতে হবে। Version pin করুন। v0.52.0-এ configuration format পরিবর্তিত হয়েছে এবং এরপর option-এর নামও পরিবর্তন হয়েছে। তাই পুরোনো tutorial অনুসরণ করলে আপনার binary যে key চিনতে পারে না, সেগুলো পেতে পারেন। এই নির্দেশিকায় v0.71.0 ব্যবহার করা হয়েছে, যা 14 August 2026-এ প্রকাশিত হয়েছে।
# on the VPS
FRP_VERSION=0.71.0
ARCH=amd64 # use arm64 if `uname -m` prints aarch64
cd /tmp
curl -fsSLO "https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_linux_${ARCH}.tar.gz"
curl -fsSLO "https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_sha256_checksums.txt"
sha256sum --check --ignore-missing frp_sha256_checksums.txtsha256sum-এর output-এ অবশ্যই ঠিক একটিই line থাকতে হবে:
frp_0.71.0_linux_amd64.tar.gz: OK--ignore-missing প্রয়োজন, কারণ checksum file-এ release-এর সব eighteenটি asset অন্তর্ভুক্ত আছে, কিন্তু আপনি সেগুলোর একটি download করেছেন। এই flag ছাড়া sha256sum বাকি seventeenটি asset missing হিসেবে দেখাবে এবং non-zero status-এ exit করবে। এতে verification ব্যর্থ হয়েছে বলে মনে হবে, যদিও কোনো সমস্যা নেই।
# on the VPS
tar xzf "frp_${FRP_VERSION}_linux_${ARCH}.tar.gz"
sudo install -m 755 "frp_${FRP_VERSION}_linux_${ARCH}/frps" /usr/local/bin/frps
sudo useradd --system --no-create-home --shell /usr/sbin/nologin frp
sudo install -d -m 750 -o root -g frp /etc/frp
frps --versionfrps --version-এর output হলো 0.71.0। শুধু frps VPS-এ থাকবে। frpc home box-এ থাকবে। সব জায়গায় উভয় binary ইনস্টল করলে মানুষ ভুল করে বাড়িতে tunnel server চালু করে ফেলে।
VPS-এর কনফিগারেশন: token, বাধ্যতামূলক TLS, loopback listener
প্রথমে একটি token তৈরি করুন। VPS-এ port scan করা যেকোনো ব্যক্তির হাত থেকে আপনার tunnel-কে রক্ষা করার একমাত্র উপাদান এটি।
# on the VPS
openssl rand -base64 32এই মানটি /etc/frp/frps.toml-এ লিখুন:
bindAddr = "0.0.0.0"
bindPort = 7000
# Every listener frp creates for a proxy, including the HTTP vhost, stays on loopback.
proxyBindAddr = "127.0.0.1"
vhostHTTPPort = 8080
auth.method = "token"
auth.token = "PASTE_THE_OPENSSL_OUTPUT_HERE"
transport.tls.force = true
webServer.addr = "127.0.0.1"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "PASTE_A_SECOND_SECRET_HERE"
log.level = "info"এই লাইনগুলোর মধ্যে চারটি নিরাপত্তার কাজ করে। তাই একবারে একটি করে দেখুন।
auth.token-এর মান client-এর auth.token-এর সঙ্গে মিলতে হবে। এটি না থাকলে, port 7000 খুঁজে পাওয়া যেকোনো client-কে frps গ্রহণ করবে। সেই client তখন আপনার VPS এবং certificate ব্যবহার করে নিজের ইচ্ছামতো যেকোনো কিছু publish করতে পারবে।
transport.tls.force = true TLS (transport layer security) ছাড়া অন্য কোনো control connection প্রত্যাখ্যান করে। v0.50.0 থেকে client-গুলো ডিফল্টভাবে TLS সক্রিয় রাখে। তাই বাস্তবে এর জন্য আপনার অতিরিক্ত কোনো কাজ নেই। এর ফলে পুরোনো বা হাতে তৈরি কোনো client আপনাকে না জানিয়ে cleartext-এ সংযোগ করার ঝুঁকিও বন্ধ হয়।
proxyBindAddr = "127.0.0.1" হলো সেই line, যা অধিকাংশ guide বাদ দেয়। এই line-এর কারণেই এই setup চালু রেখে দেওয়া নিরাপদ। এটি proxy-এর হয়ে frp যে listener-গুলো খোলে, সেগুলো সব loopback interface-এ সরিয়ে দেয়। এর মধ্যে HTTP vhost এবং client চাইলে তৈরি করা যেকোনো remotePort অন্তর্ভুক্ত। Internet এসব listener-এ কোনোভাবেই পৌঁছাতে পারে না। একমাত্র public entry point হলো 443-এ nginx, যা আপনি configure ও নিয়ন্ত্রণ করেন।
webServer.addr = "127.0.0.1" dashboard-কে public interface থেকে দূরে রাখে। Dashboard-এ আপনার private service এবং তাদের traffic-এর সম্পূর্ণ বিবরণ থাকে। এটি শুধু একটি HTTP basic auth password দিয়ে সুরক্ষিত। তাই এটি 0.0.0.0-এ রাখা উচিত নয়।
token-টি যেন world-readable না হয়, সে জন্য ownership সেট করুন। এরপর কিছু চালু করার আগে syntax পরীক্ষা করুন:
# on the VPS
sudo chown root:frp /etc/frp/frps.toml
sudo chmod 640 /etc/frp/frps.toml
sudo -u frp frps verify -c /etc/frp/frps.tomlবৈধ file হলে এটি দেখাবে:
frps: the configuration file /etc/frp/frps.toml syntax is okএকটি format-সংক্রান্ত তথ্য আপনার প্রায় এক ঘণ্টা সময় বাঁচাতে পারে। frp file extension দেখে parser নির্বাচন করে। এটি .toml, .yaml, .yml এবং .json চেনে। পুরোনো .ini file এখনও একটি legacy conversion path-এর মাধ্যমে load হয়। তবে INI deprecated, এবং নতুন option-গুলোর documentation শুধু TOML-এর জন্য দেওয়া হয়। কোনো tutorial-এ যদি [common] section এবং server_addr = x.x.x.x দেখেন, তাহলে সেটি v0.52.0-এর আগের। সেখানে ব্যবহৃত key name আপনার সদ্য install করা binary-এর সঙ্গে মিলবে না।
অসুবিধাবিহীন ব্যবহারকারী হিসেবে frps চালান
bindPort হলো 7000 এবং vhostHTTPPort হলো 8080। উভয় port-ই 1024-এর বেশি। তাই frps-এর কখনো root দরকার হয় না এবং কখনো CAP_NET_BIND_SERVICE-এরও দরকার হয় না। এই কারণেই vhost-কে port 80-এ না রেখে nginx-কে সেটি ব্যবহার করতে দেওয়া উচিত।
/etc/systemd/system/frps.service লিখুন:
[Unit]
Description=frp reverse tunnel server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=frp
Group=frp
ExecStart=/usr/local/bin/frps -c /etc/frp/frps.toml
Restart=on-failure
RestartSec=5s
LimitNOFILE=65535
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ProtectKernelTunables=true
[Install]
WantedBy=multi-user.target# on the VPS
sudo systemctl daemon-reload
sudo systemctl enable --now frps
sudo journalctl -u frps -n 20 --no-pagerলগে উভয় listener দেখা উচিত। এখানে port-এর চেয়ে address বেশি গুরুত্বপূর্ণ:
frps tcp listen on 0.0.0.0:7000
http service listen on 127.0.0.1:8080ProtectSystem=strict এই service-এর জন্য সম্পূর্ণ filesystem read-only করে। frps এতে কাজ করতে পারে, কারণ ডিফল্টভাবে এর log standard output-এ যায় এবং journald তা সংগ্রহ করে। আপনি যদি log.to-কে কোনো file path হিসেবে সেট করেন, তাহলে সংশ্লিষ্ট ReadWritePaths= line যোগ না করা পর্যন্ত service সেটিতে লিখতে ব্যর্থ হবে। তাই ডিফল্ট সেটিং পরিবর্তন করবেন না।
Firewall: একটি range নয়, শুধু একটি port খুলুন
# on the VPS
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 7000/tcp
sudo ufw enable
sudo ufw status numberedচারটি rule আছে, এবং এর একটি শুধু certificate renewal-এর জন্য ব্যবহৃত হয়। 22 হলো SSH। 80, 443-এ redirect করে এবং ACME (automatic certificate management environment) challenge-এর উত্তর দেয়। 443 সব tunnelled app পরিবেশন করে। 7000 হলো frp control port, এবং client-কে কখনো যে port-এ পৌঁছাতে হয়, এটি সেটিই।
যেসব guide-এ sudo ufw allow 20000:30000/tcp-এর মতো একটি range খুলতে বলা হয়, সেগুলো অন্য নকশা বর্ণনা করে। সেখানে প্রতিটি service নিজের public TCP port ব্যবহার করে। এখানে এটি দরকার নেই, কারণ সব অনুরোধ 443-এ আসে এবং frp hostname অনুযায়ী সেগুলো route করে। পরে যদি সত্যিই একটি public TCP port দরকার হয়, তাহলে proxyBindAddr-কে আবার 0.0.0.0-এ ফেরত দিন এবং এমন limit যোগ করুন, যাতে client শুধু আপনার নির্ধারিত port-গুলো claim করতে পারে:
allowPorts = [
{ start = 20000, end = 20010 }
]
maxPortsPerClient = 5বেশিরভাগ provider control panel-এ একটি network firewall-ও চালায়। এটি সার্ভারের ufw থেকে আলাদা। sudo ufw status-এ সঠিক দেখানো কোনো rule ব্যবহার করেও যদি connection timeout হয়, সাধারণত সেটি ওই firewall-এ blocked রয়েছে। VPS-এর আসলে যে ufw rule দরকার এই section-এ ধরা default-deny setup ধাপে ধাপে ব্যাখ্যা করে।
VPS-এ প্রকৃত certificate দিয়ে HTTPS termination
home.example.com-এর জন্য একটি A record VPS-এর public IP-তে নির্দেশ করুন। আপনার বাড়ির IP-তে নয়। আপনার বাড়িতে নির্দেশ করার মতো স্থায়ী address নেই, আর আপনি যে সমস্যাটি সমাধান করছেন সেটিই এটি।
# on the VPS
sudo apt update
sudo apt install -y nginx certbot python3-certbot-nginxপ্রথমে সাধারণ port 80 block দিয়ে /etc/nginx/sites-available/home.example.com তৈরি করুন, যাতে certbot কাজ করার জন্য একটি মিলে যাওয়া server_name পায়:
server {
listen 80;
listen [::]:80;
server_name home.example.com;
location / { return 404; }
}# on the VPS
sudo ln -s /etc/nginx/sites-available/home.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot certonly --nginx -d home.example.comফাইলগুলো parse হলে nginx -t, nginx: configuration file /etc/nginx/nginx.conf test is successful প্রদর্শন করে। প্রতিটি reload-এর আগে এটি চালান। reload ব্যর্থ হলে nginx পুরোনো configuration চালু রাখে। তাই ভুল edit করলে মনে হতে পারে edit কার্যকর হয়নি।
WebSocket upgrade-এর জন্য http level-এ একটি map প্রয়োজন। এটি /etc/nginx/conf.d/upgrade.conf-এ রাখুন:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}এখন site file-টি প্রকৃত configuration দিয়ে প্রতিস্থাপন করুন:
server {
listen 80;
listen [::]:80;
server_name home.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name home.example.com;
ssl_certificate /etc/letsencrypt/live/home.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/home.example.com/privkey.pem;
client_max_body_size 512m;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
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_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 3600s;
}
}এখানে proxy_set_header Host $host; ঐচ্ছিক নয়। frp-এর HTTP vhost Host header অনুযায়ী route করে এবং client config-এর customDomains তালিকার সঙ্গে সেটি মিলিয়ে দেখে। ওই header বাদ দিলে nginx Host: 127.0.0.1 পাঠায়, frp ওই নামের জন্য কোনো proxy খুঁজে পায় না, এবং আপনার visitor অ্যাপের page-এর বদলে frp থেকে সরাসরি 404 পায়। nginx reverse proxy block-এর প্রতিটি line-এর ব্যাখ্যা-এ অন্য header-গুলো কী কাজ করে তা ব্যাখ্যা করা হয়েছে।
# on the VPS
sudo nginx -t && sudo systemctl reload nginx
sudo certbot renew --dry-runএই dry run প্রমাণ করে যে নব্বই দিন পরে renewal কাজ করবে, যখন আপনি এটি পর্যবেক্ষণ করছেন না। এর জন্য port 80-এ পৌঁছানো সম্ভব হতে হবে। সেই কারণেই ওই ufw rule রাখা হয়েছে।
হোম সাইড: অprivileged service হিসেবে frpc
হোম বক্সে frpc ইনস্টল করুন ঠিক যেভাবে frps ইনস্টল করেছিলেন। একই version ব্যবহার করুন এবং একই checksum ধাপ অনুসরণ করুন। এরপর একই frp user এবং /etc/frp directory তৈরি করুন। /etc/frp/frpc.toml লিখুন:
serverAddr = "vps.example.com"
serverPort = 7000
auth.method = "token"
auth.token = "PASTE_THE_SAME_TOKEN_HERE"
transport.tls.enable = true
loginFailExit = false
proxies = [
{ name = "home-app", type = "http", localIP = "127.0.0.1", localPort = 3000, customDomains = ["home.example.com"] }
]এই file-এ key-এর ক্রম গুরুত্বপূর্ণ। এর কারণ style নয়। TOML-এ table header-এর পরের প্রতিটি key ওই table-এর অন্তর্ভুক্ত হয়। তাই serverAddr-এর মতো top-level setting কোনো proxy table header-এর নিচে লিখলে সেটি নীরবে proxy setting হয়ে যায়, যা frp উপেক্ষা করে। উপরের মতো proxy list-টি inline array হিসেবে লিখলে এই সমস্যা এড়ানো যায়। এতে প্রতিটি top-level key স্পষ্টভাবে top level-এই থাকে।
type = "http" এই proxy-কে নিজের public TCP port নেওয়ার পরিবর্তে vhost listener-এর মাধ্যমে route করে। এই কারণেই firewall চারটি rule-এই সীমাবদ্ধ ছিল। customDomains-এ Host header-এ nginx যে hostname পাঠায়, সেটিই থাকতে হবে। তাই এটি home.example.com হবে, VPS-এর IP address কখনোই নয়।
loginFailExit = false প্রত্যাশার চেয়ে বেশি গুরুত্বপূর্ণ। Default হলো true। এর ফলে frpc-এর প্রথম login attempt ব্যর্থ হলে frpc exit করে। ISP link চালু হওয়ার আগেই কোনো home box boot শেষ করলে এমন service আপনি খেয়াল না করা পর্যন্ত বন্ধই থাকে। এটিকে false সেট করুন। তাহলে VPS সাড়া দেওয়া পর্যন্ত frpc পুনরায় চেষ্টা করতে থাকবে।
/etc/systemd/system/frpc.service লিখুন:
[Unit]
Description=frp reverse tunnel client
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=frp
Group=frp
ExecStart=/usr/local/bin/frpc -c /etc/frp/frpc.toml
Restart=always
RestartSec=10s
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
[Install]
WantedBy=multi-user.target# on the home box
sudo chown root:frp /etc/frp/frpc.toml
sudo chmod 640 /etc/frp/frpc.toml
sudo -u frp frpc verify -c /etc/frp/frpc.toml
sudo systemctl daemon-reload
sudo systemctl enable --now frpc
sudo journalctl -u frpc -n 20 --no-pagerযে client connection করেছে, সেটি একটি run id log করে:
login to server success, get run id [3a1f9c2b7d4e5f60]Browser-এ https://home.example.com খুলুন। তাহলে হোমে 127.0.0.1:3000-এ চলমান app-টি দেখতে পাবেন। Client-এর Restart=always ইচ্ছাকৃতভাবে রাখা হয়েছে। Home connection বিচ্ছিন্ন হতে পারে, এবং আপনার হস্তক্ষেপ ছাড়াই service-টি পুনরায় চালু হওয়া উচিত।
Public interface থেকে dashboard দূরে রাখুন
webServer.addr = "127.0.0.1" ব্যবহার করলে dashboard শুধু VPS-এর ভেতরেই সাড়া দেয়। কোনো port খুলে না দিয়ে local forward ব্যবহার করে আপনার laptop থেকে এতে প্রবেশ করুন:
# on your laptop
ssh -N -L 7500:127.0.0.1:7500 you@vps.example.comhttp://127.0.0.1:7500 খুলুন এবং frps.toml থেকে পাওয়া webServer.user ও webServer.password দিয়ে sign in করুন। পৃষ্ঠায় প্রতিটি সংযুক্ত client এবং প্রতিটি proxy-এর traffic counter দেখা যায়। তাই “home box এই মুহূর্তে সংযুক্ত কি না”—এই প্রশ্নের উত্তর দ্রুত পাওয়ার এটি সবচেয়ে সহজ উপায়। SSH session বন্ধ করলে dashboard আবার unreachable হয়ে যায়।
টানেল যা করে না
এই অংশটি দুবার পড়ুন, কারণ এখানেই মানুষ সমস্যায় পড়ে। টানেল একটি private service-কে public internet থেকে অ্যাক্সেসযোগ্য করে। এটি সেই service-এ অ্যাক্সেসকারীদের authentication করে না। https://home.example.com resolve হওয়ার পর কয়েক দিনের মধ্যেই scanner এটি খুঁজে পাবে। আপনি কাউকে hostname জানিয়েছেন কি না, তাতে কিছু যায় আসে না। Certificate transparency log-এ আপনি যে hostname-এর জন্য certificate issue করেন, তা প্রকাশিত হয়। তাই certbot সফল হওয়ার সঙ্গে সঙ্গেই নামটি public হয়ে যায়।
আপনি যা expose করবেন, সেটির নিজস্ব authentication থাকতে হবে। অ্যাপটিতে rate limiting-সহ সঠিক login থাকলে ভালো। login যদি একটি shared password-নির্ভর হয়, অথবা একেবারেই login না থাকে, তাহলে VPS-এ অ্যাপটির সামনে একটি authenticating proxy বসান। অ্যাপটির সামনে থাকা oauth2-proxy সাধারণত এ ক্ষেত্রের প্রচলিত সমাধান। এটি nginx এবং frp vhost-এর মাঝখানে বসানো যায়, টানেলের কোনো প্রান্তে পরিবর্তন না করেই।
frps.toml-এর token টানেলকে সুরক্ষিত রাখে, অ্যাপগুলোকে নয়। এটি কোনো অপরিচিত ব্যক্তিকে আপনার VPS-এ নিজের proxy register করা থেকে আটকায়। আপনি ইচ্ছাকৃতভাবে প্রকাশ করা কোনো hostname-এর জন্য 443-এ আসা request-এর ক্ষেত্রে এটি কিছুই করে না।
দুটি অভ্যাস বজায় রাখা ভালো। দুইটি file edit করে এবং দুইটি service restart করে token rotate করুন, কারণ এটি নিজে থেকে কখনো expire হয় না। frp-ও আপ-to-date রাখুন। এই binary-ই আপনার public-facing front door। v0.71.0-এর release note-এ client থেকে পাঠানো একটি ভুল value-এর কারণে server panic-এর কথা উল্লেখ আছে। এই ধরনের bug patch করা উচিত; এর আচরণ বিশ্লেষণ করে সমাধান করার চেষ্টা করা উচিত নয়।
ব্যর্থতার ধরন এবং যে বার্তাগুলো দেখবেন
ক্লায়েন্ট কখনও সংযোগ করে না। journalctl -u frpc বারবার connect to server error: দেখায়, এরপর dial timeout হয়। port 7000-এ কোনো network traffic পৌঁছাচ্ছে না। VPS-এ ufw পরীক্ষা করুন। এরপর control panel-এ provider-এর network firewall পরীক্ষা করুন। সবশেষে getent hosts vps.example.com দিয়ে নিশ্চিত করুন যে নামটি সঠিকভাবে resolve হচ্ছে।
Token ভুল। ক্লায়েন্ট সরাসরি তা জানায়:
login to the server failed: token in login doesn't match token from configurationআবার token কপি করুন। শেষে থাকা newline অথবা উদ্ধৃতিহীন shell string-এ এমন একটি $, যা expand হয়ে ফাঁকা হয়েছে, প্রায় সব ক্ষেত্রে এই সমস্যা তৈরি করে। তাই TOML file-এ openssl rand -base64 32-এর output quotes-এর মধ্যে রাখতে হবে।
Tunnel চালু আছে, কিন্তু browser খালি 404 পায়। frpc সফল login-এর log লিখেছে এবং dashboard-এ proxy দেখা যাচ্ছে, তবুও page 404 ফেরত দিচ্ছে এবং app-এর কোনো styling নেই। এর অর্থ frp এই Host header-এর জন্য কোনো proxy পাচ্ছে না। nginx এবং TLS দুটিই এড়িয়ে VPS-এ সরাসরি vhost পরীক্ষা করুন:
# on the VPS
curl -s -o /dev/null -w '%{http_code}\n' -H 'Host: home.example.com' http://127.0.0.1:8080/এই command থেকে 404 পাওয়া মানে customDomains ভুল। অন্য কোনো code পাওয়া মানে nginx থেকে অনুরোধটি সঠিক Host পায়নি।
nginx থেকে 502। nginx উত্তর দিচ্ছে, কিন্তু frp উত্তর দিচ্ছে না। VPS-এ sudo ss -lntp | grep 8080 চালালে frps-এর 127.0.0.1:8080-এ listening করার বিষয়টি দেখা উচিত। কোনো output না থাকলে frps বন্ধ আছে, অথবা vhostHTTPPort, frps.toml-এ সেট করা নেই।
App মনে করে প্রত্যেক visitor local। আপনার app প্রতিটি request-এর জন্য 127.0.0.1 log করে। frp X-Forwarded-For সেট করে এবং nginx সেটির সঙ্গে client address যোগ করে। তাই প্রকৃত client address ওই header-এ থাকে। App-কে এটি trust করার জন্য configure করুন। App IP address অনুযায়ী rate limit করলে এই ধাপ বাদ দেবেন না, কারণ এই মুহূর্তে Internet-এর সব visitor একই bucket ব্যবহার করছে।
দীর্ঘ request 60 সেকেন্ডে কেটে যায়। Upload অথবা streaming response মাঝপথে বন্ধ হয়ে যায়। এটি tunnel-এর সমস্যা নয়; এটি nginx-এর default proxy_read_timeout। উপরের block-এ এটি 3600s করা হয়েছে। Upload size-এর জন্য client_max_body_size হলো সমতুল্য limit। এর default 1 MB হওয়ায় বড় body 413 সহ প্রত্যাখ্যাত হয়।
সবকিছু কাজ করে, তারপর router reboot-এর পরে বন্ধ হয়ে যায়। frpc unit-এ Restart=always এবং loginFailExit = false এই সমস্যা সমাধান করে। sudo systemctl is-enabled frpc দিয়ে নিশ্চিত করুন; এতে enabled print হওয়া উচিত।
FAQ
আমি কীভাবে বুঝব যে আমি CGNAT-এর পেছনে আছি?
আপনার router-এর admin page-এ দেখানো WAN address-এর সঙ্গে একই network-এর ভেতর থেকে curl -4 -s https://ifconfig.me যে address দেখায়, তা তুলনা করুন। দুটির মধ্যে পার্থক্য থাকলে এবং router-এর WAN address 100.64.0.0/10-এর মধ্যে পড়লে, আপনার ISP carrier-grade NAT ব্যবহার করছে। এটি RFC 6598 shared address space, এবং এই কাজের জন্যই নির্ধারিত। কিছু ISP WAN side-এ 10.0.0.0/8 ব্যবহার করে; এর অর্থও একই। দুটি address মিলে গেলে আপনার public IP আছে: port forward করুন, কাজ শেষ।
Reverse tunnel-এর জন্য কি domain name প্রয়োজন?
এখানে বর্ণিত HTTPS setup-এর জন্য প্রয়োজন। Certificate একটি hostname-এর নামে issue হয়, এবং frp-এর HTTP vhost Host header দেখে request route করে। তাই দুই প্রান্তের মধ্যে একই name ব্যবহার করতে হবে। Numbered port-এ raw TCP proxy কোনো domain ছাড়াই VPS-এর সরাসরি IP দিয়ে কাজ করে। তবে তখন কোনো certificate বা hostname routing থাকে না, ফলে একটি public port দিয়ে ঠিক একটি service-ই চালানো যায়।
Public VPS-এ frp চালানো কি নিরাপদ?
Control port একমাত্র exposed port হলে এবং authentication চালু থাকলে এটি নিরাপদ। দুই প্রান্তেই auth.token-এ একটি random value সেট করুন এবং server-এ transport.tls.force = true সেট করুন। এরপর proxyBindAddr = "127.0.0.1" সেট করুন, যাতে frp যে proxy খোলে তার কোনোটি Internet-এর দিকে exposed না হয়। Dashboard webServer.addr = "127.0.0.1"-এ রাখুন এবং SSH local forward-এর মাধ্যমে সেখানে প্রবেশ করুন। নতুন release প্রকাশিত হলে binary update করুন, কারণ এটিই আপনার public address-এ listening করা process।
আমার ssh -R forwarded port-এ কেউ পৌঁছাতে পারছে না কেন?
sshd ডিফল্টভাবে GatewayPorts no ব্যবহার করে, তাই remote forward শুধু VPS-এর loopback interface-এ bind হয়। VPS-এর ভেতর থেকেই curl চালালে কাজ করে, কিন্তু অন্য যেকোনো স্থান থেকে curl timeout হয়। সঠিক সমাধান হলো forward-টি loopback-এ রাখা এবং এর সামনে 443 port-এ nginx বসানো। GatewayPorts yes সেট করলে certificate ও TLS ছাড়া একটি raw port public হয়ে যায়। এতে যে সমস্যার সমাধান করতে চান, তার চেয়ে বড় সমস্যা তৈরি হয়।
আমার কি frp ব্যবহার করা উচিত, নাকি Tailscale বা WireGuard-এর মতো mesh VPN?
শুধু আপনার নিজের device-গুলোকে access দিতে হলে mesh VPN ব্যবহার করুন। এতে কিছুই public করা হয় না এবং scan করার মতো কোনো public hostname থাকে না। এমন public HTTPS address প্রয়োজন হলে frp ব্যবহার করুন, যা যেকোনো browser load করতে পারে। উদাহরণ হিসেবে webhook receiver বা এমন কোনো page, যা এমন ব্যক্তিদের সঙ্গে share করবেন যারা VPN client install করবেন না। একই VPS-এ, ভিন্ন port-এ এবং ভিন্ন কাজের জন্য, দুটি একসঙ্গে সহজেই চলতে পারে।