SSD Nodes Learn Hosting plans →
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-08-23

วิธีติดตั้ง openGym ด้วยตนเองผ่าน Docker Compose

เรียนรู้วิธีติดตั้ง openGym บน VPS ด้วย Docker Compose พร้อมตั้งค่า TLS ก่อนใช้งาน Passkey การจัดการไฟล์ข้อมูล JSON และการเชื่อมต่อ MCP server แบบอ่านอย่างเดียวให้ถูกต้อง

สิ่งที่คุณจะได้รับเมื่อโฮสต์ openGym ด้วยตนเอง

คุณสามารถโฮสต์ openGym ด้วยตนเองได้โดยการ clone repository, แก้ไขสองบรรทัดใน .env และรัน docker compose up -d --build ไว้หลัง reverse proxy ที่ทำหน้าที่จัดการ TLS (transport layer security) openGym เป็นแอปพลิเคชันสำหรับติดตามการออกกำลังกายและน้ำหนักตัว โดยมีฟีเจอร์แผนรายสัปดาห์, การแนะนำการออกกำลังกาย, การบันทึกทุกเซต และการติดตามน้ำหนักตามช่วงเวลา แอปนี้ใช้สัญญาอนุญาตแบบ AGPL-3.0 และจัดเก็บข้อมูลทั้งหมดไว้ในไฟล์ JSON ธรรมดาบนดิสก์ของคุณ จึงไม่จำเป็นต้องรัน database server ใดๆ

สแต็กของระบบประกอบด้วย container ที่ทำงานต่อเนื่องสองตัว ได้แก่ container ของ nginx ที่ทำหน้าที่เสิร์ฟ React build และ container ของ Node ที่ทำหน้าที่จัดการ API รวมถึงงานแบบ one-shot ที่จะดาวน์โหลดรูปภาพและไฟล์ GIF ของท่าออกกำลังกายขนาดประมาณ 140 MB ในการเริ่มต้นใช้งานครั้งแรก

มีสองสิ่งที่ README ของโปรเจกต์สื่อเป็นนัยแต่ไม่ได้ระบุไว้อย่างชัดเจนสำหรับผู้ที่ติดตั้งบนเซิร์ฟเวอร์สาธารณะ ประการแรก การล็อกอินด้วย Passkey จะผูกติดกับชื่อโฮสต์ ดังนั้นโดเมนและใบรับรอง (certificate) ของโดเมนนั้นจะต้องมีอยู่ก่อนการล็อกอินครั้งแรก ไม่ใช่หลังจากนั้น ประการที่สอง MCP server แบบทางเลือกนั้นเป็นแบบอ่านอย่างเดียว (read-only) และทำงานบนเครื่องที่ AI client ของคุณรันอยู่ ไม่ใช่รันอยู่ภายในสแต็ก ซึ่งส่งผลต่อสิ่งที่คุณต้องทำเมื่อข้อมูลถูกจัดเก็บอยู่บน VPS

openGym ยังเป็นโปรเจกต์ใหม่ โดย release แรกที่มีการติดแท็กคือ v1.0.0 ลงวันที่ 20 กรกฎาคม 2026 และ v1.2.7 ถูกปล่อยออกมาเมื่อวันที่ 18 สิงหาคม 2026 การที่มีการปล่อยแท็กถึง 13 ครั้งในเวลาประมาณหนึ่งเดือนหมายความว่าแอปยังมีการเปลี่ยนแปลงอยู่ตลอด ดังนั้นควรเลือกใช้ release tag แทนการ build จากสิ่งที่อยู่ใน default branch

วางแผนโดเมนก่อนการเข้าสู่ระบบครั้งแรก

Passkeys คือวิธีการที่คุณใช้ลงชื่อเข้าใช้ openGym โดย passkey จะผูกอยู่กับ relying party ID (RP ID) ซึ่งก็คือโดเมนที่ใช้สร้าง credential นั้นๆ และเบราว์เซอร์จะสร้าง passkeys ผ่าน HTTPS เท่านั้น โดยมีข้อยกเว้นเพียงอย่างเดียวคือ localhost

