SSD Nodes Learn
Panduan Matt ConnorOleh Matt Connor · Dikemas kini 2026-07-24

Cara jalankan program sebagai systemd service

Pelajari cara buat fail servis systemd untuk VPS supaya program terus berjalan selepas reboot, automatik restart jika crash, dan cara baca log sistem.

Apa itu perkhidmatan systemd, dan mengapa anda memerlukannya

Perkhidmatan systemd ialah fail teks kecil yang memberitahu pelayan anda cara untuk menjalankan program: memulakannya semasa but, memulakan semula jika ia terhenti, dan menghantar outputnya ke log sistem. Itu sahaja fungsinya. Program yang anda mulakan secara manual dalam sesi SSH akan terhenti sebaik sahaja anda log keluar atau pelayan but semula. Program yang dibungkus dalam perkhidmatan systemd akan terus berjalan kerana pelayan itu sendiri yang mengurusnya, bukan shell anda.

systemd ialah sistem init pada Ubuntu, Debian, Fedora, dan kebanyakan pelayan Linux moden. Ia adalah proses pertama yang bermula dan ia menyelia semua proses lain. Apabila anda menulis fail perkhidmatan, anda menyerahkan program anda kepada penyelia tersebut. Panduan ini menunjukkan unit terkecil yang berfungsi, tiga bahagian yang ada pada setiap unit, cara mengaktifkannya dan membaca lognya, cara menjalankannya mengikut jadual dengan timer, dan cara mengehadkan keistimewaannya supaya ia berjalan dengan tahap akses yang paling minimum.

Servis paling ringkas yang berfungsi

Fail servis disimpan di dalam /etc/systemd/system/, berakhir dengan .service, dan hanya memerlukan beberapa baris kod. Cipta satu fail 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.target

Itu adalah unit lengkap yang berfungsi. ExecStart ialah arahan untuk dijalankan. WantedBy=multi-user.target bermaksud mulakan servis ini sebaik sahaja pelayan mencapai operasi multi-user normal, yang membolehkannya bermula semasa boot. Segala perkara lain hanyalah penambahbaikan.

Tiga bahagian, dan kegunaan setiap satu

Setiap fail unit dibahagikan kepada bahagian dalam kurungan segi empat. Sebuah perkhidmatan menggunakan tiga bahagian.

[Unit] menerangkan perkhidmatan dan hubungannya. Dua baris yang paling kerap digunakan:

[Unit]
Description=My application
After=network-online.target
Wants=network-online.target

Description ialah label manusia yang anda lihat dalam systemctl status. After=network-online.target memberitahu systemd supaya tidak memulakan program anda sehingga rangkaian tersedia, yang penting untuk apa-apa sahaja yang mengikat port atau membuat sambungan keluar.

[Service] ialah cara program dijalankan. Di sinilah kebanyakan tetapan anda diletakkan:

[Service]
ExecStart=/usr/local/bin/myapp --config /etc/myapp/config.toml
WorkingDirectory=/opt/myapp
User=myapp
Restart=on-failure
RestartSec=5
Environment=LOG_LEVEL=info

User=myapp menjalankan program sebagai akaun tanpa keistimewaan (unprivileged) dan bukannya root, yang merupakan baris paling penting untuk keselamatan. Restart=on-failure dan RestartSec=5 mempunyai bahagian tersendiri di bawah, kerana itulah sebab utama kebanyakan orang menulis perkhidmatan.

[Install] ialah apa yang berlaku apabila anda mengaktifkan perkhidmatan:

[Install]
WantedBy=multi-user.target

WantedBy=multi-user.target ialah apa yang menghubungkan perkhidmatan ke dalam proses but apabila anda menjalankan systemctl enable. Tanpa bahagian [Install], perkhidmatan boleh dimulakan secara manual tetapi tidak akan bermula sendiri selepas but semula.

Aktifkan dan pantau

Selepas menulis atau menyunting mana-mana fail unit, muat semula systemd supaya perubahan dibaca, kemudian aktifkan dan mulakan perkhidmatan dalam satu langkah:

sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service

daemon-reload adalah langkah yang sering dilupakan: systemd menyimpan cache fail unit, jadi penyuntingan tidak akan berkesan sehingga anda melakukan muat semula. enable --now akan mengaktifkan perkhidmatan untuk but semasa pemulaan dan memulakannya dengan segera. Semak statusnya:

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 output yang anda perlukan. Untuk membaca output program, minta jurnal bagi unit ini sahaja:

