/etc/init.d/ terlihat baik-baik saja. systemctl status bilang active, tidak ada pesan error, tapi aplikasinya tidak merespons. Kasus lain, service jalan normal saat di-start manual, lalu tidak muncul lagi setelah server reboot. Penyebabnya biasanya sama: script itu tidak dijalankan systemd secara langsung. systemd membungkusnya dengan unit buatan otomatis, dan unit ini punya perilaku yang berbeda dari unit native.
Artikel ini fokus ke cara mengeceknya lewat CLI. Tujuannya supaya kamu bisa membedakan service yang benar-benar hidup dari service yang cuma terlihat hidup di status.
Apa yang dilakukan systemd-sysv-generator
systemctl daemon-reload. Salah satunya, systemd-sysv-generator, bertugas memindai script di /etc/init.d/. Generator membaca header LSB di bagian atas script (blok ### BEGIN INIT INFO sampai ### END INIT INFO), lalu membuat file .service sementara untuk tiap script.
File hasil generator itu tidak ditulis ke /etc/systemd/system/ atau /lib/systemd/system/, melainkan ke direktori runtime di bawah /run/systemd/. Ini sering bikin bingung. Admin mencari file unit-nya di lokasi biasa, tidak ketemu, lalu mengira service itu tidak dikelola systemd sama sekali. Satu hal lagi yang perlu diingat: kalau sudah ada unit native dengan nama yang sama, generator akan melewati script init.d-nya. Jadi bisa saja script yang kamu edit ternyata tidak pernah dipakai.
Bagian yang paling penting adalah properti unit hasil generator. Umumnya unit ini memakai Type=forking, RemainAfterExit=yes, Restart=no, dan GuessMainPID=no. Artinya kurang lebih begini:
- systemd menganggap tugas script selesai begitu
startberhasil keluar. - Unit tetap dianggap aktif meski proses yang dijalankan script sudah tidak ada.
- Kalau prosesnya crash, systemd tidak akan me-restart-nya.
- systemd tidak berusaha menebak proses mana yang jadi proses utama.
Pastikan dulu service itu memang hasil generator
nama-app dengan nama script di /etc/init.d/ milikmu. Semua perintah di bawah ini read-only.
BASH
# Lihat unit apa saja yang dibuat generator di boot ini
ls -l /run/systemd/generator.late/
# Tampilkan isi unit. Unit hasil generator biasanya diawali komentar
# yang menyebut systemd-sysv-generator dan punya SourcePath ke /etc/init.d
systemctl cat nama-app.service
# Ambil properti kunci dalam satu perintah
systemctl show -p SourcePath -p FragmentPath -p Type -p RemainAfterExit -p Restart nama-app.serviceSourcePath mengarah ke /etc/init.d/nama-app dan FragmentPath berada di bawah /run/systemd/, berarti service itu memang dibungkus generator. Kalau FragmentPath justru menunjuk ke /etc/systemd/system/ atau /lib/systemd/system/, berarti ada unit native yang menang. Dalam kasus itu, perubahan apa pun di script init.d tidak akan berpengaruh. Kondisi ini sering terjadi setelah upgrade, karena paket versi baru kadang membawa unit native sendiri.
Perhatikan juga nilai RemainAfterExit dan Restart. Dua nilai ini menjelaskan hampir semua kebingungan di bagian berikutnya.
Kenapa status bisa active padahal prosesnya sudah mati
RemainAfterExit=yes, systemd mencatat unit sebagai aktif begitu perintah start di script selesai dengan kode keluar sukses. Setelah itu, kalau daemon yang dijalankan script mati karena crash, kehabisan memori, atau error konfigurasi yang baru terbaca belakangan, unit tetap tercatat aktif. Di output status, kondisi ini biasanya muncul sebagai active (exited), bukan active (running).
Banyak orang hanya membaca kata active dan berhenti di situ. Padahal kata di dalam kurung itulah yang penting. exited pada service yang seharusnya berupa daemon jangka panjang adalah tanda kamu perlu mengecek prosesnya langsung.
BASH
# Status lengkap. Perhatikan baris Active dan daftar proses di bagian CGroup
systemctl status nama-app.service --no-pager
# MainPID 0 berarti systemd tidak melacak proses utama
systemctl show -p ActiveState -p SubState -p MainPID nama-app.service
# Proses apa saja yang masih ada di cgroup unit ini
systemd-cgls -u nama-app.service
# Cek proses dan port langsung, tanpa lewat systemd
pgrep -af nama-app
sudo ss -ltnp- Kalau
SubStatebernilaiexiteddan cgroup kosong, unit cuma "ingat" bahwa dulu start-nya berhasil. Prosesnya sudah tidak ada. - Kalau
pgrepmenemukan prosesnya tapi cgroup unit kosong, kemungkinan daemon dijalankan di luar systemd. Misalnya ada yang menjalankan/etc/init.d/nama-app startlangsung, bukan lewatsystemctl. Proses seperti ini tidak dilacak unit, jadisystemctl stoppun tidak akan menghentikannya dengan benar. - Terakhir, cocokkan port di
ssdengan port yang seharusnya dipakai aplikasi. Kalau port-nya tidak ada di daftar listen, service itu tidak melayani apa pun, apa pun kata status.
Restart=no, systemd juga tidak akan mencoba menghidupkan ulang daemon yang mati. Di sistem lama berbasis SysV, perilakunya memang sama. Bedanya, sekarang status di systemd memberi kesan semuanya aman.
Cek apakah service benar-benar ikut start saat boot
/etc/systemd/system/*.wants/ seperti unit native. Generator menentukannya dari symlink S* di direktori /etc/rc?.d/, yang dibuat dari nilai Default-Start di header LSB.
Perintah systemctl is-enabled untuk script SysV biasanya diteruskan ke tool bawaan distro. Di keluarga Debian/Ubuntu ke systemd-sysv-install, di keluarga RHEL ke chkconfig. Karena itu output-nya kadang disertai pesan bahwa service tersebut bukan service native. Pesan ini wajar, bukan error.
BASH
# Status enable menurut systemd (dan tool SysV di belakangnya)
systemctl is-enabled nama-app.service
# Symlink runlevel yang dipakai generator. S = start, K = kill
ls -l /etc/rc?.d/ | grep nama-app
# Apakah unit masuk ke dependensi target boot normal
systemctl list-dependencies multi-user.target --no-pager | grep nama-app
# Log unit untuk boot saat ini, lalu boot sebelumnya
journalctl -u nama-app.service -b --no-pager
journalctl -u nama-app.service -b -1 --no-pager
# Rantai dependensi yang menunda atau mendahului service ini saat boot
systemd-analyze critical-chain nama-app.serviceis-enabled menjawab enabled tapi unit tidak muncul di list-dependencies target boot, periksa header LSB di script. Header yang hilang, Default-Start yang kosong, atau Required-Start yang menyebut facility yang tidak dikenal bisa membuat urutan atau penempatan unit tidak sesuai harapan. Setelah memperbaiki header, jalankan sudo systemctl daemon-reload supaya generator membaca ulang script. Perintah ini aman dan tidak me-restart service.
Untuk journalctl -b -1, log boot sebelumnya hanya tersedia kalau journal disimpan permanen. Kalau perintah itu menjawab tidak ada data boot sebelumnya, cek dulu konfigurasi journald. Pembahasannya ada di cara cek journald menyimpan log permanen setelah pindah dari rsyslog. Tanpa log boot sebelumnya, kamu cuma bisa menebak kenapa service gagal start saat boot.
Yang biasanya terlihat di journal untuk unit hasil generator adalah output dari script itu sendiri, misalnya pesan Starting ... dan kode keluar. Kalau script menyembunyikan error daemon ke /dev/null atau ke file log sendiri, journal akan terlihat bersih padahal daemon gagal. Dalam kasus ini, buka juga file log aplikasi yang disebut di script.
Uji ulang setelah reboot dan kapan sebaiknya pindah ke unit native
systemctl show -p SubState -p MainPIDuntuk melihat status unit.systemd-cgls -udanss -ltnpuntuk memastikan prosesnya hidup dan port-nya listen.journalctl -u ... -buntuk membaca apa yang terjadi saat boot.
RemainAfterExit.
Bungkus dari generator ini pada dasarnya adalah lapisan kompatibilitas, bukan tujuan akhir. Upstream systemd sudah lama menandai dukungan script SysV sebagai deprecated. Di versi baru, dukungan ini direncanakan atau sudah dihapus, jadi cek changelog systemd dan catatan rilis distro kamu sebelum upgrade berikutnya.
Unit native juga menyelesaikan masalah yang dibahas di sini. Dengan Type=simple atau Type=notify, systemd melacak proses utama secara langsung. Dengan Restart=on-failure, daemon yang crash dihidupkan ulang. Status active (running) pun benar-benar berarti prosesnya ada.
Saat pertama kali menulis unit native, error paling umum adalah service langsung gagal karena path atau izin eksekusi di ExecStart. Kalau itu terjadi, panduan melacak service systemd yang keluar dengan status 203/EXEC bisa membantu. Ingat juga bahwa unit native dengan nama yang sama akan langsung menggantikan script init.d setelah daemon-reload. Hentikan dulu service lama lewat systemctl stop supaya tidak ada dua instance yang berebut port.
Aturan praktisnya sederhana. Untuk service yang berasal dari /etc/init.d/, jangan pernah percaya kata active saja. Pastikan dulu unit-nya hasil generator lewat systemctl show -p SourcePath. Lalu cocokkan SubState, isi cgroup, dan port yang listen. Kalau service itu penting untuk produksi, jadwalkan pemindahannya ke unit native, sebelum upgrade OS berikutnya membuat lapisan kompatibilitas ini hilang.