เรื่องนี้ส่งผลกระทบที่ผู้ใช้มักพบเจอเมื่อใช้งานผ่านโทรศัพท์มือถือ หากคุณเปิด http://203.0.113.10:8080 จากอุปกรณ์อื่นแล้วไม่มีหน้าต่างแจ้งเตือนให้ใช้ passkey ปรากฏขึ้น นั่นเป็นเพราะเบราว์เซอร์ปฏิเสธที่จะสร้าง credential บน origin ที่เป็น HTTP ธรรมดาหรือบน IP address โดยตรง บันทึกการแก้ไขปัญหาของโปรเจกต์เองก็ได้ระบุไว้เช่นกันว่า หากไม่มีการแจ้งเตือนปรากฏขึ้น แสดงว่าคุณกำลังใช้งานบน http:// หรือใช้งานผ่าน IP

ที่แย่ไปกว่านั้นคือ RP ID จะถูกฝังอยู่ในทุก credential ที่ผู้ใช้ของคุณลงทะเบียนไว้แล้ว หากคุณเปลี่ยน RP_ID ในภายหลัง passkeys ที่จัดเก็บไว้ในอุปกรณ์ของผู้ใช้จะไม่ตรงกันอีกต่อไป ส่งผลให้ไม่มีใครสามารถลงชื่อเข้าใช้ได้ ดังนั้นคุณควรตัดสินใจเลือก hostname ให้เรียบร้อย ชี้ DNS ไปยัง VPS และตั้งค่า certificate ให้ใช้งานได้ก่อนที่จะมีใครกดปุ่ม Create profile

การติดตั้ง openGym ด้วย Docker Compose

ไฟล์ compose จะทำการ bind-mount ./data และ ./media โดยอ้างอิงจากตำแหน่งของไฟล์ ดังนั้นไดเรกทอรีที่คุณโคลนโปรเจกต์ลงมาจึงเป็นที่เก็บฐานข้อมูลของคุณโดยตรง ควรวางไว้ในตำแหน่งที่จัดเก็บข้อมูลได้อย่างถาวร

sudo install -d -o "$USER" -g "$USER" /opt/opengym
git clone https://gitea.com/DuarteSantos/openGym /opt/opengym
cd /opt/opengym
cp .env.example .env

ไฟล์ README ยังคงแสดง URL สำหรับโคลนเป็น github.com ซึ่งที่อยู่นั้นไม่สามารถใช้งานได้แล้ว และที่เก็บโค้ดบน Gitea ที่ระบุไว้ข้างต้นคือแหล่งข้อมูลหลักของโปรเจกต์ในปัจจุบัน

แก้ไขไฟล์ .env โดยมี 3 บรรทัดที่สำคัญสำหรับการใช้งานบน VPS

RP_ID=gym.example.com
ORIGIN=https://gym.example.com
WEB_PORT=127.0.0.1:8080

RP_ID คือชื่อโฮสต์เปล่าๆ และ ORIGIN คือ URL เต็มรูปแบบรวมถึง scheme ค่าเหล่านี้ต้องตรงกับที่ปรากฏบนแถบที่อยู่ของเบราว์เซอร์อย่างแม่นยำ มิฉะนั้นการเข้าสู่ระบบจะล้มเหลวพร้อมข้อผิดพลาด verification failed ส่วนค่า WEB_PORT ได้อธิบายไว้ในส่วนของการจำกัดการเข้าถึงพอร์ต 8080

docker compose up -d --build
docker compose ps
docker compose logs media

docker compose ps ควรแสดงสถานะ web และ api ว่ากำลังทำงานอยู่ (running) และ media มีสถานะเป็น exited ด้วยรหัส 0 การหยุดทำงานนี้ถือเป็นเรื่องปกติ เนื่องจากงานด้านสื่อมี restart: "no" เพราะเป็นการดาวน์โหลดข้อมูลเพียงครั้งเดียว บันทึกการทำงาน (log) จะสิ้นสุดด้วยบรรทัดที่ขึ้นต้นว่า ✓ Exercise media ready และ ls media/img | wc -l ควรแสดงจำนวนไฟล์หลักร้อย ไม่ใช่ 0 หากไดเรกทอรีว่างเปล่าแสดงว่าการดาวน์โหลดล้มเหลว และแอปพลิเคชันจะแสดงการ์ดออกกำลังกายโดยไม่มีรูปภาพ

