কিভাবে HRConvert2 দিয়ে নিজের ফাইল কনভার্টার তৈরি করবেন
আপনার সার্ভারে HRConvert2 ইনস্টল করে ফাইল কনভার্সন নিরাপদ করুন। ডকার বা অ্যাপাচি ব্যবহার করে 488টি ফরম্যাট সাপোর্ট এবং বাবলর্যাপ স্যান্ডবক্সিংয়ের মাধ্যমে ডেটা সুরক্ষা নিশ্চিত করুন।
কেন একটি ফাইল কনভার্টার নিজে হোস্ট করবেন
একটি সেলফ-হোস্টেড ফাইল কনভার্টার ফাইলটিকে আপনার নিজের ডিস্কেই রাখে। এটিই এটি চালানোর একমাত্র কারণ। একটি ফ্রি কনভার্টার সাইট ফাইলটি আপলোড করার পর সেটির সাথে কী করা হয় তা জানার কোনো উপায় আপনাকে দেয় না। যখন ফাইলটি কোনো স্বাক্ষরিত ক্লায়েন্ট চুক্তি বা স্ক্যান করা মেডিকেল রেকর্ড হয়, তখন আপলোড করাই একটি নিরাপত্তা ঝুঁকি। HRConvert2 হলো PHP-তে লেখা একটি ড্র্যাগ-অ্যান্ড-ড্রপ ফাইল কনভার্সন সার্ভার, যা GPLv3 লাইসেন্সের অধীনে প্রকাশিত। 18 আগস্ট 2026-এ 3.7.4 সংস্করণটি রিলিজ করা হয়েছে এবং প্রজেক্টটি 488টি ফরম্যাট সাপোর্ট করার দাবি করে।
এটিতে কোনো ডাটাবেস, অ্যাকাউন্ট বা কুকি নেই। একজন ব্যবহারকারী মানেই একটি অস্থায়ী ডিরেক্টরি। প্রতিটি কনভার্সন একটি লোকাল কমান্ড লাইন টুলের মাধ্যমে সম্পন্ন হয়: ডকুমেন্টের জন্য LibreOffice, অডিও ও ভিডিওর জন্য FFmpeg, ইমেজের জন্য ImageMagick, অপটিক্যাল ক্যারেক্টার রিকগনিশন (OCR)-এর জন্য Tesseract এবং অন্যান্য ফরম্যাটের জন্য আরও অনেক ছোট ছোট টুল। HRConvert2 হলো আপলোড পেজ, পাইপলাইন এবং সেগুলোর চারপাশের ক্লিনআপ প্রক্রিয়া।
এটি একটি ফাইলকে এক ফরম্যাট থেকে অন্য ফরম্যাটে রূপান্তর করে। এটি কোনো ব্রাউজার-ভিত্তিক অফিস স্যুট নয়, তাই আপনি যদি চান যে ব্যবহারকারীরা ব্রাউজার ট্যাবে ডকুমেন্ট এডিট করুক, তবে সেলফ-হোস্টেড OnlyOffice এবং Collabora তুলনা করে দেখুন। এটি কোনো স্টোরেজও নয়। কনভার্ট করা আউটপুট মুছে ফেলার জন্য তৈরি, তাই ফাইলগুলো যদি কোথাও সংরক্ষণ করে রাখতে হয়, তবে সেই কাজটি একটি সেলফ-হোস্টেড ফাইল ম্যানেজারের।
প্রয়োজনীয় বিষয়সমূহ
Debian বা Ubuntu, Apache 2.4, PHP 8 বা তার পরবর্তী সংস্করণ এবং bubblewrap প্রয়োজন। Bubblewrap (bwrap) হলো স্যান্ডবক্স, এবং এটি ঐচ্ছিক নয়: যে সার্ভার স্যান্ডবক্স তৈরি করতে পারে না, সেটি কোনো সুরক্ষা ছাড়াই চলার পরিবর্তে কনভার্সন প্রক্রিয়াটি বাতিল করে দেয়। আপস্ট্রিম README অনুযায়ী Raspberry Pi Model B+ এর জন্য যথেষ্ট, যা PHP অংশের ক্ষেত্রে সত্য। কনভার্টার বাইনারিগুলো আপনার হার্ডওয়্যারের সক্ষমতা নির্ধারণ করে, যা নিচে বিস্তারিত আলোচনা করা হয়েছে।
এখানে কাজ শুরু করার দুটি উপায় আছে। Docker ইমেজটি আজ রাতেই কাজ শুরু করার জন্য উপযুক্ত। Apache এবং PHP ইনস্টল করতে এক সন্ধ্যা সময় লাগতে পারে, তবে এটি আপনার সার্ভারে ঠিক কী কী আছে তা স্পষ্টভাবে দেখাবে।
আজ রাতে Docker-এর মাধ্যমে এটি চালান
এই ইমেজে প্রতিটি কনভার্টার বাইনারি অন্তর্ভুক্ত থাকে, তাই এর আকার বেশ বড়: আগস্ট 2026 অনুযায়ী প্রায় 3 GB। ইমেজ পুল করার আগে ডিস্কে পর্যাপ্ত জায়গা আছে কি না তা যাচাই করুন।
এখানে ট্যাগগুলো গুরুত্বপূর্ণ। 17 আগস্ট 2026 অনুযায়ী Docker Hub-এ প্রকাশিত সর্বশেষ ট্যাগ হলো v3.7.2, এবং GitHub-এর সর্বশেষ রিলিজ হলো v3.7.4। latest ট্যাগটি নিয়মিত পরিবর্তিত হয় এবং এই অ্যাপ্লিকেশনটির পার্সার সারফেস অনেক বড়, তাই একটি নির্দিষ্ট ভার্সন পিন করে রাখুন এবং প্রয়োজন অনুযায়ী আপডেট করুন।
docker pull zelon88/hrconvert2:v3.7.2
docker run -d --name hrconvert2 \
-p 127.0.0.1:8080:80 \
--security-opt seccomp=unconfined \
zelon88/hrconvert2:v3.7.2docker ps
curl -I http://127.0.0.1:8080/একটি সচল কন্টেইনার Up অবস্থায় থাকে এবং curl কমান্ডটি HTTP/1.1 200 OK রিটার্ন করে। যে কন্টেইনার বারবার রিস্টার্ট হয়, সেটির স্টার্টআপে সমস্যা আছে; তাই অন্য কিছু পরিবর্তন করার আগে docker logs hrconvert2 পড়ুন।
দুটি ফ্ল্যাগ এখানে গুরুত্বপূর্ণ ভূমিকা পালন করে। -p 127.0.0.1:8080:80 ফ্ল্যাগটি শুধুমাত্র লুপব্যাক ইন্টারফেসে পোর্ট পাবলিশ করে, ফলে আপনি নিজে থেকে সামনে কোনো প্রক্সি বসানোর আগে কনভার্টারের কাছে কোনো অনুরোধ পৌঁছাবে না। প্রজেক্টের নিজস্ব উদাহরণে -p 8080:80 -p 8443:443 ম্যাপ করা হয়েছে, যা পাবলিক ইন্টারফেসসহ সব ইন্টারফেসে লিসেন করে। --security-opt seccomp=unconfined ফ্ল্যাগটি প্রয়োজন কারণ bubblewrap তার স্যান্ডবক্স তৈরির জন্য এমন user namespace এবং mount system call ব্যবহার করে, যা Docker-এর ডিফল্ট seccomp প্রোফাইল ব্লক করে দেয়। এই ফ্ল্যাগ ছাড়া কনভার্সন ব্যর্থ হয় এবং অ্যাপ্লিকেশন আপনাকে কারণ জানিয়ে দেয়: A sandbox blocks the required syscalls unless it was started with the correct options.
এই ফ্ল্যাগটি ব্যবহারের ক্ষেত্রে একটি আপস করতে হয়। আপনি কন্টেইনারের syscall ফিল্টার শিথিল করছেন যাতে অ্যাপ্লিকেশনটি তার ভেতরে আরও কঠোর স্যান্ডবক্স তৈরি করতে পারে। যে দুটি সেটিং এই আচরণ নির্ধারণ করে তা হলো Resources/config.php ফাইলের $RequireSandbox এবং $RequireSandboxOnDocker, যেগুলোর ডিফল্ট মান যথাক্রমে TRUE এবং FALSE। যেহেতু Docker-এর এই রিকোয়ারমেন্ট ডিফল্টভাবে বন্ধ থাকে, তাই seccomp ফ্ল্যাগ ছাড়া একটি কন্টেইনার কোনো স্যান্ডবক্স ছাড়াই কনভার্সন করতে পারে। একবার ফ্ল্যাগটি যুক্ত করলে, $RequireSandboxOnDocker = TRUE; সেট করুন এবং আপনি কন্টেইনারের ভেতরে পুনরায় সেই রিফিউজাল আচরণ ফিরে পাবেন।
যদি এই মেশিনে Docker নতুন হয়, তবে প্রথমে ডেমোন সেটআপ করুন। VPS-এ Docker চালানো অংশে ইন্সটলেশন, স্টোরেজ ড্রাইভার এবং Docker কীভাবে নিজস্ব ফায়ারওয়াল রুল লেখে তা আলোচনা করা হয়েছে।
এর পরিবর্তে Apache এবং PHP-তে ইনস্টল করুন
রিপোজিটরিতে থাকা Documentation/INSTALLATION_INSTRUCTIONS.txt ফাইলটিই মূল নির্দেশিকা, যেখানে নয়টি ধাপ রয়েছে। এর গঠনটি নিম্নরূপ। ওয়েব সার্ভার, ল্যাঙ্গুয়েজ এবং স্যান্ডবক্স দিয়ে শুরু করুন:
sudo apt update
sudo apt install -y apache2 php libapache2-mod-php php-all-dev php8.3-zip php8.3-gd bubblewrapphp8.3-* নামগুলো Ubuntu 24.04-এর সাথে সামঞ্জস্যপূর্ণ। php -v কমান্ডটি চালান এবং আপনার ভার্সনের সাথে মিল রেখে প্রিফিক্স ব্যবহার করুন, কারণ প্রতিটি PHP রিলিজের সাথে প্যাকেজের নাম পরিবর্তিত হয় এবং ভুল প্যাকেজ ব্যবহার করলে Unable to locate package ত্রুটি দেখা দেবে।
এরপর কনভার্টারগুলো ইনস্টল করুন। এটি ডকুমেন্ট, ইমেজ, অডিও, ভিডিও এবং OCR-এর জন্য প্রয়োজনীয়, যা সাধারণত বেশিরভাগ কনভার্সন কাজের জন্য যথেষ্ট:
sudo apt install -y imagemagick ffmpeg libreoffice-common libreoffice-java-common \
default-jre ghostscript poppler-utils libgxps-utils tesseract-ocr inkscape \
xvfb clamav curl tar libxcb-cursor0আর্কাইভ ফরম্যাট, 3D মডেল, ই-বুক এবং বুটেবল ISO ইমেজের জন্য আরও প্যাকেজের প্রয়োজন হয় এবং এর মধ্যে কিছু Ubuntu-এর multiverse কম্পোনেন্টে থাকে। অফিসিয়াল নির্দেশিকার 3 এবং 5 নম্বর ধাপে সম্পূর্ণ তালিকা ক্রমানুসারে দেওয়া আছে। দুটি ডিপেন্ডেন্সি apt প্যাকেজ নয়: রিপোজিটরিতে Documentation/Build/ffmpeg-build.sh এবং Documentation/Build/build-imagemagick-v7.sh দেওয়া আছে তাদের জন্য যাদের এনকোডার বা ImageMagick 7 প্রয়োজন, যা Ubuntu-এর প্যাকেজে নেই। ই-বুক সাপোর্ট calibre-এর নিজস্ব ইনস্টলার থেকে আসে, যা নির্দেশিকায় এক লাইনে দেওয়া হয়েছে:
sudo -v && wget -nv -O- https://download.calibre-ebook.com/linux-installer.sh | sudo sh /dev/stdinএটি একটি ভেন্ডর স্ক্রিপ্ট যা root হিসেবে সরাসরি শেল-এ পাইপ করা হয়। এটিই আপস্ট্রিম পদ্ধতি এবং এটি ঐচ্ছিক: এটি এড়িয়ে চললে শুধুমাত্র ই-বুক কনভার্সন সুবিধাটি পাবেন না।
এরপর, PHP-এর লিমিটগুলো দেখুন। কনভার্সন প্রক্রিয়া ধীর এবং ফাইলগুলো বড় হয়, তাই ডিফল্ট মানগুলো যথেষ্ট নয়। প্রজেক্টটি php.ini ফাইলে এগুলো সেট করে:
max_execution_time = 1200
max_input_time = 90
memory_limit = 512M
post_max_size = 5000M
upload_max_filesize = 5000M
max_file_uploads = 100
display_errors = Off
zlib.output_compression = Onএই সংখ্যাগুলো পর্যাপ্ত রিসোর্স আছে এমন মেশিনের জন্য। ছোট VPS-এ কাজ করার আগে এগুলো কমিয়ে নিন, কারণ upload_max_filesize = 5000M এবং max_file_uploads = 100 ব্যবহার করে একটি সিঙ্গেল রিকোয়েস্ট 40 GB ডিস্কের চেয়েও বেশি জায়গা দখল করতে পারে। Apache রিস্টার্ট করুন এবং PHP আসলে কী লোড করেছে তা নিশ্চিত করুন:
sudo service apache2 restart
php -i | grep -E "upload_max_filesize|post_max_size|memory_limit"এখন ওয়ার্কিং ডিরেক্টরি সেট করুন। Resources/config.php ফাইলের $ConvertLoc এটি নির্ধারণ করে এবং ডিফল্ট মান হলো /DATA/HRConvert2। ওয়েব সার্ভার ব্যবহারকারীর অবশ্যই এর মালিকানা থাকতে হবে:
sudo mkdir -p /DATA/HRConvert2
sudo chmod -R 0755 /DATA/HRConvert2
sudo chown -R www-data:www-data /DATA/HRConvert2আপনার Apache ডকুমেন্ট রুটের নিচে রিলিজটি আনপ্যাক করুন। ডিফল্ট লেআউটে এটি একটি HRProprietary/HRConvert2 ফোল্ডারে থাকে এবং Resources/config.php ফাইলের $InstLoc-এ আপনি যেখানে এটি রেখেছেন তার পাথ উল্লেখ করতে হবে। এরপর বিল্ট-ইন ডায়াগনস্টিক চালান, যা ব্যবহারকারীর কাছে যাওয়ার আগেই কোনো মিসিং ডিপেন্ডেন্সি খুঁজে বের করার দ্রুততম উপায়:
sudo php /path/to/HRConvert2/convertCore.php -v-v পুরো ইনস্টলেশনটি যাচাই করে: কোর ভার্সন, ডিপেন্ডেন্সি চেক, স্যান্ডবক্স স্ট্যাটাস এবং ল্যাঙ্গুয়েজ প্যাক। কমান্ড লাইন থেকে ফাইল কনভার্সন সাপোর্ট করে না, তাই এই আর্গুমেন্ট সেটটি শুধুমাত্র প্রশাসনিক কাজের জন্য।
কেন নতুন Ubuntu 24.04 ইনস্টলেশনে প্রতিটি কনভার্সন ব্যর্থ হয়?
এর কারণ হলো স্যান্ডবক্স, এবং এটি প্রথম দিনের সবচেয়ে সাধারণ সমস্যা। Ubuntu 24.04 এবং Debian 12 ডিফল্টভাবে unprivileged user namespace-কে সীমাবদ্ধ করে রাখে। Bubblewrap-এর স্যান্ডবক্স তৈরি করার জন্য একটি user namespace প্রয়োজন, তাই bwrap চালু হতে পারে না। যেহেতু অ্যাপ্লিকেশনটি স্যান্ডবক্স ছাড়া কনভার্সন করতে অস্বীকার করে, তাই প্রতিটি কাজই ব্যর্থ হয়।
সরাসরি পরীক্ষা করুন:
bwrap --ro-bind / / --dev /dev /bin/true && echo sandbox okএকটি permission denied এরর মানে হলো namespace-টি ব্লক করা হয়েছে। এর সমাধান হলো bwrap বাইনারির জন্য একটি AppArmor প্রোফাইল তৈরি করা। প্রথমে ABI ফাইলগুলোর তালিকা দেখুন এবং সেখানে থাকা সর্বোচ্চ সংখ্যাটি নোট করুন:
ls /etc/apparmor.d/abi/এরপর /etc/apparmor.d/bwrap লিখুন এবং 4.0-এর জায়গায় সেই সর্বোচ্চ সংখ্যাটি বসান:
abi <abi/4.0>,
include <tunables/global>
profile bwrap /usr/bin/bwrap flags=(unconfined) {
userns,
include if exists <local/bwrap>
}এটি লোড করুন:
sudo apparmor_parser -r /etc/apparmor.d/bwrapকোনো আউটপুট না আসা মানে প্রোফাইলটি সফলভাবে লোড হয়েছে। আবার bwrap চেকটি চালান, এবার এটি sandbox ok প্রিন্ট করবে। এরপর থেকে কনভার্সন কাজ করবে।
একটি পাবলিক কনভার্টার হলো অপরিচিতদের জন্য উন্মুক্ত একটি পার্সার
এই অংশটিই এই পোস্টের মূল উদ্দেশ্য। ইন্টারনেট থেকে অ্যাক্সেসযোগ্য একটি ফাইল কনভার্টার যেকোনো বেনামী ব্যক্তির কাছ থেকে ফাইল গ্রহণ করে এবং তা LibreOffice, ImageMagick, FFmpeg বা Ghostscript-এর কাছে হস্তান্তর করে। এগুলো বিশাল C এবং C++ কোডবেস, যার দীর্ঘ ইতিহাসে অনেক পার্সার বাগ রয়েছে। যিনি ফাইল আপলোড করছেন তিনি ফরম্যাট নির্বাচন করেন, যার অর্থ হলো তিনিই নির্ধারণ করছেন কোন পার্সারটি চলবে এবং তার ভেতরের কোন কোড পাথটি কার্যকর হবে।
HRConvert2-এর সমাধান হলো প্রতিটি ডিপেন্ডেন্সিকে একটি bubblewrap নেমস্পেসের ভেতরে চালানো। প্রতিটি কনভার্সন দুটি ডিরেক্টরি দেখতে পায়: একটি যেখানে ইনপুট থাকে (যা read-only হিসেবে মাউন্ট করা), এবং অন্যটি যেখানে আউটপুট জমা হয়। নেটওয়ার্কটি unshared রাখা হয়, যা প্রজেক্টের ভাষায়, closes every URL handler in every dependency at once। এটি শোনার চেয়েও বেশি গুরুত্বপূর্ণ। ImageMagick এবং Ghostscript উভয়ই এমন রেফারেন্স গ্রহণ করে যা URL থেকে ডেটা আনতে পারে, আর এভাবেই একটি কনভার্টার সার্ভার সাইড রিকোয়েস্ট ফরজেরি (SSRF) টুলে পরিণত হয়, যা আপনার নেটওয়ার্কের ভেতর থেকে ক্লাউড মেটাডেটা এন্ডপয়েন্টে পৌঁছাতে পারে। নেমস্পেসে কোনো নেটওয়ার্ক না থাকলে, এই ফেচ (fetch) প্রক্রিয়াটি সম্পন্ন হতে পারে না।
প্রত্যাখ্যান বা বাধা প্রদানই হলো এর অন্য অর্ধেক: A server that cannot build a sandbox refuses the conversion rather than quietly running without one. একটি টুল যা ব্যর্থ হলে বন্ধ হয়ে যায় (fails closed), সেটি এমন টুলের চেয়ে বেশি মূল্যবান যা কেবল এমন লগে সতর্কবার্তা দেয় যা কেউ পড়ে না। এই কারণেই উপরের AppArmor ধাপটি ঐচ্ছিক নয়, এবং এই কারণেই কন্টেইনারটি উন্মুক্ত করার আগে $RequireSandboxOnDocker যাচাই করে দেখা প্রয়োজন।
policy.xml দিয়ে ImageMagick সুরক্ষিত করা
ImageMagick-এর নিজস্ব policy ফাইলটি স্যান্ডবক্সের নিচে একটি দ্বিতীয় স্তরের সুরক্ষা প্রদান করে, যা কনফিগার করা জরুরি। Ubuntu 24.04 এবং ImageMagick 6-এর ক্ষেত্রে এই ফাইলটি হলো /etc/ImageMagick-6/policy.xml। বর্তমানে কী সক্রিয় আছে তা দেখতে নিচের কমান্ডটি চালান:
identify -list policyএই প্রজেক্টটি Documentation/Build/policy.xml-এ একটি পলিসি ফাইল সরবরাহ করে, যা একটি ভালো মডেল হিসেবে কাজ করে। এটি PS, PS2, PS3, EPS, XPS এবং MVG কোডারগুলোকে (coders) অস্বীকার করে এবং URL, HTTPS, HTTP ও gs ডেলিগেটগুলোকে (delegates) ব্লক করে, তবে PDF-কে অনুমতি দেয়:
<policy domain="coder" rights="none" pattern="PS" />
<policy domain="coder" rights="none" pattern="MVG" />
<policy domain="delegate" rights="none" pattern="URL" />
<policy domain="delegate" rights="none" pattern="gs" />
<policy domain="coder" rights="read|write" pattern="PDF" />gs লাইনটি অত্যন্ত গুরুত্বপূর্ণ। ImageMagick নিজে PostScript পার্স করে না। এটি Ghostscript-এর ওপর নির্ভর করে এবং সেই ডেলিগেটেই ImageMagick-এর সুপরিচিত রিমোট কোড এক্সিকিউশন (RCE) বাগগুলো থাকে। এই ডেলিগেটটিকে অস্বীকার করলে ImageMagick কোনো আপলোড করা ফাইলকে gs-এর কাছে পাঠাবে না, ফাইলটি যাই দাবি করুক না কেন।
একই পলিসিতে রিসোর্স ক্যাপ (resource caps) সেট করা থাকে, যা কোনো বিশেষভাবে তৈরি ইমেজ ফাইলকে সার্ভারের রিসোর্স শেষ করা থেকে বিরত রাখে:
<policy domain="resource" name="memory" value="256MiB"/>
<policy domain="resource" name="map" value="512MiB"/>
<policy domain="resource" name="disk" value="1GiB"/>
<policy domain="resource" name="width" value="16KP"/>
<policy domain="resource" name="height" value="16KP"/>
<policy domain="resource" name="area" value="128MP"/>ডিকম্প্রেশন বম্ব (decompression bomb) হলো এমন একটি ছোট ফাইল যা বিশাল ডাইমেনশন ঘোষণা করে। width, height এবং area লিমিটগুলো মেমোরি অ্যালোকেশন হওয়ার আগেই সেটিকে প্রত্যাখ্যান করে, ফলে কার্নেল কোনো প্রসেস কিল করার আগেই প্রসেসটি বন্ধ হয়ে যায়।
এখানে একটি বিষয় খেয়াল রাখতে হবে। Ubuntu-এর ডিফল্ট পলিসি সরাসরি PDF কোডারকে অস্বীকার করে, তাই কোনো পরিবর্তন না করা সিস্টেমে PDF নিয়ে কাজ করলে attempt to perform an operation not allowed by the security policy 'PDF' এরর দেখাবে। এই স্ট্রিংটি নির্দেশ করে যে পলিসি তার কাজ করছে। কোডারটিকে পুনরায় অনুমতি দেওয়ার সিদ্ধান্তটি আপনাকে ভেবেচিন্তে নিতে হবে এবং তা করার সময় gs ডেলিগেটটিকে অবশ্যই অস্বীকার করে রাখতে হবে।
ছোট VPS-এ ডিপেন্ডেন্সি চেইনের খরচ
আইডল অবস্থায় এর কোনোটিই ব্যয়বহুল নয়। Apache এবং PHP মাত্র কয়েক দশ মেগাবাইট জায়গা নেয় এবং কনভার্টার বাইনারিগুলো তখন মোটেও চলে না। পুরো খরচটি একসাথে আসে যখন কোনো ফাইল প্রসেসিংয়ের জন্য আসে।
একটি ডকুমেন্ট কনভার্সন LibreOffice চালু করে, যা আবার একটি Java runtime শুরু করে। একটি ইমেজ কনভার্সন ImageMagick-কে 256 MiB মেমোরি এবং উপরের পলিসি অনুযায়ী 512 MiB মেমোরি ম্যাপ দেয়। একটি ভিডিও কনভার্সন FFmpeg-কে আপনার সবকটি কোর ব্যবহারের সুযোগ দেয়, কারণ ভিডিওর ক্ষেত্রে FFmpeg ঠিক এটাই করে। প্রজেক্টের কনফিগারেশনে PHP-এর নিজস্ব memory_limit হলো 512M। একটি সিঙ্গেল জব চলাকালীন এই সংখ্যাগুলো অপারেটিং সিস্টেম এবং ওয়েব সার্ভারের ওপর বাড়তি চাপ সৃষ্টি করে।
তাই 1 GB RAM-এর একটি VPS প্রথম বড় ডকুমেন্টটি প্রসেস করার সময়ই সোয়াপ (swap) ব্যবহার শুরু করে এবং এরপর থ্র্যাশিং (thrashing) হতে থাকে। মেমোরি শেষ হয়ে গেলে কার্নেলের out of memory killer সবচেয়ে বেশি রেসিডেন্ট সাইজের প্রসেসটিকে বন্ধ করে দেয়। সাধারণত এটি হয় soffice.bin, এবং ব্যবহারকারী কোনো কার্যকর বার্তা ছাড়াই কনভার্সন ব্যর্থ হতে দেখেন। কখনো কখনো এটি apache2 হয় এবং পুরো সাইটটি ডাউন হয়ে যায়। ঘটনার পর dmesg -T | grep -i "killed process" কমান্ড দিয়ে এটি নিশ্চিত করুন।
এটি কোনো বেঞ্চমার্ক নয়, বরং সাইজিং সংক্রান্ত পরামর্শ: ছোট টিমের জন্য 4 GB RAM এবং দুটি কোর বেশ আরামদায়ক। যদি লোড শুধু ডকুমেন্ট এবং ইমেজের হয় এবং আপনি অপেক্ষার সময়টুকু মেনে নিতে পারেন, তবে 2 GB RAM এবং একটি সোয়াপ ফাইল দিয়েও কাজ চালানো সম্ভব। সোয়াপ ফাইল কনভার্সনকে দ্রুত করে না। এটি কেবল একটি বার্স্ট (burst) অবস্থাকে মারাত্মক হওয়ার বদলে ধীরগতির করে তোলে, যা একটি আটকে থাকা পেজ এবং পুরো সাইট ডাউন হয়ে যাওয়ার মধ্যে পার্থক্য গড়ে দেয়। ডিস্কে প্রয়োজনের চেয়ে বেশি জায়গা রাখুন, কারণ 3 GB ইমেজ, বড় আপলোড লিমিট এবং কনভার্ট করা আউটপুট অন্য যেকোনো কিছুর আগেই ডিস্ক পূর্ণ করে ফেলে।
কনভার্সনগুলো স্বভাবতই বার্স্টি (bursty)। একই সময়ে দুজন ব্যক্তি ভিডিও আপলোড করলে তা সবকটি কোর ব্যবহার করবে এবং পরবর্তী অনুরোধগুলো তাদের পেছনে অপেক্ষা করবে। এর সামনে কোনো জব কিউ (job queue) নেই, তাই আপনার হাতে থাকা একমাত্র নিয়ন্ত্রণ হলো লিমিট বা সীমাবদ্ধতা।
ডিস্ক পূর্ণ হওয়া রোধ করতে আপলোডের সীমা নির্ধারণ করুন
প্রথমে PHP-এর মানগুলো কমিয়ে আনুন। একটি 4 GB র্যামের শেয়ার্ড সার্ভারের জন্য upload_max_filesize = 512M, post_max_size = 512M এবং max_file_uploads = 20 একটি যুক্তিসঙ্গত শুরুর পয়েন্ট হতে পারে। মনে রাখবেন যে, max_execution_time = 1200 একটি PHP রিকোয়েস্টকে বিশ মিনিট পর্যন্ত চলার অনুমতি দেয়, যা দীর্ঘ ভিডিও কনভার্সনের জন্য প্রয়োজন। তবে এর অর্থ হলো, একটি ধীরগতির আপলোড বিশ মিনিটের জন্য একটি ওয়ার্কারকে আটকে রাখবে।
এরপর, রিকোয়েস্ট PHP-তে পৌঁছানোর আগেই প্রক্সি লেভেলে ফাইলের আকার এবং রেট নিয়ন্ত্রণ করুন:
limit_req_zone $binary_remote_addr zone=convert:10m rate=6r/m;
server {
listen 443 ssl;
server_name convert.example.com;
client_max_body_size 512M;
client_body_timeout 300s;
location / {
limit_req zone=convert burst=4 nodelay;
proxy_pass http://127.0.0.1:8080;
proxy_read_timeout 1200s;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}client_max_body_size অবশ্যই আপনার কনভার্ট করতে চাওয়া সবচেয়ে বড় ফাইলের আকারের সমান বা তার চেয়ে বড় হতে হবে, অন্যথায় Nginx 413 Request Entity Too Large এরর দেবে এবং PHP কখনোই আপলোডটি দেখতে পাবে না। proxy_read_timeout অবশ্যই আপনার দীর্ঘতম কনভার্সন সময়ের চেয়ে বেশি হতে হবে, অন্যথায় প্রক্সির পেছনে সঠিকভাবে চলতে থাকা কোনো কাজ ব্রাউজারে 504 Gateway Time-out এরর পাঠাবে। TLS (transport layer security) টার্মিনেশনসহ ওই সার্ভার ব্লকের বাকি অংশ একটি nginx reverse proxy কনফিগারেশনের লাইন-বাই-লাইন ব্যাখ্যা-তে আলোচনা করা হয়েছে।
কনভার্ট করা ফাইলগুলো মুছে ফেলা
প্রতিটি কনভার্সন প্রক্রিয়ার পর একটি সংবেদনশীল ফাইলের কপি এমন একটি ডিরেক্টরিতে থেকে যায় যা ওয়েব সার্ভার পড়তে পারে। কনভার্টার এবং আর্কাইভের মধ্যে মূল পার্থক্য হলো এই ক্লিনআপ প্রক্রিয়া, যা নিশ্চিত করে যে সার্ভারে কনভার্ট করা কোনো ফাইলই অযথা জমা হয়ে থাকবে না।
$DeleteThreshold হলো Resources/config.php-এর সেই প্যারামিটার যা নির্ধারণ করে কত মিনিট পর একটি সেশন এক্সপায়ার করবে, যার ডিফল্ট মান 60। বিষয়বস্তু সংবেদনশীল হলে এটিকে 15-তে নামিয়ে আনুন। এই ক্লিনআপ বা সুইপ প্রক্রিয়াটি কোরের একটি কমান্ড লাইন আর্গুমেন্ট হিসেবে কাজ করে:
sudo -u www-data php /path/to/HRConvert2/convertCore.php -c
sudo -u www-data php /path/to/HRConvert2/convertCore.php -c=15-c কনফিগার করা থ্রেশহোল্ড ব্যবহার করে উভয় ডেটা লোকেশন থেকে এক্সপায়ার হওয়া সেশনগুলো মুছে ফেলে। -c=15 শুধুমাত্র সেই নির্দিষ্ট রানটির জন্য 15 মিনিট সময় ব্যবহার করে। -c=now বয়সের তোয়াক্কা না করে প্রতিটি সেশন মুছে ফেলে, এমনকি কোনো ব্যবহারকারী সেই মুহূর্তে কোনো ফাইল কনভার্ট করলেও তা মুছে যাবে, তাই এটি শুধুমাত্র রক্ষণাবেক্ষণের জন্য ব্যবহার করুন। একই আর্গুমেন্টগুলো docker exec-এর মাধ্যমে কন্টেইনারের ভেতরেও কাজ করে।
সুইপ প্রক্রিয়াটিকে একটি টাইমারের ওপর রাখুন যাতে ক্লিনআপ কোনো ব্যবহারকারীর পেজ লোড করার ওপর নির্ভর না করে। /etc/cron.d/hrconvert2-এ একটি লাইন যোগ করাই যথেষ্ট:
*/10 * * * * www-data php /path/to/HRConvert2/convertCore.php -cকয়েক মিনিট পর ls /DATA/HRConvert2 দিয়ে এটি চেক করুন এবং দেখুন পুরনো সেশন ডিরেক্টরিগুলো মুছে যাচ্ছে কি না। যেহেতু ওয়েব সার্ভার ব্যবহারকারী এই ডিরেক্টরির মালিক, তাই কোনো পার্সার হ্যাক হলে হ্যাকার ঠিক এই অ্যাকাউন্টটির নিয়ন্ত্রণই পাবে। তাই এই অ্যাকাউন্টের মালিকানায় গুরুত্বপূর্ণ অন্য কিছু রাখা উচিত নয়। VPS-এ Least privilege user account হলো এই ক্ষেত্রে অনুসরণীয় সাধারণ নিয়ম, যা এখানে আরও বেশি প্রযোজ্য।
পাবলিক করার উদ্দেশ্য না থাকলে এটিকে অথেনটিকেশনের পেছনে রাখুন
ডিজাইন অনুযায়ী, ডিফল্ট ইনস্টলেশনে কোনো অ্যাকাউন্ট থাকে না। যে কেউ এই পেজে পৌঁছাতে পারলে ফাইল আপলোড করতে পারবে এবং আপনার কনভার্টার বাইনারিগুলো চালাতে পারবে, আর রেট লিমিট শুধুমাত্র এই প্রক্রিয়াকে কিছুটা ধীর করবে। তাই আপনার পরিস্থিতি অনুযায়ী সিদ্ধান্ত নিন।
যদি এটি শুধুমাত্র আপনার এবং আপনার কয়েকজন সহকর্মীর জন্য হয়, তবে এটিকে ইন্টারনেটে উন্মুক্ত করবেন না। উপরে দেখানো অনুযায়ী কন্টেইনারটিকে লুপব্যাক (loopback)-এ বাইন্ড করুন এবং একটি প্রাইভেট নেটওয়ার্ক বা SSH টানেলের মাধ্যমে এটি ব্যবহার করুন। সেক্ষেত্রে পাবলিক ইন্টারনেটের কেউ ফাইল পাঠাতে পারবে না, যা ফিল্টার করার পরিবর্তে আক্রমণের পুরো ক্ষেত্রটিই (attack surface) দূর করে দেবে।
যদি এটিকে ব্রাউজার থেকে অ্যাক্সেসযোগ্য করতেই হয়, তবে প্রক্সির সামনে অথেনটিকেশন যুক্ত করুন। বেসিক অথ (Basic auth) মাত্র দুটি কমান্ডের কাজ এবং এটি অপরিচিতদের আপলোড ফর্ম থেকে দূরে রাখে:
sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd alicelocation / {
auth_basic "Converter";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://127.0.0.1:8080;
}Nginx রিলোড করুন এবং পেজটি লোড করুন। একটি প্রম্পট দেখালে বুঝবেন এটি কাজ করছে, আর প্রম্পট না দেখালে বুঝবেন আপনি যে location ব্লকটি এডিট করেছেন সেটি অনুরোধটি হ্যান্ডেল করছে না। শেয়ারড পাসওয়ার্ডের পরিবর্তে প্রকৃত অ্যাকাউন্টের জন্য, একটি সিঙ্গেল সাইন-অন প্রোভাইডারে টার্মিনেট করুন: একটি সেলফ-হোস্টেড Authentik SSO সার্ভার আপনাকে এমন অ্যাপ্লিকেশনের সামনে ফরওয়ার্ড অথেনটিকেশন দেয়, যার নিজস্ব কোনো লগইন সিস্টেম নেই।
যদি একটি সত্যিকারের পাবলিক কনভার্টার তৈরি করাই লক্ষ্য হয়, তবে এর পরিণাম মেনে নিন এবং সেই অনুযায়ী পরিকল্পনা করুন। ধরে নিন স্যান্ডবক্সটি পরীক্ষা করা হবে। ইমেজ ট্যাগ পিন করে রাখুন, ImageMagick পলিসি কঠোর রাখুন, আপলোড লিমিট কম রাখুন এবং এমন একটি VPS-এ এটি চালান যেখানে আপনার গুরুত্বপূর্ণ অন্য কোনো তথ্য নেই।
ব্যর্থতার ধরন এবং যে বার্তাগুলো আপনি দেখবেন
প্রতিটি কনভার্সন তাৎক্ষণিকভাবে ব্যর্থ হচ্ছে। স্যান্ডবক্স তৈরি করা যাচ্ছে না। সাধারণ ইনস্টলেশনে এটি AppArmor প্রোফাইলের কারণে হয়। Docker-এর ক্ষেত্রে এটি --security-opt seccomp=unconfined-এর অনুপস্থিতি। অ্যাপ্লিকেশনটি এর নাম উল্লেখ করে: A sandbox blocks the required syscalls unless it was started with the correct options. এবং See --Require Sandbox-- & --Require Sandbox On Docker-- in config.php.-এর দিকে নির্দেশ করে।
শুধুমাত্র ইমেজ কনভার্সন ব্যর্থ হচ্ছে। Bubblewrap is missing or non functional, so this image conversion cannot be isolated! মানে হলো bwrap অনুপস্থিত অথবা ওয়েব সার্ভার ইউজারের পাথ (path) থেকে এটি খুঁজে পাওয়া যাচ্ছে না।
একটি ফরম্যাট ব্যর্থ হচ্ছে কিন্তু বাকিগুলো কাজ করছে। একটি বাইনারি ফাইল অনুপস্থিত, যা স্পষ্টভাবে জানানো হয়: ImageMagick may not be installed, or may not be reachable on the system path used by the web server user.। FFmpeg এবং LibreOffice উভয়ের জন্যই একই বার্তা দেখা যায়। ইনস্টলেশনটি কী খুঁজে পাচ্ছে তা দেখতে convertCore.php -v চালান এবং মনে রাখবেন যে Apache ওয়ার্কারের PATH আপনার লগইন শেলের PATH থেকে ভিন্ন।
PDF-এর কাজ পলিসি এররের কারণে ব্যর্থ হচ্ছে। attempt to perform an operation not allowed by the security policy 'PDF' বার্তাটি HRConvert2 থেকে নয়, বরং ImageMagick-এর policy.xml থেকে আসে।
বড় ফাইল আপলোড করলে 413 এরর দিচ্ছে। nginx client_max_body_size ফাইলের আকারের চেয়ে ছোট। এই চেইনে তিনটি সীমা (limit) আছে, একটি nginx-এ এবং দুটি PHP-তে, যার মধ্যে যেটি সবচেয়ে ছোট সেটিই কার্যকর হয়।
কনভার্সন থেমে যাচ্ছে এবং দৃশ্যত কোনো পরিবর্তন হয়নি। The device where data is stored has an insufficient amount of storage space available. ডিস্কের খালি জায়গা পরীক্ষা করুন এবং ক্লিনআপ সুইপ (cleanup sweep) সঠিকভাবে চলছে কি না তা নিশ্চিত করুন।
লগে ক্লিনআপ সংক্রান্ত অভিযোগ দেখাচ্ছে। Could not clean the temporary location! এবং Could not clean the convert location! হলো মালিকানা (ownership) সংক্রান্ত সমস্যা। $ConvertLoc দ্বারা নির্দেশিত ডিরেক্টরির মালিক অবশ্যই ওয়েব সার্ভার ইউজার হতে হবে।
FAQ
একটি self-hosted ফাইল কনভার্টার ইন্টারনেটে উন্মুক্ত করা কি নিরাপদ?
যদি আপনি এটিকে অপরিচিতদের জন্য উন্মুক্ত একটি পার্সার হিসেবে বিবেচনা করেন, তবে এটি যথেষ্ট নিরাপদ। প্রতিটি আপলোড LibreOffice, ImageMagick, FFmpeg বা Ghostscript-এর কাছে পাঠানো হয় এবং আপলোডকারী ব্যক্তিই নির্ধারণ করেন কোনটি ব্যবহার করা হবে। HRConvert2 এই টুলগুলোকে একটি bubblewrap নেমস্পেসের ভেতরে চালায়, যেখানে কোনো নেটওয়ার্ক অ্যাক্সেস থাকে না এবং ইনপুট ডিরেক্টরি শুধুমাত্র রিড-অনলি (read-only) থাকে। এটি এমন যেকোনো কনভার্সন প্রত্যাখ্যান করে যা স্যান্ডবক্স করা সম্ভব নয়, যা একটি শক্তিশালী ডিফল্ট নিরাপত্তা ব্যবস্থা। তবুও, প্রমাণীকরণ (authentication) বাধ্যতামূলক করা, আপলোড লিমিট কম রাখা এবং এমন একটি VPS-এ এটি চালানো ভালো যেখানে অন্য কোনো গুরুত্বপূর্ণ ডেটা নেই।
নতুন Ubuntu 24.04 ইনস্টলেশনে কেন প্রতিটি কনভার্সন ব্যর্থ হয়?
Ubuntu 24.04 এবং Debian 12 আনপ্রিভিলেজড ইউজার নেমস্পেসকে সীমাবদ্ধ করে, আর স্যান্ডবক্স তৈরির জন্য bubblewrap-এর এটি প্রয়োজন হয়। যেহেতু অ্যাপ্লিকেশনটি স্যান্ডবক্স ছাড়া কনভার্সন করতে অস্বীকার করে, তাই কিছু কাজের পরিবর্তে প্রতিটি কাজই ব্যর্থ হয়। /usr/bin/bwrap-এর জন্য flags=(unconfined) ব্যবহার করে একটি AppArmor প্রোফাইল লিখুন, sudo apparmor_parser -r /etc/apparmor.d/bwrap দিয়ে তা লোড করুন এবং তারপর bwrap --ro-bind / / --dev /dev /bin/true দিয়ে নিশ্চিত করুন।
Docker-এ কনভার্সন কেন ব্যর্থ হয় কিন্তু সাধারণ ইনস্টলেশনে কাজ করে?
Docker-এর ডিফল্ট seccomp প্রোফাইল bubblewrap-এর ব্যবহৃত সিস্টেম কলগুলোকে ব্লক করে, তাই কন্টেইনারের ভেতরে স্যান্ডবক্স তৈরি করা যায় না। এটিকে --security-opt seccomp=unconfined দিয়ে শুরু করুন, যা প্রজেক্টের নিজস্ব রান কমান্ডে করা হয়। মনে রাখবেন যে $RequireSandboxOnDocker ডিফল্টভাবে FALSE থাকে, তাই কোনো ফ্ল্যাগ ছাড়া কন্টেইনার স্যান্ডবক্স ছাড়াই কনভার্সন করতে পারে। seccomp ফ্ল্যাগটি কার্যকর করার পর এটিকে TRUE সেট করুন।
একটি ফাইল কনভার্সন সার্ভারের জন্য কতটুকু RAM প্রয়োজন?
আইডল অবস্থায় এটি খুব কম মেমোরি নেয়, কিন্তু লাইভ কনভার্সনের সময় অনেক বেশি প্রয়োজন হয়। LibreOffice একটি Java রানটাইম শুরু করে, ImageMagick ডিফল্ট পলিসিতে 256 MiB মেমোরি এবং 512 MiB ম্যাপ নেয়, এবং PHP-এর নিজস্ব লিমিট 512M। 1 GB RAM-এর VPS-এ এই সমন্বয়টি সোয়াপ (swap) ব্যবহার করতে শুরু করে এবং আউট-অফ-মেমোরি কিলার (OOM killer) soffice.bin বা apache2-কে বন্ধ করে দেয়। একটি ছোট টিমের জন্য 4 GB RAM এবং দুটি কোর পরিকল্পনায় রাখুন এবং যখনই কোনো কনভার্সন কোনো বার্তা ছাড়াই বন্ধ হয়ে যায়, তখন dmesg -T | grep -i "killed process" চেক করুন।
কনভার্ট করা ফাইলগুলো কোথায় যায় এবং কখন সেগুলো মুছে ফেলা হয়?
সেগুলো Resources/config.php-এর ভেতরে $ConvertLoc দ্বারা নির্ধারিত ওয়ার্কিং ডিরেক্টরিতে যায়, যার ডিফল্ট মান /DATA/HRConvert2। $DeleteThreshold সেশন মেয়াদোত্তীর্ণ হওয়ার সময় মিনিট হিসেবে নির্ধারণ করে, যার ডিফল্ট মান 60। সুইপ (sweep) কমান্ড লাইন থেকে চালানো হয়: php convertCore.php -c মেয়াদোত্তীর্ণ সেশনগুলো মুছে ফেলে এবং -c=now সক্রিয় সেশনসহ প্রতিটি সেশন তাৎক্ষণিকভাবে মুছে ফেলে। -c-কে একটি cron এন্ট্রি বা systemd টাইমারে রাখুন যাতে ফাইল মুছে ফেলার বিষয়টি সাইটে ভিজিট করার ওপর নির্ভর না করে।