SSD Nodes Learn Hosting plans →
คู่มือ Matt Connorโดย Matt Connor

วิธีติดตั้ง Open Connector แบบ Self-host สำหรับ AI Agent

เรียนรู้วิธีติดตั้ง Open Connector บน VPS เพื่อจัดการ OAuth และโทเค็นสำหรับ AI Agent อย่างปลอดภัย ป้องกันปัญหาโทเค็นรั่วไหลด้วยการตั้งค่า TLS และการสำรองข้อมูล SQLite

หน้าที่ของ Open Connector สำหรับ AI agent

การติดตั้ง Open Connector ด้วยตนเองช่วยสร้างเกตเวย์การยืนยันตัวตนเพียงจุดเดียวระหว่าง AI agent ของคุณกับ API ของซอฟต์แวร์แบบ SaaS ทุกตัวที่เรียกใช้งาน ทำให้ agent ไม่จำเป็นต้องถือครอง token ของผู้ให้บริการโดยตรง Open Connector เป็นเกตเวย์แบบ source-available จาก OOMOL Lab ซึ่งปัจจุบันอยู่ภายใต้สัญญาอนุญาต Apache 2.0 ฉบับแก้ไขที่มีเงื่อนไขเพิ่มเติม โดยเวอร์ชัน v1.9.4 ลงไปจะยังคงเป็น Apache 2.0 ส่วนเวอร์ชัน v1.9.5 เป็นต้นไปมีการเปลี่ยนแปลงเงื่อนไข หากคุณให้บริการแบบ hosted หรือ managed service ที่มีมูลค่าหลักมาจากฟังก์ชันการทำงานของ OpenConnector คุณจำเป็นต้องขอใบอนุญาตเชิงพาณิชย์จาก OOMOL ซอฟต์แวร์นี้ทำงานเป็น container เดียว เก็บสถานะไว้ในไฟล์ SQLite ไฟล์เดียว และเปิดเผยการทำงานของผู้ให้บริการผ่าน HTTP และ MCP (model context protocol)

ปัญหาจะเริ่มขึ้นเมื่อมีการเชื่อมต่อตัวที่สอง ผู้ให้บริการแต่ละรายมีขั้นตอน OAuth (open authorization) ของตนเอง มีอายุการใช้งานของ refresh token ที่ต่างกัน และมีชื่อ scope ที่ไม่เหมือนกัน การเชื่อมต่อผู้ให้บริการห้าแห่งเข้ากับ agent ด้วยตนเองหมายถึงการต้องสร้าง redirect handler ห้าชุด, ที่เก็บข้อมูลประจำตัวห้าแห่ง และลูปการรีเฟรช token ห้าชุดที่ต้องทำงานก่อนที่ token จะหมดอายุ แทบไม่มีใครเขียนโค้ดเหล่านั้นด้วยตัวเอง ส่วนใหญ่มักจะสร้าง personal access token แบบอายุการใช้งานยาวนานขึ้นมาหนึ่งชุดต่อหนึ่งบริการ แล้วนำไปวางไว้ในไฟล์ตั้งค่าของ agent, ไฟล์ environment หรือแม้แต่ใน prompt โดยตรง ซึ่ง token ดังกล่าวจะถูกอ่านได้โดยเครื่องมือทุกตัวที่ agent เรียกใช้ และจะไปปรากฏอยู่ใน transcript ซึ่งเป็นความล้มเหลวที่อธิบายไว้ใน การเก็บความลับให้พ้นจาก AI agents

เกตเวย์การยืนยันตัวตนจะแยกข้อมูลประจำตัวออกเป็นสองส่วน เกตเวย์จะทำหน้าที่จัดเก็บข้อมูลประจำตัวของผู้ให้บริการและดำเนินการตามขั้นตอน OAuth ส่วน agent จะได้รับเพียง runtime token ที่ใช้ได้เฉพาะกับเกตเวย์เท่านั้น เมื่อ agent เรียกใช้การทำงาน เกตเวย์จะโหลดข้อมูลประจำตัวที่จัดเก็บไว้ แล้วแทรกข้อมูลนั้นลงในคำขอขาออกที่ฝั่งเซิร์ฟเวอร์ จากนั้นจึงส่งกลับเฉพาะเนื้อหาการตอบกลับเท่านั้น agent จะไม่ได้รับ access token ของผู้ให้บริการ ดังนั้นหาก transcript ของ agent รั่วไหล สิ่งที่คุณเสียไปจะมีเพียง runtime token ที่เพิกถอนได้ แทนที่จะเป็นการเข้าถึงบัญชี GitHub ของคุณทั้งหมด

แคตตาล็อกระบุว่ารองรับผู้ให้บริการมากกว่า 1,000 ราย และมี action ที่สร้างไว้ล่วงหน้ากว่า 10,000 รายการ ซึ่งเป็นตัวเลขที่โครงการระบุเองและไม่สามารถตรวจสอบจากภายนอกได้ สิ่งที่คุณสามารถตรวจสอบได้คือรูปแบบการทำงาน: หนึ่ง HTTP endpoint ต่อหนึ่ง action, หนึ่งการเชื่อมต่อที่จัดเก็บไว้ต่อหนึ่งผู้ให้บริการ และหนึ่ง token ต่อหนึ่ง agent หากฝั่งของ agent ยังเป็นเรื่องใหม่และคำศัพท์อย่าง tool call หรือ MCP server ยังไม่มีนิยามที่ชัดเจน เส้นทางการเรียนรู้ใน วิธีเรียนรู้ AI agents ตั้งแต่เริ่มต้น จะช่วยสร้างลูปการทำงาน, เครื่องมือ และนิสัยด้านความปลอดภัยที่เกตเวย์ประเภทนี้คาดหวังว่าคุณควรมีอยู่แล้ว

