ব্লগে ফিরুন

Systemd Service চালু হচ্ছে না? ঠিক করার উপায়

১৪ সেপ্টেম্বর, ২০২৬

চালু না হওয়া একটি systemd service প্রায় কখনোই রহস্যময় নয়। systemctl status <unit> চালান, তারপর journalctl -u <unit> -n 50 --no-pager দিয়ে ওই unit-এর শেষ 50টি journal লাইন পড়ুন — এই দুটোর মাঝেই পাঁচটি কারণের একটি সাধারণত সরাসরি ধরা পড়ে: ভুল path, হারিয়ে যাওয়া binary, ভুল permission, SELinux/AppArmor denial, বা unit ফাইলের syntax error। ব্যর্থতার কারণ লগেই লেখা আছে; নিচের সমাধানগুলো কেবল সেটার সঙ্গে pattern matching।

systemd service কেন ব্যর্থ হলো তা দেখবেন কীভাবে?

প্রথমে status, তারপর journal:

systemctl status myapp.service
journalctl -u myapp.service -n 50 --no-pager

status আপনাকে state দেখায় (inactive (dead), failed (exit-code), activating (auto-restart)) এবং শেষ কয়েকটি লগ লাইন। journal দেয় পুরো গল্প: stdout, stderr, আর unit সম্পর্কে systemd-এর নিজের অভিযোগ।

unit আগে একবার ব্যর্থ হয়েছিল এবং সেই run-এর রেকর্ড চাইলে বর্তমান boot-এর জন্য -b, বা --since today যোগ করুন:

journalctl -u myapp.service -b --no-pager

পুরো টুলকিট — boot, priority, লাইভ output ফলো করা — দেখুন journalctl cheat sheet-এ। একই অভ্যাস এখানেও কাজ করে।

আরেক জোড়া কমান্ড জেনে রাখা ভালো:

systemctl list-units --failed
systemctl reset-failed myapp.service

প্রথমটি মেশিনের প্রতিটি লাল unit দেখায়। দ্বিতীয়টি ঠিক করার পরে failed state পরিষ্কার করে — নান্দনিকতা মাত্র, কিন্তু status পেজে বৃথা সতর্কবার্তা আটকায়।

সবচেয়ে সাধারণ কারণগুলো কী কী?

লগ লক্ষণটা বলে দিলে, কারণ প্রায় সবসময় এই পাঁচটির একটি:

লগ কী বলেসম্ভাব্য কারণসমাধান
status=203/EXECভুল ExecStart= path বা interpreter নেইAbsolute path, chmod +x, shebang দেখুন
স্ক্রিপ্টে status=203/EXECস্ক্রিপ্টে CRLF line ending বা ভুল shebangdos2unix script.sh, প্রথম লাইন ঠিক করুন
status=1/FAILURE, app-এর লগ নেইWorking directory বা environment variable অনুপস্থিতWorkingDirectory= সেট করুন, Environment= যোগ করুন
Permission deniedব্যবহারকারী ফাইল পড়তে বা port bind করতে পারছে নামালিকানা ঠিক করুন; 1024-এর নিচের port-এ AmbientCapabilities=CAP_NET_BIND_SERVICE বা root দরকার
Unit is maskedকেউ systemctl mask চালিয়েছেsystemctl unmask myapp.service
unit ফাইল সম্পাদনা “কিছুই করছে না”daemon reload করা হয়নিsystemctl daemon-reload

203/EXEC পরিবারের আলাদা উল্লেখ দরকার, কারণ অর্ধেক দিন খেয়ে ফেলে এটাই। systemd আপনার শেল ব্যবহার করে না ExecStart= চালু করতে। অর্থাৎ:

# ভুল — শেল নেই, ~ কখনো expand হয় না, PATH lookup নেই
ExecStart=~/app/run.sh

# সঠিক
ExecStart=/opt/app/run.sh

