İçeriğe geç

Headless bir sunucu çalıştırma

Sürekli açık kalan bir makinede cc_server çalıştırın, ardından masaüstünüzden, bir tarayıcıdan ya da telefonunuzdan ona bağlanın. Sunucu, saf Dart ile yazılmış yerel bir ikilidir — Flutter motoru yoktur — bu yüzden macOS, Linux ya da Windows üzerinde headless çalışır. Veritabanına sahiptir, ajanları çalıştırır ve tüm dış API çağrılarını yapar; istemciler yalnızca çizer.

Her sürüm, dört GHCR imajından oluşan ve kendi sunucunuzda barındırabileceğiniz bir yığın yayımlar — arka uç, iki statik ince istemci ve isteğe bağlı eşleştirme aktarıcısı — ayrıca genel demo ana makinesi için ayrı bir cc-server-demo imajı. Kendi sunucunuzda barındırılan bir kurulum, kaynak kodu kopyası gerektirmez. Bir sürüm etiketi sabitleyin (ghcr.io/samuelalev/<image>:v0.0.1-rc.1) ya da latest ile ilerleyin.

İmaj Ne olduğu Yayımladığı portlar
ghcr.io/samuelalev/cc-server Arka uç: veritabanı, ajanlar, MCP, webhook’lar -p 9030:9030
ghcr.io/samuelalev/cc-webapp Web istemcisi (statik nginx) -p 8080:8080
ghcr.io/samuelalev/cc-remote Telefon yardımcı PWA’sı (statik nginx) -p 8081:8080
ghcr.io/samuelalev/cc-signaling-server WebRTC eşleştirme aktarıcısı (isteğe bağlı) -p 8788:8788

Tüm yığın, tek bir compose dosyası olarak:

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:

Bunlardan herhangi birini loopback dışına açmadan önce bilmeye değer şeyler:

  • cc-server imajı CC_SERVER_INSECURE=1 ile gelir (yayımlanan port trafiğini alabilmesi için 0.0.0.0 adresine bağlanmak zorundadır); bu yalnızca güvenilir bir ağda, TLS sonlandıran bir ters proxy’nin — Caddy, Traefik, nginx ya da bir Cloudflare Tunnel — arkasında güvenlidir. TLS’i bunun yerine süreç içinde sonlandırmak için bir sertifika bağlayın ve CC_SERVER_TLS_CERT / CC_SERVER_TLS_KEY değişkenlerini ayarlayın (ardından CC_SERVER_INSECURE değişkenini kaldırın). Her şey docker run -e … ya da compose dosyasındaki environment: bloğu ile geçersiz kılınabilir.

  • Tek durum /data dizinidir. SQLite veritabanları, eşleştirilmiş cihaz sırları, indirilen modeller ve toplantı sesleri hep bu birimde tutulur — onu yedekleyin, kapsayıcı gözden çıkarılabilir hale gelir.

  • İlk bağlantıdan önce imajın içinden bir istemci eşleştirin; bu, 3. adımın kapsayıcıdaki karşılığıdır:

    Terminal penceresi
    docker run --rm -it -v cc_data:/data \
    --entrypoint /app/bin/cc_server ghcr.io/samuelalev/cc-server:latest pair
  • İki istemci imajı da statik nginx barındırıcısıdır — çalışma zamanında yapılandırılacak hiçbir şey yoktur; her istemcinin bağlantı formu sunucu URL’nizi, cihaz kimliğini ve eşleştirme anahtarını alır. Sinyal aktarıcısı da aynı şekilde yalnızca portuna ihtiyaç duyar (SIGNALING_HOST / SIGNALING_PORT geçersiz kılınabilir); durumsuzdur, hiçbir sır tutmaz ve bir yedek yoldur — bir telefon, erişilebilir bir yol olduğunda loopback’i, LAN’ı, tailnet’i ya da doğrudan bir wss:// yolunu kullanır ve yalnızca hiçbiri yoksa aktarıcıya düşer. İstemcileriniz sunucuya her zaman doğrudan erişiyorsa bunu atlayın.

Bu kılavuzun geri kalanı sunucuyu kaynaktan derler; ele aldığı bayraklar ve davranış, imajın ortam değişkenlerinin beslediği şeylerin aynısıdır.

  • Dart SDK. Bu depo SDK’sını fvm ile sabitler, bu yüzden her komutun başına fvm ekleyin.
  • Bu deponun kopyası alınmış olmalı.
  • Hazırlama betiğinin ihtiyaç duyduğu yerel araç zinciri — Rust/cargo ile birlikte meson, ninja, pkg-config, git ve bir C++ derleyicisi. Her derleme betiği, bulamadığı şeyi ve nasıl kurulacağını belirtir.
  • Erişilebilir bir ana makine: yerel kullanım için loopback ya da uzak istemciler için TLS’li bir LAN/genel adres.