แฟล็ก --build เป็นสิ่งที่จำเป็นในกรณีนี้ เนื่องจากไฟล์ compose อ้างอิงถึงอิมเมจที่สร้างไว้ล่วงหน้าบน ghcr.io ซึ่งไม่มีการเผยแพร่อีกต่อไป ดังนั้นการใช้ docker compose pull จะล้มเหลวด้วยข้อผิดพลาด denied หรือ manifest unknown บริการทั้งสองจึงต้องถูกสร้างขึ้นจากซอร์สโค้ดที่คุณเพิ่งโคลนมา ทั้งสองบริการมีส่วนของ build เพื่อรองรับการทำงานนี้โดยเฉพาะ หากคุณยังไม่คุ้นเคยกับ Compose ให้เริ่มต้นที่ Docker Compose บน VPS แล้วจึงกลับมาดำเนินการต่อ

ตรึงเวอร์ชันไว้ เนื่องจากโปรเจกต์นี้ยังอยู่ในช่วงเริ่มต้น

เนื่องจาก namespace ของ registry ดังกล่าวถูกลบออกไปแล้ว จึงไม่มี image tag เหลือให้ตรึง สิ่งที่คุณต้องตรึงแทนคือ checkout บนดิสก์ เนื่องจากเป็นตัวกำหนดว่าแอปพลิเคชันเวอร์ชันใดจะถูกนำไปใส่ใน container

cd /opt/opengym
git fetch --tags
git checkout v1.2.7

git status จะรายงานสถานะ detached HEAD ที่ tag นั้น ซึ่งเป็นสิ่งที่คุณต้องการบนเซิร์ฟเวอร์ จะไม่มีการเปลี่ยนแปลงใดๆ เกิดขึ้นจนกว่าคุณจะ checkout ไปยัง tag อื่น

จากนั้นให้สั่งให้ Compose เลิกดึงข้อมูลจาก registry โดยสิ้นเชิง ให้ใส่ค่านี้ลงใน docker-compose.override.yml ซึ่ง Compose จะโหลดและรวมเข้ากับไฟล์ที่ถูก track ไว้โดยอัตโนมัติ ค่าที่เป็น scalar จะถูกแทนที่ด้วยไฟล์ override ดังนั้นจึงไม่จำเป็นต้องแก้ไขไฟล์ใดๆ ใน git และ git pull จะยังคงสะอาดอยู่ ดู วิธีการที่ Compose รวมไฟล์ override สำหรับกฎการรวมไฟล์ทั้งหมด

services:
  api:
    pull_policy: build
  web:
    pull_policy: build

เมื่อตั้งค่าเรียบร้อยแล้ว การรัน docker compose up -d ในภายหลังจะทำการ build จากซอร์สที่คุณมีอยู่แทนที่จะล้มเหลวจากการพยายาม pull ให้ตรวจสอบว่าการรวมไฟล์มีผลแล้ว จากนั้นจึงทำการ rebuild ที่ tag นั้น

docker compose config | grep pull_policy
docker compose up -d --build

การทำ TLS termination ด้วย reverse proxy

คอนเทนเนอร์จะสื่อสารผ่าน HTTP ปกติ ดังนั้นต้องมีส่วนประกอบด้านหน้าทำหน้าที่เก็บใบรับรอง (certificate) Caddy เป็นวิธีที่สั้นที่สุดเนื่องจากสามารถร้องขอและต่ออายุใบรับรองจาก Let's Encrypt ได้โดยอัตโนมัติ

gym.example.com {
    reverse_proxy 127.0.0.1:8080
}

nginx, Traefik และ Nginx Proxy Manager ต่างทำงานในลักษณะเดียวกัน รวมถึง Cloudflare Tunnel ซึ่งมีเอกสารประกอบโครงการไว้และไม่จำเป็นต้องเปิดพอร์ตขาเข้าใดๆ เลย

curl -sI https://gym.example.com | head -1

