Cara Menjalankan Program Sebagai Servis systemd di VPS
Ketahui cara membina fail unit systemd untuk memastikan program anda berjalan secara automatik selepas but, bermula semula jika ranap, dan merekod log ke journalctl.
Apakah itu servis systemd, dan mengapa anda memerlukannya
Servis systemd ialah fail teks kecil yang memberitahu pelayan anda cara untuk menjalankan sesuatu program: memulakannya semasa but, memulakan semula jika ia terhenti, dan menghantar outputnya ke log sistem. Itu sahaja tugasnya. Program yang anda mulakan secara manual dalam sesi SSH akan mati sebaik sahaja anda log keluar atau pelayan but semula. Program yang dibalut dalam servis systemd akan terus berjalan, kerana pelayan itu sendiri yang memilikinya dan bukannya shell anda.
systemd ialah sistem init pada Ubuntu, Debian, Fedora, dan kebanyakan pelayan Linux moden. Ia merupakan proses pertama yang bermula dan proses yang menyelia segala-galanya. Perkara ini tidak selalunya benar, dan bagaimana systemd menggantikan skrip init yang wujud sebelumnya berbaloi untuk dibaca sebaik sahaja anda mengetahui fungsi fail unit. Apabila anda menulis fail servis, anda menyerahkan program anda kepada penyelia tersebut. Panduan ini menunjukkan unit paling kecil yang berfungsi, tiga bahagian yang dimiliki oleh setiap unit, cara untuk menghidupkannya dan membaca lognya, cara untuk menjalankannya mengikut jadual dengan pemasa (timer), serta cara untuk mengehadkannya supaya ia berjalan dengan keistimewaan (privilege) yang paling minimum.
Servis paling ringkas yang berfungsi
Fail servis terletak di dalam /etc/systemd/system/, berakhir dengan .service, dan hanya memerlukan beberapa baris. 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.targetItu adalah unit yang lengkap dan berfungsi. ExecStart ialah arahan untuk dijalankan. WantedBy=multi-user.target bermaksud mulakan servis ini sebaik sahaja pelayan mencapai operasi berbilang pengguna (multi-user) yang normal, iaitu perkara yang menyebabkannya bermula semasa but. Segala perkara lain hanyalah penambahbaikan.
Tiga bahagian, dan tujuan setiap satunya
Setiap fail unit dibahagikan kepada bahagian dalam kurungan segi empat sama. Satu servis menggunakan tiga bahagian.
[Unit] menerangkan servis tersebut dan hubungannya. Dua baris yang paling kerap anda gunakan:
[Unit]
Description=My application
After=network-online.target
Wants=network-online.targetDescription 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 bagi 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=infoUser=myapp menjalankan program sebagai akaun tanpa keistimewaan dan bukannya root, yang merupakan baris paling penting untuk keselamatan. Tiada baris Type= di sini, jadi systemd kembali kepada simple dan menganggap proses ExecStart kekal di latar depan; program yang melakukan fork ke latar belakang sebaliknya memerlukan Type= yang betul untuk cara ia bermula, atau unit tersebut akan melaporkan aktif sedangkan daemon sebenar sudah tiada. Restart=on-failure dan RestartSec=5 mempunyai bahagian sendiri di bawah, kerana ia adalah sebab kebanyakan orang menulis servis.
[Install] ialah perkara yang berlaku apabila anda mendayakan servis tersebut:
[Install]
WantedBy=multi-user.targetWantedBy=multi-user.target ialah perkara yang memautkan servis ke dalam proses but apabila anda menjalankan systemctl enable. Tanpa bahagian [Install], servis boleh dimulakan secara manual tetapi tidak akan bermula dengan sendirinya selepas but semula.
Hidupkan dan pantau servis
Selepas menulis atau menyunting mana-mana fail unit, muat semula systemd supaya ia membaca perubahan tersebut, kemudian aktifkan dan mulakan servis dalam satu langkah:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.servicedaemon-reload ialah langkah yang sering dilupakan orang: systemd menyimpan cache fail unit, jadi suntingan tidak akan memberi kesan sehingga anda memuat semula. enable --now akan mengaktifkan servis untuk but dan memulakannya serta-merta. 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 status yang anda mahukan. Untuk membaca output program, minta journal untuk unit ini sahaja:
sudo journalctl -u myapp.service -f-f akan mengikuti baris baharu apabila ia tiba, seperti tail -f. Apa sahaja yang ditulis oleh program anda ke standard output atau standard error akan dipaparkan di sini, tanpa perlu anda membuat sebarang tetapan log.
Mula semula apabila gagal, sebab anda berada di sini
Kelebihan utama servis ialah systemd memulakan semula program anda apabila ia terhenti. Dua baris ini melakukannya:
[Service]
Restart=on-failure
RestartSec=5Restart=on-failure memulakan semula program apabila ia keluar dengan kod bukan sifar atau mati akibat isyarat ranap seperti SIGKILL atau SIGSEGV. Keluar secara bersih, atau pemberhentian oleh SIGTERM, SIGINT, SIGHUP, atau SIGPIPE, tidak akan mencetuskannya. RestartSec=5 menunggu lima saat antara percubaan, supaya program yang ranap serta-merta tidak berpusing dalam gelung yang ketat. Sahkan perkara ini dengan mematikan proses tersebut dan perhatikan systemd membawanya kembali. Gunakan SIGKILL: SIGTERM lalai dikira sebagai pemberhentian bersih, jadi on-failure tidak akan memulakan semula servis tersebut:
sudo systemctl kill -s SIGKILL myapp.service
sudo systemctl status myapp.serviceDalam masa lima saat, status menunjukkan Main PID baharu dan active (running) sekali lagi. Itulah keseluruhan ciri tersebut, dan itulah sebabnya servis lebih baik daripada membiarkan program berjalan dalam tmux atau screen.
Jalankan sebagai pengguna tanpa keistimewaan, dan perketatkan keselamatannya
Servis yang dijalankan sebagai root boleh melakukan apa sahaja terhadap pelayan anda jika program tersebut dieksploitasi. Jalankan ia sebagai pengguna tersendiri, dan berikan systemd beberapa arahan untuk mengehadkannya. Mula-mula, cipta akaun sistem tanpa log masuk dan tanpa direktori home:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin myappKemudian, tetapkan User=myapp dan tambahkan baris pengukuhan keselamatan ke dalam [Service]:
[Service]
User=myapp
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=trueSetiap baris membuang sesuatu yang tidak diperlukan oleh program tersebut. NoNewPrivileges=true menghalang proses daripada memperoleh keistimewaan baharu, walaupun melalui binari setuid. PrivateTmp=true memberikan ia /tmp peribadi yang tidak boleh dilihat oleh proses lain. ProtectSystem=strict menjadikan keseluruhan sistem fail sebagai baca-sahaja (read-only) kecuali untuk beberapa laluan yang anda namakan dengan ReadWritePaths=. ProtectHome=true menyembunyikan /home daripadanya secara keseluruhan. Ini adalah pemikiran keistimewaan minimum yang sama seperti meletakkan servis di sebalik firewall: berikan hanya apa yang ia perlukan. Jika anda telah membaca panduan mengenai menutup jurang firewall IPv6 pada VPS, ini adalah bahagian hos bagi idea yang sama. Bagi servis yang menghadap internet, gandingkan pengukuhan ini dengan Fail2ban di hadapan SSH dan firewall default-deny.
Daripada menaip semua ini secara manual dan tersilap mengingati arahan, jana unit yang lengkap dan diperketatkan, kemudian salin keluar:
Timer: pengganti moden cron
Timer systemd menjalankan servis mengikut jadual, dan ia merupakan pengganti moden bagi cron job. Satu timer terdiri daripada dua fail: satu .service yang melaksanakan tugas, dan satu .timer yang menetapkan masanya. Katakan anda mahukan sandaran pada pukul 3 pagi setiap hari. Servis tersebut melaksanakan tugas sekali lalu tamat:
# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.shType=oneshot memberitahu systemd bahawa program tersebut berjalan, selesai, dan berhenti, bukannya kekal berjalan di latar belakang. Timer tersebut menjadualkannya:
# /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 bermaksud pukul 3 pagi setiap hari. Uji sebarang ungkapan kalendar dengan systemd-analyze calendar "*-*-* 03:00:00", yang mengesahkan sama ada ia dihuraikan dengan betul dan memaparkan waktu seterusnya ia akan dicetuskan. Persistent=true menjalankan tugas yang terlepas sebaik sahaja pelayan kembali aktif jika ia dimatikan pada pukul 3 pagi, sesuatu yang tidak boleh dilakukan oleh cron. Perhatikan bahawa timer diaktifkan melalui timers.target, bukan multi-user.target. Aktifkan timer, bukan servisnya:
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timerslist-timers memaparkan setiap timer berserta waktu larian seterusnya dan terakhir, supaya anda boleh melihat sepintas lalu bila tugas anda akan dijalankan. Penjana di atas membina pasangan .service dan .timer untuk anda apabila anda menghidupkan mod timer. Berbanding baris cron, timer memberikan anda log sebenar dalam journal, arahan pengukuhan (hardening) yang sama seperti mana-mana servis, dan fungsi mengejar larian yang terlepas yang disediakan oleh Persistent=true. Cron masih memadai untuk tugas mudah; timer adalah alat yang lebih baik apabila tugas tersebut penting.
FAQ
Apakah perbezaan antara servis systemd dan cron job?
Servis memastikan program yang berjalan lama kekal aktif: ia bermula semasa but, bermula semula jika gagal, dan merekodkan log ke dalam journal. Cron job menjalankan arahan ringkas mengikut jadual dan kemudian tamat. Apabila anda memerlukan penjadualan tetapi juga mahukan log journal, pengukuhan keselamatan, dan pelaksanaan semula bagi tugasan yang terlepas, gunakan systemd timer. Ia menggandingkan jadual .timer dengan servis oneshot dan menggantikan cron untuk kebanyakan tugasan pelayan.
Di manakah saya perlu meletakkan fail servis systemd saya?
Letakkan unit anda sendiri di dalam /etc/systemd/system/, dengan nama yang berakhir dengan .service. Direktori tersebut adalah untuk unit yang ditambah oleh pentadbir, dan ia mempunyai keutamaan lebih tinggi berbanding unit yang dibekalkan oleh 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 membuatkan servis 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 servis tersebut. systemd akan melancarkan semula program apabila ia tamat dengan kod bukan sifar atau mati akibat isyarat crash, dengan menunggu selama lima saat antara setiap percubaan. Uji perkara ini dengan sudo systemctl kill -s SIGKILL myapp.service; SIGTERM, iaitu isyarat lalai, dianggap sebagai pemberhentian bersih dan tidak akan mencetuskan on-failure, dan perhatikan systemctl status memaparkan PID baharu dalam masa beberapa saat.
Bagaimanakah cara untuk menjalankan servis 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 tersebut berjalan dengan akses minimum yang diperlukan. Menjalankan servis sebagai pengguna tanpa keistimewaan (unprivileged) adalah perubahan tunggal paling penting yang boleh anda lakukan untuk keselamatan servis.
Mengapakah servis saya gagal bermula?
Jalankan systemctl status myapp.service untuk ringkasan dan journalctl -u myapp.service untuk output penuh. Punca paling biasa ialah laluan yang salah dalam ExecStart, WorkingDirectory yang hilang, ralat kebenaran kerana User= tidak dapat membaca fail, atau terlupa menjalankan sudo systemctl daemon-reload selepas penyuntingan. Journal akan memaparkan mesej ralat program itu sendiri, yang biasanya menyatakan masalah tersebut secara terus.