কিভাবে HRConvert2 দিয়ে ফাইল কনভার্টার সেলফ-হোস্ট করবেন
আপনার নিজের সার্ভারে HRConvert2 ইনস্টল করার নিয়ম জানুন। Docker বা Apache ব্যবহার করে ফাইল কনভার্টার সেটআপ করুন এবং 488টি ফরম্যাট সাপোর্ট সহ নিরাপদ ফাইল প্রসেসিং নিশ্চিত করুন।
কেন নিজে file converter host করবেন
নিজে host করা file converter ফাইলটি আপনার নিজের disk-এ রাখে। এটি চালানোর মূল কারণ এটাই। একটি free converter site আপনার ফাইল upload করে নেয়, কিন্তু পরে সেটির কী হয় তা জানার কোনো উপায় দেয় না। ফাইলটি যদি কোনো signed client contract বা scanned medical record হয়, তাহলে upload করাটিই security incident। HRConvert2 হলো PHP-তে লেখা এবং GPLv3-এর অধীনে licensed একটি drag-and-drop file conversion server। এই guide-টি 3.7.4 version ধরে লেখা হয়েছে, যা 18 August 2026-এ released হয়েছিল। এরপর project-টির উন্নয়ন দ্রুত হয়েছে: 13 October 2026 অনুযায়ী newest release হলো v3.9.1, যা 6 September 2026-এ published হয়েছে। Project-টি 488টি supported format-এর দাবি করে।
এতে database, account বা cookie নেই। একজন user-এর জন্য একটি temporary directory তৈরি হয়। প্রতিটি conversion-এর কাজ করে একটি local command-line tool: document-এর জন্য LibreOffice, audio ও video-এর জন্য FFmpeg, image-এর জন্য ImageMagick, optical character recognition (OCR)-এর জন্য Tesseract এবং অন্যান্য format-এর জন্য আরও অনেক ছোট tool। HRConvert2 upload page, processing pipeline এবং এগুলোর cleanup পরিচালনা করে।
এটি একটি file-কে অন্য format-এ convert করে। এটি browser office suite নয়। তাই আপনার প্রয়োজন যদি হয় browser tab-এ document edit করা, তাহলে নিজে host করা OnlyOffice ও Collabora দেখুন। এটি storage-ও নয়। Converted output মুছে ফেলার জন্যই নির্ধারিত। তাই ফাইল কোথাও সংরক্ষণ করতে হলে সেই কাজের জন্য নিজে host করা file manager ব্যবহার করুন।
প্রয়োজনীয় বিষয়সমূহ
Debian অথবা Ubuntu, Apache 2.4, PHP 8 বা তার পরবর্তী সংস্করণ এবং bubblewrap প্রয়োজন। Bubblewrap (bwrap) হলো স্যান্ডবক্স, এবং এটি ঐচ্ছিক নয়: যে সার্ভারে স্যান্ডবক্স তৈরি করা সম্ভব নয়, সেটি কোনো স্যান্ডবক্স ছাড়াই চলার পরিবর্তে কনভার্সন প্রক্রিয়াটি প্রত্যাখ্যান করবে। আপস্ট্রিম README অনুযায়ী, Raspberry Pi Model B+ এর জন্য যথেষ্ট, যা PHP অংশের ক্ষেত্রে সত্য। কনভার্টার বাইনারিগুলো আপনার হার্ডওয়্যারের প্রকৃত সক্ষমতা নির্ধারণ করে, যা নিচে বিস্তারিত আলোচনা করা হয়েছে।
এখানে কাজ শুরু করার দুটি উপায় রয়েছে। Docker ইমেজটি আজ রাতেই কাজ শুরু করার জন্য উপযুক্ত। Apache এবং PHP ইনস্টলেশন করতে এক সন্ধ্যা সময় লাগতে পারে, তবে এটি সার্ভারে ঠিক কী কী আছে তা আপনাকে স্পষ্টভাবে দেখাবে।
Docker দিয়ে আজ রাতেই চালান
এই image-এ প্রতিটি converter binary থাকে, তাই এটি বড়: August 2026 অনুযায়ী প্রায় 3 GB। pull করার আগে disk-এ পর্যাপ্ত free space আছে কি না পরীক্ষা করুন।
এখানে tag গুরুত্বপূর্ণ। এই guide-এ v3.7.2 নির্দিষ্ট করা হয়েছে। 17 August 2026 তারিখে Docker Hub-এ এটিই newest tag ছিল এবং সেদিনের newest GitHub release-ও এটিই ছিল। 18 August-এ v3.7.4 প্রকাশিত হয়। 13 October 2026 অনুযায়ী newest GitHub release হলো v3.9.1 (6 September 2026)। newest Docker Hub tag হলো edge (22 September 2026) এবং latest, যা হলো v3.8.4 (31 August 2026)। latest tag আপনার অজান্তে পরিবর্তিত হতে পারে। এই application-এর parser surface বড়, তাই একটি version নির্দিষ্ট করে দিন এবং পরিকল্পনা অনুযায়ী upgrade করুন।
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/স্বাভাবিক container Up state-এ থাকে এবং curl HTTP/1.1 200 OK ফেরত দেয়। কোনো container বারবার restart হলে startup সমস্যা আছে। তাই অন্য কিছু পরিবর্তনের আগে docker logs hrconvert2 পড়ুন।
দুটি flag এখানে গুরুত্বপূর্ণ। -p 127.0.0.1:8080:80 port-টি শুধু loopback-এ publish করে। তাই ইচ্ছাকৃতভাবে সামনে proxy না বসানো পর্যন্ত converter-এ কোনো অনুরোধ পৌঁছাবে না। প্রকল্পের বর্তমান example-এ -p 8080:80 map করা আছে। এটি public interface-সহ প্রতিটি interface-এ listen করে। Docker-এর default seccomp profile bubblewrap-এর sandbox তৈরির জন্য ব্যবহৃত user namespace এবং mount system call block করে। তাই --security-opt seccomp=unconfined প্রয়োজন। 3.7-এর config.php comments-এ বলা আছে, কিছু host-এ --security-opt apparmor=unconfined-ও প্রয়োজন হতে পারে। এই flag না থাকলে conversion ব্যর্থ হয় এবং application কারণটি জানায়: A sandbox blocks the required syscalls unless it was started with the correct options.
এই flag ব্যবহারের ক্ষেত্রে বাস্তব trade-off আছে। এতে container-এর syscall filter শিথিল হয়, যাতে application container-এর ভেতরে নিজস্ব আরও কঠোর sandbox তৈরি করতে পারে। আচরণ নির্ধারণকারী দুটি setting হলো $RequireSandbox এবং $RequireSandboxOnDocker, যা Resources/config.php-এ রয়েছে। v3.7.4 release-এ এগুলোর মান TRUE এবং FALSE। এখানে নির্দিষ্ট করা v3.7.2 tag-এ দুটির মানই FALSE। এর comments-এ বলা আছে, container-কে $RequireSandbox বন্ধ রাখতে হবে এবং $RequireSandboxOnDocker-কে সিদ্ধান্ত নিতে দিতে হবে। Docker requirement default-এ বন্ধ থাকায় seccomp flag ছাড়া container কোনো sandbox ছাড়াই conversion করতে পারে। flag যোগ করার পরে $RequireSandboxOnDocker = TRUE; সেট করলে container-এর ভেতরে refusal behaviour আবার চালু হবে।
নতুন image ভিন্নভাবে শুরু হয়। প্রকল্পটি v3.8.0-এ (25 August 2026) Docker process পরিবর্তন করেছে। বর্তমান README এবং Docker Hub page-এ seccomp option-এর পরিবর্তে --cap-add SYS_ADMIN দিয়ে container চালানো হয়। সেখানে বলা আছে, এটি ছাড়া conversion প্রত্যাখ্যান করা হবে। pin 3.8 বা 3.9 tag-এ সরালে ওই image যে flag নির্দেশ করে, সেগুলো ব্যবহার করুন। এই capability বিস্তৃত, তাই 127.0.0.1 port binding বজায় রাখুন।
এই মেশিনে Docker নতুন হলে আগে daemon সেট up করুন। VPS-এ Docker চালানো অংশে installation, storage driver এবং Docker কীভাবে নিজের firewall rule লেখে, তা ব্যাখ্যা করা হয়েছে।
Apache ও PHP-তে এটি ইনস্টল করুন
v3.7.4 পর্যন্ত repository-র Documentation/INSTALLATION_INSTRUCTIONS.txt ফাইলে এটি নয়টি ধাপে manual install হিসেবে দেখানো ছিল। এই section সেই install অনুসরণ করে। v3.8.0 থেকে একই ফাইলে setup script বর্ণনা করা হয়েছে। cloned repository থেকে sudo bash Documentation/Build/hrconvert2-setup.sh চালালে এটি dependencies ইনস্টল করে, php.ini সম্পাদনা না করে PHP settings একটি drop-in file হিসেবে লেখে, এবং bubblewrap-এর জন্য AppArmor profile প্রসারিত করে। এরপর php convertCore.php -v এবং --status ফলাফল যাচাই করে। Manual পদ্ধতিতে বেশি সময় লাগে, তবে মেশিনে কী ইনস্টল হয়েছে তা আপনি স্পষ্টভাবে জানতে পারেন। পদ্ধতিটি এভাবে শুরু হয়। প্রথমে web server, language এবং sandbox ইনস্টল করুন:
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 চালিয়ে আপনার version-এর সঙ্গে মেলা prefix ব্যবহার করুন। কারণ প্রতিটি PHP release-এর সঙ্গে package name পরিবর্তিত হয়, এবং ভুলটি ব্যবহার করলে Unable to locate package পাওয়া যায়।
এরপর converters ইনস্টল করুন। এতে document, image, audio, video এবং OCR অন্তর্ভুক্ত থাকে। বাস্তবে ব্যবহারকারীরা সাধারণত এগুলোই convert করেন:
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-cursor0Archive format, 3D model, ebook এবং bootable ISO image-এর জন্য এর চেয়ে বেশি package প্রয়োজন। এগুলোর কিছু Ubuntu-র multiverse component-এ থাকে। v3.7.4-এ official instructions-এর Step 3-এ সম্পূর্ণ apt list এবং Step 5-এ source build দেওয়া ছিল। বর্তমান guide-এ কোনো package list নেই। Installer Resources/Engine/Contract/depends.php manifest পড়ে, আর php convertCore.php --setup --check-depends বর্তমান list ও তার state দেখায়। দুটি dependency source থেকে build করাও যায়। Packaged FFmpeg-এ নেই এমন encoder-এর জন্য repository-তে Documentation/Build/ffmpeg-build.sh দেওয়া আছে। Ubuntu 22.04 বা 24.04-এ ImageMagick 7-এর জন্য Documentation/Build/build-imagemagick-v7.sh ব্যবহার করা যায়, কারণ ওই version-গুলোতে এখনও 6.9 branch package করা হয়। Ubuntu 25.10 এবং 26.04 LTS-এ ImageMagick 7.1 package করা হয়। Ebook support calibre-এর নিজস্ব installer থেকে আসে। 3.7-এর instructions-এ এটি এক লাইনে দেওয়া ছিল:
sudo -v && wget -nv -O- https://download.calibre-ebook.com/linux-installer.sh | sudo sh /dev/stdinএটি একটি vendor script, যা root হিসেবে shell-এ pipe করা হয়। এটি upstream পদ্ধতি এবং ঐচ্ছিক। এটি বাদ দিলে শুধু ebook conversion ব্যবহার করতে পারবেন না।
এরপর PHP-এর limits নির্ধারণ করুন। Conversion ধীর এবং file বড় হয়, তাই default value যথেষ্ট নয়। 3.7-এর instructions-এ এগুলো 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এই সংখ্যাগুলো পর্যাপ্ত resource থাকা মেশিনের জন্য ধরা হয়েছে। ছোট VPS-এ ব্যবহার করার আগে value কমিয়ে দিন। কারণ upload_max_filesize = 5000M এবং max_file_uploads = 100 একসঙ্গে এমন একটি request বোঝায়, যা 40 GB disk-এর ধারণক্ষমতার চেয়ে অনেক বেশি data লিখতে পারে। Apache restart করে PHP আসলে কী load করেছে তা যাচাই করুন:
sudo service apache2 restart
php -i | grep -E "upload_max_filesize|post_max_size|memory_limit"এখন working directory নির্ধারণ করুন। $ConvertLoc, Resources/config.php-এ এর নাম নির্ধারণ করে, এবং default হলো /DATA/HRConvert2। Web server user-এর ওই directory-র owner হতে হবে:
sudo mkdir -p /DATA/HRConvert2
sudo chmod -R 0755 /DATA/HRConvert2
sudo chown -R www-data:www-data /DATA/HRConvert2Apache document root-এর অধীনে release unpack করুন। Default layout-এ এটি একটি HRProprietary/HRConvert2 folder-এ রাখা হয়। $InstLoc, Resources/config.php-এ আপনি এটি বাস্তবে যে location-এ রেখেছেন সেটি উল্লেখ করতে হবে। এরপর built-in diagnostic চালান। কোনো user সমস্যাটি দেখার আগেই missing dependency শনাক্ত করার এটি দ্রুততম উপায়:
sudo php /path/to/HRConvert2/convertCore.php -v-v পুরো installation পরীক্ষা করে: core version, dependency check, sandbox status এবং language pack। Command line থেকে file conversion সমর্থিত নয়, তাই এই argument set শুধু administrative কাজের জন্য।
নতুন Ubuntu 24.04 ইনস্টলে প্রতিটি conversion কেন ব্যর্থ হয়?
কারণ sandbox। এটি প্রথম দিনের সবচেয়ে সাধারণ সমস্যা। Ubuntu 24.04 ডিফল্টভাবে AppArmor-এর মাধ্যমে unprivileged user namespace সীমাবদ্ধ করে। Bubblewrap-এর sandbox তৈরি করতে একটি user namespace প্রয়োজন। তাই bwrap চালু হতে পারে না। আর sandbox ছাড়া application conversion করতে অস্বীকৃতি জানায় বলে প্রতিটি job ব্যর্থ হয়।
সরাসরি পরীক্ষা করুন:
bwrap --ro-bind / / --dev /dev /bin/true && echo sandbox okpermission denied error-এর অর্থ হলো namespace ব্লক করা হয়েছে। এর সমাধান হলো bwrap binary-এর জন্য একটি AppArmor profile তৈরি করা। প্রথমে ABI file-গুলো তালিকাভুক্ত করুন এবং উপস্থিত সর্বোচ্চ number-টি নোট করুন:
ls /etc/apparmor.d/abi/এরপর /etc/apparmor.d/bwrap লিখুন। এখানে 4.0-এর জায়গায় সেই সর্বোচ্চ number বসান:
abi <abi/4.0>,
include <tunables/global>
profile bwrap /usr/bin/bwrap flags=(unconfined) {
userns,
include if exists <local/bwrap>
}এটি load করুন:
sudo apparmor_parser -r /etc/apparmor.d/bwrapকোনো output না থাকলে profile load হয়েছে। আবার bwrap check চালান। এটি sandbox ok print করার কথা। এরপর conversion কাজ করবে।
Debian 12-এ এই সমস্যা নেই। এর kernel unprivileged user namespace অনুমোদন করে। Boot-এর সময় bubblewrap package kernel.unprivileged_userns_clone-কে 1 সেট করে। তাই profile ছাড়াই সেখানে উপরের check সফল হয়। v3.8.0 এবং পরবর্তী version-এ setup script distribution-এর bubblewrap AppArmor profile আপনার হয়ে প্রসারিত করে।
একটি পাবলিক কনভার্টার হলো অপরিচিতদের জন্য উন্মুক্ত একটি পার্সার
এই অংশটিই এই পোস্টের মূল উদ্দেশ্য। ইন্টারনেট থেকে অ্যাক্সেসযোগ্য একটি ফাইল কনভার্টার একজন বেনামী ব্যক্তির কাছ থেকে যেকোনো ফাইল গ্রহণ করে এবং সেটি LibreOffice, ImageMagick, FFmpeg বা Ghostscript-এর কাছে হস্তান্তর করে। এগুলো বিশাল C এবং C++ কোডবেস, যার পার্সার বাগ-এর দীর্ঘ ইতিহাস রয়েছে। যিনি ফাইল আপলোড করছেন তিনি ফরম্যাট নির্বাচন করেন, যার অর্থ হলো আপলোডকারীই নির্ধারণ করছেন কোন পার্সারটি চলবে এবং এর ভেতরের কোন কোড পাথটি কার্যকর হবে।
HRConvert2-এর সমাধান হলো প্রতিটি ডিপেন্ডেন্সিকে একটি bubblewrap নেমস্পেসের ভেতরে চালানো। প্রতিটি কনভার্সন দুটি ডিরেক্টরি দেখতে পায়: একটি ইনপুট ধারণকারী ডিরেক্টরি, যা রিড-অনলি হিসেবে মাউন্ট করা থাকে এবং অন্যটি আউটপুট গ্রহণকারী ডিরেক্টরি। নেটওয়ার্কটি আনশেয়ার করা থাকে, যা প্রজেক্টের ভাষায়, closes every URL handler in every dependency at once। এটি শোনার চেয়েও বেশি গুরুত্বপূর্ণ। ImageMagick এবং Ghostscript উভয়ই এমন রেফারেন্স গ্রহণ করে যা একটি URL ফেচ করতে পারে, আর এভাবেই একটি কনভার্টার আপনার নেটওয়ার্কের ভেতর থেকে ক্লাউড মেটাডেটা এন্ডপয়েন্টে পৌঁছানোর জন্য একটি server side request forgery (SSRF) টুলে পরিণত হয়। নেমস্পেসের ভেতরে কোনো নেটওয়ার্ক না থাকলে, এই ফেচ করা সম্ভব হয় না।
প্রত্যাখ্যান বা রিফিউজাল হলো অন্য অর্ধেক: A server that cannot build a sandbox refuses the conversion rather than quietly running without one. একটি টুল যা ব্যর্থ হলে বন্ধ হয়ে যায়, সেটি এমন টুলের চেয়ে বেশি মূল্যবান যা কেবল এমন লগে সতর্কবার্তা দেয় যা কেউ পড়ে না। এজন্যই উপরের 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 কোডারগুলোকে অস্বীকার করে এবং URL, HTTPS, HTTP ও gs ডেলিগেটগুলোকে ব্লক করে, তবে 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-এর কাছে পাঠাবে না, ফাইলটি যাই দাবি করুক না কেন।
একই পলিসিতে রিসোর্স ক্যাপ নির্ধারণ করা হয়, যার মাধ্যমে একটি বিশেষভাবে তৈরি ইমেজ ফাইলকে পুরো সিস্টেমের রিসোর্স দখল করা থেকে আটকানো যায়:
<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 ভিডিওর ক্ষেত্রে ঠিক এই কাজটিই করে। প্রজেক্টের কনফিগারেশনে 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-এ ন্যূনতম সুবিধাপ্রাপ্ত ব্যবহারকারী অ্যাকাউন্ট হলো সাধারণ নিয়ম, এবং এখানে এটি অন্য যেকোনো সময়ের চেয়ে বেশি প্রযোজ্য।
পাবলিক করার উদ্দেশ্য না থাকলে এটিকে অথেনটিকেশনের পেছনে রাখুন
ডিজাইন অনুযায়ী ডিফল্ট ইনস্টলেশনে কোনো অ্যাকাউন্ট থাকে না। যে কেউ এই পেজে পৌঁছাতে পারলে ফাইল আপলোড করতে পারবে এবং আপনার কনভার্টার বাইনারিগুলো চালাতে পারবে, আর রেট লিমিট কেবল এই প্রক্রিয়াকে কিছুটা ধীর করবে। তাই আপনার পরিস্থিতি অনুযায়ী সিদ্ধান্ত নিন।
যদি এটি শুধু আপনার এবং আপনার কয়েকজন সহকর্মীর জন্য হয়, তবে এটিকে ইন্টারনেটে উন্মুক্ত করবেন না। উপরে দেখানো উপায়ে কন্টেইনারটিকে লুপব্যাক (loopback)-এ বাইন্ড করুন এবং প্রাইভেট নেটওয়ার্ক বা SSH টানেলের মাধ্যমে এটি ব্যবহার করুন। সেক্ষেত্রে পাবলিক ইন্টারনেটের কেউ ফাইল পাঠাতে পারবে না, যা ফিল্টার করার পরিবর্তে আক্রমণের পুরো ক্ষেত্রটিকেই (attack surface) সরিয়ে ফেলবে। যদি সহকর্মীদের কোনো হোস্টনাম প্রকাশ না করে বা পোর্ট না খুলেই ব্রাউজারে এটি খোলার প্রয়োজন হয়, তবে v3 onion service হিসেবে সার্ভ করা কনভার্টারটিকে লুপব্যাকে বাইন্ড রেখেও তাদের ভিজিট করার জন্য একটি ঠিকানা প্রদান করবে।
যদি এটি ব্রাউজার থেকে অ্যাক্সেসযোগ্য করতেই হয়, তবে প্রক্সির সামনে অথেনটিকেশন বসান। বেসিক অথ (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 সার্ভার আপনাকে এমন অ্যাপ্লিকেশনের সামনে ফরওয়ার্ড অথেনটিকেশন দেবে যার নিজস্ব কোনো লগইন সিস্টেম নেই।
যদি একটি সত্যিকারের পাবলিক কনভার্টারই আপনার লক্ষ্য হয়, তবে এর পরিণাম মেনে নিন এবং সেই অনুযায়ী পরিকল্পনা করুন। ধরে নিন যে স্যান্ডবক্সটি পরীক্ষা (probe) করা হবে। ইমেজ ট্যাগটি পিন করে রাখুন, ImageMagick পলিসি কঠোর রাখুন, আপলোড লিমিট ছোট রাখুন এবং এমন একটি VPS-এ এটি চালান যেখানে আপনার গুরুত্বপূর্ণ অন্য কোনো তথ্য নেই।
ব্যর্থতার ধরন এবং যে বার্তাগুলো দেখবেন
প্রতিটি conversion সঙ্গে সঙ্গে ব্যর্থ হয়। sandbox তৈরি করা যায় না। সাধারণ Ubuntu 24.04 ইনস্টলেশনে এর কারণ হলো AppArmor profile। নির্দিষ্ট 3.7 Docker image-এ কারণ হলো --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.-এর নির্দেশ দেয়।
শুধু image conversion ব্যর্থ হয়। Bubblewrap is missing or non functional, so this image conversion cannot be isolated! এর অর্থ হলো bwrap অনুপস্থিত, অথবা web server user-এর উপলভ্য PATH-এ সেটি পৌঁছানো যায় না।
একটি format ব্যর্থ হয়, কিন্তু অন্যগুলো কাজ করে। এটি অনুপস্থিত binary-এর সরাসরি বার্তা: ImageMagick may not be installed, or may not be reachable on the system path used by the web server user. FFmpeg এবং LibreOffice-এর ক্ষেত্রেও একই বার্তা দেখা যায়। ইনস্টলেশন কোন কোন binary খুঁজে পাচ্ছে তা দেখতে convertCore.php -v চালান। মনে রাখবেন, Apache worker-এর PATH আপনার login shell-এর PATH নয়।
PDF-সংক্রান্ত কাজ policy error-এ ব্যর্থ হয়। attempt to perform an operation not allowed by the security policy 'PDF' এসেছে ImageMagick-এর policy.xml থেকে, HRConvert2 থেকে নয়।
বড় upload-এ 413 ফেরত আসে। nginx-এর client_max_body_size ফাইলটির চেয়ে ছোট। এই chain-এ 3টি limit আছে: nginx-এ 1টি এবং PHP-তে 2টি। এর মধ্যে সবচেয়ে ছোট limit কার্যকর হয়।
Conversion বন্ধ হয়ে যায়, কিন্তু দৃশ্যমানভাবে কিছু পরিবর্তন হয়নি। The device where data is stored has an insufficient amount of storage space available.। খালি disk space পরীক্ষা করুন এবং cleanup sweep সত্যিই চলছে কি না যাচাই করুন।
Log-এ cleanup-সংক্রান্ত অভিযোগ দেখা যায়। Could not clean the temporary location! এবং Could not clean the convert location! ownership সমস্যার নির্দেশ করে। $ConvertLoc-এ উল্লেখিত directory-টির owner web server user-কে হতে হবে।
FAQ
Internet-এ self-hosted file converter প্রকাশ করা কি নিরাপদ?
এটি কেবল তখনই যথেষ্ট নিরাপদ, যখন আপনি এটিকে অপরিচিত ব্যবহারকারীদের জন্য উন্মুক্ত একটি parser হিসেবে বিবেচনা করবেন। প্রতিটি upload LibreOffice, ImageMagick, FFmpeg অথবা Ghostscript-এর কাছে পাঠানো হয়, এবং কোনটি ব্যবহার করা হবে তা upload করা ব্যক্তি নির্ধারণ করে। HRConvert2 এই tool-গুলোকে network-বিহীন এবং read only input directory-সহ একটি bubblewrap namespace-এর ভিতরে চালায়। যে conversion sandbox-এ চালানো সম্ভব নয়, এটি তা প্রত্যাখ্যান করে। এটি একটি শক্তিশালী default। তবু authentication বাধ্যতামূলক করা, upload limit ছোট রাখা এবং এমন একটি VPS-এ এটি চালানো ভালো, যেখানে অন্য কোনো গুরুত্বপূর্ণ data নেই।
নতুন Ubuntu 24.04 install-এ প্রতিটি conversion ব্যর্থ হয় কেন?
Ubuntu 24.04 AppArmor-এর মাধ্যমে unprivileged user namespace সীমাবদ্ধ করে, আর sandbox তৈরি করতে bubblewrap-এর একটি namespace প্রয়োজন। Application sandbox ছাড়া conversion চালাতে অস্বীকার করে। তাই কিছু job ব্যর্থ হওয়ার বদলে প্রতিটি job ব্যর্থ হয়। /usr/bin/bwrap-এর জন্য flags=(unconfined) দিয়ে একটি AppArmor profile লিখুন, sudo apparmor_parser -r /etc/apparmor.d/bwrap দিয়ে তা load করুন, তারপর bwrap --ro-bind / / --dev /dev /bin/true দিয়ে নিশ্চিত করুন। Debian 12 default হিসেবে unprivileged user namespace অনুমোদন করে। তাই সেখানে এই ধাপের প্রয়োজন নেই।
Docker-এ conversion ব্যর্থ হয়, কিন্তু সাধারণ install-এ কাজ করে কেন?
Docker-এর default seccomp profile bubblewrap যে system call ব্যবহার করে তা block করে। ফলে container-এর ভিতরে sandbox তৈরি করা যায় না। এখানে নির্দিষ্ট 3.7 image-এর জন্য --security-opt seccomp=unconfined দিয়ে এটি চালু করুন। ওই release-এর config.php comments-এ এটাই নির্দেশ করা হয়েছে। v3.8.0 থেকে project-এর documentation-এ এর পরিবর্তে --cap-add SYS_ADMIN উল্লেখ করা হয়েছে। মনে রাখবেন, $RequireSandboxOnDocker default হিসেবে FALSE থাকে। তাই flag ছাড়া container কোনো sandbox ছাড়াই conversion চালাতে পারে। seccomp flag সক্রিয় করার পর এটি TRUE সেট করুন।
File conversion server-এর কত RAM প্রয়োজন?
Idle অবস্থায় server-এর memory ব্যবহার কম থাকে। কিন্তু চলমান conversion-এর ক্ষেত্রে তা নয়। LibreOffice একটি Java runtime চালু করে। ImageMagick 256 MiB memory এবং shipped policy অনুযায়ী 512 MiB map ব্যবহার করে। PHP-এর নিজস্ব limit হলো 512M। 1 GB VPS-এ এই সমন্বয় swap ব্যবহার করে, এবং out of memory killer soffice.bin অথবা apache2 বন্ধ করে দেয়। ছোট একটি team-এর জন্য 4 GB RAM এবং দুইটি core পরিকল্পনা করুন। কোনো message ছাড়াই conversion বন্ধ হলে dmesg -T | grep -i "killed process" পরীক্ষা করুন।
Converted file-গুলো কোথায় যায় এবং কখন মুছে ফেলা হয়?
Resources/config.php-এ $ConvertLoc দ্বারা নির্ধারিত working directory-তে file-গুলো রাখা হয়। এর default হলো /DATA/HRConvert2। $DeleteThreshold নির্ধারণ করে কত মিনিট পরে একটি session expire হবে। এর default মান 60। Sweep command line থেকে চালানো হয়। php convertCore.php -c expired session মুছে দেয়। -c=now active session-সহ সব session সঙ্গে সঙ্গে মুছে দেয়। কোনো ব্যবহারকারী site-এ visit করলেই deletion হবে—এমন নির্ভরতা এড়াতে cron entry অথবা systemd timer-এ -c যোগ করুন।