systemd timer บน Linux VPS

ใช้ systemd Timer แทน Cron บน VPS Linux

อัปเดต 15 ตุลาคม 2026 · อ่าน 8 นาที

หลายคนคุ้นเคยกับ cron มาตั้งแต่เริ่มใช้ Linux แต่ systemd timer คือทางเลือกที่ทรงพลังกว่า โดยเฉพาะบน VPS สมัยใหม่ที่รัน systemd อยู่แล้ว — จัดการ log ผ่าน journalctl ได้ทันที กำหนด dependency ได้ และควบคุมเวลาได้ละเอียดกว่า

cron vs systemd timer ต่างกันอย่างไร

ฟีเจอร์cronsystemd timer
Log การทำงานต้องส่งออก stdout เองjournalctl ดูได้ทันที
รันหลัง boot แม้เลยเวลาไม่รองรับรองรับ (Persistent=true)
Dependencyไม่มีAfter=network.target เป็นต้น
เวลาสัมพัทธ์ไม่รองรับOnBootSec, OnUnitActiveSec
หยุดชั่วคราวต้องลบ crontabsystemctl disable --now

ส่วนประกอบของ systemd timer

timer หนึ่งชุดประกอบด้วย 2 ไฟล์ใน /etc/systemd/system/:

สร้าง systemd timer ครั้งแรก

ตัวอย่าง: รัน script backup ทุกวันเวลา 02:00 น.

1. สร้าง service unit

sudo nano /etc/systemd/system/daily-backup.service
[Unit]
Description=Daily backup script
After=network.target

[Service]
Type=oneshot
User=root
ExecStart=/usr/local/bin/backup.sh
StandardOutput=journal
StandardError=journal
Note: Type=oneshot เหมาะกับงานที่รันครั้งเดียวแล้วจบ (เหมือน cron) ต่างจาก simple ที่ใช้กับ daemon

2. สร้าง timer unit

sudo nano /etc/systemd/system/daily-backup.timer
[Unit]
Description=Run daily-backup.service every day at 02:00

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
RandomizedDelaySec=300

[Install]
WantedBy=timers.target
Tip: Persistent=true ทำให้งานที่พลาดระหว่าง server ปิดอยู่จะรันทันทีหลัง boot — ป้องกัน backup หายเงียบๆ

3. เปิดใช้งานและสั่งรัน

# โหลด unit ใหม่
sudo systemctl daemon-reload

# เปิด timer ให้ทำงานอัตโนมัติและสั่งรันทันที
sudo systemctl enable --now daily-backup.timer

# ดูสถานะ
sudo systemctl status daily-backup.timer

รูปแบบ OnCalendar ที่ใช้บ่อย

ความต้องการOnCalendar
ทุกชั่วโมงhourly
ทุกวัน 03:00*-*-* 03:00:00
ทุกจันทร์ 09:00Mon *-*-* 09:00:00
ทุกวันที่ 1 ของเดือน*-*-01 00:00:00
ทุก 5 นาที*:0/5
ทุก 30 วินาทีOnUnitActiveSec=30s

timer หลัง boot (OnBootSec)

ถ้าต้องการให้รันหลัง server boot โดยไม่สนเวลานาฬิกา ใช้ OnBootSec:

[Timer]
OnBootSec=5min
OnUnitActiveSec=1h

รูปแบบนี้หมายถึง: รันครั้งแรก 5 นาทีหลัง boot จากนั้นรันซ้ำทุก 1 ชั่วโมง

รัน timer ในฐานะ user ปกติ (user timer)

ไม่จำเป็นต้องใช้ root เสมอ — สร้าง user timer ที่ไม่ต้องการ sudo:

# สร้างไดเรกทอรีสำหรับ user timer
mkdir -p ~/.config/systemd/user/

# สร้าง service
nano ~/.config/systemd/user/myapp-task.service
[Unit]
Description=My app periodic task

[Service]
Type=oneshot
ExecStart=/home/user/scripts/run-task.sh
# สร้าง timer
nano ~/.config/systemd/user/myapp-task.timer
[Unit]
Description=Run myapp-task every 6 hours

[Timer]
OnCalendar=*-*-* 00/6:00:00
Persistent=true

[Install]
WantedBy=timers.target
# เปิดใช้งาน (ไม่ต้องใช้ sudo)
systemctl --user daemon-reload
systemctl --user enable --now myapp-task.timer
systemctl --user list-timers
Note: User timer จะทำงานเฉพาะตอน user logged in เว้นแต่เปิด lingering: sudo loginctl enable-linger username

ดูรายการ timer ทั้งหมด