เหตุผลที่ควร self-host Open Connector แทนการใช้บริการ connector แบบ hosted

บริการ connector แบบ hosted ทำงานในลักษณะเดียวกัน และเป็นผู้เก็บ refresh token สำหรับทุกผู้ให้บริการที่คุณเชื่อมต่อไว้ refresh token ของ Google หรือ GitHub เปรียบเสมือนกุญแจที่มีอายุการใช้งานยาวนานสำหรับเข้าถึงอีเมลและ repository ของคุณ หากบริการเหล่านั้นถูกเจาะ ข้อมูลของคุณก็จะถูกเจาะไปด้วย การทำ self-hosting จะย้ายข้อมูลเหล่านี้ไปเก็บไว้ใน SQLite บนเครื่องที่คุณเช่าและดูแลเอง โดยถูกล็อกไว้ด้วยคีย์ที่ไม่เคยออกจากเครื่องของคุณ

จงตระหนักถึงต้นทุนก่อนเริ่มดำเนินการ VPS เครื่องนี้จะกลายเป็นเซิร์ฟเวอร์ที่มีค่าที่สุดที่คุณใช้งาน เนื่องจากมันเก็บข้อมูลรับรองการเข้าถึงของบริการต่างๆ ไว้ในไฟล์เดียว จึงควรได้รับการดูแลเช่นเดียวกับโฮสต์ของโปรแกรมจัดการรหัสผ่าน (password manager) เช่น การตั้งค่า firewall ให้เปิดเฉพาะพอร์ต 443, ไม่ใช้บัญชีผู้ใช้ร่วมกัน, มีการสำรองข้อมูลที่คุณเคยทดสอบกู้คืนจริงแล้ว และมีการแจ้งเตือนเมื่อเซิร์ฟเวอร์หยุดตอบสนอง หากคุณไม่คิดจะวางคลังรหัสผ่านของคุณไว้บนเครื่องนี้ ก็ไม่ควรติดตั้ง connector ไว้บนเครื่องนี้เช่นกัน

กำหนดเวอร์ชันให้คงที่ก่อนเริ่มติดตั้ง

Open Connector ยังเป็นซอฟต์แวร์ใหม่ คู่มือนี้กำหนดให้ใช้ v1.3.3 ซึ่งเผยแพร่เมื่อวันที่ 30 กรกฎาคม 2026 เป็นเวอร์ชันสำหรับการติดตั้ง ณ วันที่ 1 สิงหาคม 2026 โดยปัจจุบันไม่ใช่เวอร์ชันล่าสุดแล้ว ทั้งนี้ registry ยังมีการเผยแพร่ tag tip ซึ่งสร้างจาก commit ล่าสุดบน main อีกด้วย

สำหรับโปรเจกต์ที่ยังใหม่เช่นนี้ tag ที่มีการเปลี่ยนแปลงบ่อยมักจะขยับเวอร์ชันอยู่เสมอ การใช้ docker compose pull ที่ข้ามไปถึง 2 เวอร์ชันอาจทำให้ endpoint ที่ agent ของคุณใช้งานอยู่เกิดการเปลี่ยนแปลง และคุณจะต้องเสียเวลาทั้งคืนเพื่อแก้ไขปัญหาที่เข้าใจว่าเป็นปัญหาของ agent ดังนั้น ให้กำหนด image ไว้ที่ release tag และค่อยอัปเกรดเมื่อคุณตัดสินใจทำหลังจากอ่านบันทึกประจำรุ่น (release notes) แล้วเท่านั้น

การติดตั้ง Open Connector หลัง TLS บน VPS ของคุณเอง

ก่อนที่คอนเทนเนอร์จะเริ่มทำงาน คุณต้องมีสิ่งต่อไปนี้:

  • Docker Engine 28.0.0 หรือใหม่กว่า พร้อมปลั๊กอิน Compose บน Ubuntu 24.04 หรือระบบที่ใกล้เคียงกัน
  • ชื่อโฮสต์ที่มี A record ชี้มาที่ VPS นี้ เช่น connect.example.com
  • reverse proxy ที่ทำ TLS (transport layer security) termination สำหรับชื่อโฮสต์นั้นอยู่แล้ว
  • ค่าความลับแบบสุ่มสองค่า ซึ่งสร้างขึ้นตามด้านล่างนี้

Traefik reverse proxy สำหรับแอป Docker Compose หลายตัว ครอบคลุมฝั่งของ proxy ส่วนการตั้งค่า certificate ตั้งแต่ต้นจนจบสำหรับแอปเดียวอยู่ในคู่มือ n8n บน VPS ด้วย Docker และ HTTPS

