Selama tiga chapter terakhir kita memakai service buatan orang lain: memantaunya lewat systemctl, membaca lognya lewat journalctl, dan menatanya lewat target. Sekarang giliran kita membuat service sendiri. Bayangkan sebuah aplikasi — skrip backup, bot internal, atau server kecil — yang ingin selalu hidup, dinyalakan ulang otomatis saat mati, ikut menyala saat boot, dan meninggalkan log rapi tanpa konfigurasi tambahan. Semuanya kita dapatkan dengan menulis satu file unit. Chapter ini membedah anatomi unit service, menjalankan verifikasi statis untuk setiap tulisan kita, lalu membedah mekanisme enable sampai ke symlink-nya.
Anatomi Tiga Section #
File unit service adalah file teks INI dengan tiga section utama, dan masing-masing punya tugas yang jelas:
| Section | Tugasnya |
|---|---|
[Unit] | metadata dan relasi ke unit lain — Description, After, Wants, Requires |
[Service] | cara program dijalankan — Type, ExecStart, User, Restart |
[Install] | bagaimana unit dikaitkan ke target saat di-enable — WantedBy |
Mari kita tulis unit pertama kita utuh dari nol — aplikasinya sengaja dibuat sederhana supaya fokusnya jatuh ke strukturnya:
cat > aplikasi.sh << 'EOF'
#!/bin/bash
while true; do
echo "denyut dari aplikasi latihan"
sleep 5
done
EOF
chmod +x aplikasi.sh
cat > latihan.service << EOF
[Unit]
Description=Contoh service latihan
[Service]
Type=simple
ExecStart=$PWD/aplikasi.sh
[Install]
WantedBy=multi-user.target
EOF
systemd-analyze verify latihan.service && echo "unit lolos verifikasi statis"Output yang Dihasilkan:
unit lolos verifikasi statisPerintah systemd-analyze verify memeriksa file unit tanpa menjalankannya — seperti bash -n untuk shell script — dan echo di ujung && menandai bahwa pemeriksaan lolos. Mari kita bedah baris per baris:
- Baris 1-7 (
cat > aplikasi.sh): aplikasi yang akan diawasi — loop tanpa akhir yang mencetak satu baris tiap lima detik, karena service memang untuk program yang hidup terus. - Baris 8 (
chmod +x aplikasi.sh): memberi bit eksekusi — systemd tidak menjalankanExecStartlewat shell, jadi file harus benar-benar executable. - Baris 12 (
Description=): deskripsi manusiawi yang tampil disystemctl status. - Baris 15 (
Type=simple): bawaan — systemd menganggap service siap begitu prosesnya berjalan, jadi aplikasinya harus tetap di foreground. - Baris 16 (
ExecStart=$PWD/aplikasi.sh): perintah inti; path-nya wajib absolut. Heredoc ini sengaja tidak dikutip agar$PWDberkembang ke folder latihan — di sistem nyata tulis path permanen seperti/usr/local/bin/aplikasi.sh. - Baris 19 (
WantedBy=multi-user.target): saat di-enable, unit ini ditarik olehmulti-user.target. - Baris 22 (
systemd-analyze verify): pemeriksaan sintaks, absolut path, dan bit eksekusi — semua lolos.
Untuk memasang di sistem nyata: salin skrip ke /usr/local/bin/ dan unit ke /etc/systemd/system/ (folder /lib/systemd/system/ milik paket — jangan mengedit isinya karena akan tertimpa saat update), lalu jalankan sudo systemctl daemon-reload supaya systemd membaca ulang disk, dan nyalakan dengan systemctl enable --now latihan.service.
Mengatur Perilaku: Type dan Restart #
Directive Type= menentukan kapan systemd menganggap service “sudah jalan”, dan pilihannya harus cocok dengan perilaku aplikasi:
| Type | Cocok untuk |
|---|---|
simple | aplikasi foreground modern (default) |
forking | daemon klasik yang mem-fork lalu keluar, gunakan PIDFile= agar systemd tahu induknya |
oneshot | skrip yang berjalan sekali lalu selesai — pasangan timer di Chapter systemd Timers |
notify | aplikasi yang mengirim sinyal “ready” lewat sd_notify, seperti nginx |
Sedangkan Restart= mengatur kebangkitan setelah kematian: on-failure (hidup lagi saat exit code bukan nol), on-abnormal (hanya saat sinyal atau timeout), always, atau no sebagai bawaan. Delay antar kebangkitan diatur RestartSec= — tanpa jeda, crash loop akan menghabiskan CPU dalam sekejap.
Lingkungan Eksekusi: User, WorkingDirectory, Environment #
Service berjalan sebagai root bila tidak dinyatakan lain — dan itu jarang yang kita inginkan. Directive di section [Service] memungkinkan kita mengunci identitas dan lingkungannya:
cat > aplikasi.sh << 'EOF'
#!/bin/bash
while true; do
echo "denyut dari aplikasi latihan"
sleep 5
done
EOF
chmod +x aplikasi.sh
printf 'LOG_LEVEL=info\n' > latihan.env
cat > latihan.service << EOF
[Unit]
Description=Contoh service latihan
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=$PWD/aplikasi.sh
Restart=on-failure
RestartSec=5s
User=app
WorkingDirectory=$PWD
Environment=MODE=produksi
EnvironmentFile=$PWD/latihan.env
[Install]
WantedBy=multi-user.target
EOF
systemd-analyze verify latihan.service && echo "unit baru lolos verifikasi"
grep -E '^(User|WorkingDirectory|Environment)' latihan.serviceOutput yang Dihasilkan:
unit baru lolos verifikasi
User=app
WorkingDirectory=/home/budi
Environment=MODE=produksi
EnvironmentFile=/home/budi/latihan.envKarena setiap blok latihan berdiri sendiri, blok ini menulis ulang aplikasi.sh dan latihan.env dengan cat/printf yang menimpa file lama — pembaca yang melompat langsung ke sini tetap mendapat hasil sama. Bedah barisnya:
- Baris 9 (
printf 'LOG_LEVEL=info'): file environment — cukup barisKEY=valuepolos. - Baris 14-15 (
After=danWants=network-online.target): relasi ke unit lain, persis materi Chapter Service Dependencies . - Baris 20-21 (
Restart=on-failure,RestartSec=5s): bila aplikasi mati dengan exit code bukan nol, systemd menunggu lima detik lalu menyalakannya lagi; stop manual tetap dihormati. - Baris 22 (
User=app): proses berjalan sebagai userapp, bukan root. Catatan:systemd-analyze verifytidak memeriksa keberadaan user — di sistem nyata buat dulu user-nya, karena service akan gagal start di tahap paling awal. - Baris 23-25 (
WorkingDirectory,Environment,EnvironmentFile): direktori kerja proses, variabel inline, dan variabel dari file — awali nama file dengan minus (EnvironmentFile=-/path) bila file itu boleh tidak ada. - Baris 31-32 (
systemd-analyze verifydangrep): verifikasi lolos, lalugrepmenampilkan kembali directive lingkungan —$PWDtelah menjadi path absolut di file jadinya.
Satu hal yang membedakan file environment dari file shell biasa: systemd mem-parsing isinya sendiri tanpa melewati shell, jadi tidak ada substitusi variabel maupun command substitution. Formatnya memang sengaja sederhana sehingga bisa juga disumber shell untuk menguji:
printf 'LOG_LEVEL=info\n' > latihan.env
set -a
. latihan.env
set +a
printf 'service akan melihat LOG_LEVEL=%s\n' "$LOG_LEVEL"Output yang Dihasilkan:
service akan melihat LOG_LEVEL=infoset -a membuat semua variabel yang dibaca ikut diekspor, meniru yang dialami proses service — cara cepat mengetes file environment sebelum dipasang.
Mengaitkan ke Target: Cara enable Bekerja #
Apa yang sebenarnya dilakukan systemctl enable? Chapter systemd Targets
sudah menyinggungnya: pembuatan symlink di folder .wants milik target yang tertulis di [Install]. Kita bisa meniru mekanismenya dengan tangan untuk melihatnya dari dekat:
printf '%s\n' '[Unit]' 'Description=Contoh service latihan' > latihan.service
mkdir -p multi-user.target.wants
ln -s ../latihan.service multi-user.target.wants/latihan.service
ls multi-user.target.wants/
readlink multi-user.target.wants/latihan.serviceOutput yang Dihasilkan:
latihan.service
../latihan.serviceSymlink dibuat relatif (../latihan.service) persis seperti gaya systemctl, agar bundle folder tetap bisa dipindah-pindah. Di sistem nyata, hasil perintah aslinya begini:
Created symlink /etc/systemd/system/multi-user.target.wants/latihan.service → /etc/systemd/system/latihan.service.Sejak symlink itu ada, setiap multi-user.target diaktifkan saat boot, latihan.service ikut ditarik. Dan begitu service hidup, semua peralatan chapter sebelumnya langsung bekerja — berikut tampilan status tipikalnya:
● latihan.service - Contoh service latihan
Loaded: loaded (/etc/systemd/system/latihan.service; enabled; preset: enabled)
Active: active (running) since Sat 2026-01-17 09:30:12 WIB; 42s ago
Main PID: 3122 (aplikasi.sh)
Tasks: 2 (limit: 4586)
Memory: 1.2M (peak: 1.5M)
CPU: 12ms
CGroup: /system.slice/latihan.service
├─3122 /bin/bash /usr/local/bin/aplikasi.sh
└─3123 sleep 5
Jan 17 09:30:12 laptop-budi systemd[1]: Started latihan.service - Contoh service latihan.
Jan 17 09:30:12 laptop-budi aplikasi.sh[3122]: denyut dari aplikasi latihanBaris “denyut dari aplikasi latihan” itu bukan kebetulan: stdout service ditangkap journald otomatis, jadi journalctl -u latihan.service -f menampilkan denyutnya setiap lima detik tanpa konfigurasi apa pun.
Daftar directive lengkap dengan seluruh nilainya didokumentasikan di systemd.service(5) , directive lingkungan eksekusi di systemd.exec(5) , dan koleksi contoh unit siap contek di wiki Arch tentang systemd .
Unit yang baru kita tulis kini resmi bagian dari graf boot — dan perjalanan lengkapnya dari tombol power sampai layar login adalah kisah chapter berikutnya.