VPS-এ systemd সার্ভিস তৈরি ও কনফিগ করার নিয়ম
systemd সার্ভিস ফাইল তৈরি করে আপনার প্রোগ্রাম বুটে চালু ও ক্র্যাশে রিস্টার্ট করানো যায়। সার্ভিস লেখা, টাইমার যোগ ও সুরক্ষিত করার পদ্ধতি জানুন।
systemd সার্ভিস কী এবং আপনার এটি কেন প্রয়োজন
systemd সার্ভিস হলো একটি ছোট টেক্সট ফাইল যা আপনার সার্ভারকে জানায় কীভাবে একটি প্রোগ্রাম চালাতে হবে: বুট হওয়ার সময় এটি শুরু করা, ক্র্যাশ করলে পুনরায় চালু করা এবং এর আউটপুট সিস্টেম লগে পাঠানো। এটিই এর সম্পূর্ণ কাজ। SSH সেশনে আপনি নিজে হাতে চালু করা একটি প্রোগ্রাম লগআউট করা বা সার্ভার রিবুট হওয়ার সাথে সাথেই বন্ধ হয়ে যায়। systemd সার্ভিসে মোড়ানো একটি প্রোগ্রাম চালু থাকে, কারণ আপনার শেলের বদলে সার্ভার নিজেই এটির মালিকানা ধরে রাখে।
Ubuntu, Debian, Fedora এবং বেশিরভাগ আধুনিক Linux সার্ভারে systemd হলো init সিস্টেম। এটি প্রথম চালু হওয়া প্রসেস এবং এটিই বাকি সবকিছু তদারকি করে। আপনি যখন একটি সার্ভিস ফাইল লেখেন, তখন আপনি আপনার প্রোগ্রামটি সেই তদারককারীর হাতে দেন। এই নির্দেশিকাটি দেখায় কোনটি কাজ করে এমন সবচেয়ে ছোট ইউনিট, প্রতিটি ইউনিটে থাকা তিনটি বিভাগ, এটি চালু করে এর লগ পড়ার উপায়, একটি টাইমারের মাধ্যমে নির্দিষ্ট সময়ে এটি চালানোর পদ্ধতি এবং সর্বনিম্ন বিশেষাধিকার নিয়ে চলতে এটিকে কীভাবে সুরক্ষিত করবেন।
সবচেয়ে ছোট কার্যকর সার্ভিস
একটি সার্ভিস ফাইল /etc/systemd/system/ এ থাকে, .service এ শেষ হয়, এবং মাত্র কয়েকটি লাইন প্রয়োজন। /usr/local/bin/myapp এ অবস্থিত একটি প্রোগ্রামের জন্য একটি তৈরি করুন:
sudo nano /etc/systemd/system/myapp.service[Unit]
Description=My application
[Service]
ExecStart=/usr/local/bin/myapp
[Install]
WantedBy=multi-user.targetএটি একটি সম্পূর্ণ, কার্যকর ইউনিট। ExecStart হলো চালানোর জন্য কমান্ড। WantedBy=multi-user.target অর্থ সার্ভার স্বাভাবিক মাল্টি-ইউজার অবস্থায় পৌঁছালে এটি একবার শুরু করুন, যা বুটের সময় এটিকে চালু করে। বাকি সবকিছুই কেবল উন্নতি।
তিনটি বিভাগ এবং প্রতিটির কাজ
প্রতিটি unit ফাইল তৃতীয় বন্ধনীর ভেতরে বিভাগে বিভক্ত থাকে। একটি সার্ভিস তিনটি ব্যবহার করে।
[Unit] সার্ভিস এবং এর সম্পর্কগুলো বর্ণনা করে। আপনি সবচেয়ে বেশি যে দুটি লাইন ব্যবহার করবেন:
[Unit]
Description=My application
After=network-online.target
Wants=network-online.targetDescription হলো মানুষের পড়ার জন্য একটি লেবেল, যা আপনি systemctl status-এ দেখবেন। After=network-online.target systemd-কে নির্দেশ দেয় যেন নেটওয়ার্ক চালু হওয়া পর্যন্ত আপনার প্রোগ্রাম শুরু না করে। যেকোনো পোর্টে বাইন্ড করা বা বাইরের দিকে সংযোগ স্থাপন করার ক্ষেত্রে এটি গুরুত্বপূর্ণ।
[Service] নির্ধারণ করে প্রোগ্রামটি কীভাবে চলবে। আপনার বেশিরভাগ সেটিং এখানেই থাকে:
[Service]
ExecStart=/usr/local/bin/myapp --config /etc/myapp/config.toml
WorkingDirectory=/opt/myapp
User=myapp
Restart=on-failure
RestartSec=5
Environment=LOG_LEVEL=infoUser=myapp প্রোগ্রামটিকে root-এর বদলে একটি সাধারণ অ্যাকাউন্ট হিসেবে চালায়। নিরাপত্তার জন্য এটি সবচেয়ে গুরুত্বপূর্ণ লাইন। Restart=on-failure এবং RestartSec=5 নিচে আলাদা বিভাগে আলোচনা করা হয়েছে, কারণ এগুলোই মূলত মানুষকে সার্ভিস লেখার প্রধান কারণ।
[Install] নির্ধারণ করে আপনি সার্ভিসটি enable করলে কী ঘটবে:
[Install]
WantedBy=multi-user.targetWantedBy=multi-user.target নির্ধারণ করে আপনি systemctl enable চালানোর সময় সার্ভিসটি কীভাবে বুটে যুক্ত হবে। একটি [Install] বিভাগ ছাড়া সার্ভিসটি হাতে শুরু করা যাবে, কিন্তু রিবুটের পর এটি নিজে থেকে চালু হবে না।
চালু করুন এবং পর্যবেক্ষণ করুন
যেকোনো unit ফাইল লেখার বা সম্পাদনার পর, systemd পুনরায় লোড করুন যাতে এটি পরিবর্তনটি পড়ে। এরপর এক ধাপে পরিষেবাটি enable এবং start করুন:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.servicedaemon-reload হল সেই ধাপটি যা মানুষ ভুলে যায়: systemd unit ফাইলগুলো ক্যাশে করে রাখে, তাই আপনি পুনরায় লোড না করা পর্যন্ত কোনো সম্পাদনা কাজ করবে না। enable --now পরিষেবাটিকে বুটের জন্য enable করে এবং সাথে সাথে এটি start করে। এটি যাচাই করুন:
sudo systemctl status myapp.service* myapp.service - My application
Loaded: loaded (/etc/systemd/system/myapp.service; enabled)
Active: active (running) since Wed 2026-07-15 22:40:11 UTC; 3s ago
Main PID: 4123 (myapp)Active: active (running) এবং enabled হল যা আপনি দেখতে চান। প্রোগ্রামের আউটপুট পড়তে, শুধুমাত্র এই unit-এর জন্য journal-কে বলুন:
sudo journalctl -u myapp.service -f-f নতুন লাইনগুলো আসার সাথে সাথে সেগুলো অনুসরণ করে, ঠিক tail -f-এর মতো। আপনার প্রোগ্রাম যা কিছু standard output বা standard error-এ লেখে তা এখানে এসে পৌঁছায়, আপনার তরফ থেকে কোনো logging সেটআপ ছাড়াই।
ব্যর্থ হলে পুনরায় চালু করুন, আপনি এই কারণেই এখানে আছেন
একটি সার্ভিসের মূল সুবিধা হলো আপনার প্রোগ্রাম বন্ধ হয়ে গেলে systemd সেটি আবার চালু করে। এর জন্য দুটি লাইন কাজ করে:
[Service]
Restart=on-failure
RestartSec=5Restart=on-failure প্রোগ্রামটি অশূন্য কোডে বন্ধ হলে বা SIGKILL বা SIGSEGV-এর মতো ক্র্যাশ সিগন্যালে বিলুপ্ত হলে সেটি পুনরায় চালু করে। একটি স্বাভাবিক বন্ধ হওয়া, বা SIGTERM, SIGINT, SIGHUP, বা SIGPIPE দিয়ে থামানো এটিকে ট্রিগার করে না। RestartSec=5 চেষ্টার মধ্যে পাঁচ সেকেন্ড অপেক্ষা করে, যাতে তাৎক্ষণিকভাবে ক্র্যাশ হওয়া একটি প্রোগ্রাম একটি ঘন লুপে ঘুরতে না থাকে। প্রসেসটি কিল করে এবং systemd সেটি ফিরিয়ে আনতে দেখে এটি নিশ্চিত করুন। SIGKILL ব্যবহার করুন: ডিফল্ট SIGTERM একটি স্বাভাবিক বন্ধ হিসেবে গণ্য হয়, তাই on-failure সার্ভিসটি পুনরায় চালু করত না:
sudo systemctl kill -s SIGKILL myapp.service
sudo systemctl status myapp.serviceপাঁচ সেকেন্ডের মধ্যে স্ট্যাটাস একটি নতুন Main PID দেখায় এবং আবার active (running)। এটিই পুরো ফিচার, এবং এই কারণেই একটি সার্ভিস tmux বা screen-এ একটি প্রোগ্রাম চালু রেখে দেওয়ার চেয়ে উত্তম।
একজন অ-বিশেষাধিকারপ্রাপ্ত ব্যবহারকারী হিসেবে চালান, এবং এটিকে শক্তিশালী করুন
root হিসেবে চলা একটি পরিষেবা কখনো শোষিত হলে আপনার সার্ভারে যা খুশি তাই করতে পারে। এটিকে তার নিজস্ব ব্যবহারকারী হিসেবে চালান, এবং systemd-কে কয়েকটি নির্দেশ দিন যা এটিকে আবদ্ধ রাখে। প্রথমে লগইন বা হোম ছাড়া একটি সিস্টেম অ্যাকাউন্ট তৈরি করুন:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin myappতারপর User=myapp নির্ধারণ করুন এবং [Service]-এ হার্ডেনিং লাইন যোগ করুন:
[Service]
User=myapp
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=trueপ্রতিটি লাইন এমন কিছু সরিয়ে দেয় যা প্রোগ্রামের প্রয়োজন নেই। NoNewPrivileges=true প্রক্রিয়াটিকে নতুন বিশেষাধিকার অর্জন করা থেকে চিরতরে আটকায়, একটি setuid বাইনারির মাধ্যমেও। PrivateTmp=true এটিকে একটি ব্যক্তিগত /tmp দেয় যা অন্য কোনো প্রক্রিয়া দেখতে পারে না। ProtectSystem=strict আপনি ReadWritePaths= দিয়ে উল্লেখ করা কয়েকটি পাথ ছাড়া পুরো ফাইলসিস্টেমকে শুধুমাত্র পঠনযোগ্য করে তোলে। ProtectHome=true এটি থেকে /home সম্পূর্ণ লুকিয়ে রাখে। এটি একটি পরিষেবাকে ফায়ারওয়ালের পেছনে রাখার মতো একই ন্যূনতম-বিশেষাধিকার চিন্তাভাবনা: এটিকে শুধু ততটুকু দিন যতটুকু এর প্রয়োজন। আপনি যদি একটি VPS-এ IPv6 ফায়ারওয়াল শূন্যস্থান বন্ধ করা-র গাইড পড়ে থাকেন, তবে এটি একই ধারণার হোস্ট-স্তরের অংশ। ইন্টারনেটের মুখোমুখি একটি পরিষেবার জন্য, এই হার্ডেনিংটিকে SSH-এর সামনে Fail2ban এবং একটি ডিফল্ট-ডিনাই ফায়ারওয়ালের সাথে যুক্ত করুন।
সবকিছু হাতে টাইপ করে একটি নির্দেশ ভুলে যাওয়ার বদলে, একটি সম্পূর্ণ, হার্ডেন করা ইউনিট তৈরি করুন এবং এটি কপি করে নিন:
টাইমার: আধুনিক cron
systemd টাইমার একটি সময়সূচী অনুযায়ী একটি সার্ভিস চালায়। এটি cron জব-এর আধুনিক বিকল্প। একটি টাইমার দুটি ফাইল নিয়ে গঠিত: একটি .service যা কাজটি সম্পাদন করে, এবং একটি .timer যা সময় নির্ধারণ করে। ধরুন আপনি প্রতিদিন ভোর 3টায় একটি ব্যাকআপ চান। সার্ভিসটি কাজটি একবার সম্পাদন করে বেরিয়ে যায়:
# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.shType=oneshot systemd-কে জানায় যে প্রোগ্রামটি চলে, শেষ হয়, এবং সম্পূর্ণ হয়, পটভূমিতে চলতে থাকে না। টাইমারটি এটি নির্ধারণ করে:
# /etc/systemd/system/backup.timer
[Unit]
Description=Run the nightly backup
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.targetOnCalendar=*-*-* 03:00:00 মানে প্রতিদিন ভোর 3টা। যেকোনো ক্যালেন্ডার এক্সপ্রেশন systemd-analyze calendar "*-*-* 03:00:00" দিয়ে পরীক্ষা করুন। এটি নিশ্চিত করে যে এক্সপ্রেশনটি সঠিক, এবং এটি পরবর্তী যে সময়গুলোতে ট্রিগার হবে তা প্রিন্ট করে। Persistent=true একটি মিস হওয়া জব সার্ভার চালু হওয়ার সাথে সাথেই চালায়, যদি ভোর 3টায় সার্ভার বন্ধ থাকে। cron এটি করতে পারে না। মনে রাখবেন, একটি টাইমার timers.target দিয়ে সক্রিয় করা হয়, multi-user.target দিয়ে নয়। সার্ভিস নয়, টাইমার সক্রিয় করুন:
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timerslist-timers প্রতিটি টাইমারের পরবর্তী এবং শেষ রানের সময় সহ তালিকা দেখায়। ফলে আপনি এক নজরেই দেখতে পারবেন আপনার জব পরবর্তী কবে ট্রিগার হবে। উপরের জেনারেটরটি আপনি টাইমার মোড চালু করলে জোড়া .service এবং .timer তৈরি করে দেয়। cron লাইনের তুলনায়, একটি টাইমার জার্নালে আসল লগ দেয়। যেকোনো সার্ভিসের মতো একই হার্ডেনিং ডিরেক্টিভ দেয়। এবং Persistent=true যে মিস হওয়া রান ক্যাচ-আপ দেয় তা প্রদান করে। সাধারণ কাজের জন্য cron এখনও ঠিক আছে। কাজটি গুরুত্বপূর্ণ হলে টাইমার একটি উন্নত টুল।
FAQ
একটি systemd service এবং একটি cron job-এর মধ্যে পার্থক্য কী?
একটি service একটি দীর্ঘকাল চলমান প্রোগ্রামকে সচল রাখে। এটি বুট হওয়ার সময় শুরু হয়, ব্যর্থ হলে পুনরায় চালু হয় এবং journal-এ লগ করে। একটি cron job নির্দিষ্ট সময়সূচিতে একটি ছোট কমান্ড চালায় এবং তারপর বেরিয়ে যায়। আপনি যখন সময়সূচি চান কিন্তু একইসাথে journal লগ, হার্ডেনিং এবং মিস হওয়া রান পুনরুদ্ধারও চান, তখন একটি systemd timer ব্যবহার করুন। এটি একটি .timer সময়সূচিকে একটি oneshot service-এর সাথে যুক্ত করে এবং বেশিরভাগ সার্ভার কাজের জন্য cron-কে প্রতিস্থাপন করে।
আমার systemd service ফাইলটি আমি কোথায় রাখব?
আপনার নিজের unit-গুলো /etc/systemd/system/-এ রাখুন, যার নাম .service দিয়ে শেষ হবে। সেই ডিরেক্টরিটি অ্যাডমিনিস্ট্রেটর যোগ করা unit-গুলোর জন্য, এবং এটি /lib/systemd/system/-এ প্যাকেজ দ্বারা সরবরাহ করা unit-গুলোর চেয়ে অগ্রাধিকার পায়। সেখানে একটি ফাইল তৈরি বা সম্পাদনা করার পর, sudo systemctl daemon-reload চালান যাতে systemd পরিবর্তনটি গ্রহণ করে।
একটি service ক্র্যাশ করলে কীভাবে আমি এটি পুনরায় চালু করব?
[Service] বিভাগে Restart=on-failure এবং RestartSec=5 যোগ করুন, তারপর sudo systemctl daemon-reload চালান এবং service-টি পুনরায় চালু করুন। প্রোগ্রামটি নন-জিরো কোডে বের হলে বা ক্র্যাশ সিগন্যালে বন্ধ হলে systemd এটি পুনরায় চালু করে, প্রতিটি চেষ্টার মধ্যে পাঁচ সেকেন্ড অপেক্ষা করে। এটি sudo systemctl kill -s SIGKILL myapp.service দিয়ে পরীক্ষা করুন — SIGTERM, ডিফল্ট সিগন্যাল, একটি পরিষ্কার বন্ধ হিসেবে গণ্য হয় এবং on-failure-কে ট্রিগার করে না — এবং কয়েক সেকেন্ডের মধ্যে systemctl status একটি নতুন PID দেখাচ্ছে কিনা তা পর্যবেক্ষণ করুন।
আমি কীভাবে একটি systemd service নন-রুট ব্যবহারকারী হিসেবে চালাব?
sudo useradd --system --no-create-home --shell /usr/sbin/nologin myapp দিয়ে একটি সিস্টেম অ্যাকাউন্ট তৈরি করুন, তারপর [Service] বিভাগে User=myapp যোগ করুন। NoNewPrivileges=true, PrivateTmp=true, এবং ProtectSystem=strict যোগ করুন যাতে প্রসেসটি তার প্রয়োজনমতো সর্বনিম্ন অ্যাক্সেস নিয়ে চলে। একজন অবিশেষাধিকারপ্রাপ্ত ব্যবহারকারী হিসেবে চালানো হলো একটি service-এর নিরাপত্তায় আপনি যে একক পরিবর্তনটি করতে পারেন তার মধ্যে সবচেয়ে গুরুত্বপূর্ণ।
আমার service চালু হতে ব্যর্থ হলো কেন?
সারাংশের জন্য systemctl status myapp.service এবং সম্পূর্ণ আউটপুটের জন্য journalctl -u myapp.service চালান। সবচেয়ে সাধারণ কারণগুলো হলো ExecStart-এ ভুল পথ, একটি অনুপস্থিত WorkingDirectory, User= একটি ফাইল পড়তে না পারার কারণে অনুমতি ত্রুটি, বা সম্পাদনার পর একটি ভুলে যাওয়া sudo systemctl daemon-reload। journal প্রোগ্রামের নিজস্ব ত্রুটি বার্তা দেখায়, যা সাধারণত সরাসরি সমস্যাটির নাম উল্লেখ করে।