ให้สร้างค่าความลับก่อน encryption key จะทำหน้าที่ล็อกข้อมูลประจำตัวที่จัดเก็บไว้ ส่วน admin token จะทำหน้าที่ป้องกันเว็บคอนโซลและพื้นที่ทั้งหมดของ /api ทั้งสองค่าไม่มีค่าเริ่มต้น และระบบจะเริ่มทำงานได้โดยไม่มีค่าเหล่านี้

mkdir -p ~/open-connector && cd ~/open-connector
umask 077
printf 'OOMOL_CONNECT_ENCRYPTION_KEY=%s\n' "$(openssl rand -base64 32)" > .env
printf 'OOMOL_CONNECT_ADMIN_TOKEN=%s\n' "$(openssl rand -base64 32)" >> .env
chmod 600 .env

คัดลอกค่าทั้งสองลงในโปรแกรมจัดการรหัสผ่านของคุณทันที ก่อนการเริ่มทำงานครั้งแรก encryption key ไม่มีช่องทางกู้คืน และเหตุผลระบุอยู่ในรายการความล้มเหลวด้านล่าง

ตอนนี้คือ compose.yaml ซึ่งแตกต่างจากตัวอย่างต้นฉบับในสองจุด และทั้งสองจุดมีความสำคัญ

services:
  connector:
    image: ghcr.io/oomol-lab/open-connector:v1.3.3
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:3000"
    volumes:
      - connector-data:/app/data
    environment:
      OOMOL_CONNECT_DATA_DIR: /app/data
      OOMOL_CONNECT_ORIGIN: "https://connect.example.com"
      OOMOL_CONNECT_ENCRYPTION_KEY: "${OOMOL_CONNECT_ENCRYPTION_KEY:?set this in .env}"
      OOMOL_CONNECT_ADMIN_TOKEN: "${OOMOL_CONNECT_ADMIN_TOKEN:?set this in .env}"

volumes:
  connector-data:

การเปลี่ยนแปลงแรกคือการระบุ tag ที่แน่นอนแทนที่ latest ส่วนการเปลี่ยนแปลงที่สองคือพอร์ต ไฟล์ต้นฉบับเผยแพร่พอร์ต 3000:3000 ซึ่งผูกกับทุกอินเทอร์เฟซบนโฮสต์ Docker จะเขียนพอร์ตที่เผยแพร่ลงในตาราง NAT (network address translation) ก่อนที่ ufw filter chain จะเห็นแพ็กเก็ต ดังนั้น ufw deny 3000 จึงไม่ปิดพอร์ตนั้น ซึ่งเป็นกับดักที่อธิบายไว้ใน เหตุใดพอร์ต Docker จึงข้าม ufw การเขียน 127.0.0.1:3000:3000 จะเผยแพร่บนอินเทอร์เฟซ loopback เท่านั้น และ reverse proxy ของคุณจะเชื่อมต่อจากโฮสต์เดียวกัน ก่อน Docker Engine 28.0.0 โฮสต์บน L2 segment เดียวกันสามารถเข้าถึงพอร์ตที่เผยแพร่ไปยัง localhost ได้ ซึ่งเป็นเหตุผลว่าทำไมคู่มือนี้จึงกำหนดให้ใช้ 28.0.0 หรือใหม่กว่า

:? ระบุว่าตัวแปรแต่ละตัวเป็นค่าบังคับ ดังนั้น stack จะปฏิเสธที่จะเริ่มทำงานเมื่อ .env หายไป แทนที่จะเริ่มทำงานโดยไม่มีการเข้ารหัสข้อมูลประจำตัว การเก็บค่าไว้ใน .env แทนที่จะเก็บในไฟล์ compose เป็นรูปแบบที่มาจาก ไฟล์ env และความลับของ Docker Compose ให้เก็บ /v1 และ /mcp ไว้เป็นส่วนตัวที่ reverse proxy จนกว่าคุณจะสร้าง runtime token แรกตามด้านล่างนี้

docker compose up -d
docker compose logs -n 30 connector
curl -s http://127.0.0.1:3000/health
sudo ss -tlnp | grep 3000

/health จะตอบสนองต่อ { "ok": true } เมื่อ runtime เริ่มทำงานแล้ว ss ต้องแสดงผลเป็น 127.0.0.1:3000 บรรทัดที่อ่านว่า 0.0.0.0:3000 หมายความว่า listener ถูกผูกไว้กับทุก IPv4 interface แต่ไม่ได้พิสูจน์ว่าสามารถเข้าถึงได้จากอินเทอร์เน็ต: ไฟร์วอลล์ต้นทางหรือกฎใน chain DOCKER-USER ของ Docker ยังคงสามารถบล็อกทราฟฟิกจากภายนอกได้ หากการตรวจสอบสถานะ (health check) แจ้งว่า Connection refused หมายความว่าคอนเทนเนอร์ยังไม่พร้อมรับการเชื่อมต่อ ดังนั้นให้อ่าน log ก่อนที่คุณจะไปยุ่งกับ proxy

Traefik labels สำหรับบริการเดียวกัน
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.connector.rule=Host(`connect.example.com`)"
      - "traefik.http.routers.connector.entrypoints=websecure"
      - "traefik.http.routers.connector.tls.certresolver=le"
      - "traefik.http.services.connector.loadbalancer.server.port=3000"