Yerel kitaplıklar zorunludur — düşürülmüş bir mod yoktur. Her şeyden önce bunları depo kökünden derleyin:

Terminal penceresi
scripts/natives/build_natives.sh

Bu, rift, fff, tree-sitter ve dil bilgilerini, aec, lame, ccpty, cc_watcher, cc_inference ile SAML yerel kitaplığını build/natives/ dizinine derler. cc_server derleme kancası, orada hazırlanan her şeyi pakete yeniden yazar; bu yüzden bu adımı atlamak ya derlemeyi doğrudan başarısız kılar ya da — aşağıdaki kaçış kapısıyla — açılış ön denetimi başlamayı reddeden ve eksik kitaplığın adını veren bir ikili üretir.

Terminal penceresi
cd apps/cc_server
fvm dart build cli

Paket, ikilinin yanında libsqlite3 ile hazırlanan yerel kitaplıkları da taşır — sistem SQLite’ı ve Flutter motoru gerekmez. Çalıştırılabilir dosya ./build/cli/<os_arch>/bundle/bin/cc_server yoluna yerleşir.

3. Adım: İlk başlatmadan önce bir istemci eşleştirme

Bölüm başlığı “3. Adım: İlk başlatmadan önce bir istemci eşleştirme”

Yeni bir veri dizininde eşleştirilmiş cihaz ve önceden paylaşılan anahtar yoktur, bu yüzden bir istemcinin eşleştirme anahtarı istemi henüz karşılanamaz. pair alt komutuyla bir tane üretin. global.db ile secrets.json dosyalarını doğrudan yazar; o veri dizinini zaten sunan bir sunucu, yeni cihazı yeniden başlatma olmadan alır:

Terminal penceresi
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030

İstemcinin bağlantı formuna yapıştıracağınız üç değer yazdırır:

Connect a thin client (paste into its connect form):
Server ws://localhost:9030/rpc
Device id web-client
Pairing key <a freshly generated key>

İşe yarar bayraklar: --device (varsayılanı web-client; kimlik aynı zamanda cihaz katmanını da seçer — desktop, ios, android, başka her şey bir web istemcisidir), --label (varsayılanı platform adı artı bu makinenin ana makine adıdır), --host (URL’de yazdırılacak ana makine; çünkü loopback’e başka bir makineden erişilemez) ve --client-url. pair komutunu yeniden çalıştırmak o cihazın anahtarını döndürür ve açık oturumlarını düşürür. Eşleştirme hiçbir zaman çalışma alanı oluşturmaz: bağlanan istemcinin ilk kurulum akışı ilkini adlandırır ve oluşturur.

--client-url ile ayrıca, web istemcisini önceden doldurulmuş halde açan, terminalden taranabilir bir QR kodu yazdırır:

Terminal penceresi
./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.dev

cc_server pair ile üretilen bir kimlik bilgisinin son kullanma tarihi yoktur; uygulamada üretilen bir tanesinin ise süresi her zaman 30 gün sonra dolar. İşiniz bittiğinde CLI ile üretilmiş bir cihazı Ayarlar → Siz → Cihazlarınız yolundan iptal edin.

Loopback üzerinde — varsayılan budur ve aynı makinedeki bir istemci için ihtiyacınız olan tek şeydir:

Terminal penceresi
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030

Ona başka bir makineden erişmek için tüm arayüzlere bağlanın. TLS olmadan loopback dışı bir bağlanma başlangıçta reddedilir (Refusing to bind non-loopback address … without TLS), bu yüzden bir sertifika sağlayın:

Terminal penceresi
./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/rpc

Ya da güvenilir bir özel ağda TLS’i bir ters proxy’de sonlandırın ve onun arkasında düz metin bir bağlanmayı seçin:

Terminal penceresi
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030 \
--bind any --insecure --public-url wss://server.example/rpc

--tls-cert ve --tls-key birlikte ayarlandığında --insecure yok sayılır — TLS her zaman kazanır. Sunucu, düz metin durumunu GET /healthz içinde insecure: true olarak duyurur ve istemciler böyle bir bağlantıyı güvensiz olarak işaretler.

Sunucu SIGINT/SIGTERM alana kadar çalışır, ardından temiz biçimde kapanır.