คำสั่งดังกล่าวควรส่งค่ากลับเป็น HTTP/2 200 โดยไม่มีการแจ้งเตือนเรื่องใบรับรอง จากนั้นให้เปิดเว็บไซต์ในเบราว์เซอร์แล้วกด Create profile หากมีหน้าต่างแจ้งเตือน passkey ปรากฏขึ้นแล้วการล็อกอินรายงานค่า verification failed, RP_ID หรือ ORIGIN ไม่ตรงกับ URL ในแถบที่อยู่ ให้แก้ไขค่า .env แล้วรันคำสั่ง docker compose up -d อีกครั้งเพื่อสร้างคอนเทนเนอร์ใหม่ให้โหลดค่าที่กำหนดไว้ล่าสุด การใช้คำสั่ง docker compose restart ไม่สามารถโหลดค่า .env ใหม่ได้

จำกัดไม่ให้พอร์ต 8080 เข้าถึงได้จากอินเทอร์เน็ตสาธารณะ

โดยปกติแล้วเว็บเซอร์วิสจะเผยแพร่ 8080 บนทุกอินเทอร์เฟซ ทำให้แอปพลิเคชันสามารถเข้าถึงได้ผ่าน HTTP ปกติที่ IP สาธารณะของคุณ ในขณะที่พร็อกซีให้บริการ HTTPS บนเครื่องเดียวกัน กฎของไฟร์วอลล์ไม่สามารถแก้ไขปัญหานี้ได้ Docker เผยแพร่พอร์ตด้วยกฎ DNAT ในตาราง nat และทราฟฟิกนั้นจะถูกจัดการในเชน FORWARD ซึ่งกฎของ Docker เองจะยอมรับทราฟฟิกดังกล่าว ในขณะที่กฎของ ufw จะอยู่ในเส้นทาง INPUT ดังนั้น sudo ufw deny 8080/tcp จึงไม่สามารถบล็อกอะไรได้เลย

วิธีแก้ไขคือการเผยแพร่บน loopback address เท่านั้น ไฟล์ compose จะแมป "${WEB_PORT:-8080}:${NGINX_PORT:-80}" ดังนั้นไม่ว่าคุณจะตั้งค่าอะไรใน WEB_PORT ค่าดังกล่าวจะถูกแทนที่ทางด้านซ้ายของการแมปนั้น และไวยากรณ์แบบย่อของ Docker ยอมรับคู่ ip:port ที่นั่น นี่คือเหตุผลว่าทำไม WEB_PORT=127.0.0.1:8080 ถึงใช้งานได้

docker compose config
sudo ss -ltnp | grep 8080

ในไฟล์คอนฟิกที่รวมแล้ว ภายใต้ ports ของเว็บเซอร์วิส คุณควรเห็น host_ip: 127.0.0.1 ส่วน ss ควรแสดง 127.0.0.1:8080 และไม่ใช่ 0.0.0.0:8080 จากเครื่องอื่น curl http://<your-vps-ip>:8080 ควรถูกปฏิเสธหรือหมดเวลาการเชื่อมต่อ ในขณะที่ชื่อโฮสต์ HTTPS ยังคงทำงานได้ตามปกติ

ปิดการลงทะเบียนหลังจากสร้างโปรไฟล์ของคุณแล้ว

การลงทะเบียนจะเปิดใช้งานโดยค่าเริ่มต้นและโหมดผู้เยี่ยมชมจะเปิดอยู่ หากใช้งานบน hostname สาธารณะ หมายความว่าใครก็ตามที่พบ URL จะสามารถสร้างโปรไฟล์บนเซิร์ฟเวอร์ของคุณได้ ให้ลงทะเบียนโปรไฟล์ของคุณเองก่อน จากนั้นจึงค้นหา user ID ของคุณ: ls data/ จะแสดงรายการไฟล์ที่ชื่อ state-<uid>.json สำหรับผู้ใช้แต่ละคน และ <uid> นั้นคือค่าที่คุณต้องการ

ADMIN_UIDS=<your-uid>
INVITE_ONLY=1
ALLOW_GUEST=0