เมื่อ Traefik ทำงานใน Docker บนโฮสต์เดียวกัน ให้เชื่อมต่อบริการนี้เข้ากับเครือข่ายของ Traefik และลบบล็อก ports: ออก เพราะ Traefik สามารถเข้าถึงคอนเทนเนอร์ผ่านเครือข่ายภายในได้โดยไม่ต้องเผยแพร่พอร์ตใดๆ ออกมาที่โฮสต์ certresolver=le ต้องตรงกับชื่อ resolver ในการตั้งค่าแบบ static ของ Traefik มิฉะนั้น router จะทำงานโดยไม่มี certificate

เหตุใด OAuth callback จึงจำเป็นต้องใช้ origin ที่ถูกต้อง

OOMOL_CONNECT_ORIGIN คือการตั้งค่าที่ผู้ใช้มักข้ามไป และการข้ามขั้นตอนนี้จะทำให้ OAuth ทำงานผิดพลาดในลักษณะที่ดูเหมือนเป็นบั๊กของผู้ให้บริการ ตัว runtime จะสร้าง redirect URI จาก origin นั้นในรูปแบบ <origin>/oauth/callback หากไม่ได้ตั้งค่าไว้ origin จะถูกกำหนดเป็นค่าเริ่มต้นที่ http://localhost:3000 ส่งผลให้ runtime ส่ง redirect URI ไปยังผู้ให้บริการเป็น http://localhost:3000/oauth/callback ในขณะที่แอป OAuth ของคุณลงทะเบียนไว้เป็น https://connect.example.com/oauth/callback เมื่อสตริงทั้งสองไม่ตรงกัน GitHub จึงตอบกลับมาว่า:

The redirect_uri MUST match the registered callback URL for this application.

ผู้ให้บริการ OAuth จะ redirect เบราว์เซอร์กลับไปยัง URI ดังกล่าว ดังนั้นที่อยู่นั้นจะต้องสามารถเข้าถึงได้โดยเบราว์เซอร์นั้นๆ OAuth ไม่ได้บังคับว่าต้องใช้ public hostname เสมอไป โดย OpenConnector ได้ระบุเอกสารเกี่ยวกับ GitHub callback ไว้ที่ http://localhost:3000/oauth/callback การติดตั้งบน VPS นี้ใช้ hostname และ certificate เพื่อให้เบราว์เซอร์เข้าถึง gateway ได้ที่ HTTPS origin ของมัน โปรดตั้งค่า origin ก่อนการเริ่มทำงานครั้งแรก เนื่องจากค่านี้จะถูกอ่านในขณะเริ่มต้นระบบ หลังจากแก้ไข .env หรือ compose.yaml แล้ว ให้รัน docker compose up -d อีกครั้งเพื่อนำการตั้งค่าไปใช้

เชื่อมต่อผู้ให้บริการรายแรกของคุณผ่าน OAuth

สร้างแอป OAuth ที่ฝั่งผู้ให้บริการก่อน สำหรับ GitHub ให้ไปที่เส้นทาง Settings ตามด้วย Developer settings จากนั้นเลือก OAuth Apps และ New OAuth App กำหนด URL สำหรับ authorization callback เป็น https://connect.example.com/oauth/callback เก็บ client ID และ client secret ไว้

การเรียกใช้งาน /api ทุกครั้งจะต้องใช้ admin token ดังนั้นให้ export ค่านี้ไว้สำหรับ session ของ shell หนึ่งครั้ง

export ADMIN_TOKEN='paste-the-admin-token'
curl -s https://connect.example.com/api/oauth/configs \
  -H "authorization: Bearer $ADMIN_TOKEN"

รายการดังกล่าวจะแสดง redirect URI ที่ runtime คาดหวังสำหรับผู้ให้บริการแต่ละราย ซึ่งเป็นวิธีตรวจสอบที่รวดเร็วที่สุดว่าค่า origin ที่คุณตั้งไว้มีผลแล้ว หากยังคงแสดงค่าเป็น localhost แสดงว่า container กำลังทำงานด้วยค่าเดิม และขั้นตอน OAuth จะล้มเหลวในขั้นตอนสุดท้าย

จัดเก็บ client credentials จากนั้นเริ่มกระบวนการ authorization

curl -s -X PUT https://connect.example.com/api/oauth/configs/github \
  -H "authorization: Bearer $ADMIN_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"clientId":"...","clientSecret":"..."}'

curl -s -X POST https://connect.example.com/api/oauth/authorizations \
  -H "authorization: Bearer $ADMIN_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"service":"github"}'

การเรียกใช้งานครั้งที่สองจะส่งคืนค่า authorizationUrl ให้เปิด URL ดังกล่าวในเบราว์เซอร์ อนุมัติขอบเขตการเข้าถึง (scopes) แล้วผู้ให้บริการจะส่งเบราว์เซอร์กลับไปยัง /oauth/callback ซึ่ง runtime จะทำการแลกเปลี่ยน code และจัดเก็บ credential ไว้ เว็บคอนโซลที่ origin ของคุณจะดำเนินการตามขั้นตอนเดียวกันผ่านฟอร์ม โดยใช้ admin token เดียวกัน สำหรับผู้ให้บริการที่ใช้ API key แบบปกติจะข้ามขั้นตอนเหล่านี้ทั้งหมด โดยการใช้ PUT /api/connections/<service> ร่วมกับ {"authType":"api_key","values":{"apiKey":"..."}} จะเป็นการจัดเก็บ key โดยตรง

