WordPress থিম ডিপ্লয়ের সবচেয়ে নিরাপদ উপায় হলো দুই জবের একটা GitHub Actions ওয়ার্কফ্লো: একটা টেস্ট জব, যা প্রতিটা পুশে সব PHP আর JSON ফাইল চেক করে, আর একটা ডিপ্লয় জব, যা শুধু main ব্রাঞ্চে টেস্ট পাস করলে SSH-এর ওপর rsync দিয়ে থিম সার্ভারে কপি করে। SSH কী-টা থাকে সীমিত ডিপ্লয় ইউজারের, যে থিমের ফোল্ডারে লেখা ছাড়া আর কিছু পারে না।
ক্লায়েন্টের থিম আর নিজের সাইট, দুই জায়গাতেই আমি এই GitHub Actions পাইপলাইন ব্যবহার করি। FTP আপলোড পুরোপুরি বাদ গেছে, আর তার সাথে লাইভ সাইটে “আমার কম্পিউটারে তো চলছিল” ধরনের চমকও।
মূল কথা
- থিম রাখুন প্রাইভেট GitHub রিপোজিটরিতে; লাইভ সার্ভারে থিমের ফাইল কখনো এডিট করবেন না।
- জব ১, টেস্ট: আপনার সাপোর্ট করা সবচেয়ে পুরোনো আর নতুন PHP ভার্সনে সিনট্যাক্স চেক, সাথে ACF JSON ফিল্ড গ্রুপ যাচাই।
- জব ২, ডিপ্লয়: টেস্ট জবের ওপর নির্ভর করে আর শুধু
main-এ চলে; পুল রিকোয়েস্ট টেস্ট হয়, ডিপ্লয় হয় না। - আলাদা ডিপ্লয় ইউজার ব্যবহার করুন, যার SSH কী
rrsyncদিয়ে একটা ফোল্ডারে, শুধু লেখার জন্য বাঁধা। - শেষে একটা স্মোক টেস্ট রাখুন, সাইট ঠিকমতো উত্তর না দিলে যা রানটাকে ফেল করায়।

FTP দিয়ে WordPress ডিপ্লয় কেন বন্ধ করবেন?
FTP ডিপ্লয়ের তিনটা সমস্যা:
- কোনো চেক নেই। একটা সেমিকোলন বাদ গেলেই পুরো সাইটে সাদা স্ক্রিন।
- কোনো ইতিহাস নেই। কে কী বদলেছে, কীভাবে আগের অবস্থায় ফিরবেন, কেউ জানে না।
- অতিরিক্ত অ্যাক্সেস। FTP লগইনে প্রায়ই পুরো সার্ভারে ঢোকা যায়, আর পাসওয়ার্ড ইমেইলে ঘোরে।
Git-ভিত্তিক পাইপলাইন তিনটাই ঠিক করে: প্রতিটা পরিবর্তন টেস্ট হয়, প্রতিটা ভার্সন লেখা থাকে, আর সার্ভার শুধু একটা সীমিত কী থেকে ফাইল নেয়।
GitHub Actions পাইপলাইনটা দেখতে কেমন?
| ধাপ | কখন চলে | কী করে | ফেল করলে |
|---|---|---|---|
| টেস্ট (PHP 8.1) | প্রতিটা পুশ আর পুল রিকোয়েস্টে | সব PHP ফাইলে php -l, JSON যাচাই | কিছুই ডিপ্লয় হয় না |
| টেস্ট (PHP 8.5) | প্রতিটা পুশ আর পুল রিকোয়েস্টে | সার্ভারের PHP ভার্সনে একই চেক | কিছুই ডিপ্লয় হয় না |
| ডিপ্লয় | main-এ পুশ, টেস্ট পাস | VPS-এ থিম rsync | সাইটে আগের ভার্সনই থাকে |
| স্মোক টেস্ট | ডিপ্লয়ের পরে | সাইটে রিকোয়েস্ট পাঠিয়ে স্ট্যাটাস দেখে | রান ফেল দেখায়; আপনাকে জানানো হয় |
ধাপ ১: থিমের রিপোজিটরি কীভাবে সাজাবেন?
রিপোজিটরিতে শুধু থিম রাখুন: WordPress core নয়, আপলোড নয়, অন্য প্লাগইনও নয়। সাধারণ কাঠামো:
style.css,functions.phpআর টেমপ্লেট- PHP মডিউলের জন্য
inc/(ব্লক, হেল্পার, সিকিউরিটি) - ACF ব্লক টেমপ্লেটের জন্য
template-parts/blocks/ - ACF ফিল্ড গ্রুপের জন্য
acf-json/, যাতে ফিল্ড কোডের সাথেই ভার্সনে থাকে - CSS, JS, ফন্ট আর ছবির জন্য
assets/ - GitHub Actions পাইপলাইনের জন্য
.github/workflows/deploy.yml
node_modules, লগ আর .env ফাইলের জন্য .gitignore দিন। সিক্রেট কখনো রিপোজিটরিতে যায় না।