เรียกใช้ docker compose up -d อีกครั้ง ขณะนี้หน้า Settings จะแสดง Admin dashboard ซึ่งคุณสามารถสร้างและเพิกถอนรหัสเชิญได้ เพื่อให้คนที่คุณฝึกด้วยสามารถลงทะเบียนได้และไม่มีผู้อื่นทำได้ openGym ไม่รู้จักผู้ให้บริการยืนยันตัวตนภายนอก ดังนั้นรหัสเชิญเหล่านั้นจึงควบคุมเฉพาะแอปนี้เท่านั้นและไม่มีผลกับส่วนอื่นบนเซิร์ฟเวอร์ หากคุณต้องการแจกจ่ายบัญชีเดียวต่อหนึ่งคนสำหรับทุกบริการที่คุณรัน การใช้ Authentik เป็น forward auth proxy จะช่วยกั้นการเข้าถึง hostname ก่อนที่ระบบล็อกอินด้วย passkey ของ openGym จะโหลดขึ้นมา

ตำแหน่งจัดเก็บข้อมูลและการสำรองข้อมูลเพื่อความปลอดภัย

ข้อมูลทั้งหมดอยู่ในไดเรกทอรี ./data ซึ่งถูก mount เข้าไปในคอนเทนเนอร์ API ที่ตำแหน่ง /data โดยมีไฟล์ 4 ประเภท ได้แก่ db.json ซึ่งเก็บโปรไฟล์และข้อมูลรับรอง passkey สาธารณะ, state-<uid>.json ซึ่งเก็บกิจวัตร การออกกำลังกาย และน้ำหนักตัวของผู้ใช้แต่ละคน, secret ซึ่งเป็นคีย์สำหรับ session cookie และ vapid.json ซึ่งเก็บคีย์สำหรับการแจ้งเตือนแบบ push ที่สร้างขึ้นในการรันครั้งแรก

cd /opt/opengym
docker compose stop api
tar czf ~/opengym-$(date +%F).tar.gz data/
docker compose start api

ให้หยุดการทำงานของ API ก่อนเสมอ เนื่องจาก tar จะคัดลอกไฟล์ในขณะที่ API อาจกำลังเขียนข้อมูลอยู่ ซึ่งหากไฟล์ JSON ถูกคัดลอกไปเพียงบางส่วน จะทำให้ไฟล์เสียหายเมื่อนำกลับมาใช้งาน การหยุดและเริ่มการทำงานใหม่ใช้เวลาเพียงประมาณ 2 วินาที จากนั้นให้คัดลอกไฟล์สำรองออกจากเซิร์ฟเวอร์ เพราะไฟล์สำรองที่เก็บไว้บน VPS จะสูญหายไปพร้อมกับ VPS หากเกิดความเสียหาย ให้ละเว้น media/ ออกจากการสำรองข้อมูล เนื่องจากเป็นไฟล์รูปภาพการออกกำลังกายขนาด 140 MB ซึ่งงานจัดการสื่อสามารถดาวน์โหลดใหม่ได้โดยไม่มีค่าใช้จ่าย

การกู้คืนข้อมูลทำได้โดยการแตกไฟล์ tar ลงใน path เดิมบนโฮสต์ที่ให้บริการโดเมนเดียวกัน เนื่องจาก passkey ที่เก็บไว้ในโทรศัพท์ของคุณจะถูกจำกัดขอบเขตไว้ที่ RP ID ที่สร้างขึ้น ดังนั้นการกู้คืนไปยัง hostname ใหม่จะทำให้คุณได้ฐานข้อมูลที่ใช้งานได้ แต่จะไม่มีใครสามารถเข้าสู่ระบบได้ คุณต้องใช้โดเมนเดิม หรือวางแผนที่จะลงทะเบียน passkey ใหม่ทั้งหมด หลักการเดียวกันนี้ใช้กับทุกบริการที่คุณรัน และ การสำรองข้อมูลและการอัปเกรด Docker Compose stack ได้ครอบคลุมขั้นตอนการปฏิบัติงานทั่วไปไว้แล้ว

เซิร์ฟเวอร์ MCP เป็นแบบอ่านได้อย่างเดียวและทำงานบนเครื่องของคุณ