กำหนด runtime token ให้ agent แต่ละตัว แทนการใช้ credential จริง

Agent จะยืนยันตัวตนกับ gateway โดยใช้ runtime token ซึ่งสร้างขึ้นผ่าน admin API

curl -s -X POST https://connect.example.com/api/runtime-tokens \
  -H "authorization: Bearer $ADMIN_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"name":"research-agent"}'

การตอบกลับจะมี token ที่ขึ้นต้นด้วย oct_ ให้สร้าง token หนึ่งชุดต่อ agent หนึ่งตัว และตั้งชื่อตาม agent นั้นๆ เนื่องจากหากคุณเพิกถอน token โดยไม่ทราบว่าของ agent ใด คุณจะต้องเพิกถอนทั้งหมด หลังจากนั้น agent จะเรียกใช้งาน action ต่างๆ ผ่าน HTTP ปกติ

curl -s -X POST https://connect.example.com/v1/actions/github.get_current_user \
  -H "authorization: Bearer oct_..." \
  -H 'content-type: application/json' \
  -d '{"input":{}}'

การตอบกลับที่ถูกต้องจะเป็น envelope ที่มีฟิลด์ success เป็น true โดยมี payload ของผู้ให้บริการอยู่ภายใต้ data ซึ่งในคำตอบนี้จะไม่มี GitHub token ปรากฏอยู่ สำหรับ MCP client ให้ชี้ไปที่ https://connect.example.com/mcp โดยใช้ bearer header เดียวกัน และ gateway จะนำเสนอเครื่องมือค้นหา (discovery tools) เช่น search_actions และ execute_action แทนที่จะเป็นเครื่องมือหนึ่งตัวต่อหนึ่ง API ซึ่งช่วยให้รายการเครื่องมือของ agent มีขนาดเล็ก การรัน MCP server บน VPS ครอบคลุมส่วนการเชื่อมต่อในฝั่ง client

ตรวจสอบอีกครั้งก่อนที่คุณจะสรุปงานนี้ ให้ลองเรียก action ซ้ำโดยลบ header authorization ออก เนื่องจากคู่มือเริ่มต้นใช้งานของโปรเจกต์มีการเรียก /v1 โดยไม่มี bearer เลย ดังนั้นการติดตั้งที่ไม่ได้กำหนดค่า runtime auth ไว้จะอนุญาตให้ใครก็ตามที่เข้าถึงพอร์ตได้สามารถสั่งรัน action ต่างๆ ได้ หากการเรียกโดยไม่ยืนยันตัวตนของคุณสำเร็จ คุณมีทางเลือกสองทางคือ กำหนดค่า runtime token แล้วตรวจสอบว่าการเรียกแบบไม่ระบุตัวตนล้มเหลว หรือจำกัดการเข้าถึง /api, /v1 และ /mcp ที่ reverse proxy ให้รับเฉพาะที่อยู่ IP ที่ agent ของคุณใช้งานอยู่เท่านั้น ทั้งนี้ /oauth/callback จะต้องสามารถเข้าถึงได้จากเบราว์เซอร์ที่ใช้ทำ authorization แต่ไม่จำเป็นต้องเปิดให้สาธารณะบนอินเทอร์เน็ตเข้าถึงได้ทั้งหมด

จำกัดรายการคำสั่งให้เหลือเพียงสิ่งที่เอเจนต์จำเป็นต้องใช้

เกตเวย์ที่มีผู้ให้บริการจำนวนมากอยู่เบื้องหลังถือเป็นช่องทางที่กว้างเกินไปสำหรับการส่งต่อให้โมเดลภาษา และช่องทางนี้จะยิ่งกว้างขึ้นทันทีที่โมเดลเริ่มอ่านข้อความที่ไม่ได้เขียนขึ้นเอง เนื่องจากหน้าเว็บที่ส่งกลับมาจาก อินสแตนซ์ SearXNG ของคุณเองที่ตอบกลับการค้นหาเว็บของเอเจนต์ อาจมีคำสั่งที่มุ่งเป้าไปยังการกระทำใดก็ตามที่เอเจนต์นั้นมีสิทธิ์เข้าถึง การยับยั้งชั่งใจแบบเดียวกับที่ทำให้ เอเจนต์เขียนโค้ดเลือกการเปลี่ยนแปลงที่เล็กที่สุดที่ใช้งานได้ ควรนำมาใช้กับสิทธิ์ของเอเจนต์ด้วย นั่นคือให้สิทธิ์เฉพาะคำสั่งจำนวนน้อยที่จำเป็นต่องานจริงๆ เท่านั้น และห้ามให้สิทธิ์เกินกว่านั้น การควบคุมสองประการจะช่วยจำกัดขอบเขตนี้

