Cara Menjalankan Program sebagai Service systemd di VPS
Pelajari cara membuat service systemd agar program berjalan saat boot, otomatis restart setelah crash, tercatat di journal, dijadwalkan dengan timer, dan lebih aman.
Apa itu service systemd dan alasan Anda memerlukannya
Service systemd adalah file teks kecil yang memberi tahu server cara menjalankan program: menjalankannya saat boot, me-restart-nya jika crash, dan mengirimkan outputnya ke system log. Itulah seluruh fungsinya. Program yang Anda jalankan secara manual dalam sesi SSH akan berhenti begitu Anda logout atau server reboot. Program yang dibungkus dalam service systemd tetap berjalan karena server itu sendiri yang mengelolanya, bukan shell Anda.
systemd adalah init system pada Ubuntu, Debian, Fedora, dan sebagian besar server Linux modern. systemd merupakan proses pertama yang dijalankan dan proses yang mengawasi semua proses lainnya. Hal ini tidak selalu demikian, dan cara systemd menggantikan init script yang digunakan sebelumnya layak dibaca setelah Anda memahami fungsi unit file. Saat menulis service file, Anda menyerahkan program kepada supervisor tersebut. Panduan ini menjelaskan unit paling sederhana yang berfungsi, tiga section yang dimiliki setiap unit, cara mengaktifkan dan membaca log-nya, cara menjalankannya sesuai jadwal dengan timer, serta cara membatasi hak aksesnya agar berjalan dengan privilege seminimal mungkin.
Layanan paling sederhana yang berfungsi
File service berada di /etc/systemd/system/, diakhiri dengan .service, dan hanya memerlukan beberapa baris. Buat file untuk program di /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.targetItu adalah unit yang lengkap dan berfungsi. ExecStart adalah perintah yang dijalankan. WantedBy=multi-user.target berarti menjalankan service ini setelah server mencapai operasi multi-user normal, sehingga service mulai saat boot. Bagian lainnya adalah penyempurnaan.
Tiga bagian dan fungsi masing-masing
Setiap unit file dibagi menjadi beberapa bagian dalam tanda kurung siku. Sebuah service menggunakan tiga bagian.
[Unit] menjelaskan service dan hubungannya. Dua baris yang paling sering Anda gunakan:
[Unit]
Description=My application
After=network-online.target
Wants=network-online.targetDescription adalah label yang terlihat oleh Anda di systemctl status. After=network-online.target memberi tahu systemd agar tidak menjalankan program sampai jaringan aktif. Hal ini penting untuk program yang mengikat port atau membuat koneksi keluar.
[Service] menentukan cara program dijalankan. Sebagian besar pengaturan Anda berada di sini:
[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 menjalankan program sebagai akun tanpa hak istimewa, bukan sebagai root. Ini adalah satu baris yang paling penting untuk keamanan. Tidak ada baris Type= di sini, sehingga systemd menggunakan simple dan menganggap proses ExecStart tetap berjalan di foreground. Program yang melakukan fork ke background memerlukan Type= yang sesuai dengan cara program tersebut dimulai, atau unit akan dilaporkan aktif meskipun daemon sebenarnya sudah berhenti. Restart=on-failure dan RestartSec=5 dibahas dalam bagian tersendiri di bawah karena keduanya adalah alasan utama orang membuat service.
[Install] menentukan tindakan saat Anda mengaktifkan service:
[Install]
WantedBy=multi-user.targetWantedBy=multi-user.target menghubungkan service ke proses boot saat Anda menjalankan systemctl enable. Tanpa bagian [Install], service dapat dijalankan secara manual, tetapi tidak akan berjalan sendiri setelah reboot.
Nyalakan dan pantau
Setelah menulis atau mengedit file unit, reload systemd agar membaca perubahan, lalu enable dan start service dalam satu langkah:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.servicedaemon-reload adalah langkah yang sering dilupakan: systemd menyimpan cache file unit, sehingga perubahan tidak berpengaruh sampai Anda melakukan reload. enable --now mengaktifkan service agar berjalan saat boot dan langsung menjalankannya. Periksa hasilnya:
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) dan enabled adalah hasil yang diharapkan. Untuk membaca output program, minta journal menampilkan unit ini saja:
sudo journalctl -u myapp.service -f-f mengikuti baris baru saat baris tersebut muncul, seperti tail -f. Apa pun yang ditulis program ke standard output atau standard error akan masuk ke sini tanpa konfigurasi logging tambahan.
Restart saat gagal, alasan Anda berada di sini
Manfaat utama sebuah service adalah systemd me-restart program saat program tersebut berhenti karena error. Dua baris sudah cukup:
[Service]
Restart=on-failure
RestartSec=5Restart=on-failure me-restart program saat program keluar dengan kode non-zero atau berhenti akibat sinyal crash seperti SIGKILL atau SIGSEGV. Program yang berhenti secara normal, atau dihentikan oleh SIGTERM, SIGINT, SIGHUP, atau SIGPIPE, tidak memicunya. RestartSec=5 menunggu lima detik di antara setiap percobaan agar program yang langsung crash tidak terus berjalan dalam loop ketat. Pastikan fitur ini bekerja dengan menghentikan proses dan memantau systemd saat menjalankannya kembali. Gunakan SIGKILL: SIGTERM default dianggap sebagai penghentian normal, sehingga on-failure tidak akan me-restart service:
sudo systemctl kill -s SIGKILL myapp.service
sudo systemctl status myapp.serviceDalam lima detik, status menampilkan Main PID baru dan active (running) kembali. Itulah seluruh fitur ini, dan itulah alasan service lebih baik daripada membiarkan program berjalan dalam tmux atau screen.
Jalankan sebagai pengguna tanpa hak istimewa, lalu perketat keamanannya
Service yang berjalan sebagai root dapat melakukan apa pun pada server jika program tersebut berhasil dieksploitasi. Jalankan service sebagai pengguna khusus, lalu tambahkan beberapa direktif systemd untuk membatasi ruang geraknya. Pertama, buat akun sistem tanpa akses login dan tanpa direktori home:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin myappKemudian tetapkan User=myapp dan tambahkan baris hardening ke [Service]:
[Service]
User=myapp
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=trueSetiap baris menghapus kemampuan yang tidak diperlukan program. NoNewPrivileges=true mencegah proses memperoleh hak istimewa baru, termasuk melalui biner setuid. PrivateTmp=true memberinya /tmp privat yang tidak dapat dilihat proses lain. ProtectSystem=strict menjadikan seluruh filesystem hanya-baca, kecuali beberapa path yang Anda tentukan dengan ReadWritePaths=. ProtectHome=true menyembunyikan /home sepenuhnya dari service tersebut. Ini menerapkan prinsip hak istimewa minimum yang sama seperti menempatkan service di belakang firewall: berikan hanya hal-hal yang diperlukan. Jika Anda telah membaca panduan menutup celah firewall IPv6 pada VPS, ini adalah penerapan pada host dari konsep yang sama. Untuk service yang menghadap Internet, padukan hardening ini dengan Fail2ban di depan SSH dan firewall dengan kebijakan default-deny.
Daripada mengetik semua ini secara manual dan salah mengingat suatu direktif, buat unit yang lengkap dan telah diperketat, lalu salin hasilnya:
Timer: cron modern
Timer systemd menjalankan service sesuai jadwal dan merupakan pengganti modern untuk cron job. Sebuah timer terdiri dari dua file: .service yang menjalankan tugas dan .timer yang menentukan waktunya. Misalnya, Anda ingin menjalankan backup setiap hari pada pukul 3.00. Service menjalankan tugas sekali lalu berhenti:
# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.shType=oneshot memberi tahu systemd bahwa program dijalankan, selesai, lalu berhenti, bukan tetap berjalan sebagai proses latar belakang. Timer menjadwalkannya:
# /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 berarti pukul 3.00 setiap hari. Uji ekspresi kalender apa pun dengan systemd-analyze calendar "*-*-* 03:00:00". Perintah ini memastikan ekspresi dapat diproses dan menampilkan waktu berikutnya saat tugas akan dijalankan. Persistent=true menjalankan tugas yang terlewat segera setelah server kembali aktif jika server mati pada pukul 3.00. Cron tidak dapat melakukan hal ini. Perhatikan bahwa timer diaktifkan melalui timers.target, bukan multi-user.target. Aktifkan timer, bukan service:
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timerslist-timers menampilkan semua timer beserta waktu eksekusi berikutnya dan terakhir. Dengan demikian, Anda dapat langsung melihat kapan tugas akan dijalankan berikutnya. Generator di atas membuat pasangan .service dan .timer untuk Anda saat mengaktifkan mode timer. Dibandingkan baris cron, timer menyediakan log nyata di journal, direktif hardening yang sama seperti service lain, serta mekanisme menjalankan kembali tugas yang terlewat, yang disediakan oleh Persistent=true. Cron tetap sesuai untuk tugas sederhana. Namun, timer merupakan pilihan yang lebih baik jika tugas tersebut penting.
FAQ
Apa perbedaan antara service systemd dan cron job?
Service menjaga program yang berjalan dalam jangka panjang tetap aktif: service dimulai saat boot, dimulai ulang jika gagal, dan mencatat log ke journal. Cron job menjalankan perintah singkat sesuai jadwal, lalu berhenti. Jika Anda memerlukan penjadwalan sekaligus log journal, hardening, dan eksekusi susulan untuk jadwal yang terlewat, gunakan systemd timer. Timer ini memasangkan jadwal .timer dengan service oneshot dan menggantikan cron untuk sebagian besar tugas server.
Di mana saya harus meletakkan file service systemd?
Letakkan unit Anda sendiri di /etc/systemd/system/, dengan nama yang diakhiri .service. Direktori tersebut digunakan untuk unit yang ditambahkan administrator dan memiliki prioritas lebih tinggi daripada unit yang disediakan oleh paket di /lib/systemd/system/. Setelah membuat atau mengedit file di sana, jalankan sudo systemctl daemon-reload agar systemd memuat perubahan tersebut.
Bagaimana cara membuat service dimulai ulang jika mengalami crash?
Tambahkan Restart=on-failure dan RestartSec=5 ke bagian [Service], lalu jalankan sudo systemctl daemon-reload dan mulai ulang service. systemd menjalankan kembali program ketika program keluar dengan kode selain nol atau berhenti akibat sinyal crash, dengan jeda lima detik di antara setiap percobaan. Uji dengan sudo systemctl kill -s SIGKILL myapp.service. SIGTERM, yaitu sinyal default, dianggap sebagai penghentian normal dan tidak memicu on-failure. Pantau systemctl status untuk memastikan PID baru muncul dalam beberapa detik.
Bagaimana cara menjalankan service systemd sebagai pengguna non-root?
Buat akun sistem dengan sudo useradd --system --no-create-home --shell /usr/sbin/nologin myapp, lalu tambahkan User=myapp ke bagian [Service]. Tambahkan NoNewPrivileges=true, PrivateTmp=true, dan ProtectSystem=strict agar proses berjalan dengan akses seminimal mungkin sesuai kebutuhannya. Menjalankan service sebagai pengguna tanpa hak istimewa adalah perubahan tunggal paling penting yang dapat Anda lakukan untuk meningkatkan keamanannya.
Mengapa service saya gagal dimulai?
Jalankan systemctl status myapp.service untuk melihat ringkasan dan journalctl -u myapp.service untuk melihat output lengkap. Penyebab yang paling umum adalah path yang salah di ExecStart, WorkingDirectory yang tidak tersedia, kesalahan izin karena User= tidak dapat membaca file, atau sudo systemctl daemon-reload yang terlupa setelah melakukan pengeditan. Journal menampilkan pesan error dari program itu sendiri, yang biasanya menyebutkan masalahnya secara langsung.