หลายคนเริ่มเขียน Discord Bot บนเครื่องตัวเอง พอปิดคอม บอทก็ offline ทันที บทความนี้จะพาย้ายบอทขึ้น Linux VPS (Ubuntu) แล้วตั้งให้รันเป็น systemd service — บอทจะ restart เองเมื่อ crash และกลับมาออนไลน์เองหลัง reboot โดยไม่ต้องพึ่ง tool เสริม

คำสั่งทั้งหมดเขียนสำหรับ Ubuntu 22.04/24.04 ครับ

สิ่งที่ต้องมี

  • Linux VPS 1 เครื่อง (Ubuntu) ที่เข้า SSH ได้ บอทเล็ก ๆ ใช้ทรัพยากรน้อยมาก สเปกเริ่มต้นของผู้ให้บริการส่วนใหญ่ก็พอ ถ้าแค่อยากลองก่อนโดยยังไม่ผูกรายเดือน มีผู้ให้บริการที่ให้เช่าแบบรายวัน เช่น VPSKUB (เช่ารายวัน/รายสัปดาห์/รายเดือน มี Ubuntu ให้เลือก) หรือใช้เจ้าไหนก็ได้ที่คุ้นเคย
  • Discord Application + Bot Token จาก Discord Developer Portal
  • Client ID ของแอป และ Guild ID (Server ID) ของเซิร์ฟเวอร์ที่ใช้ทดสอบ (เปิด Developer Mode ใน Discord แล้วคลิกขวาที่เซิร์ฟเวอร์ → Copy Server ID)

1) เตรียมเครื่อง: update + firewall

SSH เข้าเครื่อง (เปลี่ยน YOUR_SERVER_IP เป็น IP ของคุณ):

ssh root@YOUR_SERVER_IP 

อัปเดตแพ็กเกจและเปิด firewall แบบอนุญาตเฉพาะ SSH:

apt update && apt upgrade -y apt install -y ufw git curl ufw allow OpenSSH ufw enable ufw status 

Discord Bot ทั่วไปเชื่อมต่อ ขาออก ไปยัง Discord Gateway เท่านั้น จึงไม่ต้องเปิด port ขาเข้าเพิ่ม (ยกเว้นคุณทำ web dashboard หรือ webhook server เอง)

2) สร้าง user แยกสำหรับรันบอท

อย่ารันบอทด้วย root — ถ้าโค้ดหรือ dependency มีช่องโหว่ ความเสียหายจะจำกัดอยู่ที่ user นี้:

adduser --system --group --home /opt/mybot mybot 

3) ติดตั้ง Node.js LTS

ใช้ repository ของ NodeSource (Node 22 LTS):

curl -fsSL https://deb.nodesource.com/setup_22.x | bash - apt install -y nodejs node -v npm -v 

4) สร้างโปรเจกต์บอท

cd /opt/mybot sudo -u mybot npm init -y sudo -u mybot npm install discord.js 

สร้างไฟล์ .env เก็บ secret (ห้าม commit ขึ้น Git):

sudo -u mybot tee /opt/mybot/.env > /dev/null <<'ENV' DISCORD_TOKEN=ใส่_bot_token_ตรงนี้ CLIENT_ID=ใส่_application_id GUILD_ID=ใส่_server_id ENV chmod 600 /opt/mybot/.env 

index.js — ตัวบอท

// /opt/mybot/index.js const { Client, Events, GatewayIntentBits } = require('discord.js'); const client = new Client({ intents: [GatewayIntentBits.Guilds] }); client.once(Events.ClientReady, (c) => { console.log(`Ready! Logged in as ${c.user.tag}`); }); client.on(Events.InteractionCreate, async (interaction) => { if (!interaction.isChatInputCommand()) return; if (interaction.commandName === 'ping') { await interaction.reply(`Pong! 🏓 (${client.ws.ping} ms)`); } }); client.login(process.env.DISCORD_TOKEN); 

deploy-commands.js — ลงทะเบียน slash command