OOMOL_CONNECT_ALLOWED_ACTIONS รับค่าเป็นรายการที่คั่นด้วยเครื่องหมายจุลภาค (allowlist) และรองรับ service.* รวมถึง * ส่วน OOMOL_CONNECT_BLOCKED_ACTIONS คือรายการที่ไม่อนุญาต (denylist) ซึ่งจะมีลำดับความสำคัญสูงสุด การตั้งค่า allowlist เป็น github.get_current_user,github.list_issues หมายความว่าคำสั่งอื่นทั้งหมดจะถูกปฏิเสธไม่ว่าเอเจนต์จะร้องขออย่างไรก็ตาม ซึ่งนี่คือจุดตัดสินระหว่างความผิดพลาดทั่วไปกับเหตุการณ์ความปลอดภัยร้ายแรง โทเค็นขณะรันไทม์ (runtime tokens) จะมีกฎการกระทำของตนเองเพิ่มเติมจากกฎส่วนกลาง และรายการ allowedProxies ของโทเค็นจะเริ่มต้นด้วยความว่างเปล่า ดังนั้น POST /v1/proxy/:service จะถูกปฏิเสธจนกว่าคุณจะอนุญาตให้ใช้ จุดเชื่อมต่อพร็อกซีนั้นจะส่งคำขอแบบดิบไปยังผู้ให้บริการพร้อมกับแนบข้อมูลประจำตัวของคุณไปด้วย ดังนั้นควรปล่อยให้ว่างไว้เว้นแต่จะมีเอเจนต์เฉพาะตัวที่จำเป็นต้องใช้มันจริงๆ

OOMOL_CONNECT_ALLOW_PRIVATE_NETWORK มีค่าเริ่มต้นเป็น false ซึ่งจะป้องกันไม่ให้การเชื่อมต่อกับผู้ให้บริการที่โฮสต์เองชี้ไปยังที่อยู่ส่วนตัว เช่น บริการ metadata ของคลาวด์บน 169.254.169.254 หรือฐานข้อมูลของคุณที่อยู่ในเครือข่ายเดียวกัน ควรปล่อยให้ค่านี้ปิดไว้ และเปิดใช้งานเฉพาะสำหรับผู้ให้บริการที่คุณโฮสต์ด้วยตนเองเท่านั้น

สำรองข้อมูลเซิร์ฟเวอร์ที่เก็บโทเค็นทั้งหมด

มีสองสิ่งที่สำคัญ และแต่ละอย่างจะไร้ประโยชน์หากขาดอีกสิ่งหนึ่ง ฐานข้อมูลที่ /app/data/connect.sqlite ภายใน volume connector-data ทำหน้าที่เก็บข้อมูลรับรองที่ถูกปิดผนึกไว้ ส่วนกุญแจเข้ารหัสใน .env ใช้สำหรับปลดล็อกข้อมูลเหล่านั้น การสำรองข้อมูล volume โดยไม่มีกุญแจจะไม่สามารถกู้คืนสิ่งใดได้ และการมีกุญแจโดยไม่มี volume ก็ไม่สามารถกู้คืนสิ่งใดได้เช่นกัน ดังนั้นกุญแจควรถูกเก็บไว้ในโปรแกรมจัดการรหัสผ่านของคุณ และ volume ควรถูกรวมอยู่ในรอบการสำรองข้อมูลปกติ

ให้หยุดการทำงานของ container ก่อนที่คุณจะคัดลอกไฟล์ SQLite เนื่องจากสำเนาที่คัดลอกในขณะที่มีการเขียนข้อมูลอาจทำให้ฐานข้อมูลเสียหายเมื่อนำไปกู้คืน

docker volume ls | grep connector-data
docker compose stop connector
docker run --rm -v open-connector_connector-data:/data -v "$PWD":/backup alpine \
  tar czf /backup/connector-data.tgz -C /data .
docker compose start connector

ชื่อของ volume คือชื่อไดเรกทอรีโปรเจกต์ของคุณบวกด้วย _connector-data ซึ่งเป็นเหตุผลว่าทำไมคำสั่งแรกจึงอยู่ที่นั่น ให้คัดลอกชื่อจริงไปวางในคำสั่งที่สาม ส่งไฟล์ archive ออกจาก VPS ด้วย การสำรองข้อมูล restic จาก VPS ซึ่งจะทำการเข้ารหัสไฟล์ก่อนส่งออกไป เพราะไฟล์ archive นั้นคือที่เก็บข้อมูลรับรองทั้งหมด

ระบบ runtime จะเก็บประวัติการทำงานล่าสุดไว้เป็นบันทึกการตรวจสอบ โดยค่าเริ่มต้นจะเก็บไว้ 5,000 รายการ เพื่อให้คอนโซลสามารถแจ้งคุณได้ว่า agent ใดทำอะไรและเมื่อใด บันทึกดังกล่าวเป็นสิ่งแรกที่ควรตรวจสอบเมื่อ agent มีพฤติกรรมผิดปกติ นอกจากนี้ ให้เชื่อมต่อ หน้าสถานะ Uptime Kuma ไปยัง https://connect.example.com/health ด้วย เมื่อ gateway หยุดตอบสนอง agent จะทำงานล้มเหลวในรูปแบบที่ชวนสับสน การทราบว่า gateway ล่มจะช่วยประหยัดเวลาในการอ่านผลลัพธ์จาก agent ไปได้นับชั่วโมง

สิ่งที่มักจะเกิดข้อผิดพลาดและข้อความที่คุณจะพบ