# ดู timer ทั้งหมดในระบบ
systemctl list-timers --all

# ดูเฉพาะที่ active
systemctl list-timers

# ดู timer ของ user
systemctl --user list-timers

ตรวจสอบว่า systemd timer ทำงานถูกต้อง

# ดูสถานะ timer
systemctl status daily-backup.timer

# ดูว่า service รันสำเร็จครั้งล่าสุดเมื่อไหร่
systemctl status daily-backup.service

# ดู log ของ service
journalctl -u daily-backup.service -n 50

# ดู log ย้อนหลัง 24 ชั่วโมง
journalctl -u daily-backup.service --since "24 hours ago"

# ทดสอบรัน service ทันทีโดยไม่รอ timer
systemctl start daily-backup.service
Tip: ใช้ systemd-analyze calendar "*-*-* 02:00:00" เพื่อตรวจว่า expression ที่เขียนถูกต้องและดูว่าจะ trigger ครั้งถัดไปเมื่อไหร่

แก้ปัญหาที่พบบ่อย

Error: "Failed to enable unit: Unit file daily-backup.timer does not exist"

เกิดจาก systemd ยังไม่โหลด unit file ใหม่ หรือชื่อไฟล์ผิด

# โหลด unit ใหม่ก่อนเสมอ
sudo systemctl daemon-reload

# ตรวจว่าไฟล์อยู่ถูกที่
ls -la /etc/systemd/system/daily-backup.*

# ตรวจ syntax ของ unit file
systemd-analyze verify /etc/systemd/system/daily-backup.timer

Error: "daily-backup.service: Main process exited, code=exited, status=127"

Exit code 127 หมายถึงหา command ไม่เจอ — script path ผิดหรือไม่มี execute permission

# ตรวจว่า script มีอยู่และรันได้
ls -la /usr/local/bin/backup.sh
chmod +x /usr/local/bin/backup.sh

# ตรวจ path ใน ExecStart ต้องเป็น absolute path
# ผิด: ExecStart=backup.sh
# ถูก: ExecStart=/usr/local/bin/backup.sh

Error: timer ไม่รันแม้ถึงเวลา

ตรวจสอบว่า timer active และเวลาระบบถูกต้อง

# ตรวจว่า timer active
systemctl is-active daily-backup.timer

# ตรวจเวลาระบบ (ต้องตรง timezone ที่ต้องการ)
timedatectl status

# ดู next trigger time
systemctl list-timers daily-backup.timer

Error: "daily-backup.service: Skipped due to already running"

เกิดเมื่อ service ก่อนหน้ายังรันอยู่ไม่เสร็จ timer trigger ซ้ำ

# เพิ่ม Type=oneshot และ RemainAfterExit ใน service
[Service]
Type=oneshot
RemainAfterExit=no

# หรือตรวจว่ามี stale process ค้างอยู่
systemctl status daily-backup.service
systemctl reset-failed daily-backup.service

Error: "Condition check resulted in daily-backup.service being skipped"

มี ConditionPathExists หรือ Condition อื่นที่ไม่ผ่าน

# ดู condition ที่กำหนดไว้
systemctl cat daily-backup.service

# ตรวจ log เพื่อดู condition ที่ fail
journalctl -u daily-backup.service -n 20 --no-pager

คำถามที่พบบ่อย

systemd timer กับ cron อันไหนเหมาะกับ VPS มากกว่า?

สำหรับ VPS ที่ใช้ Ubuntu/Debian/CentOS สมัยใหม่ systemd timer เหมาะกว่า เพราะ log รวมอยู่ใน journald ไม่ต้องกำหนด output แยก และ Persistent=true ป้องกันงานหายถ้า server restart กลางดึก — cron ยังใช้ดีถ้าต้องการ syntax สั้นๆ หรือต้องใช้ร่วมกับระบบเก่า

จะดู log ของงานที่รันผ่าน systemd timer ได้อย่างไร?

ใช้ journalctl -u ชื่อ-service.service — ดูได้ทันทีโดยไม่ต้องกำหนด log file เอง เพิ่ม -f เพื่อดูแบบ real-time หรือ --since "1 hour ago" เพื่อกรองช่วงเวลา

timer สามารถรันคำสั่งหลายอันพร้อมกันได้ไหม?

ใน service unit หนึ่งไฟล์ใส่ ExecStart ได้หลายบรรทัด (ต้องมี Type=oneshot) หรือสร้าง script รวมคำสั่งทั้งหมดแล้วชี้ ExecStart ไปที่ script นั้น — ทำให้ log ครบทุกคำสั่งในที่เดียว