শুক্রবার রাতে cPanel-এ ঢুকে Softaculous থেকে এক ক্লিকে WordPress বসিয়ে দিলেন — সময় লাগল দুই মিনিট। থিম বসালেন, চারটা পেজ বানালেন, ক্লায়েন্টকে লিংক পাঠিয়ে ঘুমাতে গেলেন। তিন মাস পর ফোন এল: সাইট খুলছে না। হোমপেজে অচেনা ভাষার স্প্যাম লিংক ঝুলছে, wp-admin-এ লগইন করলে সাদা স্ক্রিন, আর হোস্টিং সাপোর্ট বলছে অ্যাকাউন্ট সাসপেন্ড করা হয়েছে কারণ সার্ভার থেকে স্প্যাম মেইল যাচ্ছে।
এই গল্পটা বাংলাদেশে এত ঘন ঘন ঘটে যে এখন আর একে গল্প মনে হয় না, রুটিন মনে হয়। মজার ব্যাপার হলো, ইনস্টল করার সময় আপনি ভুল কিছু করেননি — Softaculous ঠিক যা করার কথা তা-ই করেছে। সমস্যাটা অন্য জায়গায়: এক-ক্লিক ইনস্টলার আপনার হয়ে অন্তত আটটা সিদ্ধান্ত নিয়ে ফেলে, আর তার প্রতিটাই একটা ডেমো সাইটের জন্য যুক্তিসঙ্গত, লাইভ প্রোডাকশন সাইটের জন্য নয়। একটা wordpress installation ঠিকভাবে দাঁড় করাতে আসলে দুই মিনিট লাগে না, লাগে চল্লিশ মিনিট। আর সেই চল্লিশ মিনিট বাঁচাতে গিয়েই পরে দুই সপ্তাহ চলে যায়।
ইনস্টল ভুল হয়নি, ডিফল্ট সেটিংসগুলো ভুল ছিল
ইনস্টলার আপনাকে যা দেয় সেটা হলো সবচেয়ে কম ঝামেলার কনফিগারেশন — যাতে যেকোনো সার্ভারে, যেকোনো হাতে সেটা অন্তত চালু হয়ে যায়। কিন্তু চালু হওয়া আর টিকে থাকা এক জিনিস নয়। নিচের পাঁচটা ডিফল্টই বেশিরভাগ হ্যাক আর সাদা স্ক্রিনের পেছনে দায়ী:
- ইউজারনেম `admin`, টেবিল প্রিফিক্স `wp_` — বট দুটোই ধরে নিয়ে ব্রুট-ফোর্স শুরু করে। টেবিলের নাম
wp_usersজানা থাকলে SQL injection-এর পেলোড লেখাও সহজ হয়ে যায়। অনুমান করার কিছু থাকে না। - PHP 7.4 বা 8.0 — বাংলাদেশের অনেক শেয়ার্ড হোস্টিংয়ে এখনো এটাই ডিফল্ট। PHP 7.4-এর নিরাপত্তা আপডেট বহু আগেই বন্ধ হয়ে গেছে। সাইট চলবে ঠিকই, কিন্তু WooCommerce থাকলে PHP 8.2-এর তুলনায় লক্ষণীয় ধীর, আর পরিচিত দুর্বলতাগুলো খোলা থাকে।
- memory_limit 128M — WooCommerce, Elementor আর একটা ব্যাকআপ প্লাগিন একসাথে চললেই মেমরি শেষ। ফল: white screen of death, কোনো এরর মেসেজ ছাড়াই।
- SSL বসেনি, কিংবা বসেছে কিন্তু Site URL এখনো `http://` — এতে bKash, SSLCommerz বা যেকোনো পেমেন্ট গেটওয়ে mixed-content হিসেবে ব্লক হয়ে যায়। কাস্টমার চেকআউটে গিয়ে আটকে যান, আপনি কারণ খুঁজে পান না।
- ব্যাকআপ শূন্য — সবচেয়ে বড় ভুলটা এখানেই। হ্যাক হওয়ার পর ফিরে যাওয়ার কোনো জায়গা না থাকলে বাকি সব আলোচনা অর্থহীন।
cPanel খোলার আগে পাঁচ মিনিটের যাচাই
ইনস্টল শুরু করার আগে হোস্টিং প্যানেলে ঢুকে এই কয়টা জিনিস দেখে নিন। বেশিরভাগ প্যানেলে MultiPHP Manager আর Select PHP Version নামে অপশন থাকে, সেখান থেকেই সব বদলানো যায়:
- PHP 8.2 বা 8.3 সিলেক্ট করুন। এক্সটেনশন হিসেবে অন্তত
mysqli,curl,gd,mbstring,zip,intlচালু আছে কিনা দেখুন — না থাকলে অনেক প্লাগিন নীরবে কাজ করা বন্ধ করে দেয়। - MySQL 8.0 বা MariaDB 10.6+ — পুরোনো MySQL 5.6-এ ইমোজি আর বাংলা টেক্সট (utf8mb4) নিয়ে ঝামেলা হয়। বাংলা কনটেন্টের সাইটে এটা তুচ্ছ ব্যাপার নয়।
- memory_limit 256M,
upload_max_filesize 64M,post_max_size 64M,max_execution_time 300— শেষ দুটো না বাড়ালে বড় থিম বা ডেমো কনটেন্ট ইমপোর্ট করতে গিয়ে টাইমআউট খাবেন। - ফ্রি Let's Encrypt SSL আছে কিনা দেখুন। প্রায় সব লোকাল হোস্ট এখন দেয়, কিন্তু কারও কারও ক্ষেত্রে ম্যানুয়ালি চালু করতে হয়।
- অটোমেটিক ব্যাকআপ পলিসি কী — দৈনিক না সাপ্তাহিক, আর কত দিনের ব্যাকআপ রাখা হয়। সাপোর্ট টিকিটে জিজ্ঞেস করে নিন, ওয়েবসাইটের বিজ্ঞাপনে যা লেখা থাকে সেটা সবসময় বাস্তব নয়।
ক্লায়েন্টের সাইট যদি WooCommerce হয়, বছরে ১,৫০০ টাকার শেয়ার্ড প্যাকেজে বসাবেন না। ২০-৩০ জন কনকারেন্ট ইউজার হলেই CPU ও entry-process লিমিটে ধাক্কা লাগে, হোস্ট আপনাকে throttle করে — সাইট হামাগুড়ি দিতে থাকে, কিন্তু কোনো এরর লগে কিছু পাবেন না। ছোট একটা VPS বা ভালো ক্লাউড প্ল্যান মাসে ৮০০-২,০০০ টাকায় পাওয়া যায়; একটা অর্ডার হারানোর চেয়ে সেটা সস্তা।
ডেটাবেস আর ডেটাবেস-ইউজার নিজের হাতে বানান
cPanel → MySQL Databases-এ গিয়ে আলাদা করে ডেটাবেস তৈরি করুন, ইনস্টলারকে করতে দেবেন না। নাম দিন কাজের মতো করে — যেমন stackalix_shop। এরপর আলাদা একটা ইউজার বানান (stackalix_shopusr), পাসওয়ার্ড অন্তত ৩২ অক্ষরের র্যান্ডম স্ট্রিং, আর সেই ইউজারকে ALL PRIVILEGES দিন শুধুমাত্র ওই একটা ডেটাবেসে।
কেন এত কষ্ট? কারণ একটা হোস্টিং অ্যাকাউন্টে যদি আপনার পাঁচটা ক্লায়েন্ট সাইট থাকে আর পাঁচটাই একই DB ইউজার শেয়ার করে, তাহলে একটা সাইটের একটা দুর্বল প্লাগিন থেকে পাসওয়ার্ড ফাঁস হলে পাঁচটাই একসাথে যায়। আলাদা ইউজার মানে ক্ষতিটা এক সাইটেই আটকে থাকে। এই একটা অভ্যাস এজেন্সি হিসেবে আপনাকে অনেক রাতের ঘুম ফিরিয়ে দেবে।
wp-config.php: যে কয়েকটা লাইন আসলেই কাজে দেয়
ইনস্টল শেষে wp-config.php খুলে এই লাইনগুলো যোগ করুন বা ঠিক করুন। ইন্টারনেটে ছড়ানো বিশাল বিশাল hardening লিস্টের বেশিরভাগই অপ্রয়োজনীয়; নিচেরগুলো আসল কাজের:
$table_prefix = 'sx7_';— ইনস্টলের সময়েই সেট করুন। পরে বদলাতে গেলে ডেটাবেসের ভেতরের অপশন-নামও বদলাতে হয়, ঝামেলা বাড়ে।- সল্ট কি-গুলো
https://api.wordpress.org/secret-key/1.1/salt/থেকে নিয়ে বসান। কেউ কুকি চুরি করে থাকলে সল্ট বদলে দিলেই সব সেশন লগআউট হয়ে যায় — হ্যাক পরিষ্কারের সময় এটাই প্রথম কাজ। define('DISALLOW_FILE_EDIT', true);— অ্যাডমিন প্যানেল থেকে থিম/প্লাগিন এডিটর বন্ধ। কারও অ্যাডমিন অ্যাকাউন্ট বেহাত হলে সে যেন সরাসরি PHP ব্যাকডোর লিখতে না পারে।define('WP_DEBUG', false);লাইভে, সাথেWP_DEBUG_DISPLAYfalse আরWP_DEBUG_LOGtrue — এরর দর্শককে দেখাবেন না, কিন্তু ফাইলে জমা রাখুন।define('WP_POST_REVISIONS', 5);আরdefine('EMPTY_TRASH_DAYS', 7);— না হলে দুই বছর পরwp_postsটেবিল রিভিশনে ফুলে ঢোল হয়ে যায় আর ব্যাকআপ ভারী হতে থাকে।
WP-CLI: চল্লিশ মিনিটের কাজ চার মিনিটে
যদি হোস্টিংয়ে SSH থাকে (বেশিরভাগ ভালো লোকাল হোস্টেই এখন আছে, চেয়ে নিতে হয়), তাহলে WP-CLI দিয়ে ইনস্টল করাই সবচেয়ে দ্রুত আর সবচেয়ে নির্ভুল। কারণ প্রতিটা সিদ্ধান্ত আপনি স্পষ্ট করে লিখে দিচ্ছেন, কোনো ডিফল্ট নীরবে ঢুকছে না:
wp core download --locale=en_USwp config create --dbname=stackalix_shop --dbuser=stackalix_shopusr --dbpass='...' --dbprefix=sx7_wp core install --url=https://example.com.bd --title='...' --admin_user=nasif_ops --admin_email=...wp rewrite structure '/%postname%/'— পরে permalink নিয়ে আর ভাবতে হবে নাwp plugin delete hello akismetআরwp theme delete twentytwentythree twentytwentytwo— যা ব্যবহার করবেন না তা রেখে দেওয়া মানে অতিরিক্ত আক্রমণের রাস্তা খোলা রাখা
XAMPP থেকে লাইভে নেওয়ার সময় সবচেয়ে বড় ভুলটা
লোকালহোস্টে বানিয়ে লাইভে তোলার সময় প্রায় সবাই একই কাজ করে: ডেটাবেস এক্সপোর্ট করে, phpMyAdmin-এ SQL চালিয়ে http://localhost/shop কে https://shop.com.bd দিয়ে রিপ্লেস করে দেয়। এরপর দেখা যায় থিম অপশন উধাও, উইজেট ফাঁকা, স্লাইডার নেই।
কারণটা সহজ: WordPress অনেক সেটিংস serialize করে রাখে, যেমন s:21:"http://localhost/shop"; — এখানে ২১ মানে স্ট্রিংটার দৈর্ঘ্য। আপনি URL বদলে ফেললেন কিন্তু ২১ সংখ্যাটা রয়ে গেল, ফলে PHP আর unserialize করতে পারে না, মানটা চুপচাপ null হয়ে যায়। তাই সাধারণ find-replace এখানে বিষ।
সঠিক উপায় হলো serialization-সচেতন টুল দিয়ে রিপ্লেস করা। WP-CLI-তে আগে ড্রাই রান করুন: wp search-replace 'http://localhost/shop' 'https://shop.com.bd' --all-tables --precise --skip-columns=guid --dry-run। আউটপুট দেখে সন্তুষ্ট হলে --dry-run বাদ দিয়ে আবার চালান। WP-CLI না থাকলে Better Search Replace প্লাগিন একই কাজ করে।
--skip-columns=guid অংশটা বাদ দেবেন না। guid হলো পোস্টের স্থায়ী পরিচয়, কোনো লিংক নয়। ওটা বদলে দিলে RSS রিডার আর কিছু ক্যাশ সিস্টেম আপনার পুরোনো পোস্টগুলোকে নতুন পোস্ট ভেবে বসে।ইনস্টলের পর প্রথম আধঘণ্টা
- Settings → Permalinks-এ গিয়ে Post name সিলেক্ট করুন। ডিফল্ট
?p=123SEO-র জন্য অপচয়। - অ্যাডমিন ইউজারের নাম
adminহলে নতুন একটা অ্যাডমিন বানিয়ে পুরোনোটা ডিলিট করে দিন (কনটেন্ট নতুন ইউজারে reassign করে নেবেন)। - Wordfence বা Limit Login Attempts বসিয়ে লগইন চেষ্টা সীমিত করুন। শুধু এটুকুতেই ব্রুট-ফোর্সের ৯০ শতাংশ ঝরে যায়।
- UpdraftPlus বসিয়ে Google Drive-এ সাপ্তাহিক অটো-ব্যাকআপ চালু করুন। হোস্টের ব্যাকআপের উপর একা ভরসা করবেন না — অ্যাকাউন্ট সাসপেন্ড হলে সেই ব্যাকআপেও আপনি ঢুকতে পারবেন না।
- SMTP প্লাগিন বসান (Brevo, Mailgun বা হোস্টের SMTP)। শেয়ার্ড হোস্টিংয়ের PHP
mail()দিয়ে পাঠানো অর্ডার কনফার্মেশন Gmail-এ সোজা স্প্যামে যায় — ক্লায়েন্ট ভাববেন সাইট কাজ করছে না। - Tools → Site Health দেখে নিন। WordPress নিজেই বলে দেবে PHP পুরোনো কিনা, কোন মডিউল নেই, কোথায় আপডেট বাকি।
যে প্রশ্নগুলো ক্লায়েন্ট আর জুনিয়র ডেভরা সবচেয়ে বেশি করেন
Softaculous কি তাহলে একেবারেই ব্যবহার করব না? করবেন, সমস্যা নেই — শুধু ইনস্টল ফর্মের Advanced অপশনটা খুলুন। ওখানেই টেবিল প্রিফিক্স, অ্যাডমিন ইউজারনেম আর ডেটাবেসের নাম বদলানো যায়, আর অটো-আপডেট সেট করা যায়। ডিফল্ট মেনে Next চাপাটাই আসল অপরাধ, টুলটা নয়।
লোকাল হোস্টিং নেব নাকি বিদেশি? ভিজিটর যদি মূলত বাংলাদেশ থেকে আসেন, তাহলে ঢাকা বা সিঙ্গাপুরের সার্ভার latency-তে সুবিধা দেয়। কিন্তু সিদ্ধান্তটা শুধু লোকেশন দিয়ে নেবেন না — PHP ভার্সন কত, ব্যাকআপ কত দিনের, সাপোর্ট রাত ২টায় সাড়া দেয় কিনা, এগুলোই বেশি গুরুত্বপূর্ণ।
সাব-ডিরেক্টরিতে ইনস্টল করব নাকি রুটে? মূল সাইট সবসময় রুটে (public_html)। ব্লগ বা দোকান আলাদা রাখতে চাইলে example.com/blog সাব-ডিরেক্টরি সাব-ডোমেইনের চেয়ে ভালো, কারণ ডোমেইন অথরিটি ভাগ হয়ে যায় না।
ইনস্টল ঠিকঠাক হয়েছে কিনা বুঝব কীভাবে? তিনটা জিনিস দেখুন: Site Health-এ কোনো critical issue নেই, SSL Labs-এ সাইট অন্তত A গ্রেড পাচ্ছে, আর https://example.com/?author=1 দিলে আপনার লগইন ইউজারনেম ফাঁস হয়ে যাচ্ছে না।
ছাপিয়ে রাখার মতো চেকলিস্ট
- PHP 8.2+, MySQL 8/MariaDB 10.6+, memory_limit 256M
- আলাদা ডেটাবেস + আলাদা DB ইউজার, শক্ত পাসওয়ার্ড
- টেবিল প্রিফিক্স ডিফল্ট নয়, অ্যাডমিন ইউজারনেম
adminনয় - wp-config-এ নতুন সল্ট,
DISALLOW_FILE_EDIT,WP_DEBUGfalse - SSL চালু এবং Site URL
https:// - Permalink = Post name
- অব্যবহৃত থিম ও প্লাগিন ডিলিট
- লগইন লিমিট + অফসাইট অটো-ব্যাকআপ + SMTP চালু
- লোকাল থেকে মাইগ্রেট করলে
wp search-replace, কখনোই SQL find-replace নয়
একটা সাইট ঠিকভাবে বসাতে যে চল্লিশ মিনিট লাগে, সেটা আসলে সাইটের বাকি জীবনের ইনস্যুরেন্স। আমরা Stack Alix-এ যখন কোনো ক্লায়েন্টের হ্যাক হওয়া সাইট উদ্ধার করি, দশটার মধ্যে নয়টাতেই মূল কারণটা এই তালিকার কোনো একটা লাইন — কেউ সেদিন তাড়াহুড়ো করেছিলেন। নতুন সাইট সেটআপ করছেন, নাকি পুরোনো একটার হাল ধরতে হবে বুঝতে পারছেন না? একবার কথা বলে নিন, আমরা আগে দেখে বলি সমস্যাটা আসলে কোথায়।