MCP (model context protocol) คือวิธีการที่ไคลเอนต์อย่าง Claude Desktop หรือ Cursor ใช้สื่อสารกับเซิร์ฟเวอร์เครื่องมือภายในเครื่อง openGym มีมาให้ใน mcp/ โดยไม่ได้เป็นส่วนหนึ่งของไฟล์ compose ไม่ใช่คอนเทนเนอร์ และไม่ได้เปิดพอร์ตใดๆ ไคลเอนต์จะเริ่มการทำงานของมันในฐานะกระบวนการลูก (child process) และสื่อสารผ่าน stdio ซึ่งเป็นเหตุผลที่ README ระบุว่ามันไม่เคยส่งข้อมูลออกจากเครื่องของคุณ

ติดตั้งในที่ที่ไคลเอนต์ทำงาน ไม่ใช่บนเซิร์ฟเวอร์:

cd openGym/mcp
npm install

จากนั้นเพิ่มลงใน claude_desktop_config.json:

{
  "mcpServers": {
    "opengym": {
      "command": "node",
      "args": ["/absolute/path/to/openGym/mcp/src/index.js"],
      "env": {
        "OPENGYM_DATA": "/absolute/path/to/openGym/data",
        "OPENGYM_UID": "<your-uid>"
      }
    }
  }
}

OPENGYM_UID เป็นทางเลือกสำหรับการติดตั้งแบบผู้ใช้คนเดียว ซึ่งเซิร์ฟเวอร์จะตรวจพบโปรไฟล์เดียวที่พบ มันเปิดเผยเครื่องมือ 8 รายการ: list_routines, get_routine, get_week_plan, list_workouts, get_workout, get_bodyweight, estimate_1rm และ muscle_balance ทุกรายการเป็นแบบอ่านเท่านั้น ไม่มีรายการใดที่เขียนข้อมูลได้ ดังนั้นผู้ช่วยจึงสามารถตอบได้ว่าสัปดาห์ที่แล้วคุณยกน้ำหนักไปเท่าไหร่ แต่ไม่สามารถบันทึกเซต แก้ไขตารางฝึก หรือลบข้อมูลใดๆ ได้

นี่คือส่วนที่ผู้อ่านที่ใช้ VPS ต้องจัดการ OPENGYM_DATA คือพาธของระบบไฟล์ และข้อมูลของคุณอยู่บน VPS ในขณะที่ไคลเอนต์ AI อยู่บนแล็ปท็อปของคุณ มีสองทางเลือกที่ตรงไปตรงมาสำหรับกรณีนี้:

  1. คัดลอกข้อมูลลงมาและชี้เซิร์ฟเวอร์ไปที่สำเนา: rsync -a --delete user@gym.example.com:/opt/opengym/data/ ~/opengym-data/ จากนั้นตั้งค่า OPENGYM_DATA เป็น ~/opengym-data เนื่องจากเซิร์ฟเวอร์อ่านได้อย่างเดียว การคัดลอกจึงไม่ทำให้ข้อมูลสูญหาย ให้รัน rsync อีกครั้งเมื่อต้องการข้อมูลล่าสุด
  2. รันเซิร์ฟเวอร์ผ่าน ssh โดยตั้งค่า command เป็น ssh และ args เป็น ["-T", "user@gym.example.com", "OPENGYM_DATA=/opt/opengym/data node /opt/opengym/mcp/src/index.js"] วิธีนี้ต้องติดตั้ง Node บน VPS และต้องใช้การล็อกอินที่ไม่แสดงผลลัพธ์ใดๆ ออกทาง stdout เพราะ stdout คือช่องทางของโปรโตคอล

หาก cat data/db.json ส่งค่ากลับมาเป็น Permission denied แสดงว่าคอนเทนเนอร์ API เขียนไฟล์เหล่านั้นด้วยสิทธิ์ root และบัญชีล็อกอินของคุณไม่สามารถอ่านได้ ให้คัดลอกไฟล์เหล่านั้นด้วย sudo หรือเปลี่ยนความเป็นเจ้าของไฟล์บนโฮสต์ สำหรับเซิร์ฟเวอร์ที่ต้องการให้ฟังผ่านเครือข่ายแทนที่จะเป็น stdio โปรดดู การรันเซิร์ฟเวอร์ MCP บน VPS

openGym หรือ wger: คุณควรเลือกใช้งานตัวไหน?

