Cron Job ขั้นสูงใน cPanel ตั้งเวลาทำงานอัตโนมัติ

เรียนรู้ Cron Expression, Log output, รัน PHP Script และดีบักปัญหา Cron ไม่ทำงาน ฉบับ Shared Hosting

Cron Job ขั้นสูงใน cPanel ตั้งเวลาทำงานอัตโนมัติ cPanel

Cron Job คือระบบตั้งเวลาให้เซิร์ฟเวอร์รันคำสั่งหรือสคริปต์โดยอัตโนมัติตามช่วงเวลาที่กำหนด ไม่ว่าจะเป็นการส่งอีเมลรายวัน สำรองฐานข้อมูล ล้าง cache หรืออัพเดทข้อมูลเป็นประจำ บน Shared Hosting ที่ใช้ cPanel คุณสามารถตั้งค่า Cron Job ได้โดยไม่ต้องแตะ SSH หรือ Command Line โดยตรง แต่ถ้าต้องการใช้งานขั้นสูง การเข้าใจ Cron Expression และเทคนิคต่างๆ จะช่วยให้คุณตั้งค่าได้อย่างแม่นยำและตรวจสอบปัญหาได้เองโดยไม่ต้องพึ่งทีม Support

เข้าใจ Cron Expression ให้ถ่องแท้

Cron Expression คือรูปแบบข้อความ 5 ช่อง (field) ที่กำหนดว่าจะรันสคริปต์เมื่อไหร่ แต่ละช่องคั่นด้วยช่องว่างและมีความหมายดังนี้:

# ┌───────── นาที (0–59)
# │ ┌─────── ชั่วโมง (0–23)
# │ │ ┌───── วันที่ (1–31)
# │ │ │ ┌─── เดือน (1–12)
# │ │ │ │ ┌─ วันในสัปดาห์ (0–7, 0 และ 7 คือวันอาทิตย์)
# │ │ │ │ │
# * * * * *  คำสั่งที่ต้องการรัน

# ตัวอย่างจริง:
0 2 * * *        # ทุกวัน เวลา 02:00 น.
*/15 * * * *     # ทุก 15 นาที
0 9 * * 1        # ทุกวันจันทร์ เวลา 09:00 น.
0 0 1 * *        # วันที่ 1 ของทุกเดือน เวลาเที่ยงคืน
30 8,20 * * *    # ทุกวัน เวลา 08:30 และ 20:30 น.
Tip: ใช้เว็บ crontab.guru พิมพ์ Cron Expression แล้วระบบจะแปลเป็นภาษาอ่านง่ายทันที ช่วยตรวจสอบว่าค่าที่ตั้งตรงกับที่ต้องการ

เปิด Cron Jobs ใน cPanel และตั้งค่าขั้นพื้นฐาน

เข้า cPanel ของคุณ จากนั้นไปที่หมวด Advanced แล้วคลิก Cron Jobs หน้าแรกจะให้เลือก Email Notification ซึ่งเป็นที่อยู่อีเมลที่จะได้รับ output ของ Cron ทุกครั้งที่รัน ถ้า Cron รันบ่อย (เช่น ทุกนาที) ให้ตั้งเป็นอีเมลสำหรับ system mail หรือปิดการแจ้งเตือนแล้วเก็บ log เองแทน

ในส่วน Add New Cron Job คุณจะเห็นช่อง Common Settings ที่มี dropdown สำเร็จรูป เช่น "Once Per Day", "Once Per Week" ไว้เลือกเร็ว แต่สำหรับการตั้งค่าขั้นสูง ให้ระบุค่าตรงในช่อง Minute, Hour, Day, Month, Weekday แทน

รัน PHP Script ผ่าน Cron Job อย่างถูกต้อง

ข้อผิดพลาดที่พบบ่อยที่สุดในการรัน PHP Script คือการใช้ path ผิด ใน Shared Hosting ที่ใช้ cPanel คุณต้องระบุ path เต็มทั้งของ PHP binary และไฟล์สคริปต์ คำสั่งที่ถูกต้องมีรูปแบบดังนี้:

# รูปแบบมาตรฐาน — ระบุ PHP binary + path เต็มของสคริปต์
/usr/local/bin/php /home/username/public_html/cron/cleanup.php

# ถ้า PHP version ต่างกัน ระบุเวอร์ชันตรงๆ
/usr/local/bin/php82 /home/username/public_html/cron/send_report.php

# เก็บ output และ error ลงไฟล์ log
/usr/local/bin/php /home/username/public_html/cron/backup.php >> /home/username/logs/cron.log 2>&1

# ปิด output ทั้งหมด (ไม่รับอีเมลแจ้งเตือน)
/usr/local/bin/php /home/username/public_html/cron/task.php > /dev/null 2>&1
Tip: หา path ของ PHP binary ที่ถูกต้องได้ใน cPanel > Terminal (ถ้ามี) โดยพิมพ์ which php หรือดูจากเมนู MultiPHP Manager ใน cPanel ว่า PHP เวอร์ชันไหนที่ใช้อยู่