sudo journalctl -u myapp.service -f

-f akan memaparkan baris baharu sebaik sahaja ia diterima, seperti tail -f. Apa-apa yang ditulis oleh program anda ke standard output atau standard error akan masuk ke sini tanpa memerlukan sebarang tetapan log di pihak anda.

Mulakan semula apabila gagal, sebab anda berada di sini

Kelebihan utama sesebuah perkhidmatan adalah systemd akan memulakan semula program anda apabila ia terhenti. Dua baris kod melakukannya:

[Service]
Restart=on-failure
RestartSec=5

Restart=on-failure memulakan semula program apabila ia keluar dengan kod bukan sifar atau terhenti akibat isyarat kegagalan seperti SIGKILL atau SIGSEGV. Keluar secara bersih, atau dihentikan oleh SIGTERM, SIGINT, SIGHUP, atau SIGPIPE, tidak akan mencetuskan proses ini. RestartSec=5 menunggu lima saat antara percubaan, supaya program yang gagal secara serta-merta tidak beroperasi dalam gelung yang berterusan. Sahkan perkara ini dengan menghentikan proses tersebut dan perhatikan systemd memulihkannya semula. Gunakan SIGKILL: tetapan lalai SIGTERM dianggap sebagai pemberhentian bersih, jadi on-failure tidak akan memulakan semula perkhidmatan tersebut:

sudo systemctl kill -s SIGKILL myapp.service
sudo systemctl status myapp.service

Dalam masa lima saat, status akan menunjukkan Main PID dan active (running) yang baharu semula. Itulah fungsi utamanya, dan itulah sebabnya perkhidmatan lebih baik daripada membiarkan program berjalan dalam tmux atau screen.

Jalankan sebagai pengguna tanpa keistimewaan, dan perkukuhkannya

Perkhidmatan yang berjalan sebagai root boleh melakukan apa sahaja pada pelayan anda jika program tersebut dieksploitasi. Jalankan perkhidmatan sebagai pengguna tersendiri, dan berikan systemd beberapa arahan untuk mengehadkan ruang lingkupnya. Pertama, cipta akaun sistem tanpa keupayaan log masuk dan tanpa direktori home:

sudo useradd --system --no-create-home --shell /usr/sbin/nologin myapp

Kemudian tetapkan User=myapp dan tambah baris pengukuhan ke dalam [Service]:

[Service]
User=myapp
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true

Setiap baris membuang fungsi yang tidak diperlukan oleh program tersebut. NoNewPrivileges=true menghalang proses daripada memperoleh keistimewaan baharu, walaupun melalui binari setuid. PrivateTmp=true memberikan /tmp peribadi yang tidak boleh dilihat oleh proses lain. ProtectSystem=strict menjadikan keseluruhan sistem fail bersifat baca-sahaja kecuali beberapa laluan yang anda nyatakan dengan ReadWritePaths=. ProtectHome=true menyembunyikan /home sepenuhnya daripada program tersebut. Ini adalah prinsip keistimewaan terendah yang sama seperti meletakkan perkhidmatan di sebalik tembok api: berikan hanya apa yang diperlukan. Jika anda telah membaca panduan tentang menutup jurang tembok api IPv6 pada VPS, ini adalah bahagian dalam hos bagi idea yang sama. Untuk perkhidmatan yang berhadapan dengan internet, pasangkan pengukuhan ini dengan Fail2ban di hadapan SSH dan tembok api default-deny.

Daripada menaip semua ini secara manual dan tersalah ingat arahan, jana unit yang lengkap dan telah diperkukuh, kemudian salin hasilnya:

Toolsystemd service and timer generator

Timers: cron moden

systemd timer menjalankan perkhidmatan mengikut jadual, dan ia adalah pengganti moden untuk cron job. Timer terdiri daripada dua fail: .service yang melakukan kerja, dan .timer yang menentukan masa. Katakan anda mahu sandaran pada jam 3 pagi setiap hari. Perkhidmatan tersebut melakukan tugas itu sekali dan kemudian tamat:

# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh

Type=oneshot memberitahu systemd bahawa program tersebut berjalan, selesai, dan tamat, bukannya kekal berjalan di latar belakang. Timer menjadualkannya:

# /etc/systemd/system/backup.timer
[Unit]
Description=Run the nightly backup

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target