// /opt/mybot/deploy-commands.js const { REST, Routes, SlashCommandBuilder } = require('discord.js'); const commands = [ new SlashCommandBuilder().setName('ping').setDescription('เช็คว่าบอทยังอยู่ไหม'), ].map((c) => c.toJSON()); const rest = new REST().setToken(process.env.DISCORD_TOKEN); (async () => { await rest.put( Routes.applicationGuildCommands(process.env.CLIENT_ID, process.env.GUILD_ID), { body: commands }, ); console.log('Slash commands registered.'); })(); 

ให้สิทธิ์ไฟล์แก่ user mybot แล้วทดสอบ (Node 20.6+ อ่าน .env ได้เองด้วย --env-file):

chown mybot:mybot /opt/mybot/*.js cd /opt/mybot sudo -u mybot node --env-file=.env deploy-commands.js sudo -u mybot node --env-file=.env index.js 

ถ้าเห็น Ready! Logged in as ... ลองพิมพ์ /ping ใน Discord ได้เลย จากนั้นกด Ctrl+C เพื่อหยุด — ขั้นต่อไปเราจะให้ systemd ดูแลแทน

5) ตั้งเป็น systemd service

tee /etc/systemd/system/mybot.service > /dev/null <<'UNIT' [Unit] Description=My Discord Bot After=network-online.target Wants=network-online.target [Service] Type=simple User=mybot WorkingDirectory=/opt/mybot EnvironmentFile=/opt/mybot/.env ExecStart=/usr/bin/node index.js Restart=on-failure RestartSec=5 NoNewPrivileges=true [Install] WantedBy=multi-user.target UNIT systemctl daemon-reload systemctl enable --now mybot systemctl status mybot 

Restart=on-failure = crash แล้วเริ่มใหม่ใน 5 วินาที, enable = เปิดเองหลัง reboot

6) ดู log และอัปเดตโค้ด

journalctl -u mybot -f # ดู log แบบ real-time journalctl -u mybot --since "1 hour ago" systemctl restart mybot # หลังแก้โค้ด 

ถ้าเก็บโค้ดบน GitHub ขั้นตอน deploy ง่าย ๆ คือ:

cd /opt/mybot sudo -u mybot git pull sudo -u mybot npm ci --omit=dev systemctl restart mybot 

Troubleshooting ที่เจอบ่อย

อาการ สาเหตุ / วิธีแก้
TokenInvalid / An invalid token was provided token ผิด หรือเพิ่ง reset token ใน Developer Portal → แก้ .env แล้ว systemctl restart mybot
พิมพ์ /ping แล้วไม่ขึ้นคำสั่ง ยังไม่ได้รัน deploy-commands.js หรือ GUILD_ID ผิด
Used disallowed intents ใช้ intent อย่าง MessageContent หรือ GuildMembers แต่ยังไม่ได้เปิดในหน้า Bot ของ Developer Portal
service ขึ้น failed ทันที ดู journalctl -u mybot -n 50 ส่วนใหญ่คือ path ผิด หรือ user mybot ไม่มีสิทธิ์อ่านไฟล์

Security checklist สั้น ๆ

  • ใช้ SSH key แทนรหัสผ่าน แล้วตั้ง PasswordAuthentication no ใน /etc/ssh/sshd_config
  • chmod 600 .env และใส่ .env ใน .gitignore เสมอ — token หลุดขึ้น GitHub สาธารณะคือเคสที่เจอบ่อยมาก
  • ติดตั้ง security update อัตโนมัติ: apt install -y unattended-upgrades
  • ถ้า token เคยหลุด ให้กด Reset Token ทันที

สรุป

แค่ Ubuntu + Node.js + systemd ก็ได้บอทที่ออนไลน์ 24/7, restart ตัวเองเมื่อ crash และดู log ได้ด้วย journalctl โดยไม่ต้องติดตั้ง process manager เพิ่ม วิธีเดียวกันนี้ใช้กับบอท Python (discord.py) ได้เลย แค่เปลี่ยน ExecStart เป็น path ของ Python ใน virtualenv

อ่านต่อ (ภาษาไทย): การเลือกสเปก VPS สำหรับ Discord Bot ตามขนาดบอท

Disclosure: ผมเป็นผู้ดูแล VPSKUB ที่ลิงก์ไว้ในบทความ แต่ขั้นตอนทั้งหมดใช้ได้กับ Ubuntu VPS ทุกเจ้า