wger เป็นตัวเลือกที่เป็นที่ยอมรับในกลุ่มนี้ และเป็นซอฟต์แวร์ที่มีขนาดใหญ่กว่ามาก สแต็กการทำงานแบบ compose ของมันประกอบด้วย gunicorn ที่ให้บริการแอปพลิเคชัน Django, PostgreSQL, Redis และ Celery worker โดยมี nginx ทำหน้าที่เป็น reverse proxy อยู่เบื้องหน้า สิ่งที่คุณจะได้รับเป็นการแลกเปลี่ยนคือระบบติดตามโภชนาการและส่วนประกอบอาหาร, REST API ที่มีเอกสารประกอบครบถ้วน, ฐานข้อมูลท่าออกกำลังกายขนาดใหญ่จากชุมชน และฟีเจอร์สำหรับเทรนเนอร์ในการจัดการแผนการฝึกให้ผู้อื่น

openGym ประกอบด้วยคอนเทนเนอร์ 2 ตัว, โฟลเดอร์ไฟล์ JSON และไม่มีบัญชีผู้ใช้ที่ต้องดูแลนอกเหนือจากการใช้ passkeys นี่คือความแตกต่างทั้งหมด

เลือกใช้งาน wger หากคุณต้องการติดตามอาหารควบคู่ไปกับการฝึกซ้อม หรือหากคุณต้องการ API สำหรับพัฒนาต่อยอด เลือกใช้งาน openGym หากคุณต้องการสแต็กที่มีขนาดเล็กพอที่จะอ่านโค้ดทั้งหมดได้ภายในบ่ายวันเดียว และต้องการระบบล็อกอินที่ไม่ต้องใช้รหัสผ่านให้เสี่ยงต่อการรั่วไหล ราคาที่ต้องจ่ายสำหรับทางเลือกนี้คือความสมบูรณ์ของซอฟต์แวร์: ณ วันที่ 19 สิงหาคม 2026 รุ่นแรกของ openGym มีอายุเพียงหนึ่งเดือน ในขณะที่ wger มีประวัติการปล่อยรุ่นอัปเดตมานานหลายปี ให้ตรึงเวอร์ชัน (pin version) ไว้, หมั่นสำรองข้อมูล และอ่านบันทึกการเปลี่ยนแปลง (release notes) ก่อนการอัปเดตทุกครั้ง

หากคุณยังตัดสินใจไม่ได้ว่าอะไรควรค่าแก่การติดตั้งบนเซิร์ฟเวอร์ อะไรที่น่าทำ self-hosting ในปี 2026 ได้ครอบคลุมถึงข้อดีข้อเสียต่างๆ ไว้แล้ว และแอปนี้สามารถใช้งานร่วมกับ Mealie สำหรับจัดการสูตรอาหาร หรือ Actual Budget สำหรับจัดการการเงิน บน VPS ขนาดเล็กเครื่องเดียวกันได้อย่างลงตัว

การอัปเดตโดยไม่สูญเสียข้อมูล

cd /opt/opengym
docker compose stop api
tar czf ~/opengym-$(date +%F).tar.gz data/
docker compose start api
git fetch --tags

ตรวจสอบ release ที่คุณต้องการด้วย git checkout v<new> จากนั้นรัน docker compose up -d --build เพื่อให้ container ถูกสร้างใหม่จาก tag นั้น การสำรองข้อมูลต้องทำเป็นอันดับแรกเสมอ เนื่องจากขั้นตอนการกู้คืนไฟล์ JSON บนดิสก์นั้นใช้เพียงคำสั่ง tar เดียวและใช้เวลาเพียงไม่กี่วินาที

FAQ

ทำไม openGym ถึงไม่แสดงหน้าต่างให้ใส่ passkey บนโทรศัพท์ของฉัน?