ধাপ ২: টেস্ট জব কীভাবে লিখবেন?
টেস্ট জব matrix দিয়ে দুই PHP ভার্সনে একই চেক চালায়: আপনার থিমের সাপোর্ট করা সবচেয়ে পুরোনো ভার্সন, আর সার্ভারে চলা ভার্সন। এতে পুরোনো সার্ভারের জন্য অতিরিক্ত নতুন সিনট্যাক্স, আর নতুন সার্ভারে deprecation, দুটোই ধরা পড়ে।
প্রতিটা থিমে আমি যে চেকগুলো চালাই:
- PHP সিনট্যাক্স: প্রতিটা
.phpফাইলেphp -l। কয়েক সেকেন্ড লাগে, আর সাদা স্ক্রিনের কারণ হওয়া এররগুলো ধরে। - ACF JSON:
acf-json/-এর প্রতিটা ফাইল বৈধ JSON হতে হবে। ভাঙা ফিল্ড গ্রুপ চুপচাপ এডিটর থেকে ফিল্ড সরিয়ে দেয়। - থিম হেডার:
style.css-এTheme Name:থাকতে হবে, নইলে WordPress থিম চেনে না।
পরে আরও যোগ করতে পারেন: WordPress coding standards সহ PHP_CodeSniffer, CSS linter, বা Sass আর JavaScript-এর বিল্ড ধাপ।
ধাপ ৩: সার্ভারে সীমিত ডিপ্লয় ইউজার কীভাবে বানাবেন?
বেশিরভাগ টিউটোরিয়াল এই ধাপটা বাদ দেয়, অথচ সিকিউরিটির জন্য এটাই সবচেয়ে জরুরি।
- sudo অধিকার ছাড়া
deployনামে একটা ইউজার বানান। - থিমের ফোল্ডারের মালিক করে দিন (গ্রুপ
www-data, যাতে ওয়েব সার্ভার পড়তে পারে)। - শুধু GitHub Actions-এর জন্য নতুন SSH কী জোড়া বানান। নিজের ব্যক্তিগত কী আবার ব্যবহার করবেন না।
- forced command সহ পাবলিক কী
/home/deploy/.ssh/authorized_keys-এ যোগ করুন:
command="/usr/bin/rrsync -wo /var/www/site/wp-content/themes/mytheme",restrict ssh-ed25519 AAAA… github-actions
rrsync শুধু rsync চালাতে দেয়, শুধু ওই ফোল্ডারের ভেতরে, আর -wo একে শুধু লেখার জন্য রাখে। restrict পোর্ট ফরওয়ার্ডিং, টার্মিনাল আর বাকি সব বন্ধ করে। কী কখনো ফাঁস হলেও সেটা দিয়ে শেল খোলা বা আপনার wp-config.php পড়া যাবে না।
- টেস্ট করুন: ওই কী দিয়ে SSH লগইন করলে শেল নয়, rrsync-এর মেসেজসহ প্রত্যাখ্যান হওয়ার কথা।
ধাপ ৪: GitHub-এ কোন সিক্রেট লাগে?
রিপোজিটরির সেটিংসে এই Actions secrets যোগ করুন:
| সিক্রেট | মান |
|---|---|
DEPLOY_SSH_KEY | ডিপ্লয় কী জোড়ার প্রাইভেট কী |
DEPLOY_KNOWN_HOSTS | সার্ভারের হোস্ট কী (ssh-keyscan থেকে) |
DEPLOY_HOST | সার্ভারের IP বা হোস্টনেম |
DEPLOY_USER | deploy |
known_hosts-এ হোস্ট কী বেঁধে রাখলে ডিপ্লয় man-in-the-middle আক্রমণ থেকে বাঁচে। GitHub-এ রাখার পর নিজের কম্পিউটার থেকে প্রাইভেট কী মুছে ফেলুন।
ধাপ ৫: ডিপ্লয় জব কীভাবে লিখবেন?
ডিপ্লয় জব:
- টেস্ট জবের ওপর নির্ভর করে (
needs: test), তাই টেস্ট ফেল করলে কখনো চলে না। - শুধু
main-এ পুশে চলে, পুল রিকোয়েস্টে নয়। - concurrency group ব্যবহার করে, যাতে দুটো ডিপ্লয় একসাথে না চলে।
- কড়া পারমিশনে কী আর known hosts
~/.ssh-এ লেখে। - রিপোজিটরি থেকে সার্ভারে
rsync -az --deleteচালায়,.git,.githubআর যা প্রকাশ্য হওয়া উচিত নয় সেসব বাদ দিয়ে। rrsync কী-কে থিমের ফোল্ডারে আটকে রাখে বলে গন্তব্য শুধু/। - কপির সময়ই পারমিশন ঠিক করে (
--chmod=D755,F644)।
--delete সার্ভার থেকে সেই ফাইলগুলো সরায় যেগুলো আপনি Git-এ মুছেছেন, তাই সার্ভার সবসময় রিপোজিটরির হুবহু মিল থাকে।
ধাপ ৬: স্মোক টেস্ট কীভাবে যোগ করবেন?
কপির পরে দুটো URL-এ রিকোয়েস্ট পাঠান:
- থিমের
style.css: 200 আসতে হবে, এতে প্রমাণ হয় ফাইল পৌঁছেছে। - হোম পেজ: 200 আসতে হবে (ইচ্ছা করে মেইনটেন্যান্স মোডে থাকলে 503)।
কোনোটা ফেল করলে GitHub Actions ওয়ার্কফ্লো ফেল করে, আর GitHub আপনাকে ইমেইল করে। ক্লায়েন্টের কাছে শোনার বদলে এক মিনিটের মধ্যেই জানতে পারেন।
কোন সমস্যায় পড়তে পারেন?
পোর্ট ২২-এ “Connection timed out”
সার্ভারের ফায়ারওয়াল SSH খোলা রেখেছে, তবু GitHub-এর রানার সংযোগ পাচ্ছে না। অনেক হোস্টিং প্রোভাইডারের কন্ট্রোল প্যানেলে বাড়তি ফায়ারওয়াল থাকে, যা শুধু কিছু IP-কে ঢুকতে দেয়। সেখানে পোর্ট ২২ খুলুন, অথবা সার্ভারেই self-hosted runner ব্যবহার করুন।
“Permission denied (publickey)”
GitHub-এর কী authorized_keys-এর সাথে মিলছে না, অথবা ডিপ্লয় ইউজারের .ssh ফোল্ডারের পারমিশন ভুল (ফোল্ডারে 700, ফাইলে 600 হবে)।
ফাইল গেছে, কিন্তু সাইট বদলায়নি
ক্যাশিং দেখুন: পেজ ক্যাশ, CDN বা OPcache পুরোনো ভার্সন দিতে পারে। CSS আর JS-এর URL-এ ফাইলের মডিফিকেশন টাইম দিন, যাতে ব্রাউজার নতুন ফাইল আনে।
Windows আর সার্ভারের লাইন এন্ডিং আলাদা
Windows-এ ডেভেলপ করলে Git আপনার ওয়ার্কিং কপির লাইন এন্ডিং বদলাতে পারে। সার্ভার পায় commit করা ভার্সন, আপনি সেটাই চান। মেলানোর সময় লোকাল ফাইলের সাথে নয়, git show HEAD:file-এর সাথে মেলান।
প্রতিদিনের কাজে এটা কীভাবে মেলে?
- লোকাল WordPress-এ পরিবর্তন করুন (LocalWP ভালো চলে)।
- ব্রাঞ্চে commit করে পুল রিকোয়েস্ট খুলুন; টেস্ট নিজে থেকেই চলে।
- চেক সবুজ হলে
main-এ merge করুন। - GitHub এক মিনিটের মধ্যে ডিপ্লয় করে; স্মোক টেস্ট নিশ্চিত করে সাইট চালু আছে।
- আগের অবস্থায় ফিরতে commit-টা revert করুন; আগের ভার্সন নিজে থেকেই ডিপ্লয় হয়।
ব্রাঞ্চ আর রিলিজ কীভাবে সামলাবেন?
বেশিরভাগ WordPress থিমে সহজ একটা ব্রাঞ্চ মডেলই যথেষ্ট:
| ব্রাঞ্চ | কাজ | ডিপ্লয় হয়? |
|---|---|---|
main | ঠিক যা লাইভ আছে | হ্যাঁ, অটোমেটিক |
feature/... | একটা পরিবর্তন বা ফিচার | না, শুধু টেস্ট |
hotfix/... | জরুরি ঠিক করা | না, দ্রুত main-এ merge |
ফিচার ব্রাঞ্চে কাজ করুন, পুল রিকোয়েস্ট খুলুন, টেস্ট চলতে দিন। সবুজ হলে তবেই merge করুন। main সবসময় লাইভ সাইটের সাথে মেলে বলে আপনি সবসময় জানেন কী ডিপ্লয় হয়ে আছে।
বড় রিলিজে ভার্সন ট্যাগ দিন (v1.4.0) আর style.css-এর Version বাড়ান। অ্যাসেটের URL-এ ফাইলের মডিফিকেশন টাইম রাখলে ব্রাউজার সাথে সাথে নতুন CSS আর JavaScript নামায়।
একই পাইপলাইনে স্টেজিং যোগ করা যায়?
হ্যাঁ, আর ক্লায়েন্টের সাইটে এটা করার মতো। একই VPS-এ স্টেজিং সাবডোমেইন বানান, নিজস্ব WordPress ইনস্টল আর নিজস্ব সীমিত ডিপ্লয় কী সহ। তারপর:
stagingব্রাঞ্চে পুশ গেলে স্টেজিং সাইটে ডিপ্লয় হয়।main-এ পুশ গেলে প্রোডাকশনে ডিপ্লয় হয়।
ক্লায়েন্ট লাইভের আগে স্টেজিংয়ে পরিবর্তন দেখে নিতে পারেন, আর প্রোডাকশনে ডিপ্লয় মানে শুধু একটা merge।
যে থিমে বিল্ড ধাপ লাগে?
থিমে Sass, JavaScript বান্ডলার বা Tailwind থাকলে টেস্ট আর ডিপ্লয়ের মাঝে একটা বিল্ড ধাপ যোগ করুন:
- GitHub Actions ওয়ার্কফ্লোতে Node.js ইনস্টল করুন।
npm ciআর আপনার বিল্ড কমান্ড চালান।- বিল্ড করা ফাইল ডিপ্লয় করুন, সোর্স ফোল্ডার আর
node_modulesবাদ দিয়ে।
লক ফাইল commit করুন, যাতে বিল্ড বারবার একই হয়, আর সোর্সের সাথে না-মেলা বিল্ড ফাইল কখনো commit করবেন না।
খারাপ ডিপ্লয় থেকে কীভাবে ফিরবেন?
প্রতিটা ডিপ্লয় একটা commit, তাই ফেরাও আরেকটা commit মাত্র:
- যে commit-এ সমস্যা হয়েছে সেটা খুঁজুন।
git revertদিয়ে সেটা উল্টে দেওয়ার commit বানান।main-এ পুশ করুন; GitHub Actions টেস্ট করে এক মিনিটের মধ্যে আগের ভার্সন ডিপ্লয় করে।
FTP নেই, কোন ফাইল বদলেছে তার অনুমান নেই, আর ইতিহাসে পরিষ্কার লেখা থাকে কী হলো, কেন হলো।
পরে কোন সিকিউরিটি চেক যোগ করা উচিত?
মৌলিক অংশ চালু হলে এই চেকগুলো সত্যিই কাজে লাগে:
- WordPress Coding Standards সহ PHP_CodeSniffer, বিশেষ করে escaping আর sanitising-এর জন্য।
- সিক্রেট স্ক্যানার, যাতে API কী ভুল করে commit না হয়।
- থিমে Composer বা npm প্যাকেজ থাকলে ডিপেন্ডেন্সি রিভিউ।
- ডিবাগ কোড (
var_dump,console.log) প্রোডাকশনে যাচ্ছে না, তার চেক।

