একটি দেশের জন্য চল্লিশটি .ovpn ফাইল প্রোভাইডারের কাছ থেকে আসে, আর পরিকল্পনাটি স্পষ্ট মনে হয়: এলোমেলো একটি ফাইল জায়গামতো কপি করুন, তারপর টানেল চালু করুন। ExecStart-এর ভিতরে পাইপলাইন হিসেবে লিখলে সেই পরিকল্পনা বুটেই মারা যায় এমন একটি স্টেটাস কোড নিয়ে যা কিছুই ব্যাখ্যা করে না। ইউনিট ফাইল কোনো স্ক্রিপ্ট নয়, আর সমাধান হলো হয় স্পষ্টভাবে একটি শেল নিয়ে আসা, নয়তো ফাইল বাছাই করা সম্পূর্ণ বন্ধ করা।

লক্ষণ: একটি ইউনিট যা শুরু হয়েই সাথে সাথে মারা যায়

স্টেটাস দেখায় সেবাটি সেকেন্ডের ভগ্নাংশে ব্যর্থ হয়েছে, আর জার্নালের লাইন এমন একটি কমান্ডের নাম দেয় যা কোনো শেল কখনো পেত না। টানেল সম্পর্কে কিছুই দেখা যায় না, কারণ টানেল কখনোই শুরু হয়নি।

জার্নাল থেকে সঠিক কমান্ড লাইন পড়াই এটি নিশ্চিত করার দ্রুততম উপায়। systemd যা চালিয়েছে তা-ই প্রতিফলিত করে, আর স্ট্রিংটি পাইপলাইনের অক্ষরগুলোকে অপারেটর নয়, আক্ষরিক আর্গুমেন্ট হিসেবে দেখাবে।

ExecStart কেন পাইপলাইন চালাতে পারে না

systemd নিজেই কমান্ড লাইনটি ভাগ করে, নিজের কোটিং ও ভেরিয়েবল প্রতিস্থাপন প্রয়োগ করে, তারপর ফলাফলটি সরাসরি চালায়। পাইপ, রিডাইরেকশন, শেলের গ্লোব সম্প্রসারণ আর কমান্ড প্রতিস্থাপন সোজা কথায় এই গ্রামারের অংশ নয়। এটি বাদ পড়া নয়, বরং একটি নকশা সিদ্ধান্ত: একটি ইউনিট কী চালাতে হবে তা ঘোষণামূলকভাবে বলে, আর শেলের লজিক সেই স্ক্রিপ্টের, যেটি ইউনিটটি ডাকে। দুটি সমাধানই সেখান থেকেই আসে, আর কোনোটিতেই ইউনিটকে বেশি অধিকার দিতে হয় না।

এটি বিভ্রান্তিকর এক্সিট কোডটিও ব্যাখ্যা করে। প্রথম আর্গুমেন্টটিকেই বাইনারি ধরা হয়, তাই ত্রুটিপূর্ণ লাইনটি আপনার কোনো লজিক চলার আগেই ব্যর্থ হয়।

নির্বাচনটি ExecStartPre-এ করুন

সরাসরি সমাধান হলো একটি প্রস্তুতি ধাপ যা স্পষ্টভাবে একটি শেল ডাকে, আর নির্বাচন ও শুরুকে একই ইউনিটে রাখে যাতে একটির ব্যর্থতা অন্যটিকে একা চলতে না দেয়।

[Service]
Type=notify
ExecStartPre=/bin/bash -c "ls /etc/openvpn/profiles/au* | shuf -n 1 | xargs -r -I{} cp -f {} /etc/openvpn/%i.conf"
ExecStart=/usr/sbin/openvpn --config /etc/openvpn/%i.conf