redirect_uri_mismatch ที่ผู้ให้บริการ ต้นทางและ URL สำหรับ callback ที่ลงทะเบียนไว้ไม่ตรงกัน ให้เปรียบเทียบสตริงที่แน่นอนจาก /api/oauth/configs กับการตั้งค่าแอปของผู้ให้บริการ รวมถึงตรวจสอบ https เทียบกับ http และเครื่องหมาย slash ปิดท้าย

ทุกการเรียก /api ส่งค่ากลับเป็น 401 ส่วนหัวของ admin token หายไปหรือสะกดผิด ส่วนหัวดังกล่าวคือ Authorization: Bearer <token> และเว็บคอนโซลจะเรียกขอ token เดียวกันนี้

คอนเทนเนอร์ทำงานได้ แต่ข้อมูลประจำตัวยังคงเป็นข้อความธรรมดา (plain text) นี่คือสิ่งที่เกิดขึ้นเมื่อ OOMOL_CONNECT_ENCRYPTION_KEY ไม่ถูกส่งไปยังคอนเทนเนอร์ เนื่องจากรันไทม์จัดเก็บข้อมูลประจำตัวโดยไม่มีการเข้ารหัสแทนที่จะปฏิเสธการเริ่มทำงาน คุณสามารถตรวจสอบได้ด้วยตนเอง: เชื่อมต่อกับผู้ให้บริการด้วย API key ที่คุณจำได้ จากนั้นค้นหาในฐานข้อมูล

docker compose cp connector:/app/data/connect.sqlite /tmp/connect.sqlite
grep -c 'github_pat_' /tmp/connect.sqlite
shred -u /tmp/connect.sqlite

หากผลลัพธ์มากกว่า 0 หมายความว่าคีย์นั้นไม่มีผล ให้ตรวจสอบว่า .env อยู่ในไดเรกทอรีเดียวกับ compose.yaml และ docker compose config แสดงค่าที่ถูกต้อง เมื่อตั้งค่าคีย์แล้ว การค้นหาแบบเดิมจะส่งค่ากลับเป็น 0 เนื่องจากบันทึกข้อมูลถูกปิดผนึกด้วย AES-256-GCM (มาตรฐานการเข้ารหัสขั้นสูง, คีย์ 256 บิต, โหมด Galois/counter)

ถอดรหัสไม่ได้หลังจากการกู้คืน คีย์การเข้ารหัสถูกเปลี่ยนหรือสูญหาย โดยการออกแบบ คีย์จะไม่ถูกเขียนไว้ข้างข้อมูล ดังนั้นจึงไม่มีช่องทางการกู้คืนและไม่มีการสนับสนุนใดๆ ที่จะช่วยได้ คุณต้องเชื่อมต่อผู้ให้บริการใหม่ทั้งหมด การหมุนเวียนคีย์ (rotation) รองรับผ่านตัวแปรคีย์แยกต่างหากและคำสั่งจัดการข้อมูลในรันไทม์ ดังนั้นโปรดอ่านบันทึกประจำรุ่น (release notes) ปัจจุบันก่อนที่คุณจะหมุนเวียนคีย์ใดๆ

เอเจนต์ได้รับข้อผิดพลาดที่ระบุถึงการกระทำที่ปรากฏในแคตตาล็อก การค้นพบ (discovery) และการดำเนินการ (execution) แยกออกจากกัน การกระทำหนึ่งอาจปรากฏใน search_actions แต่ยังคงถูกปฏิเสธโดย OOMOL_CONNECT_ALLOWED_ACTIONS, รายการที่ถูกบล็อก (denylist) หรือกฎของ token รันไทม์นั้นๆ

การอัปเกรด ให้สำรองข้อมูล volume, แก้ไข image tag เป็นรุ่นใหม่ จากนั้นใช้ docker compose pull && docker compose up -d คอยสังเกต docker compose logs -n 50 connector เพื่อดูบรรทัดการย้ายข้อมูล (migration) และเรียกใช้ health check รวมถึงการทดสอบการทำงานจริงหนึ่งครั้งก่อนที่คุณจะเชื่อมั่นในระบบอีกครั้ง การย้อนกลับ (rolling back) หมายถึงการใส่ tag เดิมกลับเข้าไป ซึ่งจะทำได้ก็ต่อเมื่อคุณได้กำหนดเวอร์ชัน (pinned) ไว้ก่อนหน้านี้เท่านั้น

FAQ

ฉันจำเป็นต้องมี public domain เพื่อ self-host Open Connector หรือไม่?

สำหรับผู้ให้บริการที่ใช้ API key นั้นไม่จำเป็น: gateway บน 127.0.0.1 ก็เพียงพอแล้ว ส่วน OAuth ก็ไม่ได้บังคับเสมอไปเช่นกัน: OpenConnector ระบุว่า GitHub รองรับ local callback เป็น http://localhost:3000/oauth/callback โดยเบราว์เซอร์ที่ทำขั้นตอน authorization จะต้องเข้าถึง callback URL นั้นได้ สำหรับการติดตั้งบน VPS นี้ ให้ตั้งค่า OOMOL_CONNECT_ORIGIN เป็น hostname https:// ของคุณก่อนเริ่มใช้งานครั้งแรก และลงทะเบียน <origin>/oauth/callback ใน OAuth app ของผู้ให้บริการ