আর স্ক্রিপ্টটা নিজে executable হতে হবে এবং সত্যিকারের shebang দিয়ে শুরু হতে হবে (#!/bin/bash বা #!/usr/bin/env bash)। টার্মিনালে চমৎকার চলা কিন্তু systemd-এর অধীনে 203 দিয়ে ব্যর্থ হওয়া স্ক্রিপ্ট প্রায় প্রতিবার এর যেকোনো একটি: executable নয়, CRLF ending, অচল shebang, বা relative path।

হাতে চালু হয় কিন্তু boot-এ হয় না কেন?

চিরাচরিত ordering bug। লগ boot-এর পরপরই ব্যর্থতা দেখায়, কিন্তু হাতে systemctl start করলে unit ঠিকঠাক চালু হয় — বুঝবেন আপনার service race-এ হারছে: network, mounted disk, বা database আসার আগেই সেটার জন্য হাত বাড়াচ্ছে।

সমাধান: আশা নয়, dependency ঘোষণা করুন:

[Unit]
After=network-online.target postgresql.service
Wants=network-online.target

[Service]
ExecStartPre=/usr/bin/test -f /opt/app/config.toml

After= start-এর ক্রম ঠিক করে; Wants= systemd-কে সত্যিই dependency তুলতে বাধ্য করে। network-online.target কাজ করে তখনই যখন আপনার distro-তে network-wait service সক্রিয় — তাই systemctl is-enabled NetworkManager-wait-online.service দেখে নিন (বা systemd-networkd-এর সমতুল্যটি)। ExecStartPre= guard হলো সস্তা, সৎ একটা উপায় — stack trace-এর বদলে পাঠযোগ্য বার্তায় জোরে ব্যর্থ হওয়ার।

দ্বিতীয় রূপ: service boot-এ চালু হয় কিন্তু সঙ্গে সঙ্গে মারা যায়। খুঁজুন এমন জিনিস যা আপনার interactive environment-এ ছিল কিন্তু boot-এ নেই — PATH-এর পার্থক্য, virtualenv, বা HOME। দরকারি জিনিস স্পষ্টভাবে সেট করুন:

[Service]
Environment="PATH=/opt/app/venv/bin:/usr/bin"
User=appuser
WorkingDirectory=/opt/app

আমার service journal-এ লগ করছে না কেন?

journalctl -u কিছুই না দেখালে, ক্রমে তিনটি জিনিস দেখুন:

  1. unit-এর StandardOutput=StandardError= — হতে হবে journal (ডিফল্ট) বা journal+console। কেউ সেগুলো null করে রেখে থাকতে পারে।
  2. app stdout-এর বদলে ফাইলে লেখে। systemd কেবল stdout/stderr ধরে; ফাইলে লেখা লগ journal-কে পুরোপুরি বাইপাস করে। হয় app-কে stdout-এর দিকে ফেরান, নয়তো ফাইলটাই পড়ুন।
  3. Storage limit পুরনো লাইন ফেলে দিয়েছে: journalctl --disk-usage দেখুন, আর journal দমবন্ধ হলে /etc/systemd/journald.conf-এ SystemMaxUse=

start-টাই ডিবাগ করতে চাইলে boot-time context-এ শেল ঢোকানোর চেয়ে ভালো কিছু নেই:

[Service]
ExecStart=/bin/bash -c 'exec /opt/app/bin/server 2>&1'

আর সত্যিকারের রহস্য হলে, unit-এর user হয়ে হুবহু ExecStart= কমান্ডটি শেলে চালান — বেশিরভাগ environment পার্থক্য প্রথম দশ সেকেন্ডেই ধরা পড়ে।

crash-এর পরে স্বয়ংক্রিয়ভাবে restart হবে কীভাবে?

ডিফল্ট নীতি Restart=no: crash করা service মৃতই থাকে, আর আপনি জানতে পারেন একজন user-এর মাধ্যমে। প্রতি service-এ সেটা ঠিক করুন:

[Service]
Restart=on-failure
RestartSec=5
সেটিংকখন restart হয়
no (ডিফল্ট)কখনোই না
on-failureশূন্যেতর exit, signal, timeout
alwaysযেকোনো exit, পরিচ্ছন্ন হলেও
on-watchdogশুধু watchdog timeout

Restart=on-failure-এর সঙ্গে start-rate guard জুড়ে দিন, যাতে crash-এর লুপ মেশিন পিটিয়ে না যায়: [Unit] সেকশনে StartLimitIntervalSec=StartLimitBurst=। ষাট সেকেন্ডে পাঁচবার ব্যর্থতা মানুষকে জাগানোর কথা, CPU ঘুরিয়ে রাখার নয়।

daemon-এর বদলে scheduled job হিসেবে বানাচ্ছেন? তাহলে আগে cron vs systemd timer মাপুন — timer journal লগিং ও dependency ordering বিনামূল্যে দেয়, এই নিবন্ধ যার জন্য বারবার হাত বাড়ায়।

60 সেকেন্ডের চেকলিস্ট

  1. systemctl status <unit> — state ও শেষ লাইনগুলো পড়ুন।
  2. journalctl -u <unit> -n 50 --no-pager — আসল error খুঁজুন।
  3. 203/EXEC? path, shebang, permission ঠিক করুন। Permission denied? user ও ফাইলের মালিকানা ঠিক করুন।
  4. শুধু boot-এ ব্যর্থ? After=/Wants=network-online.target এবং একটি ExecStartPre= guard যোগ করুন।
  5. unit ফাইল বদলেছেন? systemctl daemon-reload && systemctl restart <unit>
  6. Restart=on-failure যোগ করুন, যাতে পরের crash লুকিয়ে না থেকে নিজেই ঘোষণা করে।

বেশিরভাগ “systemd জটিল” মুহূর্ত নেমে আসে এক জায়গায়: error টা শুরু থেকেই journal-এ ছিল। unit ফাইল সম্পাদনার আগে সেটা পড়ুন, পরে নয়।

— mrsaynothing

— mrsaynothing

AI, Linux ও self-hosting নিয়ে ফিল্ড নোটস।

পোস্টটি নিয়ে dev.to-তে আলোচনা করুন dev.to ↗

পরের হাউ-টু ইমেইলে পান

প্রতি পোস্টে একটি ইমেইল। সমাধান করুন, এগিয়ে যান।

self-hosted · কোনো তৃতীয় পক্ষ নেই · এক ক্লিকে আনসাবস্ক্রাইব

এটা কী?

GGUF quantization: কোন level ব্যবহার করবেন?

লেখাগুলো ভালো লাগছে? এমন জিনিস বানানোই আমার পেশা। আমাকে নিন