Series: เข้าเครื่องจากนอกบ้าน (3 ส่วน)
- Remote Access: Expose Services with Cloudflare Tunnel (1/3) — ติดตั้ง cloudflared สร้าง tunnel ทดสอบ expose localhost
- Remote Access: Auto-start After Reboot with systemd (2/3) — systemd คืออะไร ประยุกต์กับ cloudflared (บทความนี้)
- 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
- ทำตาม เข้าเครื่องจากนอกบ้าน (1/3): Cloudflare Tunnel จน
cloudflared tunnel run my-home-serverใช้งานได้แล้ว - มีไฟล์
~/.cloudflared/config.ymlและ credentials file ครบ - ถ้าทำ Step 7 ใน post-38-remote-access-cloudflare-tunnel (
cloudflared --config ... service install) สำเร็จแล้ว — ข้ามบทนี้หรืออ่านเพื่อเข้าใจ systemd ก็ได้
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.ymlExecStart— path จากwhich cloudflaredPATH— ใส่$(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 แล้ว fail | ExecStart path ผิด | รัน which cloudflared แล้วใส่ path เต็มใน unit |
| Service restart loop | config หรือ credentials path ผิด | ดู journalctl -u cloudflared-tunnel -n 50 ตรวจ absolute path ใน config |
| หยุดหลัง reboot | ลืม enable | sudo systemctl enable cloudflared-tunnel |
| journalctl แสดง “not found” | PATH ใน unit ไม่มี brew bin | เพิ่ม $(brew --prefix)/bin ใน Environment=PATH |
| แก้ unit แล้วไม่เห็นผล | ลืม daemon-reload | sudo systemctl daemon-reload แล้ว restart |
ต่อไป
Tunnel รันอัตโนมัติแล้ว ขั้นต่อไปคือจำกัดผู้เข้าใช้ — ไปต่อที่ เข้าเครื่องจากนอกบ้าน (3/3): Cloudflare Access