จะเกิดอะไรขึ้นหากฉันทำ encryption key ของ Open Connector หาย?

ข้อมูลประจำตัวที่จัดเก็บไว้จะไม่สามารถถอดรหัสได้ และไม่มีวิธีใดในการกู้คืน เนื่องจากคีย์ถูกออกแบบมาไม่ให้เก็บไว้พร้อมกับข้อมูล เพื่อป้องกันไม่ให้ผู้ที่ถือฐานข้อมูลอ่านข้อมูลได้ รวมถึงตัวคุณเองด้วย ทางเลือกเดียวคือการตั้งค่าคีย์ใหม่และเชื่อมต่อกับผู้ให้บริการทุกรายใหม่อีกครั้ง ควรเก็บคีย์ไว้ใน password manager และเก็บฐานข้อมูลไว้ในระบบสำรองข้อมูลของคุณ เพราะการกู้คืนจำเป็นต้องใช้ทั้งสองอย่าง

AI agent ของฉันสามารถเห็น access token ของผู้ให้บริการได้หรือไม่?

ไม่สามารถเห็นได้เมื่อเรียกใช้งานผ่าน gateway โดย agent จะยืนยันตัวตนด้วย runtime token ที่ขึ้นต้นด้วย oct_ และ gateway จะแทรกข้อมูลประจำตัวของผู้ให้บริการลงในคำขอขาออกที่ฝั่งเซิร์ฟเวอร์ แล้วส่งกลับเฉพาะผลลัพธ์เท่านั้น มีสองกรณีที่ทำให้คุณสมบัตินี้เสียไป: คือ endpoint /v1/proxy/:service ซึ่งส่งต่อคำขอแบบ raw พร้อมแนบข้อมูลประจำตัวของคุณ (ซึ่งเหตุผลที่สิทธิ์การเข้าถึงถูกตั้งค่าว่างไว้ตั้งแต่ต้นก็เพื่อป้องกันเรื่องนี้) และการนำ API key ไปวางใน agent ด้วยตนเอง ซึ่งเป็นการข้าม gateway ไปโดยสิ้นเชิง

ควรให้ gateway เข้าถึงได้จาก public internet หรือไม่?

OAuth callback จะต้องเข้าถึงได้โดยเบราว์เซอร์ที่ทำขั้นตอน authorization ซึ่งไม่จำเป็นต้องเปิดให้ทั้งอินเทอร์เน็ตเข้าถึง สำหรับ Docker Engine 28.0.0 หรือใหม่กว่าที่ใช้ bridge networking แบบปกติ ให้ publish พอร์ตของ container บน 127.0.0.1 เพื่อให้พอร์ตที่เปิดใช้งานเข้าถึงได้เฉพาะจาก host เท่านั้น แล้ววาง reverse proxy ไว้ด้านหน้า สำหรับ Docker รุ่นเก่าอาจอนุญาตให้ host ใน L2 segment เดียวกันเข้าถึงพอร์ตที่ publish ไว้ที่ localhost ได้ จากนั้นให้ทดสอบการเรียกใช้งานหนึ่งครั้งโดยไม่มี header authorization หากสำเร็จ ให้จำกัด /api, /v1 และ /mcp ที่ proxy ให้เหลือเฉพาะที่อยู่ IP ที่ agent ของคุณใช้งาน จนกว่าจะเหลือเพียงการเรียกใช้งานที่ผ่านการยืนยันตัวตนเท่านั้นที่ทำงานได้

Open Connector พร้อมสำหรับการใช้งานในระดับ production หรือไม่?

รุ่นปัจจุบันใช้สัญญาอนุญาต Apache 2.0 ที่มีการแก้ไขเพิ่มเติม โดยรุ่นจนถึง v1.9.4 รวมถึง v1.3.3 ที่ถูกกำหนดเวอร์ชันไว้ ยังคงเป็น Apache 2.0 สำหรับบริการ connector แบบ hosted หรือ managed ที่มีมูลค่าหลักมาจากฟังก์ชันการทำงานของ OpenConnector จำเป็นต้องมีสัญญาอนุญาตเชิงพาณิชย์จาก OOMOL ภายใต้สัญญาอนุญาตปัจจุบัน คำสั่งติดตั้ง v1.3.3 ยังคงเป็น snapshot ของวันที่ 1 สิงหาคม 2026 และรุ่นนั้นปล่อยออกมาเมื่อวันที่ 30 กรกฎาคม 2026 ให้รันโดยระบุ release tag เสมอ ห้ามใช้ latest หรือ tip ให้อ่าน release notes ก่อนการอัปเกรดทุกครั้ง และเก็บ volume backup ที่คุณเคยทดสอบกู้คืนแล้วหนึ่งครั้ง การออกแบบมีความเหมาะสมสำหรับเซิร์ฟเวอร์ที่คุณดูแลเอง และความเสี่ยงอยู่ที่การเปลี่ยนแปลงของเวอร์ชัน ไม่ใช่ที่สถาปัตยกรรม

บทความนี้มีประโยชน์หรือไม่

#ai-agents#oauth#self-hosting#integrations#source-available