প্রশ্নোত্তর
সাধারণ প্রশ্নের উত্তর
ছোট WordPress সাইটেও কি GitHub Actions লাগে?
একেবারে জরুরি নয়, তবে সেটআপে এক-দুই ঘণ্টা লাগে আর ডিপ্লয়ের বেশিরভাগ ঝুঁকি চলে যায়। যে সাইট টাকা আনে, সেখানে প্রথমবার একটা ভাঙা ডিপ্লয় আটকালেই খরচ উঠে আসে।
GitHub Actions কি প্লাগইন আর ডেটাবেসও ডিপ্লয় করতে পারে?
কাস্টম প্লাগইন থিমের মতোই ডিপ্লয় করা যায়। ডেটাবেসের কনটেন্ট (পেজ, পোস্ট, সেটিংস) লাইভ সাইটেই থাকা উচিত; দরকার হলে শুধু মাইগ্রেশন টুল দিয়ে সরান।
GitHub Secrets-এ SSH কী রাখা কি নিরাপদ?
হ্যাঁ, যদি কী-টা এমন সীমিত ইউজারের হয় যে শুধু একটা ফোল্ডারে লিখতে পারে। root কী বা শেল অ্যাক্সেসের কী কখনো রাখবেন না।
হোস্ট যদি SSH না দেয়?
তাহলে হোস্টই পেশাদারভাবে ডিপ্লয় করার পথ আটকাচ্ছে। অনেক ম্যানেজড WordPress হোস্ট Git ডিপ্লয় দেয়; নইলে ছোট একটা VPS ভেবে দেখার মতো।
Bitbucket বা GitLab-এ কি এটা চলে?
হ্যাঁ। একই ধারণা (টেস্ট জব, ডিপ্লয় জব, সীমিত কী) Bitbucket Pipelines আর GitLab CI-তেও চলে।
আপনার WordPress থিম বা প্লাগইনের জন্য এই GitHub Actions পাইপলাইন সেটআপ করাতে চাইলে আমার VPS ও DevOps সার্ভিস দেখুন অথবা Upwork-এ হায়ার করুন।
প্রজেক্টের কথা ভাবছেন?
Upwork-এ আপনার জবে ইনভাইট করুন বা সরাসরি হায়ার করুন — সেখানেই বিস্তারিত আলাপ করব। সাধারণত কয়েক ঘণ্টার মধ্যেই উত্তর দিই।
Upwork-এ হায়ার করুন