Jalankan server headless
Jalankan cc_server di mesin yang tetap menyala, lalu hubungkan ke sana dari
desktop, peramban, atau ponsel Anda. Server ini adalah biner native Dart murni —
tanpa mesin Flutter — sehingga berjalan headless di macOS, Linux, atau Windows.
Server ini memiliki basis data, menjalankan agen, dan melakukan setiap panggilan
API eksternal; klien hanya merender.
Jalankan di Docker (image siap pakai)
Bagian berjudul “Jalankan di Docker (image siap pakai)”Setiap rilis menerbitkan stack yang dihosting sendiri berisi empat image GHCR —
backend, dua klien tipis statis, dan relay pairing opsional — plus image
cc-server-demo terpisah untuk host demo publik. Instalasi yang dihosting
sendiri tidak memerlukan checkout sumber. Pin tag versi
(ghcr.io/samuelalev/<image>:v0.0.1-rc.1) atau pakai latest.
| Image | Apa itu | Memublikasikan |
|---|---|---|
ghcr.io/samuelalev/cc-server |
Backend: basis data, agen, MCP, webhook | -p 9030:9030 |
ghcr.io/samuelalev/cc-webapp |
Klien web (nginx statis) | -p 8080:8080 |
ghcr.io/samuelalev/cc-remote |
PWA pendamping ponsel (nginx statis) | -p 8081:8080 |
ghcr.io/samuelalev/cc-signaling-server |
Relay pairing WebRTC (opsional) | -p 8788:8788 |
Seluruh stack sebagai file compose:
services: server: image: ghcr.io/samuelalev/cc-server:latest ports: ["9030:9030"] volumes: ["cc_data:/data"] restart: unless-stopped web: image: ghcr.io/samuelalev/cc-webapp:latest ports: ["8080:8080"] restart: unless-stopped remote: image: ghcr.io/samuelalev/cc-remote:latest ports: ["8081:8080"] restart: unless-stopped signaling: image: ghcr.io/samuelalev/cc-signaling-server:latest ports: ["8788:8788"] restart: unless-stopped
volumes: cc_data:Hal-hal yang perlu diketahui sebelum Anda mengekspos semua ini di luar loopback:
-
Image
cc-serverhadir denganCC_SERVER_INSECURE=1(image ini harus mengikat0.0.0.0untuk menerima lalu lintas dari port yang dipublikasikan), yang hanya aman di balik reverse proxy terminasi TLS — Caddy, Traefik, nginx, atau Cloudflare Tunnel — di jaringan tepercaya. Untuk menerminasi TLS di dalam proses sebagai gantinya, pasang sertifikat dan setelCC_SERVER_TLS_CERT/CC_SERVER_TLS_KEY(lalu hapus setelanCC_SERVER_INSECURE). Semuanya dapat ditimpa dengandocker run -e …atau blokenvironment:di compose. -
/dataadalah satu-satunya state. Basis data SQLite, rahasia perangkat yang dipasangkan, model yang diunduh, dan audio rapat semuanya berada di volume — cadangkan volumenya dan kontainer menjadi dapat dibuang. -
Pasangkan klien dari dalam image sebelum koneksi pertama, padanan kontainer dari langkah 3:
Jendela terminal docker run --rm -it -v cc_data:/data \--entrypoint /app/bin/cc_server ghcr.io/samuelalev/cc-server:latest pair -
Kedua image klien adalah host nginx statis — tidak ada yang perlu dikonfigurasi saat runtime; formulir koneksi setiap klien menerima URL server, id perangkat, dan kunci pairing Anda. Relay pensinyalan juga hanya memerlukan portnya (
SIGNALING_HOST/SIGNALING_PORTdapat ditimpa); relay ini tanpa status, tidak menyimpan rahasia, dan merupakan cadangan — ponsel memakai loopback, LAN, tailnet, atau jalurwss://langsung bila salah satunya dapat dijangkau, dan hanya beralih ke relay bila tidak ada. Lewati relay ini jika klien Anda selalu menjangkau server secara langsung.
Sisa panduan ini membangun server dari sumber; flag dan perilaku yang dibahasnya sama dengan yang diumpankan oleh variabel lingkungan image tersebut.
Prasyarat
Bagian berjudul “Prasyarat”- Dart SDK. Repo ini mematok SDK-nya dengan fvm, jadi awali setiap perintah dengan
fvm. - Repositori ini sudah di-checkout.
- Toolchain native yang dibutuhkan skrip staging — Rust/
cargo, plusmeson,ninja,pkg-config,git, dan kompilator C++. Setiap skrip build menyebutkan apa yang tidak dapat ditemukannya dan cara memasangnya. - Host yang dapat dijangkau: loopback untuk penggunaan lokal, atau alamat LAN/publik dengan TLS untuk klien jarak jauh.
Langkah 1: Siapkan pustaka native
Bagian berjudul “Langkah 1: Siapkan pustaka native”Pustaka native ini wajib — tidak ada mode terdegradasi. Bangun pustaka tersebut dari akar repo sebelum hal lainnya:
scripts/natives/build_natives.shPerintah ini membangun rift, fff, tree-sitter beserta tata bahasanya, aec,
lame, ccpty, cc_watcher, cc_inference, dan native SAML ke dalam
build/natives/. Hook build cc_server memancarkan ulang apa pun yang
di-stage di sana ke dalam bundle, jadi melewati langkah ini entah menggagalkan
build secara langsung atau — dengan jalan keluar di bawah — menghasilkan biner
yang preflight boot-nya menolak untuk mulai dan menyebutkan pustaka yang hilang.
Langkah 2: Bangun biner
Bagian berjudul “Langkah 2: Bangun biner”cd apps/cc_serverfvm dart build cliBundle menyertakan libsqlite3 dan pustaka native yang sudah di-stage bersama
biner — tidak perlu SQLite sistem maupun mesin Flutter. Executable-nya berada di
./build/cli/<os_arch>/bundle/bin/cc_server.
Langkah 3: Pasangkan klien sebelum mulai pertama kali
Bagian berjudul “Langkah 3: Pasangkan klien sebelum mulai pertama kali”Direktori data yang baru tidak memiliki perangkat yang dipasangkan dan tidak
memiliki kunci pre-shared, sehingga permintaan kunci pairing dari klien belum
dapat dipenuhi. Buat satu dengan subcommand pair. Perintah ini menulis
global.db dan secrets.json secara langsung; server yang sudah menyajikan
direktori data itu akan mengenali perangkat baru tanpa perlu dimulai ulang:
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030Perintah ini mencetak tiga nilai untuk ditempelkan ke formulir koneksi klien:
Connect a thin client (paste into its connect form): Server ws://localhost:9030/rpc Device id web-client Pairing key <a freshly generated key>Flag yang berguna: --device (bawaan web-client; id ini juga menentukan
tingkat perangkat — desktop, ios, android, selain itu dianggap klien web),
--label (bawaannya nama platform plus hostname mesin ini), --host (host yang
dicetak di URL, karena loopback tidak dapat dijangkau dari mesin lain) dan
--client-url. Menjalankan ulang pair memutar kunci perangkat itu dan memutus
sesi aktifnya. Pemasangan tidak pernah membuat ruang kerja: onboarding klien
yang terhubung yang menamai dan membuat ruang kerja pertama.
Dengan --client-url, perintah ini juga mencetak QR yang dapat dipindai dari
terminal dan membuka klien web yang sudah terisi:
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030 \ --bind any --host 192.168.1.42 --client-url https://app.usectrl.devKredensial yang dibuat oleh cc_server pair tidak memiliki masa
kedaluwarsa; kredensial yang dibuat di aplikasi selalu kedaluwarsa setelah 30
hari. Cabut perangkat yang dibuat melalui CLI dari
Pengaturan → Anda → Perangkat Anda setelah selesai menggunakannya.
Langkah 4: Jalankan server
Bagian berjudul “Langkah 4: Jalankan server”Di loopback — bawaan dan semua yang Anda perlukan untuk klien di mesin yang sama:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030Untuk menjangkaunya dari mesin lain, ikat semua antarmuka. Pengikatan
non-loopback tanpa TLS ditolak saat startup (Refusing to bind non-loopback address … without TLS), jadi sediakan sertifikat:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030 \ --bind any --tls-cert /path/fullchain.pem --tls-key /path/privkey.pem \ --public-url wss://server.example:9030/rpcAtau terminasi TLS di reverse proxy pada jaringan privat tepercaya dan pilih ikut serta dalam pengikatan plaintext di baliknya:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030 \ --bind any --insecure --public-url wss://server.example/rpc--insecure diabaikan bila --tls-cert dan --tls-key keduanya disetel — TLS
selalu menang. Server mengiklankan status plaintext sebagai insecure: true di
GET /healthz dan klien menandai koneksi semacam itu sebagai tidak aman.
Server berjalan sampai SIGINT/SIGTERM, lalu mati dengan bersih.
Langkah 5: Hubungkan klien
Bagian berjudul “Langkah 5: Hubungkan klien”Arahkan klien ke URL server dan kunci pairing dari langkah 3:
- Aplikasi desktop: di layar pertama kali dijalankan (Bagaimana Control Center harus dijalankan?), isi kolom koneksi alih-alih Jalankan di aplikasi ini, atau tambahkan server nanti di Pengaturan → Server → Koneksi & status. Lihat Hubungkan ke server jarak jauh.
- Klien web: buka app.usectrl.dev (atau salinan build web Anda sendiri) dan masukkan URL server, id perangkat, dan kunci pairing.
- Ponsel: pasangkan aplikasi Remote dari klien yang sedang berjalan — lihat Pasangkan perangkat.
Langkah 6: Hubungkan Google Calendar (opsional)
Bagian berjudul “Langkah 6: Hubungkan Google Calendar (opsional)”Untuk menyinkronkan kalender ruang kerja tanpa GUI terpasang, gunakan alur kode perangkat:
GOOGLE_OAUTH_CLIENT_ID=<id> GOOGLE_OAUTH_CLIENT_SECRET=<secret> \ ./build/cli/<os_arch>/bundle/bin/cc_server calendar connect \ --data-dir ./data --workspace <workspace-id>Perintah ini mencetak kode dan URL untuk disetujui di perangkat lain, menyimpan
token penyegaran di sisi server, lalu keluar. Build dari sumber tidak
menyertakan klien Google, jadi variabel lingkungan id dan secret wajib diisi —
tidak ada flag --google-client-id. Lihat
Hubungkan Google Calendar.
Konfigurasi
Bagian berjudul “Konfigurasi”Flag yang digunakan di atas adalah yang dibutuhkan penyiapan pertama. Permukaan
lengkapnya — 23 pasangan flag dan variabel lingkungan, empat subcommand, dan tata
letak direktori data — ada di
referensi CLI cc_server.
Empat yang paling mungkin Anda butuhkan:
| Flag | Bawaan | Arti |
|---|---|---|
--data-dir |
direktori data aplikasi per pengguna OS | Basis data, rahasia, model, dan media yang di-cache |
--port |
9030 |
Port TCP (0 = sementara) |
--bind |
loopback |
loopback, atau any untuk semua antarmuka (perlu TLS atau --insecure) |
--public-url |
diturunkan dari pengikatan | URL RPC yang diiklankan ke klien yang dipasangkan. Setel ini secara eksplisit di balik proxy, NAT, atau tunnel |
Direktori data bawaannya adalah ~/Library/Application Support/control-center
di macOS, %APPDATA%\control-center di Windows, dan
$XDG_DATA_HOME/control-center (atau ~/.local/share/control-center) di tempat
lain. .cc_server yang relatif terhadap cwd hanya digunakan bila tidak ada
direktori home atau data aplikasi yang dapat ditentukan.
Apa yang disajikan server
Bagian berjudul “Apa yang disajikan server”cc_server adalah seluruh permukaan produk, bukan sebagiannya: jalur data dan
langganan repo-RPC, endpoint alat MCP di POST /mcp dan GET /sse pada port
yang sama, webhook masuk, proksi media dan font, callback single sign-on,
protokol sewa fleet, pengambilan RSS sisi server dengan jadwal 30 menit, dan
pencarian vektor (ekstensi sqlite_vector didaftarkan sebagai auto-extension
global proses, dan hanya terdegradasi ke pencarian teks lengkap di tempat
ekstensi itu tidak tersedia).
Dispatcher bersifat stateless: tidak ada pengikatan ruang kerja per sesi.
Setiap panggilan berlingkup ruang kerja membawa workspace_id-nya sendiri dan
akses ditentukan oleh keanggotaan dan peran ruang kerja pemanggil — bukan karena
memegang kunci pairing.
Dua hal yang perlu diketahui sebelum Anda mengekspos port di luar loopback:
- MCP gagal secara tertutup di luar host. Permukaan MCP tanpa token hanya menjawab loopback. Mengikat
anytidak melebarkannya — permintaan dari luar host ditolak dengan “MCP requires a bearer token to answer non-loopback clients” sampai Anda mengonfigurasi token (mcp.setToken, atau Pengaturan → Server → Server MCP). GET /healthztidak diautentikasi secara sengaja, memakai CORS wildcard dan memublikasikan id, nama, sidik jari identitas, dan versi build server. Klien memerlukan sidik jari itu untuk mematok server, jadi ini disengaja — tetapi artinya setiapcc_serveryang dapat dijangkau mengungkapkan sebanyak itu kepada siapa pun yang bertanya.