ตั้งค่า Log Output สำหรับ Cron Job

การเก็บ log เป็นสิ่งสำคัญมากเมื่อทำงานกับ Cron Job โดยเฉพาะเมื่อต้องดีบักปัญหาว่าสคริปต์รันสำเร็จหรือไม่ มีวิธีเก็บ log หลายแบบ:

  1. Append log (ต่อท้ายไฟล์เดิม): ใช้ >> เช่น script.php >> cron.log 2>&1
  2. Overwrite log (เขียนทับทุกครั้ง): ใช้ > เช่น script.php > cron.log 2>&1 เหมาะกับ Cron ที่รันบ่อย ไม่ให้ log ใหญ่เกิน
  3. Log พร้อม timestamp: ในสคริปต์ PHP เพิ่ม echo date('Y-m-d H:i:s') . " - Task done\n"; ก่อน output

ในไฟล์ PHP ที่ใช้กับ Cron ควรตั้งค่า error reporting ให้ครบเพื่อให้เห็น warning และ error ทั้งหมดในไฟล์ log:

<?php
// ตั้งค่า error reporting สำหรับ Cron Script
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('log_errors', 1);
ini_set('error_log', '/home/username/logs/cron_errors.log');

// บันทึก timestamp เริ่มต้น
echo "[" . date('Y-m-d H:i:s') . "] Cron started\n";

// --- Logic ของคุณที่นี่ ---

// บันทึก timestamp สิ้นสุด
echo "[" . date('Y-m-d H:i:s') . "] Cron finished\n";

เทคนิคขั้นสูง: Cron Expression ซับซ้อน

นอกจากการตั้งค่าเบื้องต้น ยังมีรูปแบบ Cron Expression ที่ใช้ประโยชน์ได้มากขึ้น:

ใช้ Cron เรียก URL (Wget / Curl)

บางระบบต้องการรัน Cron ผ่าน HTTP request (เช่น WordPress WP-Cron หรือ CMS ที่รัน task ผ่าน URL) ใน cPanel ทำได้ด้วยคำสั่ง wget หรือ curl:

# ใช้ wget เรียก URL และทิ้ง output
wget -q -O /dev/null "https://yoursite.com/wp-cron.php?doing_wp_cron" > /dev/null 2>&1

# ใช้ curl พร้อมบันทึก HTTP status code ลง log
curl -s -o /dev/null -w "%{http_code}" "https://yoursite.com/cron/run.php" >> /home/username/logs/cron_http.log 2>&1

# ใช้ curl พร้อม timeout 30 วินาที
curl -s --max-time 30 "https://yoursite.com/cron/task.php" > /dev/null 2>&1
Tip: วิธีเรียกผ่าน URL มีข้อเสียคือถ้า web server โหลดสูงหรือหยุดชั่วคราว Cron จะไม่ทำงาน แนะนำให้รัน PHP โดยตรงผ่าน binary แทนในกรณีที่ต้องการความน่าเชื่อถือสูง

จัดการ Environment Variables ใน Cron

Cron รันในสภาพแวดล้อมที่จำกัดกว่าการรันปกติ ตัวแปรสภาพแวดล้อม (Environment Variables) หลายอย่างที่ PHP ใช้ได้ปกติอาจไม่มีใน Cron context เช่น $_SERVER['HTTP_HOST'] จะว่างเปล่า และ $_SERVER['DOCUMENT_ROOT'] อาจผิดพลาด แนวทางแก้ไขในสคริปต์ PHP:


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

# 1. ดู Cron Job ที่ตั้งไว้ทั้งหมดของ user ปัจจุบัน (ผ่าน cPanel Terminal)
crontab -l

# 2. ทดสอบรันสคริปต์ PHP ด้วยมือก่อนตั้ง Cron เพื่อดู error
/usr/local/bin/php /home/username/public_html/cron/backup.php

# 3. ดู log ล่าสุดของ Cron (ถ้าเก็บ log ไว้)
tail -50 /home/username/logs/cron.log

# 4. เช็คว่าไฟล์ log ถูก update ล่าสุดเมื่อไหร่
ls -la /home/username/logs/cron.log

# 5. ตรวจสอบ error log ของ PHP Cron
tail -20 /home/username/logs/cron_errors.log
Tip: วิธีที่เร็วที่สุดในการทดสอบ Cron ใน cPanel คือตั้งให้รันทุก 1 นาที (* * * * *) แล้วรอดู log ประมาณ 2–3 นาที ถ้าทำงานแล้วให้เปลี่ยน schedule กลับเป็นค่าที่ต้องการ อย่าลืมลบ Cron ทดสอบออกให้หมดหลังเสร็จสิ้น

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

Error: "command not found" หรือ Cron ไม่รันเลย

