Ang systemd service na ayaw mag-start ay halos hindi kailanman misteryo. I-run ang systemctl status <unit>, tapos basahin ang huling 50 journal lines para sa unit na iyon gamit ang journalctl -u <unit> -n 50 --no-pager — sa pagitan ng dalawa, isa sa limang sanhi ang karaniwang tuwirang nakapangalan: sirang path, kulang na binary, maling permissions, pagtanggi ng SELinux/AppArmor, o syntax error sa unit file. Nasa log ang dahilan ng pagkabigo; ang mga fix sa ibaba ay pattern matching lang laban dito.
Paano ko makikita kung bakit nag-fail ang systemd service?
Status muna, journal pangalawa:
systemctl status myapp.service
journalctl -u myapp.service -n 50 --no-pager Bibigyan ka ng status ng estado (inactive (dead), failed (exit-code), activating (auto-restart)) at ng huling ilang log lines. Ang journal ang bibigay sa iyo ng buong kuwento: stdout, stderr, at ang sariling mga reklamo ng systemd tungkol sa unit.
Kung nag-fail na dati ang unit at gusto mo ang tala ng iyon na run, magdagdag ng -b para sa current boot o --since today:
journalctl -u myapp.service -b --no-pager Para sa buong toolkit — mga boot, priorities, pagsubaybay sa output nang live — tingnan ang journalctl cheat sheet. Parehong muscle memory lang.
Isa pang pares na worth malaman:
systemctl list-units --failed
systemctl reset-failed myapp.service Inililista ng una ang bawat pulang unit sa box. Nililinis ng ikalawa ang failed state pagkatapos mo itong ayusin — pampaganda lang, pero pinipigilan nito ang mga status page sa madalas na pagsigaw ng lobo.
Ano ang mga pinakakaraniwang sanhi?
Pagkatapos pangalanan ng log ang sintomas, ang sanhi ay halos laging isa sa limang ito:
| Sabi ng log | Malamang na sanhi | Fix |
|---|---|---|
status=203/EXEC | Maling ExecStart= path o kulang na interpreter | Absolute path, chmod +x, i-check ang shebang |
status=203/EXEC sa isang script | May CRLF line endings ang script o sirang shebang | dos2unix script.sh, ayusin ang unang linya |
status=1/FAILURE, walang app log | Kulang ang working directory o env var | Itakda ang WorkingDirectory=, dagdagan ng Environment= |
Permission denied | Hindi mabasa ng user ang files o hindi maka-bind sa port | Ayusin ang ownership; mga port sa ilalim ng 1024 ay nangangailangan ng AmbientCapabilities=CAP_NET_BIND_SERVICE o root |
Unit is masked | May nag-run ng systemctl mask | systemctl unmask myapp.service |
| Ang pag-edit ng unit file ay “walang epekto” | Hindi na-reload ang daemon | systemctl daemon-reload |
Karapat-dapat sa espesyal na banggit ang pamilyang 203/EXEC dahil ito ang kumakain ng mga hapon. Hindi ginagamit ng systemd ang shell mo para ilunsad ang ExecStart=. Nangangahulugan ito:
# Wrong — no shell, ~ never expands, no PATH lookup
ExecStart=~/app/run.sh
# Right
ExecStart=/opt/app/run.sh At ang mismong script ay dapat executable at nagsisimula sa totoong shebang (#!/bin/bash o #!/usr/bin/env bash). Ang script na gumagana nang maayos sa terminal mo pero bumibigo sa 203 sa ilalim ng systemd ay halos laging isa sa mga ito: hindi executable, CRLF endings, shebang na walang tinuturo, o relative path.
Bakit gumagana nang manual pero hindi sa boot?
Ang klasikong ordering bug. Kapag ipinapakita ng log ang mga bigo mismong pagkatapos ng boot pero gumagana nang maayos ang unit kapag ginawa mo ito nang systemctl start nang mano-mano, natatalo sa karera ang service mo — umaabot ito sa network, naka-mount na disk, o database bago pa umiral ang bagay na iyon.
Ang fix ay magdeklara ng mga dependencies sa halip na umasa:
[Unit]
After=network-online.target postgresql.service
Wants=network-online.target
[Service]
ExecStartPre=/usr/bin/test -f /opt/app/config.toml Ino-order ng After= ang pagsisimula; pinapagana ng Wants= ang systemd na talagang buhayin ang dependency. Gumagana lang ang network-online.target kung naka-enable ang network-wait service sa distro mo, kaya i-check ang systemctl is-enabled NetworkManager-wait-online.service (o ang katumbas nito sa systemd-networkd). Ang ExecStartPre= guard ay murang, tapat na paraan para bumigo nang maingay na may mabasang mensahe sa halip na stack trace.
Isa pang variant: nagsisimula ang service sa boot pero namamatay agad. Maghanap ng mga bagay na meron ang interactive environment mo na wala ang boot — mga pagkakaiba sa PATH, isang virtualenv, isang HOME. Itakda nang malinaw ang kailangan mo:
[Service]
Environment="PATH=/opt/app/venv/bin:/usr/bin"
User=appuser
WorkingDirectory=/opt/app Bakit hindi naka-log sa journal ang service ko?
Kung walang ipinapakita ang journalctl -u, i-check ang tatlong bagay sa ayos:
- Ang
StandardOutput=atStandardError=sa unit — dapatjournal(ang default) ojournal+console. Pwedeng itinakda ng iba sanullang mga ito. - Sa file sumusulat ang app sa halip na stdout. Stdout/stderr lang ang hinahawakan ng systemd; ang mga sumusulat sa log file ay lumalaktawan nang buo sa journal. Ituro mo sa stdout ang app o basahin ang file.
- Nabuwal ang mga lumang linya dahil sa storage limits:
journalctl --disk-usage, atSystemMaxUse=sa/etc/systemd/journald.confkapag naiinip ang journal.
Para sa pag-debug ng mismong pagsisimula, walang tatalo sa pagpapalaglag ng shell sa boot-time context:
[Service]
ExecStart=/bin/bash -c 'exec /opt/app/bin/server 2>&1' O, para sa totoong mga misteryo, i-run ang eksaktong ExecStart= command bilang user ng unit sa isang shell — sa unang sampung segundo lumilitaw ang karamihan ng mga pagkakaiba sa environment.
Paano ko ito pagagawing mag-restart nang kusa pagkatapos ng crash?
Ang default na patakaran ay Restart=no: patay nang tuluyan ang nasirang service, at galing pa sa isang user mo lang malalaman. Ayusin iyon kada service:
[Service]
Restart=on-failure
RestartSec=5 | Setting | Kailan nagre-restart |
|---|---|
no (default) | Hindi kailanman |
on-failure | Non-zero na exit, signal, timeout |
always | Kahit anong exit, kahit malinis |
on-watchdog | Watchdog timeout lang |
Pagsamahin ang Restart=on-failure sa start-rate guard para hindi saksakin ng umiikot na crash loop ang box: StartLimitIntervalSec= at StartLimitBurst= sa seksyon ng [Unit]. Limang bigo sa loob ng isang minuto ay dapat magpage sa tao, hindi magpaikot ng CPU.
Kung itinatayo mo ito bilang naka-iskedyul na job sa halip na daemon, timbangin muna ang cron vs systemd timer — libre sa timers ang journal logging at dependency ordering, na eksaktong paulit-ulit na hinahabol ng artikulong ito.
Ang 60-segundong checklist
systemctl status <unit>— basahin ang estado at huling mga linya.journalctl -u <unit> -n 50 --no-pager— hanapin ang totoong error.203/EXEC? Ayusin ang path, shebang, permissions.Permission denied? Ayusin ang user at file ownership.- Bumibigo lang sa boot? Magdagdag ng
After=/Wants=network-online.targetatExecStartPre=guard. - May binago sa unit file?
systemctl daemon-reload && systemctl restart <unit>. - Magdagdag ng
Restart=on-failurepara ang susunod na crash ay magpakilala sa halip na magtago.
Karamihan sa mga sandaling “kumplikado ang systemd” ay nababawasan sa nasa journal pala ang error simula’t simula. Basahin ito bago mo i-edit ang unit file, hindi pagkatapos.
FAQ
Paano ko makikita kung bakit nag-fail ang systemd service?
systemctl status <unit> para sa buod, journalctl -u <unit> -e para sa mga aktwal na error line.
Ano ang ibig sabihin ng exit code 203 EXEC?
Hindi ma-execute ng systemd ang binary — maling path, kulang na interpreter, o walang exec bit. Absolute dapat ang ExecStart path.
Bakit gumagana nang manual ang service ko pero bumibigo sa systemd?
Ibang environment: walang HOME, ibang PATH, ibang user o cwd. Itakda nang malinaw ang User=, WorkingDirectory= at Environment=.
— mrsaynothing
— mrsaynothing
Mga field note sa AI, Linux at self-hosting.
Pag-usapan ang post na ito sa dev.to dev.to ↗
Ang susunod na how-to sa email
Isang email kada post. Ayusin, tuloy sa susunod.
ano ito?GGUF Quantization: Aling Level ang Gagamitin Mo?
Nag-e-enjoy ka ba sa mga sulat na ito? Ito ang tinatayo ko para sa trabaho. i-hire ako