কোডিং এজেন্ট বলছে ফিচারটা চলছে। হয়তো সত্যি। তার লেখা টেস্টগুলো পাস করে, আর তা সবাই যতটা চায় তার চেয়ে কম প্রমাণ করে। আপনি আসলে চান ব্যবহারকারীদের কাছাকাছি যাওয়ার আগেই এটা ব্রাউজারে খুলে দেখতে, আর তা এজেন্টকে প্রোডাকশন ছুঁতে না বলে।
প্রিভিউ পরিবেশ এটাই সমাধান করে, আর এর জন্য কোনো প্ল্যাটফর্ম লাগে না। নিজস্ব IPv4-সহ একটি VPS, Docker, Caddy আর দুটি ছোট স্ক্রিপ্ট প্রতিটি ব্রাঞ্চকে https://feature-login-form.preview.example.com-এর মতো নিজস্ব URL দেয়, পাসওয়ার্ডের পেছনে, প্রতিটি পুশে নতুন করে বিল্ড হয়। এজেন্ট এমন একটি SSH কী পায় যা প্রিভিউ চালু ও বন্ধ করতে পারে, আর কিছু নয়।
আমরা এটা একটি টেস্ট সার্ভারে বানিয়েছি আর লেখার আগে পুরো চক্র চালিয়ে দেখেছি: তৈরি, খোলা, আবার পুশ, সরানো, কী অপব্যবহারের চেষ্টা।
যা লাগবে
- পাবলিক IPv4-সহ একটি VPS। AI-Agent-IP-এ একসঙ্গে কয়েকটি প্রিভিউ ধরে।
- একটি ওয়াইল্ডকার্ড DNS রেকর্ড:
*.preview.example.com→ সার্ভারের IP। - আপনার অ্যাপের রিপোজিটরি, যাতে পোর্ট 8080-এ সার্ভ করা একটি
Dockerfileআছে। যেকোনো ভাষা চলবে। apt install -y docker.io caddy git-সহ Ubuntu 24.04 বা Debian 12/13।
শুধু পড়ার অনুমতির ডিপ্লয় কী দিয়ে রিপোজিটরি একবার /srv/app-এ ক্লোন করুন।
দুটি স্ক্রিপ্ট
/usr/local/bin/preview-up একটি ব্রাঞ্চ বিল্ড করে অনলাইনে তোলে:
#!/usr/bin/env bash
# preview-up <branch> — build the branch and open it at https://<name>.preview.example.com
set -euo pipefail
BRANCH="$1"
NAME=$(printf '%s' "$BRANCH" | tr '[:upper:]' '[:lower:]' | tr -c 'a-z0-9' '-' | sed 's/--*/-/g; s/^-//; s/-$//' | cut -c1-40)
DIR=/srv/previews/$NAME
git -C /srv/app fetch --quiet origin "$BRANCH"
rm -rf "$DIR"; git -C /srv/app worktree prune
git -C /srv/app worktree add --quiet --force --detach "$DIR" FETCH_HEAD
docker build --quiet -t "preview-$NAME" "$DIR" >/dev/null
docker rm -f "preview-$NAME" >/dev/null 2>&1 || true
docker run -d --name "preview-$NAME" --restart unless-stopped --memory 512m -p 127.0.0.1::8080 "preview-$NAME" >/dev/null
PORT=$(docker port "preview-$NAME" 8080/tcp | head -1 | awk -F: '{print $NF}')
cat > "/etc/caddy/previews/$NAME.caddy" <<CADDY
$NAME.preview.example.com {
import preview_common
reverse_proxy 127.0.0.1:$PORT
}
CADDY
systemctl reload caddy
echo "https://$NAME.preview.example.com"
/usr/local/bin/preview-down সেটা সরিয়ে দেয়:
#!/usr/bin/env bash
# preview-down <branch> — remove the branch preview
set -euo pipefail
NAME=$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | tr -c 'a-z0-9' '-' | sed 's/--*/-/g; s/^-//; s/-$//' | cut -c1-40)
docker rm -f "preview-$NAME" >/dev/null 2>&1 || true
docker image rm "preview-$NAME" >/dev/null 2>&1 || true
rm -f "/etc/caddy/previews/$NAME.caddy"; rm -rf "/srv/previews/$NAME"; git -C /srv/app worktree prune
systemctl reload caddy
এখানে কিছু সিদ্ধান্ত ইচ্ছাকৃত। কন্টেইনার শুধু 127.0.0.1-এ এলোমেলো পোর্টে পাবলিশ হয়, তাই Caddy ছাড়া কিছুই তাদের কাছে পৌঁছায় না। এটা জরুরি, কারণ Docker-এর পাবলিশ করা পোর্ট ufw এড়িয়ে যায়। প্রতিটি প্রিভিউতে 512 MB মেমরির সীমা আছে, যাতে লাগামছাড়া একটি ব্রাঞ্চ বাকিদের না ফেলে। আর একই ব্রাঞ্চ আবার চালালে সেটা জায়গাতেই নতুন করে বিল্ড হয়: পুশ, up চালান, রিফ্রেশ।
Caddy: প্রতিটি প্রিভিউর একটি ফাইল, সবার জন্য একটি পাসওয়ার্ড
mkdir -p /etc/caddy/previews /srv/previews
chmod +x /usr/local/bin/preview-up /usr/local/bin/preview-down
caddy hash-password --plaintext 'choose-a-review-password'
হ্যাশটা /etc/caddy/Caddyfile-এ বসান:
(preview_common) {
basicauth {
reviewer PASTE-THE-HASH-HERE
}
}
import /etc/caddy/previews/*.caddy
তারপর systemctl reload caddy। এখন প্রতিটি প্রিভিউ একই লগইনের পেছনে, তাই ডিবাগ আউটপুটসহ অর্ধেক কাজ করা ব্রাঞ্চ খোলা ইন্টারনেটে থাকে না। নতুন Caddy সংস্করণে এই নির্দেশ basic_auth নামেও লেখা হয়; basicauth দুটোতেই এখনও চলে।
এজেন্টের কী: up আর down, আর কিছু নয়
এজেন্টের দরকার প্রিভিউ চালু করা, সার্ভারের মালিক হওয়া নয়। একটি deploy ব্যবহারকারী আর এমন গেট স্ক্রিপ্ট বানান যা ঠিক দুটি কমান্ড নেয়:
#!/usr/bin/env bash
# /usr/local/bin/preview-gate — the only thing the agent's key may run
set -euo pipefail
read -r ACTION BRANCH EXTRA <<< "${SSH_ORIGINAL_COMMAND:-}"
[[ -z "${EXTRA:-}" && "${BRANCH:-}" =~ ^[A-Za-z0-9][A-Za-z0-9._/-]{0,99}$ && "$BRANCH" != *..* ]] || { echo "usage: up|down <branch>" >&2; exit 2; }
case "$ACTION" in
up) exec sudo /usr/local/bin/preview-up "$BRANCH" ;;
down) exec sudo /usr/local/bin/preview-down "$BRANCH" ;;
*) echo "usage: up|down <branch>" >&2; exit 2 ;;
esac
useradd -m -s /bin/bash deploy
echo 'deploy ALL=(root) NOPASSWD: /usr/local/bin/preview-up, /usr/local/bin/preview-down' > /etc/sudoers.d/preview
chmod 440 /etc/sudoers.d/preview && visudo -cf /etc/sudoers.d/preview
chmod 755 /usr/local/bin/preview-gate
/home/deploy/.ssh/authorized_keys-এ এজেন্টের পাবলিক কী ওই স্ক্রিপ্টের সঙ্গে বেঁধে দিন:
restrict,command="/usr/local/bin/preview-gate" ssh-ed25519 AAAA... coding-agent
যে মেশিনে এজেন্ট কাজ করে, সেখান থেকে:
ssh deploy@preview.example.com up feature/login-form
# https://feature-login-form.preview.example.com
ssh deploy@preview.example.com down feature/login-form
আমাদের পরীক্ষায় up ব্রাঞ্চ বিল্ড করে পাবলিশ করেছে, নতুন কমিটের পর দ্বিতীয় up নতুন সংস্করণ দেখিয়েছে, আর down কন্টেইনার ও সাইট সরিয়ে দিয়েছে। ওই কী দিয়ে cat /etc/shadow, up x; id, -x বা a/../b-এর মতো ব্রাঞ্চ নাম, কিংবা ইন্টারঅ্যাক্টিভ লগইনের চেষ্টা সবই শুধু usage: up|down <branch> পেয়েছে। ব্রাঞ্চের নাম অক্ষর বা অঙ্ক দিয়ে শুরু হতে হবে এবং তাতে .. থাকতে পারবে না।
এজেন্টের সঙ্গে যুক্ত করা
Claude Code বা Codex-এ প্রজেক্টের নির্দেশনা ফাইলে একটি লাইনই যথেষ্ট:
ব্রাঞ্চ পুশ করার পর
ssh deploy@preview.example.com up <branch>চালাও এবং ছাপা URL তোমার সারাংশে দাও। ব্রাঞ্চ মার্জ হলে বা বাতিল হলেdownচালাও।
আপনার CI যদি আগে থেকেই প্রতিটি পুশে চলে, তবে একই কমান্ড সেখান থেকে ডাকুন আর কীটা এজেন্টের পরিবেশ থেকে পুরোপুরি দূরে রাখুন। এটা কঠোরতর বিকল্প, আর ব্যক্তিগত প্রজেক্টের বাইরে যেকোনো কিছুর জন্য আমরা এটাই বাছতাম।
যেদিকে নজর রাখবেন
- ডিস্ক। প্রতিটি বিল্ড ইমেজ লেয়ার রেখে যায়। সাপ্তাহিক cron-এ
docker image prune -fএটা নিয়ন্ত্রণে রাখে;downপ্রিভিউর নিজের ইমেজ আগেই মুছে দেয়। - যে ব্রাঞ্চ কেউ বন্ধ করে না। এজেন্টরা মানুষের চেয়ে বেশি ব্রাঞ্চ খোলে। এক সপ্তাহের বেশি পুরোনো
preview-*কন্টেইনারের তালিকা করে তাতেpreview-downচালানো একটি cron আপনাকে বিশটা ভুলে যাওয়া প্রিভিউ পাওয়া থেকে বাঁচায়। - গোপন তথ্য। প্রিভিউ টেস্ট ক্রেডেনশিয়াল দিয়ে চলা উচিত। basic auth পাসওয়ার্ড অপরিচিতদের দূরে রাখে, কিন্তু তাতে প্রিভিউকে প্রোডাকশন ডেটাবেসে যুক্ত করা ঠিক হয়ে যায় না।
- বিল্ডের সময়। ইমেজ সার্ভারে বিল্ড হয়, তাই ভারী বিল্ড চলমান প্রিভিউর সঙ্গে CPU নিয়ে প্রতিযোগিতা করে। বিল্ডে কয়েক মিনিট লাগলে CI-তে বিল্ড করে ইমেজ টেনে আনুন।
এজেন্টকে নিজে এই সার্ভারে থাকতে হবে এমন নয়। থাকলে Claude Code-এর জন্য VPS দেখুন, আর সে যাতে এই সার্ভার নিজে অর্ডার ও দেখভাল করতে পারে, তাকে EQVPS MCP সার্ভারে যুক্ত করুন। একই মেশিন আপনার টিমের MCP গেটওয়ে-ও হোস্ট করতে পারে। কোনো সার্ভার ছাড়াই অবিশ্বস্ত কোড চালাতে আছে স্যান্ডবক্স, আর নিজস্ব IPv4-এর প্ল্যান শুরু মাসে $8 থেকে।
মন্তব্য
এখনো কোনো মন্তব্য নেই। প্রথম হোন।