توی این درس یاد میگیری سرویس (service یا daemon) برنامهای است که همیشه در پسزمینه میماند (وبسرور، دیتابیس، ssh) و systemd مدیر آنهاست. با systemctl status وضعیت یک سرویس را میخوانی؛ با start، stop، restart و reload کنترلش میکنی؛ فرق start (همین حالا) با enable (در هر بوت) را میفهمی و systemctl enable --now را میشناسی؛ یک سرویس با unit file خودت مینویسی؛ و لاگهایش را با journalctl -u نام -f دنبال میکنی. تمرین: یک سرویس ساده میسازی که بعد از ریستارت سیستم خودش بالا بیاید.
مسئله: برنامهای که باید همیشه زنده باشد
Section titled “مسئله: برنامهای که باید همیشه زنده باشد”در درس قبل دیدی اگر برنامهای را با & یا nohup اجرا کنی، با خرابشدن یا ریبوت سرور تمام است و باید خودت دوباره راهش بیندازی. وبسرور و دیتابیس چنین چیزی نمیخواهند: باید هنگام بوت خودکار بالا بیایند، اگر خراب شدند دوباره راه بیفتند و لاگشان یکجا باشد. این کار مدیر سرویسهاست، و در تقریباً همهی توزیعهای امروزی (Ubuntu، Debian، Fedora…) نامش systemd است.
تشبیه: مدیر ساختمان
Section titled “تشبیه: مدیر ساختمان”systemd مثل مدیر ساختمان است: لیستی دارد از «واحدها» (unit) که باید هر روز صبح روشن شوند (آسانسور، نگهبانی، روشنایی راهپله)، به ترتیب درست (اول برق، بعد آسانسور)، اگر چیزی خراب شد دوباره راهاندازیاش میکند، و در یک دفتر ثبت (journal) همهی اتفاقها را مینویسد. enable یعنی «این را در لیست صبحگاهی بگذار» و start یعنی «همین حالا روشنش کن».
مثالهای عملی
Section titled “مثالهای عملی”همهی این درس روی یک سرور Ubuntu با systemd واقعی (یک ماشین آزمایشی که ویژهی همین درسها ساختهام) اجرا شده است؛ در آن من root هستم. روی سرور خودت اگر کاربر عادی (با sudo) هستی، قبل از دستورهای تغییردهنده (start، stop، enable، daemon-reload) sudo بگذار. (status و journalctl معمولاً بدون sudo هم کار میکنند.)
مثال ۱: systemd کیست و چه چیزهایی را مدیریت میکند؟
Section titled “مثال ۱: systemd کیست و چه چیزهایی را مدیریت میکند؟”echo "--- اولین پروسه (PID 1):"ps -p 1 -o pid,commsystemctl --version | head -1echo "--- هدف پیشفرض بوت:"systemctl get-defaultecho "--- سرویسهای در حال اجرا:"systemctl list-units --type=service --state=running --no-pager--- اولین پروسه (PID 1): PID COMMAND 1 systemdsystemd 255 (255.4-1ubuntu8.17)--- هدف پیشفرض بوت:graphical.target--- سرویسهای در حال اجرا: UNIT LOAD ACTIVE SUB DESCRIPTION cron.service loaded active running Regular background program processing daemon dbus.service loaded active running D-Bus System Message Bus rsyslog.service loaded active running System Logging Service systemd-journald.service loaded active running Journal Service systemd-logind.service loaded active running User Login Management
Legend: LOAD → Reflects whether the unit definition was properly loaded. ACTIVE → The high-level unit activation state, i.e. generalization of SUB. SUB → The low-level unit activation state, values depend on unit type.
5 loaded units listed.PID 1 همان systemd است. هر چیزی که systemd مدیریتش میکند یک unit نام دارد، با پسوندی که نوعش را میگوید:
echo "تعداد unit ها به تفکیک نوع:"systemctl list-units --all --no-legend --plain --no-pager | awk '{print $1}' | sed 's/.*\.//' | sort | uniq -c | sort -rnتعداد unit ها به تفکیک نوع: 80 service 41 target 19 mount 13 socket 9 timer 4 slice 2 path 1 scope 1 device 1 automount| نوع | کار |
|---|---|
.service |
یک برنامهی پسزمینه (مثل nginx، cron، ssh): موضوع این درس |
.timer |
اجرای دورهای یک سرویس (جایگزین cron؛ درس cron) |
.socket |
بالا آوردن سرویس وقتی اولین اتصال میرسد (مثل ssh.socket) |
.target |
گروهی از unit ها که با هم یک «حالت» را میسازند (مثل multi-user.target) |
.mount |
یک مسیر mount شده |
مثال ۲: systemctl status، وضعیت یک سرویس
Section titled “مثال ۲: systemctl status، وضعیت یک سرویس”اول سرویسی که زنده است (cron)، بعد سرویسی که خاموش است (nginx):
systemctl status cronecho "======"systemctl status nginx● cron.service - Regular background program processing daemon Loaded: loaded (/usr/lib/systemd/system/cron.service; enabled; preset: enabled) Active: active (running) since Sat 2026-10-03 21:14:33 UTC; 25s ago Docs: man:cron(8) Main PID: 81 (cron) Tasks: 1 (limit: 4742) Memory: 320.0K (peak: 1.2M) CPU: 3ms CGroup: /system.slice/cron.service └─81 /usr/sbin/cron -f -P
Oct 03 21:14:33 server systemd[1]: Started cron.service - Regular background program processing daemon.Oct 03 21:14:33 server (cron)[81]: cron.service: Referenced but unset environment variable evaluates to an empty string: EXTRA_OPTSOct 03 21:14:33 server cron[81]: (CRON) INFO (pidfile fd = 3)Oct 03 21:14:33 server cron[81]: (CRON) INFO (Running @reboot jobs)======○ nginx.service - A high performance web server and a reverse proxy server Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; preset: enabled) Active: inactive (dead) Docs: man:nginx(8)
Oct 03 21:14:07 server systemd[1]: Starting nginx.service - A high performance web server and a reverse proxy server...Oct 03 21:14:07 server systemd[1]: Started nginx.service - A high performance web server and a reverse proxy server.Oct 03 21:14:07 server systemd[1]: Stopping nginx.service - A high performance web server and a reverse proxy server...Oct 03 21:14:07 server systemd[1]: nginx.service: Deactivated successfully.Oct 03 21:14:07 server systemd[1]: Stopped nginx.service - A high performance web server and a reverse proxy server.Oct 03 21:14:07 server systemd[1]: Starting nginx.service - A high performance web server and a reverse proxy server...Oct 03 21:14:07 server systemd[1]: Started nginx.service - A high performance web server and a reverse proxy server.Oct 03 21:14:33 server systemd[1]: Stopping nginx.service - A high performance web server and a reverse proxy server...Oct 03 21:14:33 server systemd[1]: nginx.service: Deactivated successfully.Oct 03 21:14:33 server systemd[1]: Stopped nginx.service - A high performance web server and a reverse proxy server.نقطهی اول هر خروجی وضعیت را میگوید: ● سبز یعنی فعال، ○ یعنی غیرفعال، و × یعنی شکستخورده. خطها:
Loaded: فایل unit از کجا خوانده شده، وenabled/disabled: آیا هنگام بوت خودکار شروع میشود (مثال ۴).presetپیشفرض توزیع است.Active:active (running)در حال اجرا،inactive (dead)خاموش،failedخرابشده، و از چه زمانی.Main PID،Tasks،Memory،CPU: پروسهی اصلی و مصرفش.CGroup: درخت همهی پروسههای این سرویس (systemd با cgroup دقیقاً میداند کدام پروسه مال کدام سرویس است).- چند خط آخر: آخرین لاگهای همین سرویس از journal (مثال ۷).
مثال ۳: start، stop، restart و reload
Section titled “مثال ۳: start، stop، restart و reload”nginx (وبسرور؛ دورهی خودش را دارد) نصب است ولی خاموش. راهش بینداز و وضعیتش را (کوتاهشده) ببین:
systemctl start nginxsystemctl is-active nginxecho "--- وبسرور جواب میدهد؟"curl -sI http://localhost | head -1echo "--- وضعیت (۱۲ خط اول):"systemctl status nginx --no-pager | head -12active--- وبسرور جواب میدهد؟HTTP/1.1 200 OK--- وضعیت (۱۲ خط اول):● nginx.service - A high performance web server and a reverse proxy server Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; preset: enabled) Active: active (running) since Sat 2026-10-03 21:14:59 UTC; 16ms ago Docs: man:nginx(8) Process: 323 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS) Process: 325 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS) Main PID: 326 (nginx) Tasks: 9 (limit: 4742) Memory: 6.4M (peak: 6.4M) CPU: 14ms CGroup: /system.slice/nginx.service ├─326 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"is-active فقط یک کلمه (active) میدهد و برای اسکریپتها مناسب است. حالا فرق reload و restart:
before=$(systemctl show -p MainPID --value nginx)systemctl reload nginxecho "reload: PID اصلی قبل=$before | بعد=$(systemctl show -p MainPID --value nginx) (همان ماند)"systemctl restart nginxecho "restart: PID اصلی بعد=$(systemctl show -p MainPID --value nginx) (عوض شد)"echo "--- stop:"systemctl stop nginxsystemctl is-active nginxcurl -sI http://localhost || echo "curl: اتصال برقرار نشد (کد $?)"reload: PID اصلی قبل=326 | بعد=326 (همان ماند)restart: PID اصلی بعد=360 (عوض شد)--- stop:inactivecurl: اتصال برقرار نشد (کد 7)reloadبه سرویس میگوید تنظیماتش را دوباره بخواند، بدون خاموششدن (PID همان میماند، اتصالها قطع نمیشوند)؛ همهی سرویسها پشتیبانی نمیکنند.restartمتوقف و دوباره شروع میکند (PID جدید، قطع کوتاه).stopمتوقف میکند؛ بعدش وبسرور جواب نمیدهد (curlکد ۷: اتصال رد شد).
مثال ۴: enable در برابر start
Section titled “مثال ۴: enable در برابر start”این دو دو کار جدا هستند: start یعنی «همین حالا اجرا کن»، و enable یعنی «هر بار که سیستم بوت میشود اجرا کن». systemctl enable --now هر دو را با هم انجام میدهد:
echo "--- قبل:"echo "enabled: $(systemctl is-enabled nginx) | active: $(systemctl is-active nginx)"systemctl enable --now nginxecho "--- بعد از enable --now:"echo "enabled: $(systemctl is-enabled nginx) | active: $(systemctl is-active nginx)"echo "--- enable فقط یک symlink میسازد:"ls -l /etc/systemd/system/multi-user.target.wants/ | grep nginx--- قبل:enabled: disabled | active: inactiveSynchronizing state of nginx.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.Executing: /usr/lib/systemd/systemd-sysv-install enable nginxCreated symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.--- بعد از enable --now:enabled: enabled | active: active--- enable فقط یک symlink میسازد:lrwxrwxrwx 1 root root 37 Oct 3 21:14 nginx.service -> /usr/lib/systemd/system/nginx.serviceسه خط اول خروجی enable اطلاعات SysV است (nginx یک اسکریپت قدیمی هم دارد). مهم خط Created symlink است: enable یعنی یک symlink در پوشهی multi-user.target.wants؛ systemd هنگام بوت هر چه در این پوشه باشد را راه میاندازد. و disable فقط همان symlink را برمیدارد، نه بیشتر:
systemctl disable nginxecho "enabled: $(systemctl is-enabled nginx) | active: $(systemctl is-active nginx)"Synchronizing state of nginx.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.Executing: /usr/lib/systemd/systemd-sysv-install disable nginxRemoved "/etc/systemd/system/multi-user.target.wants/nginx.service".enabled: disabled | active: activenginx الان disabled ولی هنوز در حال اجراست. این دو وضعیت مستقلاند:
enabled؟ |
active؟ |
معنی |
|---|---|---|
| بله | بله | اجراست و بعد از ریبوت هم بالا میآید (حالت عادیِ یک سرویس تولید) |
| بله | نه | الان خاموش، ولی بعد از ریبوت بالا میآید |
| نه | بله | الان اجراست، ولی بعد از ریبوت نیست (وضعیت الان nginx) |
| نه | نه | خاموش و خارج از بوت |
سرویسی را فقط systemctl start کردهای و enable نکردهای. بعد از ریبوت چه میشود؟
start فقط برای همین بوت است. این را در مثال ۸ با یک ریبوت واقعی (در آزمایشگاه) میبینی.
مثال ۵: یک سرویس خودت، با unit file
Section titled “مثال ۵: یک سرویس خودت، با unit file”سرویسهای خودت را با نوشتن یک unit file میسازی (یک فایل متنی ساده). اول خود برنامه، یک اسکریپت کوچک که هر ۵ ثانیه یک خط چاپ میکند (هر چه روی خروجی استاندارد بنویسد، systemd در journal ثبت میکند):
#!/bin/bashecho "lx-hello: شروع شد (PID $$)"while true; do echo "lx-hello: زندهام $(date +%T)"; sleep 5; doneو فایل unit، در /etc/systemd/system/ (جای unit های ساختهی مدیر):
[Unit]Description=LoopX hello demoAfter=network.target
[Service]ExecStart=/usr/local/bin/lx-hello.shRestart=on-failureRestartSec=2
[Install]WantedBy=multi-user.target| بخش و کلید | معنی |
|---|---|
[Unit] Description |
توضیح؛ در status دیده میشود |
After=network.target |
بعد از بالا آمدن شبکه شروع شود (ترتیب) |
[Service] ExecStart |
دستور اجرای سرویس؛ مسیر کامل بنویس |
Restart=on-failure |
اگر با خطا یا سیگنال مُرد، دوباره راهش بینداز (مثال ۶) |
RestartSec=2 |
قبل از شروع دوباره ۲ ثانیه صبر کن |
[Install] WantedBy=multi-user.target |
وقتی enable شود، به همین هدف (حالت عادی سرور) وصل شود |
فایل را میسازیم، به systemd خبر میدهیم (daemon-reload: فایلهای unit را دوباره بخواند)، راه میاندازیم و وضعیت را میبینیم:
chmod +x /usr/local/bin/lx-hello.shsystemd-analyze verify /etc/systemd/system/lx-hello.service && echo "unit file بدون خطا (systemd-analyze verify)"systemctl daemon-reloadsystemctl start lx-hellosleep 1systemctl status lx-hellounit file بدون خطا (systemd-analyze verify)● lx-hello.service - LoopX hello demo Loaded: loaded (/etc/systemd/system/lx-hello.service; disabled; preset: enabled) Active: active (running) since Sat 2026-10-03 21:15:00 UTC; 1s ago Main PID: 547 (lx-hello.sh) Tasks: 2 (limit: 4742) Memory: 1.0M (peak: 1.1M) CPU: 2ms CGroup: /system.slice/lx-hello.service ├─547 /bin/bash /usr/local/bin/lx-hello.sh └─550 sleep 5
Oct 03 21:15:00 server systemd[1]: Started lx-hello.service - LoopX hello demo.Oct 03 21:15:00 server lx-hello.sh[547]: lx-hello: شروع شد (PID 547)Oct 03 21:15:00 server lx-hello.sh[547]: lx-hello: زندهام 21:15:00حالا enable تا بعد از ریبوت هم بالا بیاید (و is-enabled برای تأیید):
systemctl enable lx-hellosystemctl is-enabled lx-hellols -l /etc/systemd/system/multi-user.target.wants/lx-hello.serviceCreated symlink /etc/systemd/system/multi-user.target.wants/lx-hello.service → /etc/systemd/system/lx-hello.service.enabledlrwxrwxrwx 1 root root 36 Oct 3 21:15 /etc/systemd/system/multi-user.target.wants/lx-hello.service -> /etc/systemd/system/lx-hello.serviceمثال ۶: Restart=، سرویسی که خودش بالا میآید
Section titled “مثال ۶: Restart=، سرویسی که خودش بالا میآید”وقتی سرویس خراب شود، Restart=on-failure آن را دوباره راه میاندازد. با kill -9 (در درس قبل: مرگ اجباری و بدون تمیزکاری) پروسهی اصلی را میکشم و میبینم systemd چه میکند:
pid=$(systemctl show -p MainPID --value lx-hello)echo "PID اصلی قبل: $pid"kill -9 $pidsleep 4echo "PID اصلی بعد: $(systemctl show -p MainPID --value lx-hello) | تعداد ریستارت: $(systemctl show -p NRestarts --value lx-hello)"echo "--- لاگ systemd از آنچه رخ داد:"journalctl -u lx-hello --no-pager -o cat | grep -v 'زندهام' | tail -6PID اصلی قبل: 547PID اصلی بعد: 577 | تعداد ریستارت: 1--- لاگ systemd از آنچه رخ داد:lx-hello: شروع شد (PID 547)lx-hello.service: Main process exited, code=killed, status=9/KILLlx-hello.service: Failed with result 'signal'.lx-hello.service: Scheduled restart job, restart counter is at 1.Started lx-hello.service - LoopX hello demo.lx-hello: شروع شد (PID 577)systemd متوجه شد پروسه با سیگنال ۹ مرده (code=killed)، ۲ ثانیه صبر کرد (RestartSec) و دوباره راهش انداخت؛ PID جدید است و شمارندهی ریستارت یکی بیشتر شد. گزینههای Restart=:
| مقدار | چه وقت دوباره راه میاندازد |
|---|---|
no |
هرگز (پیشفرض) |
on-failure |
کد خروج غیر صفر، مرگ با سیگنال یا timeout (توصیه برای بیشتر سرویسها) |
always |
همیشه، حتی اگر با کد ۰ تمام شود |
on-abnormal |
فقط با سیگنال یا timeout، نه با کد خروج غیرصفر |
مثال ۷: journalctl، لاگ سرویسها
Section titled “مثال ۷: journalctl، لاگ سرویسها”systemd همهی لاگها را در یک پایگاه دادهی یکپارچه (journal) نگه میدارد و journalctl میخواندشان. فیلترهای پرکاربرد:
echo "--- ۳ خط آخر لاگ یک سرویس (-u نام، -n تعداد):"journalctl -u lx-hello -n 3 --no-pagerecho "--- فقط متن پیامها (-o cat) از یک دقیقهی اخیر، تعداد خطها:"journalctl -u lx-hello --since "1 minute ago" -o cat --no-pager | wc -lecho "--- سرویسهای دیگر هم همینطور:"journalctl -u nginx --no-pager -o cat | tail -3--- ۳ خط آخر لاگ یک سرویس (-u نام، -n تعداد):Oct 03 21:15:03 server systemd[1]: Started lx-hello.service - LoopX hello demo.Oct 03 21:15:03 server lx-hello.sh[577]: lx-hello: شروع شد (PID 577)Oct 03 21:15:03 server lx-hello.sh[577]: lx-hello: زندهام 21:15:03--- فقط متن پیامها (-o cat) از یک دقیقهی اخیر، تعداد خطها:48--- سرویسهای دیگر هم همینطور:Stopped nginx.service - A high performance web server and a reverse proxy server.Starting nginx.service - A high performance web server and a reverse proxy server...Started nginx.service - A high performance web server and a reverse proxy server.پرچم -f (follow) مثل tail -f لاگ را زنده دنبال میکند، و بهترین ابزار برای دیدن اتفاقات یک سرویس هنگام restart است. اینجا journalctl -u lx-hello -f را ۸ ثانیه اجرا میکنم و در همین فاصله سرویس را restart میکنم (در ترمینال واقعی با Ctrl+C متوقفش میکنی):
timeout 8 journalctl -u lx-hello -f -n 2 --no-pager &sleep 1echo "--- (حالا در ترمینال دیگری:) systemctl restart lx-hello"systemctl restart lx-hellowaitOct 03 21:15:03 server lx-hello.sh[577]: lx-hello: شروع شد (PID 577)Oct 03 21:15:03 server lx-hello.sh[577]: lx-hello: زندهام 21:15:03--- (حالا در ترمینال دیگری:) systemctl restart lx-helloOct 03 21:15:06 server systemd[1]: Stopping lx-hello.service - LoopX hello demo...Oct 03 21:15:06 server systemd[1]: lx-hello.service: Deactivated successfully.Oct 03 21:15:06 server systemd[1]: Stopped lx-hello.service - LoopX hello demo.Oct 03 21:15:06 server systemd[1]: Started lx-hello.service - LoopX hello demo.Oct 03 21:15:06 server lx-hello.sh[595]: lx-hello: شروع شد (PID 595)Oct 03 21:15:06 server lx-hello.sh[595]: lx-hello: زندهام 21:15:06Oct 03 21:15:11 server lx-hello.sh[595]: lx-hello: زندهام 21:15:11دو خط اول لاگهای قبلیاند (-n 2)؛ بعد از restart خطهای Stopping، Stopped، Started و خروجی تازهی خود برنامه را زنده میبینی. فرمان رایج برای عیبیابی: journalctl -u نام -f در یک ترمینال و systemctl restart نام در ترمینال دیگر. فیلترهای دیگر journalctl (-p err، --since، -b) را در درس لاگها و عیبیابی کاملتر میبینی.
مثال ۸: بعد از ریبوت چه میشود؟
Section titled “مثال ۸: بعد از ریبوت چه میشود؟”حرف اصلی enable را باید با یک ریبوت واقعی دید. روی سرور واقعی sudo reboot میزنی و بعد از بالا آمدن دوباره وصل میشوی. ماشین آزمایشی من یک کانتینر است؛ معادل ریبوتش docker restart است که systemd را از صفر بوت میکند (این دستورها را از بیرون ماشین اجرا کردهام، پس docker exec lxsys اولشان است). قبل از ریبوت: nginx را start کردهام و enable نه؛ lx-hello را enable کردهام:
echo "--- قبل از ریبوت:"docker exec lxsys systemctl is-active nginx lx-hellodocker exec lxsys systemctl is-enabled nginx lx-helloecho "--- ریبوت (بوت دوبارهی systemd)..."docker restart lxsys > /dev/nullfor i in $(seq 1 60); do docker exec lxsys systemctl is-system-running 2>/dev/null | grep -qE 'running|degraded' && break; sleep 1; doneecho "--- بعد از ریبوت:"docker exec lxsys systemctl is-active nginx lx-hello--- قبل از ریبوت:activeactivedisabledenabled--- ریبوت (بوت دوبارهی systemd)...--- بعد از ریبوت:inactiveactivelx-hello (enableشده) خودش بالا آمد و nginx (فقط startشده) نیامد. این یعنی enable تنها چیزی است که یک سرویس را از ریبوت جان بهدر میبرد. (ترتیب خروجیها همان ترتیب اسمهاست: اول nginx، بعد lx-hello.) تمرین اصلی درس هم همین است: سرویسی که با ریبوت دوباره بالا بیاید.
پشت پرده: unit file ها از کجا میآیند؟
Section titled “پشت پرده: unit file ها از کجا میآیند؟”هر unit یک فایل است. systemctl cat فایل واقعی را (بههمراه مسیرش) نشان میدهد؛ بخشهای اصلی unit خود nginx:
systemctl cat nginx --no-pager | grep -vE '^(#|$)'[Unit]Description=A high performance web server and a reverse proxy serverDocumentation=man:nginx(8)After=network-online.target remote-fs.target nss-lookup.targetWants=network-online.targetConditionFileIsExecutable=/usr/sbin/nginx[Service]Type=forkingPIDFile=/run/nginx.pidExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reloadExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pidTimeoutStopSec=5KillMode=mixed[Install]WantedBy=multi-user.targetدو چیز را ببین: Type=forking یعنی برنامه خودش را به پسزمینه میبرد و PIDFile را مینویسد (سرویسهایی که در پیشزمینه میمانند مثل lx-hello از Type=simple پیشفرض استفاده میکنند)؛ و ExecStartPre قبل از شروع تنظیمات را آزمایش میکند، که اگر خراب بود سرویس اصلاً بالا نمیآید. unit ها در سه جا هستند و بالاترین اولویت با /etc/systemd/system/ است:
| مسیر | محتوا |
|---|---|
/usr/lib/systemd/system/ |
unit های بستههای نصبشده (با بهروزرسانی بسته عوض میشوند؛ دستکاری نکن) |
/etc/systemd/system/ |
unit های مدیر؛ بر فایلهای بسته اولویت دارد |
/run/systemd/system/ |
unit های موقت (تا ریبوت بعدی) |
برای تغییر یک سرویس بستهای، فایل خود بسته را عوض نکن؛ یک drop-in بساز (یک فایل کوچک با فقط بخشهای تغییریافته در نام.service.d/) تا بهروزرسانی بسته آن را پاک نکند (systemctl edit نام همین را برایت میسازد):
mkdir -p /etc/systemd/system/nginx.service.dprintf '[Service]\nRestart=on-failure\nRestartSec=5\n' > /etc/systemd/system/nginx.service.d/override.confsystemctl daemon-reloadecho "--- نمای ترکیبی (انتهای خروجی، فایل drop-in):"systemctl cat nginx --no-pager | tail -5echo "--- و مقدار مؤثر:"systemctl show -p Restart,RestartUSec nginxrm -rf /etc/systemd/system/nginx.service.dsystemctl daemon-reload--- نمای ترکیبی (انتهای خروجی، فایل drop-in):
# /etc/systemd/system/nginx.service.d/override.conf[Service]Restart=on-failureRestartSec=5--- و مقدار مؤثر:Restart=on-failureRestartUSec=5sو target ها که ترتیب بوت را میسازند (بخشی از وابستگیهای multi-user.target، یعنی «حالت عادی سرور»):
systemctl list-dependencies multi-user.target --no-pager | head -12multi-user.target● ├─cron.service● ├─dbus.service○ ├─dmesg.service○ ├─e2scrub_reap.service● ├─lx-hello.service● ├─rsyslog.service● ├─systemd-ask-password-wall.path● ├─systemd-logind.service○ ├─systemd-update-utmp-runlevel.service● ├─systemd-user-sessions.service● ├─ufw.serviceسرویسهایی که enable شدهاند (symlink در multi-user.target.wants) اینجا زیر هدف دیده میشوند و همه با هم بالا میآیند (● فعال، ○ غیرفعال).
جدولهای مرجع
Section titled “جدولهای مرجع”| دستور | کار |
|---|---|
systemctl status نام |
وضعیت و آخرین لاگها |
systemctl start نام / stop / restart |
راهاندازی، توقف، راهاندازی دوباره |
systemctl reload نام |
خواندن دوبارهی تنظیمات بدون قطع |
systemctl enable نام / disable |
افزودن/حذف از بوت |
systemctl enable --now نام |
enable و start با هم |
systemctl is-active / is-enabled / is-failed |
وضعیت یککلمهای برای اسکریپت |
systemctl daemon-reload |
خواندن دوبارهی unit file ها (بعد از هر تغییر) |
systemctl cat نام |
فایل unit (و drop-in ها) |
systemctl show -p MainPID نام |
یک ویژگی مشخص |
systemctl list-units --type=service |
سرویسهای در حال اجرا |
systemctl reset-failed نام |
پاککردن وضعیت failed |
journalctl -u نام |
لاگ یک سرویس (-f زنده، -n 50 تعداد) |
systemd-analyze verify فایل |
بررسی نحو یک unit file |
| کلید unit file | کار |
|---|---|
Description |
توضیح |
After= / Wants= / Requires= |
ترتیب و وابستگی |
ExecStart= |
دستور اصلی (مسیر کامل) |
ExecStartPre= / ExecStop= / ExecReload= |
دستورهای قبل، توقف، reload |
Type= |
simple (پیشفرض)، forking، oneshot، notify |
Restart= / RestartSec= |
سیاست و تأخیر ریستارت |
User= / WorkingDirectory= |
با چه کاربری و در کدام پوشه |
Environment= / EnvironmentFile= |
متغیرهای محیطی |
WantedBy= |
هدفی که با enable به آن وصل میشود |
اشتباهات رایج
Section titled “اشتباهات رایج”۱) فراموشکردن daemon-reload
Section titled “۱) فراموشکردن daemon-reload”sed -i 's/RestartSec=2/RestartSec=3/' /etc/systemd/system/lx-hello.servicesystemctl restart lx-helloecho "--- RestartSec مؤثر هنوز قدیمی است:"systemctl show -p RestartUSec --value lx-hellosystemctl daemon-reloadsystemctl restart lx-helloecho "--- بعد از daemon-reload:"systemctl show -p RestartUSec --value lx-helloWarning: The unit file, source configuration file or drop-ins of lx-hello.service changed on disk. Run 'systemctl daemon-reload' to reload units.--- RestartSec مؤثر هنوز قدیمی است:2s--- بعد از daemon-reload:3ssystemd فایلها را کش میکند؛ بعد از هر تغییر در unit file یا drop-in باید systemctl daemon-reload بزنی، وگرنه تغییرت اعمال نمیشود و این هشدار (changed on disk) را میبینی. راهحل: daemon-reload، بعد restart.
۲) status=203/EXEC، اسکریپت اجرایی نیست
Section titled “۲) status=203/EXEC، اسکریپت اجرایی نیست”printf '#!/bin/bash\necho hi\n' > /usr/local/bin/lx-noexec.shchmod 644 /usr/local/bin/lx-noexec.shprintf '[Unit]\nDescription=Demo: script without x\n[Service]\nExecStart=/usr/local/bin/lx-noexec.sh\n' > /etc/systemd/system/lx-noexec.servicesystemctl daemon-reloadsystemctl start lx-noexecsystemctl status lx-noexec --no-pager | head -8echo "--- راهحل:"chmod +x /usr/local/bin/lx-noexec.shsystemctl start lx-noexec && echo "حالا شروع شد (کد خروج ۰)"rm -f /etc/systemd/system/lx-noexec.service /usr/local/bin/lx-noexec.shsystemctl daemon-reload× lx-noexec.service - Demo: script without x Loaded: loaded (/etc/systemd/system/lx-noexec.service; static) Active: failed (Result: exit-code) since Sat 2026-10-03 21:15:13 UTC; 4ms ago Duration: 448us Process: 704 ExecStart=/usr/local/bin/lx-noexec.sh (code=exited, status=203/EXEC) Main PID: 704 (code=exited, status=203/EXEC) CPU: 426us
--- راهحل:حالا شروع شد (کد خروج ۰)status=203/EXEC یعنی systemd نتوانست ExecStart را اجرا کند: مسیر غلط یا (اینجا) فایل بدون حق x (درس دسترسیها). پس هر وقت سرویس همان لحظه failed شد، اول systemctl status و بعد journalctl -u را ببین. راهحل: chmod +x و مسیر کامل و درست.
۳) بدون sudo
Section titled “۳) بدون sudo”su - ali -c 'systemctl restart cron; echo "کد خروج: $?"'echo "--- با sudo (ali اجازه دارد):"su - ali -c 'sudo systemctl restart cron; echo "کد خروج: $?"; systemctl is-active cron'Failed to restart cron.service: Access deniedSee system logs and 'systemctl status cron.service' for details.کد خروج: 4--- با sudo (ali اجازه دارد):کد خروج: 0activeکاربر عادی نمیتواند سرویس را کنترل کند (Access denied؛ روی سرورهایی که polkit دارند ممکن است متن «Interactive authentication required» باشد). راهحل: sudo systemctl .... فقط خواندن وضعیت (status) بدون sudo ممکن است.
۴) System has not been booted with systemd
Section titled “۴) System has not been booted with systemd”systemctl status 2>&1 | head -3System has not been booted with systemd as init system (PID 1). Can't operate.Failed to connect to bus: Host is downدر کانتینرهای معمولی (و WSL قدیمی) PID 1 چیز دیگری است و systemctl کار نمیکند: این پیام یعنی «اینجا systemd نیست». راهحل: یک ماشین واقعی یا مجازی، یا WSL2 با systemd فعال؛ درس راهاندازی محیط. (کانتینر داکر هم برای هر برنامه یک پروسهی اصلی دارد و به جای systemd از restart policy استفاده میکند.)
۵) start بدون enable (و برعکس)
Section titled “۵) start بدون enable (و برعکس)”مثال ۸: بعد از ریبوت، nginx که فقط start شده بود نیامد. و برعکس: enable بدون start تا بوت بعدی چیزی را راه نمیاندازد. راهحل: systemctl enable --now نام.
وضعیت سرویس cron را بگیر: آیا الان در حال اجراست و آیا هنگام بوت بالا میآید؟ (با دستورهای یککلمهای.)
دیدن جواب
echo "active: $(systemctl is-active cron) | enabled: $(systemctl is-enabled cron)"systemctl status cron --no-pager | sed -n '1,3p'active: active | enabled: enabled● cron.service - Regular background program processing daemon Loaded: loaded (/usr/lib/systemd/system/cron.service; enabled; preset: enabled) Active: active (running) since Sat 2026-10-03 21:15:13 UTC; 13ms agoتمرین اصلی: یک سرویس ساده با unit file بساز که بعد از ریستارت خودش بالا بیاید. سرویس lx-clock را بساز که هر ۵ ثانیه ساعت را به فایل /tmp/lx-clock.log اضافه کند، با enable --now راهش بینداز، و ثابت کن هم در حال اجراست و هم enable است (مثال ۸ نشان داد enable یعنی بعد از ریبوت میآید).
دیدن جواب
cat > /usr/local/bin/lx-clock.sh <<'EOF'#!/bin/bashwhile true; do date +%T >> /tmp/lx-clock.log; sleep 5; doneEOFchmod +x /usr/local/bin/lx-clock.shcat > /etc/systemd/system/lx-clock.service <<'EOF'[Unit]Description=LoopX clock demo
[Service]ExecStart=/usr/local/bin/lx-clock.shRestart=always
[Install]WantedBy=multi-user.targetEOFsystemctl daemon-reloadsystemctl enable --now lx-clocksleep 2echo "active: $(systemctl is-active lx-clock) | enabled: $(systemctl is-enabled lx-clock)"ls -l /etc/systemd/system/multi-user.target.wants/lx-clock.serviceecho "--- خروجی سرویس:"cat /tmp/lx-clock.logsystemctl disable --now lx-clockrm -f /etc/systemd/system/lx-clock.service /usr/local/bin/lx-clock.sh /tmp/lx-clock.logsystemctl daemon-reloadCreated symlink /etc/systemd/system/multi-user.target.wants/lx-clock.service → /etc/systemd/system/lx-clock.service.active: active | enabled: enabledlrwxrwxrwx 1 root root 36 Oct 3 21:15 /etc/systemd/system/multi-user.target.wants/lx-clock.service -> /etc/systemd/system/lx-clock.service--- خروجی سرویس:21:15:13Removed "/etc/systemd/system/multi-user.target.wants/lx-clock.service".سرویسی بساز که هر بار بعد از یک ثانیه با خطا تمام میشود، با Restart=on-failure. با StartLimitIntervalSec=20 و StartLimitBurst=3 تنظیمش کن و نشان بده systemd بعد از چند تلاش پشتسرهم از ریستارت دست میکشد و سرویس به وضعیت failed میرود. با reset-failed پاکش کن.
دیدن جواب
cat > /etc/systemd/system/lx-crash.service <<'EOF'[Unit]Description=Demo: crash loopStartLimitIntervalSec=20StartLimitBurst=3
[Service]ExecStart=/bin/sh -c 'echo starting; sleep 1; echo crashing >&2; exit 1'Restart=on-failureRestartSec=1EOFsystemctl daemon-reloadsystemctl start lx-crashsleep 9systemctl status lx-crash --no-pager | head -12systemctl show -p NRestarts,ActiveState,SubState lx-crashsystemctl reset-failed lx-crashecho "--- بعد از reset-failed:"systemctl is-active lx-crashrm -f /etc/systemd/system/lx-crash.servicesystemctl daemon-reload× lx-crash.service - Demo: crash loop Loaded: loaded (/etc/systemd/system/lx-crash.service; static) Active: failed (Result: exit-code) since Sat 2026-10-03 21:15:22 UTC; 2s ago Duration: 1.016s Process: 875 ExecStart=/bin/sh -c echo starting; sleep 1; echo crashing >&2; exit 1 (code=exited, status=1/FAILURE) Main PID: 875 (code=exited, status=1/FAILURE) CPU: 5ms
Oct 03 21:15:22 server systemd[1]: lx-crash.service: Scheduled restart job, restart counter is at 3.Oct 03 21:15:22 server systemd[1]: lx-crash.service: Start request repeated too quickly.Oct 03 21:15:22 server systemd[1]: lx-crash.service: Failed with result 'exit-code'.Oct 03 21:15:22 server systemd[1]: Failed to start lx-crash.service - Demo: crash loop.NRestarts=3ActiveState=failedSubState=failed--- بعد از reset-failed:inactiveStart request repeated too quickly: systemd برای جلوگیری از چرخهی بیپایان، بعد از ۳ شکست در ۲۰ ثانیه دیگر تلاش نمیکند. دلیل خرابی را در journalctl -u lx-crash پیدا کن، رفعش کن، reset-failed بزن و دوباره start کن.
آزمونک
Section titled “آزمونک”systemd چیست؟
systemd هنگام بوت راه میافتد، سرویسها را بالا میآورد، مدیریتشان میکند و لاگشان را میگیرد.
فرق systemctl start و systemctl enable؟
enable یک symlink در multi-user.target.wants میسازد؛ برای هر دو با هم: enable --now.
systemctl enable --now nginx چه میکند؟
--now یعنی همزمان شروع هم بکن.
بعد از ویرایش یک unit file چه باید بزنی؟
systemd فایلهای unit را کش میکند؛ بدون daemon-reload تغییر اعمال نمیشود.
journalctl -u nginx -f چه میکند؟
-u یک unit را فیلتر میکند و -f مثل tail -f ادامه میدهد.
Restart=on-failure در unit file یعنی…
اگر برنامه با کد ۰ تمام شود (کار عادی)، ریستارت نمیشود؛ always چنین میکند.
جمعبندی
Section titled “جمعبندی”- systemd (PID 1) سرویسها (unit) را هنگام بوت راه میاندازد، ریستارت میکند و لاگشان را در journal نگه میدارد.
systemctl status ناموضعیت،start/stop/restart/reloadکنترل فوری،enable/disableرفتار هنگام بوت.enable --nowهر دو. این دو مستقلاند: start بدون enable بعد از ریبوت نمیماند.- سرویس خودت: فایل
/etc/systemd/system/نام.serviceبا[Unit]،[Service](ExecStartمسیر کامل،Restart=) و[Install](WantedBy=multi-user.target)؛ بعدشsystemctl daemon-reload. Restart=on-failureسرویس را بعد از خطا دوباره بالا میآورد؛ زیاد crash کند،start-limitآن راfailedمیکند (reset-failed).journalctl -u نام(-fزنده،-nتعداد) لاگ سرویس؛systemctl catفایل unit؛ برای تغییر سرویس بستهای از drop-in استفاده کن.- بدون sudo نمیتوانی سرویس را کنترل کنی؛ روی کانتینر معمولی systemd نیست.
| دستور | کاری که میکند |
|---|---|
systemctl status نام | وضعیت و آخرین لاگها |
systemctl start|stop|restart نام | کنترل فوری |
systemctl reload نام | خواندن دوبارهی تنظیمات بدون قطع |
systemctl enable --now نام | اجرا همین حالا و در هر بوت |
systemctl disable نام | برداشتن از بوت (سرویس همین حالا میماند) |
systemctl is-active|is-enabled نام | وضعیت یککلمهای |
systemctl daemon-reload | بعد از هر تغییر در unit file |
systemctl cat نام | دیدن فایل unit |
systemctl reset-failed نام | پاککردن وضعیت failed |
journalctl -u نام -f | لاگ زندهی یک سرویس |
journalctl -u نام -n 50 --no-pager | پنجاه خط آخر |
systemd-analyze verify فایل | بررسی نحو unit file |