তিনটি বিবরণ ঠিক করে এটি সত্যিকারের মেশিনের সংস্পর্শে টিকবে কি না। নামকরণই প্রথম ফাঁদ: systemd ইউনিট পার্স করার সময়ই, bash চলার অনেক আগেই %i প্রতিস্থাপন করে, তাই স্পেসিফায়ারটিকে একক কোটের বাইরে থাকতে হবে। গ্লোব কিছু না মিললে xargs -r cp-কে কোনো আর্গুমেন্ট ছাড়া চলা থেকে আটকায়। আর ব্যর্থ প্রস্তুতি ধাপ ইউনিটটি থামিয়ে দেয়, এবং এটাই সঠিক ফল: গতকালের কনফিগারেশন দিয়ে শুরু করা না শুরুর চেয়ে খারাপ। যে এলোমেলো বাছাই সবসময় একই ফাইল নেয় সেটি সাধারণত দুর্ভাগ্য নয়। দেখুন কপি করা ফাইলটি কোনো প্যাকেজ আপডেটে ওভাররাইট হচ্ছে কি না, অথবা গ্লোবটি একটিমাত্র পুরোনো এন্ট্রির সঙ্গে মিলছে কি না।

অথবা OpenVPN-কেই এন্ডপয়েন্ট বেছে নিতে দিন

OpenVPN ইতিমধ্যেই একটি প্রোফাইলে কয়েকটি এন্ডপয়েন্ট রাখতে পারে এবং এলোমেলোভাবে সেগুলোর মধ্যে বেছে নিতে পারে, যা শেল, কপি আর রাইট অ্যাক্সেসকে বুটের পথ থেকে সম্পূর্ণ সরিয়ে দেয়।

client
remote-random
<connection>
remote au1.example.net 1194 udp
</connection>
<connection>
remote au2.example.net 1194 udp
</connection>

এই রূপটি সার্ভার নির্বাচনকে প্রোভাইডারের লেখা ফাইলের ভিতরেই রাখে, তাই ফাইল নতুন নাম দেওয়া রোটেশন ইউনিটটি ভাঙে না। এটি প্রার্থী তালিকাটিকেও নিরীক্ষাযোগ্য করে, যা কোনো ডিরেক্টরির ওপর গ্লোব কখনো করে না। প্রোফাইলগুলো একটি এন্ডপয়েন্টের চেয়ে বেশি কিছুতে আলাদা হলে শাফল এখনো তার জায়গা রাখে: আলাদা সার্টিফিকেট, আলাদা রাউটিং নির্দেশ, আলাদা সাইফার নীতি। সেক্ষেত্রে নির্বাচনটি সম্পূর্ণ কনফিগারেশনের মধ্যে, আর একটি শেল ধাপই এটি প্রকাশের সৎ উপায়।

ইনস্ট্যান্স ও সেটি ব্যবহার করা ফাইলটি ফিরে পড়ুন

এর বিষয়বস্তু ডিবাগ করার আগে নিশ্চিত করুন কোন ইউনিটটি সত্যিই চলছে। প্যাকেজের মেটা সেবা ও টেমপ্লেট হলো অবকাঠামো; আপনার ফাইলগুলোর সঙ্গে মিলে যাওয়া ইউনিটগুলোই তাদের নামে ডাকা ইনস্ট্যান্স।

systemctl list-units 'openvpn*'
systemctl cat [email protected]
journalctl -u openvpn@au -n 30 --no-pager

যে ইনস্ট্যান্স কেউ মনে রাখে না সে সক্রিয় করেছিল, সেটি সাধারণত প্যাকেজ ডিরেক্টরির একটি পথভ্রষ্ট কনফিগারেশন ফাইলে গিয়ে ঠেকে। টেমপ্লেট নয়, ওই নামের ইনস্ট্যান্সটিই বন্ধ করুন, নইলে পরের প্যাকেজ আপগ্রেড এটি ফিরিয়ে আনবে। পরিবর্তনের পর ইউনিটটি শুরু করুন এবং জার্নাল যে কমান্ড লাইন জানায় তা পড়ুন, তারপর এটি সত্যিই যে কনফিগারেশন পথ খুলেছিল তা নিশ্চিত করুন। ওই একটি যাচাই কাজ করা এলোমেলো বাছাইকে গত মাসের ফাইল চুপচাপ পুনর্ব্যবহার করা সেবা থেকে আলাদা করে।

সম্পর্কিত নিবন্ধ