Cara Self-Host Open Connector untuk Agen AI
Jalankan gateway autentikasi Open Connector di VPS sendiri tanpa token SaaS pada agen. Gunakan image tersemat, TLS origin, callback OAuth, dan backup SQLite.
Fungsi Open Connector untuk agen AI
Self-hosting Open Connector menempatkan satu gateway autentikasi antara agen AI Anda dan setiap API software as a service (SaaS) yang dipanggilnya. Dengan demikian, agen tidak pernah menyimpan token provider. Open Connector adalah gateway open source dari OOMOL Lab dengan lisensi Apache 2.0. Aplikasi ini berjalan sebagai satu container, menyimpan statusnya dalam satu file SQLite, serta menyediakan action provider melalui HTTP dan MCP (model context protocol).
Masalah mulai muncul pada integrasi kedua. Setiap provider memiliki alur OAuth (open authorization), masa berlaku refresh token, dan nama scope masing-masing. Menghubungkan lima provider ke agen secara manual berarti menulis lima redirect handler, lima credential store, dan lima refresh loop yang harus berjalan sebelum token kedaluwarsa. Hampir tidak ada yang menulis kode tersebut. Mereka membuat satu personal access token yang berlaku lama untuk setiap service, lalu menempelkannya ke konfigurasi agen, file environment, atau prompt itu sendiri. Token tersebut kemudian dapat dibaca oleh setiap tool yang dijalankan agen dan masuk ke transcript. Inilah kegagalan yang dijelaskan oleh menjaga rahasia tetap di luar agen AI.
Gateway autentikasi memisahkan credential menjadi dua bagian. Gateway menyimpan credential provider dan menjalankan alur OAuth. Agen menerima runtime token yang hanya valid terhadap gateway. Saat agen memanggil suatu action, gateway memuat credential yang tersimpan, menyisipkannya ke dalam outbound request di sisi server, lalu hanya mengembalikan response body. Agen tidak pernah menerima access token provider. Karena itu, transcript agen yang bocor hanya membahayakan satu runtime token yang dapat dicabut, bukan akun GitHub Anda.
Katalog tersebut menyebutkan lebih dari 1,000 provider dan 10,000 action siap pakai. Angka ini berasal dari proyek itu sendiri dan tidak dapat Anda verifikasi dari luar. Hal yang dapat diverifikasi adalah strukturnya: satu endpoint HTTP untuk setiap action, satu stored connection untuk setiap provider, dan satu token untuk setiap agen.
Mengapa menjalankan Open Connector secara mandiri, bukan menggunakan layanan connector yang di-host
Layanan connector yang di-host melakukan pekerjaan yang sama dan menyimpan refresh token untuk setiap provider yang Anda hubungkan. Refresh token untuk Google atau GitHub adalah kunci jangka panjang ke email dan repositori Anda, dan biasanya tetap berlaku setelah perubahan kata sandi. Jika layanan tersebut mengalami kebocoran, Anda juga terdampak. Dengan self-hosting, data tersebut dipindahkan ke SQLite pada mesin yang Anda sewa dan administrasikan, lalu dilindungi dengan key yang tidak pernah meninggalkan mesin Anda.
Sebutkan risikonya dengan jelas sebelum memulai. VPS ini akan menjadi server paling berharga yang Anda jalankan. Server ini menyimpan kredensial aktif untuk selusin layanan dalam satu file, sehingga harus diperlakukan seperti host password manager: firewall yang hanya membuka 443, tanpa login bersama, backup yang benar-benar pernah Anda pulihkan, serta alert ketika server berhenti merespons. Jika Anda tidak bersedia menempatkan password vault pada mesin ini, jangan tempatkan connector di mesin tersebut.
Tetapkan versi sebelum menginstal apa pun
Open Connector masih baru. Repository ini pertama kali muncul pada 29 June 2026, dan per 1 August 2026 rilis terbaru yang diberi tag adalah v1.3.3, yang diterbitkan pada 30 July 2026 dan juga memiliki tag latest. Registry juga menerbitkan tag tip, yang dibuat dari commit terbaru pada main.
Pada proyek yang masih baru seperti ini, tag yang dapat berubah sering mengalami pembaruan. docker compose pull yang melompati dua rilis dapat mengubah endpoint yang diperlukan agen Anda, sehingga Anda menghabiskan waktu untuk men-debug masalah tersebut seolah-olah berasal dari agen. Tetapkan image ke tag rilis, lalu lakukan upgrade saat Anda memutuskan untuk melakukannya setelah membaca catatan rilis.
Deploy Open Connector di balik TLS pada VPS Anda sendiri
Sebelum container dimulai, Anda memerlukan:
- Docker dengan plugin Compose, pada Ubuntu 24.04 atau sistem yang serupa
- hostname yang A record-nya mengarah ke VPS ini, misalnya
connect.example.com - reverse proxy yang sudah menangani terminasi TLS (transport layer security) untuk hostname tersebut
- dua secret acak yang dibuat di bawah
Panduan reverse proxy Traefik untuk beberapa aplikasi Docker Compose membahas sisi proxy. Konfigurasi sertifikat yang sama, dari awal sampai akhir untuk satu aplikasi, tersedia dalam panduan n8n pada VPS dengan Docker dan HTTPS.
Buat secret terlebih dahulu. Kunci enkripsi melindungi kredensial yang tersimpan. Token admin melindungi konsol web dan seluruh permukaan /api. Keduanya tidak memiliki nilai default, dan runtime dapat berjalan tanpa keduanya.
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 .envSalin kedua nilai tersebut ke password manager sekarang, sebelum start pertama. Kunci enkripsi tidak memiliki jalur pemulihan. Alasannya dijelaskan dalam daftar kegagalan di bawah.
Sekarang compose.yaml. Konfigurasi ini berbeda dari contoh upstream pada dua bagian, dan keduanya penting.
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:Perubahan pertama adalah tag yang dipatok, bukan latest. Perubahan kedua adalah port. File upstream memublikasikan 3000:3000, yang mengikat semua interface pada host. Docker menulis port yang dipublikasikannya ke tabel NAT (network address translation) sebelum paket mencapai rantai filter ufw. Karena itu, ufw deny 3000 tidak menutup port tersebut. Ini adalah masalah yang dijelaskan dalam alasan port Docker melewati ufw. Penulisan 127.0.0.1:3000:3000 hanya memublikasikan port pada interface loopback, dan reverse proxy Anda terhubung dari host yang sama.
:? menandai setiap variabel sebagai wajib. Dengan demikian, stack menolak start jika .env tidak ada, alih-alih berjalan dengan kredensial yang tidak terenkripsi. Menyimpan nilai dalam .env, bukan dalam file compose, mengikuti pola dari file env dan secret Docker Compose.
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 menjawab { "ok": true } setelah runtime berjalan. ss harus mencetak 127.0.0.1:3000. Baris yang berbunyi 0.0.0.0:3000 berarti pemetaan port masih menggunakan konfigurasi upstream, dan gateway menjawab seluruh Internet secara langsung. Jika pemeriksaan kesehatan menghasilkan connection refused, berarti container belum listening. Baca log sebelum mengubah konfigurasi proxy.
Label Traefik untuk service yang sama
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"Jika Traefik berjalan dalam Docker pada host yang sama, hubungkan service ini ke network Traefik dan hapus blok ports:. Traefik mengakses container melalui network internal, sehingga tidak ada port yang perlu dipublikasikan ke host. certresolver=le harus sama dengan nama resolver dalam konfigurasi statis Traefik. Jika tidak, router berjalan tanpa sertifikat.
Mengapa OAuth mengharuskan Anda memiliki hostname nyata
OOMOL_CONNECT_ORIGIN adalah pengaturan yang sering dilewati. Jika dilewati, OAuth gagal dengan cara yang tampak seperti bug pada provider. Runtime membangun URI pengalihan dari origin tersebut, dalam bentuk <origin>/oauth/callback. Jika tidak diatur, origin akan menggunakan nilai default http://localhost:3000. Akibatnya, runtime mengirimkan URI pengalihan http://localhost:3000/oauth/callback kepada provider, sedangkan aplikasi OAuth Anda mendaftarkan https://connect.example.com/oauth/callback. Kedua string tersebut berbeda, sehingga GitHub menjawab:
The redirect_uri MUST match the registered callback URL for this application.Provider OAuth mengarahkan browser kembali ke URI tersebut. Karena itu, URI harus berupa alamat yang dapat dijangkau dari luar. Provider menolak http:// biasa untuk apa pun selain localhost. Itulah alasan deployment ini memerlukan hostname dan sertifikat. Atur origin sebelum start pertama karena nilainya dibaca saat startup. Setelah mengedit .env atau compose.yaml, jalankan docker compose up -d lagi untuk menerapkan perubahan.
Hubungkan provider pertama melalui OAuth
Buat aplikasi OAuth terlebih dahulu di provider. Di GitHub, buka Settings, lalu Developer settings, kemudian OAuth Apps, dan pilih New OAuth App. Atur URL callback otorisasi ke https://connect.example.com/oauth/callback. Simpan client ID dan client secret.
Setiap pemanggilan /api membawa token admin. Karena itu, ekspor token tersebut satu kali untuk sesi shell.
export ADMIN_TOKEN='paste-the-admin-token'
curl -s https://connect.example.com/api/oauth/configs \
-H "authorization: Bearer $ADMIN_TOKEN"Daftar tersebut menampilkan URI pengalihan yang diharapkan runtime untuk setiap provider. Dengan demikian, daftar ini menjadi pemeriksaan tercepat untuk memastikan origin Anda telah diterapkan. Jika masih menampilkan localhost, container berjalan dengan nilai lama dan alur OAuth akan gagal pada langkah terakhir.
Simpan kredensial client, lalu mulai proses otorisasi.
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"}'Pemanggilan kedua mengembalikan authorizationUrl. Buka URL tersebut di browser, setujui scope, lalu provider mengarahkan browser kembali ke /oauth/callback. Di sana, runtime menukarkan kode dan menyimpan kredensial. Web console pada origin Anda menjalankan langkah yang sama melalui formulir dengan token admin yang sama. Provider yang menggunakan API key biasa melewati semua langkah ini: PUT /api/connections/<service> dengan {"authType":"api_key","values":{"apiKey":"..."}} menyimpan key tersebut secara langsung.
Berikan setiap agent token runtime, bukan kredensial
Agent melakukan autentikasi ke gateway menggunakan token runtime yang dibuat oleh API admin.
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"}'Respons tersebut memuat token yang diawali oct_. Terbitkan satu token untuk setiap agent dan beri nama sesuai nama agent tersebut. Jika token tidak dapat diidentifikasi, pencabutannya berarti mencabut semua token. Agent kemudian memanggil action melalui HTTP biasa.
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":{}}'Respons yang sehat adalah envelope dengan field success bernilai true, sedangkan payload provider berada di bawah data. Token GitHub tidak terdapat di mana pun dalam respons tersebut. Untuk klien MCP, arahkan klien ke https://connect.example.com/mcp menggunakan header bearer yang sama. Gateway menyediakan tool discovery seperti search_actions dan execute_action, bukan satu tool untuk setiap API. Dengan demikian, daftar tool agent tetap ringkas. Menjalankan server MCP pada VPS membahas sisi klien dari konfigurasi tersebut.
Lakukan satu pemeriksaan lagi sebelum menganggap konfigurasi ini selesai. Ulangi pemanggilan action setelah menghapus header authorization. Quickstart proyek memanggil /v1 tanpa bearer sama sekali. Artinya, instalasi tanpa autentikasi runtime akan menjalankan action untuk siapa pun yang dapat mengakses port tersebut. Jika pemanggilan tanpa autentikasi berhasil, ada dua cara untuk mengatasinya: konfigurasi token runtime dan pastikan pemanggilan anonim sekarang gagal, atau batasi /api, /v1, dan /mcp pada reverse proxy agar hanya dapat diakses dari alamat asal agent. Hanya /oauth/callback yang harus tetap terbuka untuk publik, karena itulah satu-satunya jalur yang diperlukan redirect browser dari provider.
Batasi daftar tindakan sesuai kebutuhan agent
Gateway dengan seribu provider di belakangnya memberikan permukaan akses yang terlalu luas kepada model bahasa. Dua kontrol dapat mempersempitnya.
OOMOL_CONNECT_ALLOWED_ACTIONS menerima daftar yang diizinkan dalam format dipisahkan koma dan memahami service.* serta *. OOMOL_CONNECT_BLOCKED_ACTIONS adalah daftar yang ditolak, dan daftar yang ditolak memiliki prioritas. Menetapkan daftar yang diizinkan ke github.get_current_user,github.list_issues berarti semua tindakan lain ditolak, apa pun yang diminta agent. Inilah perbedaan antara kesalahan dan insiden. Token runtime memiliki aturan tindakannya sendiri di atas aturan global. Daftar allowedProxies miliknya kosong secara default, sehingga POST /v1/proxy/:service ditolak sampai Anda mengizinkannya. Endpoint proxy tersebut meneruskan permintaan mentah ke provider dengan kredensial Anda. Biarkan daftar ini kosong kecuali agent tertentu membutuhkannya.
OOMOL_CONNECT_ALLOW_PRIVATE_NETWORK secara default bernilai false. Pengaturan ini mencegah koneksi ke provider self-hosted mengarah ke alamat privat, seperti layanan metadata cloud pada 169.254.169.254 atau database Anda di jaringan yang sama. Biarkan pengaturan ini nonaktif. Aktifkan hanya untuk provider yang Anda host sendiri.
Cadangkan server yang menyimpan semua token
Ada dua hal yang penting, dan masing-masing tidak berguna tanpa yang lain. Database di /app/data/connect.sqlite dalam volume connector-data menyimpan kredensial yang disegel. Kunci enkripsi di .env membukanya. Cadangan volume tanpa kunci tidak memulihkan apa pun, dan kunci tanpa volume juga tidak memulihkan apa pun. Karena itu, simpan kunci di pengelola kata sandi dan masukkan volume ke dalam rotasi pencadangan normal Anda.
Hentikan container saat menyalin file SQLite. Salinan yang dibuat saat proses penulisan berlangsung dapat dipulihkan sebagai database yang rusak.
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 connectorNama volume terdiri dari direktori proyek Anda ditambah _connector-data. Karena itu, perintah pertama dicantumkan di sana: tempelkan nama sebenarnya ke dalam perintah ketiga. Kirim arsip keluar dari VPS dengan cadangan restic dari VPS, yang mengenkripsinya sebelum arsip meninggalkan VPS, karena arsip tersebut adalah penyimpanan kredensial.
Runtime menyimpan proses tindakan terbaru sebagai catatan audit, 5,000 catatan secara default. Dengan demikian, konsol dapat menunjukkan agen mana yang menjalankan tindakan tertentu dan kapan tindakan itu dijalankan. Baca log tersebut terlebih dahulu ketika perilaku agen tidak semestinya. Arahkan halaman status Uptime Kuma ke https://connect.example.com/health juga. Ketika gateway berhenti merespons, agen gagal dengan cara yang membingungkan. Mengetahui bahwa gateway sedang tidak aktif dapat menghemat waktu hingga satu jam yang seharusnya digunakan untuk membaca output agen.
Hal yang rusak dan pesan yang akan ditampilkan
redirect_uri_mismatch di provider. Origin dan URL callback yang terdaftar berbeda. Bandingkan string yang tepat dari /api/oauth/configs dengan pengaturan aplikasi provider, termasuk https dengan http dan setiap garis miring di akhir.
Setiap pemanggilan /api menghasilkan 401. Header token admin tidak ada atau salah eja. Header tersebut adalah Authorization: Bearer <token>, dan konsol web meminta token yang sama.
Container berjalan, dan kredensial tersimpan sebagai teks biasa. Hal ini terjadi ketika OOMOL_CONNECT_ENCRYPTION_KEY tidak pernah diteruskan ke container, karena runtime menyimpan catatan kredensial tanpa enkripsi, bukan menolak untuk melakukan start. Buktikan pada instalasi Anda sendiri: hubungkan provider dengan API key yang dapat Anda kenali, lalu cari key tersebut di database.
docker compose cp connector:/app/data/connect.sqlite /tmp/connect.sqlite
grep -c 'github_pat_' /tmp/connect.sqlite
shred -u /tmp/connect.sqliteNilai hitungan di atas 0 berarti key tidak diterapkan. Periksa apakah .env berada di direktori yang sama dengan compose.yaml dan apakah docker compose config menampilkan nilainya. Setelah key ditetapkan, pencarian yang sama menghasilkan 0 karena catatan tersebut disegel dengan AES-256-GCM (advanced encryption standard, key 256-bit, Galois/counter mode).
Tidak ada yang dapat didekripsi setelah pemulihan. Encryption key berubah atau hilang. Key tersebut sengaja tidak pernah ditulis di dekat data. Karena itu, tidak ada jalur pemulihan dan tidak ada tiket dukungan yang dapat membantu. Hubungkan kembali setiap provider. Rotasi didukung melalui variabel key terpisah dan perintah data dalam runtime. Baca catatan rilis saat ini sebelum melakukan rotasi.
Agent menampilkan error yang menyebutkan action yang dapat dilihatnya di katalog. Discovery dan eksekusi merupakan proses yang terpisah. Action dapat muncul di search_actions, tetapi tetap ditolak oleh OOMOL_CONNECT_ALLOWED_ACTIONS, denylist, atau aturan token runtime tersebut.
Upgrade. Cadangkan volume, ubah tag image ke rilis baru, lalu docker compose pull && docker compose up -d. Monitor docker compose logs -n 50 connector untuk mencari baris migrasi, lalu jalankan kembali health check dan satu action nyata sebelum menggunakannya kembali. Rollback berarti mengembalikan tag lama. Hal ini hanya berfungsi karena tag tersebut dipatok.
FAQ
Apakah saya memerlukan domain publik untuk melakukan self-hosting Open Connector?
Untuk provider yang menggunakan API key, tidak: gateway pada 127.0.0.1 sudah cukup. Untuk OAuth, secara praktik diperlukan. Provider mengarahkan browser ke URL callback Anda, sehingga URL tersebut harus dapat di-resolve dari Internet publik, dan provider menolak http:// biasa di luar localhost. Tetapkan OOMOL_CONNECT_ORIGIN ke hostname https:// Anda sebelum start pertama, lalu daftarkan <origin>/oauth/callback pada aplikasi OAuth provider.
Apa yang terjadi jika saya kehilangan encryption key Open Connector?
Kredensial yang tersimpan tidak dapat didekripsi, dan tidak ada pemulihan. Key tersebut sengaja tidak pernah disimpan bersama data, sehingga siapa pun yang memiliki database tidak dapat membacanya, termasuk Anda. Satu-satunya pilihan adalah menetapkan key baru dan menghubungkan ulang setiap provider. Simpan key di password manager dan database dalam rotasi backup, karena pemulihan memerlukan keduanya.
Dapatkah AI agent saya melihat access token provider?
Tidak saat agent memanggilnya melalui gateway. Agent melakukan autentikasi menggunakan runtime token yang diawali oct_, lalu gateway menyisipkan kredensial provider ke dalam request keluar di server dan hanya mengembalikan respons. Dua hal dapat menghilangkan perlindungan tersebut: endpoint /v1/proxy/:service, yang meneruskan request mentah dengan kredensial Anda terlampir dan grant-nya sengaja dimulai dalam keadaan kosong, serta menempelkan API key ke agent secara manual, yang sepenuhnya melewati gateway.
Apakah gateway harus dapat diakses dari Internet publik?
Hanya /oauth/callback yang harus dapat diakses. Publikasikan port container pada 127.0.0.1 agar aturan NAT Docker tidak dapat mengeksposnya melewati firewall Anda, lalu tempatkan reverse proxy di depannya. Setelah itu, uji satu pemanggilan action tanpa header authorization. Jika berhasil, batasi /api, /v1, dan /mcp pada proxy ke alamat yang digunakan agent Anda sampai hanya pemanggilan terautentikasi yang berhasil.
Apakah Open Connector siap digunakan dalam production?
Open Connector berlisensi Apache 2.0 dan berkembang cepat: repository tersebut muncul pada 29 June 2026, dan v1.3.3 dirilis pada 30 July 2026. Karena itu, anggap setiap nomor versi dalam panduan ini sebagai snapshot per 1 August 2026. Jalankan dengan release tag yang dipatok, jangan pernah menggunakan latest atau tip, baca release notes sebelum setiap upgrade, dan simpan backup volume yang sudah pernah Anda pulihkan. Desainnya sesuai untuk server yang Anda miliki. Risikonya terletak pada perubahan versi yang cepat, bukan pada arsitekturnya.