Skip to main content

> Jitrak Blog

>_ Remote Access: Auto-start After Reboot with systemd (2/3)

# เข้าเครื่องจากนอกบ้าน (2/3) — systemd รันอัตโนมัติหลัง reboot ประยุกต์กับ cloudflared tunnel

@ Yosapol Jitrak | 7 Jun 2026 17:35

Series: เข้าเครื่องจากนอกบ้าน (3 ส่วน)

  1. Remote Access: Expose Services with Cloudflare Tunnel (1/3) — ติดตั้ง cloudflared สร้าง tunnel ทดสอบ expose localhost
  2. Remote Access: Auto-start After Reboot with systemd (2/3) — systemd คืออะไร ประยุกต์กับ cloudflared (บทความนี้)
  3. Remote Access: Restrict Access with Cloudflare Access (3/3) — Email OTP ผ่าน Zero Trust

แพลตฟอร์ม: cloudflared ใช้ได้บน macOS และ Windows ด้วย แต่บทนี้เกี่ยวกับ systemd ซึ่งมีเฉพาะ Linux — บน Mac/Windows ให้ tunnel รันค้างหลัง reboot ด้วย launch agent หรือ Windows Service แทน (ไม่ครอบคลุมในชุดนี้)

Prerequisites

systemd คืออะไร?

บน Linux สมัยใหม่ (Ubuntu, Debian, Fedora ฯลฯ) ตอน boot เครื่องจะมี process หนึ่งที่รันเป็น PID 1 — ตัวนั้นคือ init system ที่คอยสตาร์ท service อื่น ๆ ตามลำดับ

systemd เป็น init system ที่ใช้กันแพร่หลาย today แทน SysV init หรือ Upstart เก่า ๆ

สิ่งที่ systemd ทำให้เรา (ในบทความนี้):

  • รัน process ค้าง — ไม่ต้องเปิด terminal ทิ้งไว้
  • สตาร์ทหลัง reboot — เปิดเครื่องใหม่ tunnel กลับมาเอง
  • restart เมื่อล้ม — process crash แล้วลองใหม่
  • ดู log รวมศูนย์ — ผ่าน journalctl แทนไล่หาไฟล์ log กระจัดกระจาย

ทุกอย่างที่ systemd จัดการเรียกว่า unit — service หนึ่งตัว = ไฟล์ .service หนึ่งไฟล์

คำสั่งพื้นฐาน

คำสั่งทำอะไร
systemctl start <name>สตาร์ท service ตอนนี้
systemctl stop <name>หยุด service
systemctl restart <name>หยุดแล้วสตาร์ทใหม่ (หลังแก้ config)
systemctl status <name>ดูว่ารันอยู่ไหม มี error อะไร
systemctl enable <name>ให้สตาร์ทอัตโนมัติทุกครั้งที่ boot
systemctl disable <name>ยกเลิกสตาร์ทอัตโนมัติ
journalctl -u <name> -fดู log แบบ real-time (-f = follow)

enable กับ start ต่างกัน: start สตาร์ททันทีครั้งเดียว enable บอกว่า “ครั้งหน้าที่ boot ให้สตาร์ทด้วย” — มักใช้คู่กันหลังสร้าง unit ใหม่

Unit file หน้าตาเป็นยังไง

Unit ที่เราสร้างเองวางที่ /etc/systemd/system/<ชื่อ>.service โครงสร้างมาตรฐานมี 3 ส่วน:

[Unit]
Description=คำอธิบายสั้น ๆ
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=your-username
ExecStart=/path/to/command arg1 arg2
Restart=always
RestartSec=5s

[Install]
WantedBy=multi-user.target
  • [Unit] — metadata และ dependency (เช่น รอเน็ตพร้อมก่อน)
  • [Service] — คำสั่งที่จะรัน ใครรัน restart ยังไง
  • [Install] — ผูกกับ boot (multi-user.target = โหมดใช้งานปกติหลัง login)

แก้ unit file แล้วต้อง reload ก่อน systemd จะอ่านเวอร์ชันใหม่:

sudo systemctl daemon-reload

ประยุกต์: cloudflared tunnel (Homebrew)

ใน post-38-remote-access-cloudflare-tunnel เราทดสอบ tunnel ด้วย cloudflared tunnel run ใน terminal — ปิด SSH หรือ reboot ก็หยุด

ถ้าติดตั้งผ่าน Homebrew หรือ cloudflared service install จาก post-38 ใช้ไม่ได้ — วิธีที่เสถียรคือ เขียน unit เอง (ส่วนนี้เป็นวิธีที่ guide นี้ใช้จริงบนเครื่องที่รัน Homebrew)

สร้าง /etc/systemd/system/cloudflared-tunnel.service:

[Unit]
Description=Cloudflare Tunnel - my-home-server
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=your-username
Environment=HOME=/home/your-username
Environment=PATH=/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ExecStart=/home/linuxbrew/.linuxbrew/bin/cloudflared tunnel run my-home-server
Restart=always
RestartSec=5s

[Install]
WantedBy=multi-user.target

ปรับให้ตรงเครื่องคุณ:

  • User / HOME — user ที่มี ~/.cloudflared/config.yml
  • ExecStart — path จาก which cloudflared
  • PATH — ใส่ $(brew --prefix)/bin ด้านหน้า
which cloudflared
brew --prefix

Enable, start และตรวจสอบ:

sudo systemctl daemon-reload
sudo systemctl enable cloudflared-tunnel
sudo systemctl start cloudflared-tunnel
systemctl status cloudflared-tunnel
journalctl -u cloudflared-tunnel -f

ทุกครั้งที่แก้ ~/.cloudflared/config.yml:

sudo systemctl restart cloudflared-tunnel

Troubleshooting

ปัญหาสาเหตุวิธีแก้
systemctl start แล้ว failExecStart path ผิดรัน which cloudflared แล้วใส่ path เต็มใน unit
Service restart loopconfig หรือ credentials path ผิดดู journalctl -u cloudflared-tunnel -n 50 ตรวจ absolute path ใน config
หยุดหลัง rebootลืม enablesudo systemctl enable cloudflared-tunnel
journalctl แสดง “not found”PATH ใน unit ไม่มี brew binเพิ่ม $(brew --prefix)/bin ใน Environment=PATH
แก้ unit แล้วไม่เห็นผลลืม daemon-reloadsudo systemctl daemon-reload แล้ว restart

ต่อไป

Tunnel รันอัตโนมัติแล้ว ขั้นต่อไปคือจำกัดผู้เข้าใช้ — ไปต่อที่ เข้าเครื่องจากนอกบ้าน (3/3): Cloudflare Access

~/shortcuts

> Keyboard shortcuts

  • Toggle this help?H
  • Back to topT
  • Scroll downJ
  • Scroll upK
  • Forward (newer post or next page)F
  • Back (older post or previous page)B
  • Go homeG
  • Close helpEsc