Bir istemciyi 3. adımdaki sunucu URL’sine ve eşleştirme anahtarına yönlendirin:

  • Masaüstü uygulaması: ilk çalıştırma ekranında (Control Center nasıl çalışsın?) Bu uygulamada çalıştır yerine bağlantı alanlarını doldurun ya da sunucuyu daha sonra Ayarlar → Sunucu → Bağlantı ve durum yolundan ekleyin. Bkz. Uzak bir sunucuya bağlanma.
  • Web istemcisi: app.usectrl.dev adresini (ya da web paketinin kendi kopyanızı) açın ve sunucu URL’sini, cihaz kimliğini ve eşleştirme anahtarını girin.
  • Telefon: Remote uygulamasını çalışan bir istemciden eşleştirin — bkz. Bir cihaz eşleştirme.

6. Adım: Bir Google Calendar bağlama (isteğe bağlı)

Bölüm başlığı “6. Adım: Bir Google Calendar bağlama (isteğe bağlı)”

Bir çalışma alanının takvimini arayüz olmadan eşitlemek için cihaz kodu akışını kullanın:

Terminal penceresi
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>

Başka bir cihazda onaylamak için bir kod ve bir URL yazdırır, yenileme belirtecini sunucu tarafında saklar ve çıkar. Kaynak derlemesi bir Google istemcisi içermez, bu yüzden kimlik ve gizli anahtar ortam değişkenleri zorunludur — --google-client-id diye bir bayrak yoktur. Bkz. Bir Google Calendar bağlama.

Yukarıda kullanılan bayraklar, ilk kurulumun ihtiyaç duyduğu bayraklardır. Tam yüzey — 23 bayrak ve ortam değişkeni çifti, dört alt komut ve veri dizini düzeni — cc_server CLI referansında yer alır.

En çok ihtiyaç duyacağınız dört tanesi:

Bayrak Varsayılan Anlamı
--data-dir işletim sisteminin kullanıcı başına uygulama verisi dizini Veritabanları, sırlar, modeller ve önbelleğe alınmış medya
--port 9030 TCP portu (0 = geçici)
--bind loopback loopback ya da tüm arayüzler için any (TLS ya da --insecure gerektirir)
--public-url bağlanmadan türetilir Eşleştirilmiş istemcilere duyurulan RPC URL’si. Bir proxy, NAT ya da tünel arkasında bunu açıkça ayarlayın

Varsayılan veri dizini macOS’ta ~/Library/Application Support/control-center, Windows’ta %APPDATA%\control-center, diğer yerlerde $XDG_DATA_HOME/control-center (yoksa ~/.local/share/control-center) olur. Çalışma dizinine göreli bir .cc_server yalnızca hiçbir ev ya da uygulama verisi dizini çözümlenemediğinde kullanılır.

cc_server ürünün bir alt kümesi değil, tüm yüzeyidir: repo-RPC veri yolu ve abonelikleri, aynı portta POST /mcp ve GET /sse üzerindeki MCP araç uç noktası, gelen webhook’lar, medya ve yazı tipi proxy’leri, tek oturum açma geri çağrıları, filo kiralama protokolü, 30 dakikalık bir zamanlamayla sunucu tarafı RSS çekme ve vektör arama (sqlite_vector uzantısı süreç genelinde bir otomatik uzantı olarak kaydedilir; yalnızca uzantının bulunmadığı yerde tam metin aramasına düşer).

Dağıtıcı durumsuzdur: oturum başına bir çalışma alanı bağlaması yoktur. Çalışma alanına özgü her çağrı kendi workspace_id değerini taşır ve erişime, çağıranın çalışma alanı üyeliği ve rolü karar verir — bir eşleştirme anahtarı taşımak değil.

Portu loopback dışına açmadan önce bilmeniz gereken iki şey:

  • MCP, ana makine dışında kapalıya düşer. Belirteçsiz bir MCP yüzeyi yalnızca loopback’e yanıt verir. any adresine bağlanmak bunu genişletmez — ana makine dışından gelen bir istek, siz bir belirteç yapılandırana kadar “MCP requires a bearer token to answer non-loopback clients” ile reddedilir (mcp.setToken ya da Ayarlar → Sunucu → MCP sunucuları).
  • GET /healthz tasarımı gereği kimlik doğrulamasızdır, joker CORS ile çalışır ve sunucunun kimliğini, adını, kimlik parmak izini ve derleme sürümünü yayımlar. İstemcilerin sunucuyu sabitlemek için parmak izine ihtiyacı vardır, bu yüzden bu kasıtlıdır — ancak bu, erişilebilir herhangi bir cc_server’ın soran herkese bu kadarını açıkladığı anlamına gelir.