OnCalendar=*-*-* 03:00:00 bermaksud jam 3 pagi setiap hari. Uji sebarang ekspresi kalendar dengan systemd-analyze calendar "*-*-* 03:00:00", yang mengesahkan jika ia berjaya dibaca dan memaparkan masa pelaksanaan seterusnya. Persistent=true menjalankan tugas yang terlepas sebaik sahaja pelayan kembali aktif jika ia terpadam pada jam 3 pagi, sesuatu yang tidak boleh dilakukan oleh cron. Perhatikan bahawa timer diaktifkan melalui timers.target, bukan multi-user.target. Aktifkan timer, bukan perkhidmatan:

sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers

list-timers memaparkan setiap timer berserta masa pelaksanaan seterusnya dan terakhir, supaya anda boleh melihat bila tugas anda akan berjalan seterusnya dengan cepat. Generator di atas membina pasangan .service dan .timer untuk anda apabila anda mengaktifkan mod timer. Berbanding baris cron, timer memberikan log sebenar dalam journal, arahan pengukuhan yang sama seperti mana-mana perkhidmatan, dan fungsi pemulihan tugasan terlepas yang disediakan oleh Persistent=true. Cron masih memadai untuk tugas ringkas; timer adalah alat yang lebih baik untuk tugas yang kritikal.

FAQ

Apakah perbezaan antara perkhidmatan systemd dan cron job?

Perkhidmatan mengekalkan program yang berjalan lama: ia bermula semasa boot, bermula semula jika gagal, dan merekod log ke dalam journal. Cron job menjalankan arahan pendek mengikut jadual dan kemudian berhenti. Jika anda memerlukan penjadualan tetapi juga mahukan log journal, pengerasan (hardening), dan fungsi pemulihan untuk tugasan yang terlepas, gunakan systemd timer. Ia menggabungkan jadual .timer dengan perkhidmatan oneshot dan menggantikan cron untuk kebanyakan tugasan pelayan.

Di manakah saya perlu letakkan fail perkhidmatan systemd saya?

Letakkan unit anda di dalam /etc/systemd/system/ dengan nama yang berakhir dengan .service. Direktori tersebut adalah untuk unit yang ditambah oleh pentadbir, dan ia mempunyai keutamaan berbanding unit daripada pakej dalam /lib/systemd/system/. Selepas mencipta atau menyunting fail di sana, jalankan sudo systemctl daemon-reload supaya systemd mengesan perubahan tersebut.

Bagaimanakah cara untuk membuat perkhidmatan bermula semula jika ia terhenti (crash)?

Tambah Restart=on-failure dan RestartSec=5 ke dalam bahagian [Service], kemudian jalankan sudo systemctl daemon-reload dan mulakan semula perkhidmatan tersebut. systemd akan melancarkan semula program apabila ia berhenti dengan kod bukan sifar atau mati akibat isyarat crash, dengan menunggu lima saat antara setiap percubaan. Uji ia dengan sudo systemctl kill -s SIGKILL myapp.service — SIGTERM, isyarat lalai, dianggap sebagai pemberhentian bersih dan tidak mencetuskan on-failure — dan perhatikan systemctl status menunjukkan PID baharu dalam masa beberapa saat.

Bagaimanakah cara untuk menjalankan perkhidmatan systemd sebagai pengguna bukan-root?

Cipta akaun sistem dengan sudo useradd --system --no-create-home --shell /usr/sbin/nologin myapp, kemudian tambah User=myapp ke dalam bahagian [Service]. Tambah NoNewPrivileges=true, PrivateTmp=true, dan ProtectSystem=strict supaya proses berjalan dengan akses minimum yang diperlukan. Menjalankan perkhidmatan sebagai pengguna tanpa keistimewaan (unprivileged user) adalah perubahan paling penting untuk keselamatan perkhidmatan anda.

Mengapakah perkhidmatan saya gagal untuk bermula?

Jalankan systemctl status myapp.service untuk ringkasan dan journalctl -u myapp.service untuk output penuh. Punca yang paling biasa adalah laluan yang salah dalam ExecStart, WorkingDirectory yang hilang, ralat keizinan kerana User= tidak boleh membaca fail, atau sudo systemctl daemon-reload yang terlupa selepas penyuntingan. Journal akan memaparkan mesej ralat program itu sendiri, yang biasanya menyatakan masalah secara terus.