เบราว์เซอร์ปฏิเสธที่จะสร้าง credential เนื่องจากคุณกำลังใช้งานบน http:// หรือบน IP address โดยตรง เช่น http://192.168.1.20:8080 เบราว์เซอร์จะอนุญาตให้ใช้ passkey ได้เฉพาะบน origin ที่เป็น HTTPS เท่านั้น โดยมี localhost เป็นข้อยกเว้นเพียงกรณีเดียว ให้ติดตั้ง openGym ไว้หลัง reverse proxy ที่มี certificate จริงสำหรับ hostname จริง จากนั้นตั้งค่า RP_ID=gym.example.com และ ORIGIN=https://gym.example.com ใน .env แล้วรัน docker compose up -d เพื่อให้ container โหลดค่าใหม่ หากหน้าต่างแสดงขึ้นมาแต่การล็อกอินแจ้งเตือน verification failed แสดงว่าค่าทั้งสองไม่ตรงกับ URL ในแถบที่อยู่ของเบราว์เซอร์แบบพอดี

openGym เก็บข้อมูลของฉันไว้ที่ไหน และฉันจะสำรองข้อมูลอย่างไร?

ข้อมูลถูกเก็บไว้ในไดเรกทอรี ./data ซึ่งอยู่ถัดจากไฟล์ compose โดยถูก mount เข้าไปใน API container ในชื่อ /data ภายในประกอบด้วย db.json สำหรับโปรไฟล์และ public passkey credential, ไฟล์ state-<uid>.json หนึ่งไฟล์ต่อผู้ใช้หนึ่งคนสำหรับบันทึกการออกกำลังกายและน้ำหนักตัว, secret สำหรับ session cookie key และ vapid.json สำหรับ push notification key ให้สำรองข้อมูลด้วยการรัน docker compose stop api ตามด้วย tar czf ~/opengym-$(date +%F).tar.gz data/ และ docker compose start api จากนั้นคัดลอกไฟล์ archive ออกจากเซิร์ฟเวอร์ คุณสามารถข้าม media/ ไปได้ เนื่องจากเป็นไฟล์รูปภาพการออกกำลังกายขนาด 140 MB ซึ่ง media job จะดาวน์โหลดใหม่เองโดยอัตโนมัติ

Claude สามารถอ่านประวัติการออกกำลังกายใน openGym ของฉันได้หรือไม่?

ได้ ผ่านทาง MCP server ที่เป็นตัวเลือกเสริมในไดเรกทอรี mcp/ โดยทำได้เฉพาะการอ่านเท่านั้น มันจะเปิดเผยเครื่องมือ 8 รายการที่ครอบคลุมกิจวัตร, แผนรายสัปดาห์, บันทึกการออกกำลังกาย, น้ำหนักตัว, ค่าประมาณ one-rep max และความสมดุลของกล้ามเนื้อ โดยไม่มีเครื่องมือใดที่สามารถเขียนข้อมูลกลับได้ ทั้งนี้มันไม่ใช่ container และไม่ได้เปิดพอร์ตใดๆ: ไคลเอนต์ของคุณจะเริ่มการทำงานผ่าน stdio และอ่านไฟล์ JSON ที่ OPENGYM_DATA โดยตรง เนื่องจากเป็น path ในระบบไฟล์ การรัน openGym บน VPS จึงหมายถึงคุณต้องซิงค์สำเนาของ data/ ลงมายังเครื่องที่รันไคลเอนต์ หรือเรียกใช้งานเซิร์ฟเวอร์ผ่าน ssh จากการตั้งค่าของไคลเอนต์

ฉันควรเลือก self-host openGym หรือ wger?

เลือก wger หากคุณต้องการติดตามโภชนาการและอาหารควบคู่ไปกับบันทึกการฝึกซ้อม หรือต้องการ REST API ที่มีเอกสารประกอบเพื่อนำไปพัฒนาต่อ มันใช้ stack ที่ใหญ่กว่า ได้แก่ Django ภายใต้ gunicorn, PostgreSQL, Redis และ Celery worker ที่อยู่หลัง nginx เลือก openGym หากคุณต้องการเพียงสอง container, ไฟล์ JSON ที่คุณสามารถอ่านได้ด้วย cat และการล็อกอินด้วย passkey โดยไม่ต้องจัดการรหัสผ่าน ณ วันที่ 19 สิงหาคม 2026 รุ่นแรกของ openGym ที่มีการติดแท็กมีอายุเพียงหนึ่งเดือน ดังนั้นควรตรวจสอบ git tag และสำรองข้อมูล data/ ก่อนการอัปเดตทุกครั้ง