สาเหตุหลักคือ path ของ PHP binary ผิด ให้ตรวจสอบโดยเข้า cPanel Terminal แล้วพิมพ์ which php เพื่อหา path ที่ถูกต้อง path ที่ใช้บ่อยใน Shared Hosting ได้แก่ /usr/local/bin/php, /usr/bin/php หรือ /usr/local/bin/php82 ขึ้นกับ PHP version ที่เลือกไว้

Error: สคริปต์รันได้ผ่านเบราว์เซอร์ แต่รันผ่าน Cron ไม่ได้

สาเหตุมักเกิดจากการอ้าง path แบบ relative หรือใช้ $_SERVER variables ที่ไม่มีใน CLI context ให้แก้สคริปต์โดยใช้ absolute path ทุกที่ เช่น require __DIR__ . '/../config.php'; แทน require '../config.php'; และอย่าลืมเพิ่ม >> /home/username/logs/cron.log 2>&1 ในคำสั่ง Cron เพื่อดู error message

Error: Cron รันแล้วแต่งานไม่สำเร็จ (ไม่มี error ชัดเจน)

ตรวจสอบ Permission ของไฟล์สคริปต์ โดยทั่วไปควรเป็น 644 (-rw-r--r--) และ directory ที่สคริปต์ต้องการเขียนไฟล์ควรเป็น 755 นอกจากนี้ให้ตรวจสอบว่า MySQL, extension หรือ library ที่สคริปต์ใช้ถูก enable ไว้ใน PHP CLI version ด้วย เพราะ PHP Web และ PHP CLI อาจมีการตั้งค่า extension ต่างกัน

Error: ได้รับอีเมลแจ้งเตือนจาก Cron จำนวนมากเกิน

เกิดเมื่อ Cron รันบ่อย (เช่นทุกนาที) และสคริปต์มี output ออกมา ให้เพิ่ม > /dev/null 2>&1 ท้ายคำสั่งเพื่อปิด output ทั้งหมด หรือเก็บลง log file แทน หรือในส่วน Email Address ของ Cron Jobs ใน cPanel ให้ปล่อยว่างเอาไว้เพื่อไม่รับอีเมล

Error: Cron ทำงานผิดเวลา (timezone ผิด)

เซิร์ฟเวอร์ Shared Hosting ส่วนมากใช้ UTC เป็นค่าเริ่มต้น ถ้าต้องการรัน Cron ตามเวลาไทย (UTC+7) ให้บวก 7 ชั่วโมงในการตั้งค่า เช่น ต้องการรันเวลา 09:00 น. ไทย ให้ตั้ง Cron ที่ชั่วโมง 2 (02:00 UTC) หรือตรวจสอบ timezone ของเซิร์ฟเวอร์ได้ในสคริปต์ PHP ด้วย echo date_default_timezone_get();


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

Q: ความถี่น้อยสุดที่ตั้ง Cron ได้ใน Shared Hosting คือเท่าไหร่?

บน Shared Hosting ส่วนมากที่ใช้ cPanel ความถี่ต่ำสุดที่ได้รับอนุญาตคือ 1 ครั้งต่อนาที (* * * * *) แต่บางผู้ให้บริการอาจจำกัดไว้ที่ 5 นาทีหรือ 15 นาทีขึ้นอยู่กับ Hosting Plan และนโยบายของผู้ให้บริการ ควรตรวจสอบ Terms of Service หรือติดต่อ Support ก่อนตั้ง Cron ที่รันบ่อยมาก

Q: จะรู้ได้อย่างไรว่า Cron Job รันสำเร็จหรือไม่?

วิธีที่แนะนำที่สุดคือเก็บ log โดยเพิ่ม >> /home/username/logs/cron.log 2>&1 ท้ายคำสั่ง และในสคริปต์ PHP ให้ echo ข้อความเมื่อทำงานสำเร็จหรือล้มเหลว จากนั้นเปิดดูไฟล์ log ผ่าน cPanel File Manager หรือ FTP เพื่อตรวจสอบ นอกจากนี้ยังสามารถตั้ง email notification ชั่วคราวในระหว่างทดสอบได้

Q: Cron Job ใน cPanel ต่างจาก WordPress WP-Cron อย่างไร?

WordPress WP-Cron ไม่ใช่ Cron Job จริง มันทำงานโดยอาศัยผู้เยี่ยมชมเว็บมา trigger เมื่อมีคนเปิดหน้าเว็บ ซึ่งหมายความว่าถ้าไม่มีคนเข้าเว็บ งานก็จะไม่รัน วิธีที่ดีกว่าคือปิด WP-Cron ใน wp-config.php ด้วย define('DISABLE_WP_CRON', true); แล้วตั้ง cPanel Cron Job รัน wp-cron.php โดยตรงทุก 5 หรือ 15 นาทีแทน เพื่อให้งานรันสม่ำเสมอโดยไม่ขึ้นกับ traffic