September 27, 2026
Dasar systemd.
Memahami unit systemd, menulis service file sendiri, mengelola service dengan systemctl, membaca log dengan journalctl, restart policy, dan timer sebagai pengganti cron.
systemd adalah init system dan pengelola service di hampir semua distro Linux modern (Ubuntu, Debian, Fedora, Arch). Ia adalah proses pertama yang berjalan (PID 1) dan bertugas menyalakan, menghentikan, serta mengawasi service. Kalau kamu pernah menjalankan systemctl restart nginx, itu berarti kamu sudah berinteraksi dengan systemd.
Catatan ini fokus ke kebutuhan sehari-hari di server: menjalankan aplikasi sendiri (Node.js, Go, Python, queue worker Laravel ) sebagai service yang otomatis hidup saat boot dan otomatis restart saat crash.
1. Unit
Semua yang dikelola systemd disebut unit, dan jenisnya ditentukan oleh ekstensi file:
| Jenis | Contoh | Fungsi |
|---|---|---|
.service | nginx.service | Proses/daemon |
.timer | backup.timer | Menjadwalkan unit lain (pengganti cron ) |
.socket | ssh.socket | Menyalakan service saat ada koneksi masuk |
.target | multi-user.target | Grup unit, mirip “runlevel” |
.mount | mnt-data.mount | Titik mount |
.path | deploy.path | Memicu unit saat file/folder berubah |
Lokasi file unit:
| Lokasi | Isi | Boleh diedit? |
|---|---|---|
/usr/lib/systemd/system/ (atau /lib/systemd/system/) | Bawaan paket | Jangan, tertimpa saat update |
/etc/systemd/system/ | Buatan admin & override | Ya, prioritas tertinggi |
~/.config/systemd/user/ | Service milik user (systemctl --user) | Ya |
2. systemctl: Perintah Sehari-hari
sudo systemctl start nginx # nyalakan sekarang
sudo systemctl stop nginx # matikan
sudo systemctl restart nginx # stop lalu start
sudo systemctl reload nginx # muat ulang konfigurasi tanpa putus (jika didukung)
systemctl status nginx # status, PID, memori, potongan log terakhir
sudo systemctl enable nginx # nyala otomatis saat boot
sudo systemctl disable nginx # batal otomatis
sudo systemctl enable --now nginx # enable + start sekaligus
systemctl is-active nginx
systemctl is-enabled nginx
systemctl list-units --type=service --state=running
systemctl --failed # unit yang gagal
Perbedaan yang sering tertukar:
starthanya berlaku untuk sesi sekarang. Setelah reboot, service tidak menyala.enablemembuat symlink agar service menyala saat boot, tapi tidak menyalakannya sekarang.
Service yang benar-benar tidak boleh dijalankan (bahkan sebagai dependensi) bisa di-mask:
sudo systemctl mask apache2
sudo systemctl unmask apache2
3. Menulis Service File Sendiri
Contoh: aplikasi Node.js di /opt/myapp.
# /etc/systemd/system/myapp.service
[Unit]
Description=My Node.js App
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=60
StartLimitBurst=5
[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
Environment=NODE_ENV=production
EnvironmentFile=-/etc/myapp/env
ExecStart=/usr/bin/node /opt/myapp/server.js
Restart=on-failure
RestartSec=5
# hardening ringan
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
[Install]
WantedBy=multi-user.target
Aktifkan:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin myapp
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
systemctl status myapp
Penting: Setiap kali membuat atau mengubah file unit, jalankan
sudo systemctl daemon-reload. Tanpa itu, systemd masih memakai versi lama yang ada di memori.
Penjelasan bagian penting
[Unit]
After=hanya mengatur urutan, bukan ketergantungan.Wants=/Requires=yang membuat unit lain ikut dinyalakan.network-online.targetmenunggu jaringan benar-benar siap, sedangkannetwork.targettidak.
[Service]
| Opsi | Keterangan |
|---|---|
Type=simple | Default. Proses di ExecStart adalah proses utama, tidak fork ke background |
Type=exec | Seperti simple, tapi dianggap sukses setelah binary berhasil dieksekusi |
Type=forking | Untuk daemon lama yang fork sendiri; biasanya butuh PIDFile= |
Type=oneshot | Tugas sekali jalan (skrip), sering dipasangkan dengan timer |
Type=notify | Aplikasi memberi sinyal “siap” lewat sd_notify |
ExecStart= | Wajib path absolut; tidak dijalankan lewat shell |
Environment= / EnvironmentFile= | Variabel lingkungan; - di depan path berarti “abaikan jika file tidak ada” |
User= | Jangan jalankan aplikasi sebagai root |
Karena ExecStart tidak melewati shell, fitur seperti pipe, &&, atau > tidak berfungsi. Jika memang perlu, bungkus: ExecStart=/bin/bash -c 'cmd1 && cmd2'.
[Install]
WantedBy=multi-user.target berarti “nyalakan saat sistem mencapai mode multi-user”, yaitu kondisi boot normal di server. Bagian inilah yang dibaca oleh systemctl enable.
4. Restart Policy
Restart= | Restart ketika… |
|---|---|
no | Tidak pernah (default) |
on-failure | Exit code bukan 0, terbunuh sinyal, timeout, atau watchdog |
on-abnormal | Terbunuh sinyal, timeout, watchdog (exit code ≠0 tidak di-restart) |
always | Selalu, termasuk exit normal |
Pilihan umum untuk aplikasi web adalah on-failure, sedangkan untuk worker yang memang keluar secara berkala (misalnya php artisan queue:work --max-time=3600) pakai always.
RestartSec= memberi jeda sebelum restart. Pembatas restart loop ada di bagian [Unit]:
StartLimitIntervalSec=60danStartLimitBurst=5berarti jika gagal start 5 kali dalam 60 detik, systemd berhenti mencoba dan unit masuk statusfailed.
Reset setelah masalahnya diperbaiki:
sudo systemctl reset-failed myapp
sudo systemctl start myapp
5. Override Tanpa Mengedit File Asli
Untuk mengubah service bawaan paket (misalnya menambah limit), jangan edit file di /usr/lib/systemd/system/. Gunakan drop-in:
sudo systemctl edit nginx
Editor terbuka untuk file /etc/systemd/system/nginx.service.d/override.conf. Isi hanya bagian yang ingin diubah:
[Service]
LimitNOFILE=65535
Restart=on-failure
systemctl edit otomatis menjalankan daemon-reload setelah disimpan. Untuk opsi yang bisa muncul berkali-kali seperti ExecStart, kosongkan dulu sebelum mengisi ulang:
[Service]
ExecStart=
ExecStart=/usr/sbin/nginx -g 'daemon off;'
Melihat hasil gabungan unit asli + override:
systemctl cat nginx
6. journalctl: Membaca Log
Output stdout/stderr service otomatis ditangkap oleh journald.
journalctl -u myapp # semua log myapp
journalctl -u myapp -f # ikuti real-time (seperti tail -f)
journalctl -u myapp -n 100 # 100 baris terakhir
journalctl -u myapp --since "1 hour ago"
journalctl -u myapp --since "2026-09-27 08:00" --until "2026-09-27 09:00"
journalctl -u myapp -p err # hanya level error ke atas
journalctl -b # log sejak boot terakhir
journalctl -b -1 # boot sebelumnya (butuh journal persisten)
journalctl -k # log kernel (seperti dmesg)
journalctl -u myapp -o json-pretty
Mengelola ukuran journal:
journalctl --disk-usage
sudo journalctl --vacuum-time=14d
sudo journalctl --vacuum-size=500M
Batas permanen diatur di /etc/systemd/journald.conf (misalnya SystemMaxUse=500M), lalu sudo systemctl restart systemd-journald.
User biasa perlu masuk grup adm atau systemd-journal untuk membaca log sistem tanpa sudo.
7. Timer: Penjadwalan ala systemd
Timer adalah alternatif cron yang terintegrasi dengan journald dan dependensi systemd. Dibutuhkan dua file: service (apa yang dijalankan) dan timer (kapan).
# /etc/systemd/system/backup-db.service
[Unit]
Description=Backup database harian
[Service]
Type=oneshot
User=backup
ExecStart=/usr/local/bin/backup-db.sh
# /etc/systemd/system/backup-db.timer
[Unit]
Description=Jalankan backup-db setiap hari jam 02:00
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
RandomizedDelaySec=5min
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now backup-db.timer # enable TIMER-nya, bukan service
systemctl list-timers
sudo systemctl start backup-db.service # tes jalankan manual sekarang
journalctl -u backup-db.service
| Opsi | Arti |
|---|---|
OnCalendar= | Jadwal kalender: daily, weekly, Mon..Fri 08:00, *-*-* *:00/15:00 |
OnBootSec= | Sekian waktu setelah boot |
OnUnitActiveSec= | Sekian waktu setelah unit terakhir aktif (interval) |
Persistent=true | Jika server mati saat jadwal lewat, jalankan segera setelah menyala |
RandomizedDelaySec= | Jeda acak agar banyak server tidak jalan bersamaan |
Validasi ekspresi kalender sebelum dipakai:
systemd-analyze calendar "Mon..Fri *-*-* 08:00:00"
8. Troubleshooting & Kesalahan Umum
| Gejala | Penyebab | Solusi |
|---|---|---|
| Perubahan file unit tidak berpengaruh | Lupa daemon-reload | sudo systemctl daemon-reload |
status=203/EXEC | Path ExecStart salah, tidak executable, atau shebang salah | Pakai path absolut (which node), chmod +x |
status=217/USER | User di User= tidak ada | Buat user-nya |
status=200/CHDIR | WorkingDirectory tidak ada / tak bisa diakses | Periksa path & permission |
| Service jalan manual tapi gagal di systemd | Env berbeda: tidak ada PATH, .bashrc, nvm | Tulis path lengkap, set Environment=/EnvironmentFile= |
| Service mati saat logout (user service) | User service berhenti tanpa sesi | loginctl enable-linger <user> |
start request repeated too quickly | Kena StartLimitBurst | Perbaiki penyebab, lalu reset-failed |
Menjalankan aplikasi dengan & atau nohup di ExecStart | Proses lepas dari pengawasan systemd | Jalankan di foreground, biarkan systemd yang mengelola |
Validasi file unit:
systemd-analyze verify /etc/systemd/system/myapp.service
Referensi

Hey! I’m Fanny, the software engineer tending to this digital garden. You can read more about me, or subscribe by email.