Docker ile AFFiNE self-host kurulum rehberi
AFFiNE uygulamasını Docker Compose ile kendi sunucunuzda çalıştırın. Dört container yapısı, veri dizinleri, yedekleme stratejileri ve 2 GB RAM ile performans analizi.
AFFiNE self-host kurulumunda elde ettikleriniz
AFFiNE uygulamasını kendi sunucunuzda barındırmak, kontrolün sizde olduğu bir sunucuda Notion benzeri bir çalışma alanı sağlar. Bu kurulum; uygulama, tek seferlik geçiş işi (migration job), Postgres ve Redis olmak üzere dört container üzerinde çalışır. Kendi kendine barındırılan bir çalışma alanı için varsayılan olarak 10 kullanıcıya kadar gerçek zamanlı iş birliği desteği dahildir. Kurulum, bir adet compose dosyası ve bir adet JSON yapılandırma dosyasından oluşur. Görüntü etiketleri (image tags), disk düzeni, bellek sınırı ve ön tarafa yerleştirilecek proxy üzerinde dikkatli düşünülmelidir.
AFFiNE, belge düzenleyiciyi ve sonsuz tuvali aynı çalışma alanında tutar; böylece bir sayfa hem belge olarak okunabilir hem de beyaz tahta olarak genişletilebilir. Hangi uygulamayı çalıştıracağınıza henüz karar vermediyseniz, önce kendi kendine barındırılan Notion alternatiflerinin karşılaştırması bölümünü okuyun. Bu kılavuz, kararın verildiğini varsayar ve AFFiNE'in tekrar karşılaştırılması yerine düzgün bir şekilde çalıştırılmasına odaklanır.
Buradaki her şey, 8 Ağustos 2026 tarihinde AFFiNE self-host belgeleri ve yayınlanan sürüm dosyaları ile kontrol edilmiştir. O tarihteki en yeni kararlı sürüm, 23 Temmuz 2026 tarihinde yayınlanan 0.27.3 sürümüdür.
Dört container'ın gerçek işlevleri
affine, tek bir imaj içerisinde hem sunucu hem de web istemcisidir. 3010 numaralı portu dinler.
affine_migration, node ./scripts/self-host-predeploy.js komutunu çalıştıran, veritabanı migrasyonlarını uygulayan ve ardından sonlanan tek seferlik bir görevdir. Uygulama, bu görev üzerinde condition: service_completed_successfully tanımlar; bu nedenle sıfırdan farklı bir durum koduyla sonlanan bir migrasyon, affine servisinin hiç başlamayacağı anlamına gelir. Web arayüzü açılmadığında, ilk okunması gereken yer bu görevin günlük kayıtlarıdır.
postgres; belgelerinizi, kullanıcılarınızı, çalışma alanlarınızı ve izinlerinizi tutar. Sunulan imaj, pgvector eklentisi derlenmiş standart Postgres 16 olan pgvector/pgvector:pg16 imajıdır. pgvector, Postgres'e vector sütun türünü ekler; bu, metinlerin anlamlarına göre aranabilmesi için gömmelerin (embeddings) saklandığı sayısal formdur.
redis zorunlu bir bağımlılıktır: hem sunucu hem de migrasyon görevi, başlamadan önce bu servisin sağlık kontrolünün (health check) geçmesini bekler. Sunulan compose dosyasının Redis'e bir volume tanımlamadığına dikkat edin. İçindeki hiçbir veri docker compose down sonrasında kalıcı olmaz; bu da Redis'in size ait herhangi bir içerik barındırmadığını ve yedeklenmesine gerek olmadığını açıkça gösterir.
Postgres imajının neden standart postgres değil de pgvector olduğu
Bu gereksinim bir tercihten değil, AFFiNE şemasından kaynaklanmaktadır. schema.prisma içerisinde veri kaynağı extensions = [pgvector(map: "vector")] olarak tanımlanmıştır ve dört tablo, vector(1024) tipinde bir embedding sütunu barındırır. Göç (migration) işi, yapay zeka özelliklerini açıp açmamanıza bakılmaksızın bu tabloları oluşturur; bu nedenle göç işleminin tamamlanabilmesi için eklentinin veritabanında halihazırda mevcut olması gerekir. İmajı postgres:16 ile değiştirdiğinizde eklenti kaybolur, göç işlemi ilgili sütunları oluşturamaz ve sunucu, başarısız olan bir işi bekleyerek askıda kalır.
AFFiNE, 0.21 sürümüyle birlikte pgvector imajına geçiş yapmıştır. Bu sürümden daha eski bir kurulumda, yalnızca imaj satırını düzenlemek yükseltme işleminin tamamı değildir; bu nedenle herhangi bir çekme (pull) işlemi yapmadan önce AFFiNE self-host belgeleri sayfasındaki yükseltme bölümünü okuyun.
Bu etiketle ilgili bir husus daha bulunmaktadır. pg16, Postgres 16 anlamına gelir ve Postgres ana sürümü öylece yükseltilebilecek bir sayı değildir. Mevcut bir veri dizini üzerinde sürümü pg17 olarak değiştirdiğinizde Postgres başlamayı reddeder ve docker compose logs postgres içerisinde The data directory was initialized by PostgreSQL version 16, which is not compatible with this version 17 benzeri bir hata satırı verir. Ana sürüm değişikliği, verilerin dump alınmasını ve yeni bir veri dizinine geri yüklenmesini (restore) gerektirir.
Self-hosted AFFiNE ne kadar CPU ve RAM gerektirir
AFFiNE gereksinimler sayfası en az 4 CPU çekirdeği ve 2 GB RAM önermektedir; dokümanlarınız 10.000 kelimeyi geçtiğinde ise bellek ihtiyacı 4 GB'a yükselmektedir. Aynı sayfa bellek kullanımının nedenini senkronizasyon sistemi ve doküman birleştirme işlemleri olarak açıklar. Akılda tutulması gereken önemli bir veri şudur: 10.000 değişiklik içeren bir dokümanın birleştirilmesi anlık olarak 1 GB bellek tüketebilir.
Bu durumu, iki kişinin yazı yazdığı 2 GB'lık bir planla kıyaslayın. Ortalama kullanım uygundur. Postgres ve Node süreci, sınırın altında kalarak yeterli alan bırakır. Sorun, anlık zirve noktalardır. Tek bir büyük birleştirme işlemi, halihazırda bellekte olan her şeyin üzerine 1 GB daha talep edebilir. Swap alanı olmayan 2 GB'lık bir sunucuda, çekirdeğin out-of-memory (OOM) killer mekanizması bu talebi, en büyük süreci yani AFFiNE sunucusunu sonlandırarak karşılar.
İş arkadaşınız bir hata mesajı görmez. Sayfanın yeniden yüklendiğini görür, çünkü restart: unless-stopped konteyneri saniyeler içinde tekrar ayağa kaldırır. Tahmin yürütmeyin, durumu doğrulayın:
docker inspect affine_server --format '{{.State.OOMKilled}} {{.RestartCount}}'
sudo dmesg -T | grep -i -E 'out of memory|killed process'İlk komuttan gelen true veya ikinci komutta node ifadesini içeren bir Killed process satırı, bir hata bulduğunuzu değil, belleğinizin tükendiğini gösterir. Sorunu her iki taraftan da çözün. Öncelikle swap ekleyin; böylece bir bellek sıçraması ölümcül olmak yerine sadece yavaşlamaya neden olur:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -hfree -h artık toplam 2.0Gi swap alanı göstermelidir. Swap, AFFiNE'i hızlandırmaz ve amacı da bu değildir. Sadece bir saniyelik bir sıçramayı, konteynerin ölmesi yerine yavaş bir saniyeye dönüştürür. Çözümün diğer ayağı ise Postgres'in önbelleğini, uygulamanın birleştirme anında ihtiyaç duyduğu alana doğru genişletmesini engellemektir; Compose servisinde bellek sınırları tam olarak bunun içindir.
Depolama alanını tahmin etmek çok daha kolaydır. AFFiNE'in aynı sayfada yayınladığı rakamlar şunlardır:
The data behind this chart
[
{
"label": "Server install",
"gb": 1.5
},
{
"label": "Postgres per 1,000 docs",
"gb": 0.1
},
{
"label": "Blob store per 1,000 uploads",
"gb": 10
}
]Sunucu kurulumu 1.5 GB yer kaplar. Yaklaşık bin kelimelik bin doküman, Postgres verisinde 0.1 GB ek yük oluşturur ki bu neredeyse yok denecek kadar azdır. Bin adet yüklenen dosya ise 10 GB ekler; hikayenin tamamı budur. Bunlar çalışan bir örnekten alınan ölçümlerden ziyade planlama için yayınlanmış rakamlardır, bu yüzden bunları bir taahhüt olarak değil, bir projeksiyon olarak değerlendirin. Önemli olan yapıdır: veritabanınız küçük kalır, disk ihtiyacınızı ise yüklediğiniz dosyalar belirler.
Compose dosyasını kendiniz yazın ve etiketleri sabitleyin
Belgelendirilmiş kurulum, curl -L -o docker-compose.yml https://github.com/toeverything/AFFiNE/releases/latest/download/docker-compose.yml ile hazır bir dosya indirir. Bu yöntem çalışır. Ancak güvenmeden önce bilinmesi gereken bir detay vardır: 8 Ağustos 2026 itibarıyla 0.27.3 sürümüne ekli dosya, yollarını hala bir .env dosyasından, ${UPLOAD_LOCATION}, ${CONFIG_LOCATION} ve ${DB_DATA_LOCATION} kullanarak okumaktadır; belgelendirme referans sayfası ise her şeyi ./data altında tutan ve .env gerektirmeyen daha yeni bir düzen göstermektedir. Her ikisi de geçerlidir. Dosyayı kendiniz yazmak bu soruyu ortadan kaldırır; ayrıca imajları sabitlemek ve veritabanı şifresini ayarlamak için dosyayı zaten düzenlemeniz gerekecektir.
mkdir -p ~/affine/config ~/affine/data
cd ~/affine
printf 'DB_PASSWORD=%s\n' "$(openssl rand -hex 24)" > .env
chmod 600 .envCompose, .env dosyasını proje dizininden otomatik olarak okur ve ${DB_PASSWORD} değerini sizin yerinize yerleştirir; böylece şifre, destek forumlarında paylaşacağınız dosyada asla görünmez. Bu alışkanlığı çalıştırdığınız her yığında sürdürmek faydalıdır; bunun gerekçesi sırları compose dosyasının dışında tutmak başlığında açıklanmıştır.
Şimdi ~/affine/docker-compose.yml dosyasını oluşturun:
name: affine
services:
affine:
image: ghcr.io/toeverything/affine:stable
container_name: affine_server
ports:
- '127.0.0.1:3010:3010'
depends_on:
redis:
condition: service_healthy
postgres:
condition: service_healthy
affine_migration:
condition: service_completed_successfully
volumes:
- ./data/storage:/root/.affine/storage
- ./config:/root/.affine/config
environment:
- REDIS_SERVER_HOST=redis
- DATABASE_URL=postgresql://affine:${DB_PASSWORD}@postgres:5432/affine
- AFFINE_INDEXER_ENABLED=false
restart: unless-stopped
affine_migration:
image: ghcr.io/toeverything/affine:stable
container_name: affine_migration_job
command: ['sh', '-c', 'node ./scripts/self-host-predeploy.js']
volumes:
- ./data/storage:/root/.affine/storage
- ./config:/root/.affine/config
environment:
- REDIS_SERVER_HOST=redis
- DATABASE_URL=postgresql://affine:${DB_PASSWORD}@postgres:5432/affine
- AFFINE_INDEXER_ENABLED=false
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
redis:
image: redis:8-alpine
container_name: affine_redis
healthcheck:
test: ['CMD', 'redis-cli', '--raw', 'incr', 'ping']
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
postgres:
image: pgvector/pgvector:pg16
container_name: affine_postgres
volumes:
- ./data/postgres:/var/lib/postgresql/data
environment:
POSTGRES_USER: affine
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: affine
POSTGRES_INITDB_ARGS: '--data-checksums'
healthcheck:
test: ['CMD', 'pg_isready', '-U', 'affine', '-d', 'affine']
interval: 10s
timeout: 5s
retries: 5
restart: unless-stoppedUpstream tarafından sağlanan dosyadan dört fark vardır ve her birinin bir nedeni bulunur.
127.0.0.1:3010:3010, portu yalnızca loopback adresinde yayınlar; böylece siz karar verene kadar sunucu dışındaki hiçbir şey AFFiNE'e erişemez. Upstream'3010:3010'ayarı tüm arayüzleri bağlar ve çoğu VPS imajında bu, genel ağ arayüzünü de kapsar.POSTGRES_HOST_AUTH_METHOD: trustkaldırılmış ve yerine bir şifre atanmıştır. Trust kimlik doğrulaması, veritabanına yapılan her bağlantıyı şifresiz olarakaffinekullanıcısı ile kabul eder. Bu durum özel Compose ağı ile sınırlıdır; ancak o ağa başka bir container bağladığınızda veya hata ayıklama sırasında 5432 portunu dışarı açtığınızda risk oluşturur.redis:8-alpine,latestdeğerine çözümlenen çıplakredisifadesinin yerini alır. Ağustos 2026 itibarıyla bu Redis 8 sürümüdür; dolayısıyla sabitleme işlemi, test ettiğiniz ana sürümü korur ve alakasız birdocker compose pullsırasında Redis 9 sürümünün gelmesini engeller.pgvector/pgvector:pg16, yukarıda belirtilen nedenden dolayı upstream tarafından belirlendiği şekilde kalır.
POSTGRES_PASSWORD yalnızca Postgres veri dizinini ilk kez oluşturduğunda okunur. Hali hazırda var olan bir örnekte, şifreyi docker compose exec postgres psql -U affine -c "ALTER USER affine WITH PASSWORD 'yourpassword'" ile ayarlayın ve ardından DATABASE_URL değerini buna uyacak şekilde güncelleyin.
Yapılandırma config/config.json dosyasında tutulur
AFFiNE, ayarlarını config/config.json dizininden okur; bu dizin /root/.affine/config konumuna mount ettiğiniz dizindir. Bu dosyayı sizin yerinize oluşturan bir mekanizma yoktur, bu nedenle ilk başlatmadan önce dosyayı oluşturmalısınız. ~/affine/config/config.json dosyasını bir düzenleyici ile açın ve örnekteki alan adı yerine kendi alan adınızı kullanarak aşağıdaki içeriği ekleyin:
{
"$schema": "https://github.com/toeverything/affine/releases/latest/download/config.schema.json",
"server": {
"name": "Team workspace",
"externalUrl": "https://affine.example.com"
},
"copilot": {
"enabled": false,
"byok": {
"enabled": false
}
}
}server.externalUrl, kullanıcılarınızın tarayıcıda gerçekten açtığı adres olmalıdır. AFFiNE, paylaşım bağlantılarını ve çalışma alanı davetlerini bu değer üzerinden oluşturur. Eğer http://localhost:3010 olarak bırakılırsa, gönderdiğiniz bir davet bağlantısı alıcıyı kendi yerel makinesine yönlendirir ve bağlantı başarısız olur. İlk başlatmadan önce bu değeri genel HTTPS adresi olarak ayarlayın; böylece dosya içeriği ile yönetim paneli arasında tutarsızlık oluşmaz.
copilot, yapay zeka özelliklerini kontrol eder. copilot.byok.enabled, çalışma alanı sahibinin kendi model sağlayıcı anahtarını çalışma alanı ayarlarına girmesine olanak tanıyan "kendi anahtarını getir" anahtarıdır. AFFiNE'i kendi sunucunuzda barındırmak (self-hosting), bir yapay zeka aboneliği içermez. Eğer bu özelliği istemiyorsanız her iki değeri de false olarak bırakın.
Stack'i başlatın:
docker compose up -d
docker compose psdocker compose ps komutu, affine_postgres ve affine_redis servislerini healthy, affine_server servisini running ve affine_migration_job servisini exited (0) durumunda listelemelidir. Migration işinde bunun dışındaki herhangi bir çıkış kodu, üzerinde durulması gereken bir sorundur; günlük kayıtları durmaya neden olan adımı belirtir:
docker compose logs affine_migrationUnutmadan önce imajı sabitleyin
stable hareketli bir etikettir. AFFiNE'in sürüm iş akışı, her kararlı derlemede birden fazla etiketi günceller; bunlardan ikisi burada önem taşır: her sürümde yeniden işaretlenen stable ve git kısa hash değeri ile takip edilen stable-. stable üzerinde bırakıldığında, altı ay sonra yapılacak bir docker compose pull işlemi farklı bir imajı çeker ve veritabanı migrasyonlarını sizin seçmediğiniz bir anda çalıştırır. Test ettiğiniz imajı tam olarak sabitleyin:
docker compose pull
docker image inspect ghcr.io/toeverything/affine:stable --format '{{index .RepoDigests 0}}'Bu komut, ghcr.io/toeverything/affine@sha256: ve ardından uzun bir hash değeri içeren bir satır çıktısı verir. Tüm dizgiyi hem affine hem de affine_migration dosyalarındaki image: satırına yapıştırın. Bu iki dosya her zaman eşleşmelidir; çünkü aynı imaj iki farklı rolü üstlenmektedir ve bir uyumsuzluk, veritabanının bir şemaya göre migre edilip diğeriyle sunulması anlamına gelir. Yükseltme işlemi böylece sürpriz bir durum olmaktan çıkıp bilinçli bir düzenlemeye dönüşür: digest değerini değiştirin, yedek alın, docker compose pull komutunu çalıştırın ve docker compose up -d işlemini gerçekleştirin.
Yönetici hesabını başkası oluşturmadan önce siz oluşturun
Yeni bir sunucuda /admin adresini açtığınızda, sunucuda henüz bir yönetici bulunmadığı için AFFiNE sizi hesap oluşturma sayfasına yönlendirir. Bu akışta herhangi bir davet kodu veya kurulum belirteci (setup token) bulunmaz. Sayfayı ilk yükleyen kişi sunucunun yöneticisi olur; bu nedenle siz kaydınızı tamamlayana kadar port kapalı tutulmalıdır.
Yukarıdaki compose dosyasının 127.0.0.1 adresine bağlanmasının nedeni budur. Buraya kendi makinenizden bir SSH tüneli aracılığıyla erişin:
ssh -L 3010:127.0.0.1:3010 you@your-server-ipTüneli açık bırakın ve yerel tarayıcınızda http://127.0.0.1:3010/admin adresini açın. Kaydolun ve giriş yapın, ardından tüneli kapatın. Ancak bu işlemden sonra sunucuyu genel bir alan adına açmak güvenlidir.
AFFiNE verilerinizi nerede tutar
Her şey, oluşturduğunuz dizinin içinde yer alan üç farklı yolda saklanır.
./data/postgres, Postgres veri dizinidir: belgeler, kullanıcılar, çalışma alanları ve izinler burada bulunur../data/storage, container içinde/root/.affine/storageyoluna bağlanır ve yüklenen tüm dosyaları barındırır../config,/root/.affine/configyoluna bağlanır veconfig.jsoniçeriğini tutar.
Upstream, burada named volume yerine bind mount kullanır; bu bilinçli bir tercihtir. Docker'a verilerin nerede olduğunu sormanıza gerek kalmadan, bu yolları standart komutlarla tar arşivine alabilir veya kopyalayabilirsiniz. Bunun karşılığında, ana makinedeki dosya sahipliği yönetimi sizin sorumluluğunuzdadır; bu konu bind mount ve named volume bölümünde ele alınan takasın bir parçasıdır.
AFFiNE yedekleme yöntemi
Yedeklenmesi gereken iki farklı bileşen bulunur ve bunlar farklı yöntemlerle yedeklenir. Veritabanı canlı bir sunucu olduğundan, dosyaları çalışır durumdayken kopyalamak bozuk bir yedek oluşturmanıza neden olur. Bunun yerine veritabanı dökümü (dump) alınmalıdır:
mkdir -p ~/affine/backup
cd ~/affine
docker compose exec -T postgres pg_dump --format c --username affine affine \
> backup/affine-$(date +%F).dump
ls -lh backup/Döküm işlemi container içerisinde yerel soket üzerinden gerçekleştirildiği için parola sormaz. ls çıktısındaki dosya boyutunu kontrol edin. Birkaç yüz baytlık bir dosya, döküm işleminin başarısız olduğu ancak shell'in yine de dosyayı oluşturduğu anlamına gelir; bu, kullanıcıların genellikle altı ay sonra fark ettiği bir hatadır. -T bayrağı da önemlidir: bu bayrak olmadan Compose bir terminal tahsis edebilir ve ikili (binary) akışı bozabilir.
Yüklenen dosyalar standart dosyalardır, bu nedenle bunları tar ile arşivleyin:
tar czf backup/storage-$(date +%F).tgz -C data storage
cp config/config.json backup/config-$(date +%F).jsonconfig.json dosyasını manuel olarak yedeğinize dahil edin. AFFiNE dokümantasyonu, Ağustos 2026 itibarıyla yönetici panelinden yapılandırma dışa aktarma özelliğinin henüz uygulanmadığını belirtmektedir; bu nedenle disk üzerindeki dosya, ayarlarınızın tek kopyasıdır. Her üç dosyayı da sunucunun dışına kopyalayın. Koruduğu verilerle aynı diskte tutulan bir yedek, yedek sayılmaz.
Geri yükleme ve yayınlanan adımlardaki bir tuzak
Resmi geri yükleme adımlarını ihtiyaç duymadan önce okuyun ve dikkatle inceleyin. Ağustos 2026'da yayınlandığı şekliyle, affine.backup adlı bir dosyayı container içine kopyalayıp ardından ./pg.backup üzerinden geri yükleme yapmaktadırlar; bunlar iki farklı isimdir. Ayrıca, mevcut compose dosyası verilerini ./data/postgres içinde tutarken, bir ./postgres dizinini silmektedirler. Kod parçacığındaki yollar yerine, fiilen kullandığınız yolları takip edin. Bu kılavuzdaki yapıya göre izlenmesi gereken sıra şöyledir:
cd ~/affine
docker compose down
sudo mv data/postgres data/postgres.old
docker compose up -d postgres
docker compose cp backup/affine-2026-08-08.dump postgres:/tmp/affine.dump
docker compose exec postgres pg_restore --format c --username affine \
--dbname affine --verbose /tmp/affine.dump
docker compose up -drm yerine mv kullanıldığına dikkat edin. Bir kopyasını saklamadığınız bir veritabanının üzerine geri yükleme yapmak, tek bir hatalı komutun toplam veri kaybına dönüşme şeklidir; eski dizini kenara taşımanın ise hiçbir maliyeti yoktur. Yüklemeleri de tar xzf backup/storage-2026-08-08.tgz -C data ile geri yükleyin, aksi takdirde her belge bozuk eklerle görüntülenir. Ardından giriş yapın ve bir resim içeren belgeyi açın. Test budur. Tarayıcıda açmadığınız bir geri yükleme, yedek değil, sadece bir dosyadır.
AFFiNE'i mevcut bir proxy arkasına almak
AFFiNE, WebSocket protokolünü kullanır ve bu zorunludur. Dokümantasyon bu konuda nettir: WebSocket, AFFiNE senkronizasyon ve iş birliği sisteminin temelidir; bu bağlantıları yükseltmeyen (upgrade) bir proxy, düzenlemelerin senkronize edilmediği bir çalışma alanı oluşturur. Sayfa yüklenir, giriş çalışır ancak bir tarayıcıda yapılan düzenleme diğerine ulaşmaz. Tarayıcınızın geliştirici araçlarında Network sekmesini açın ve WS filtresini uygulayın. Sürekli açılıp kapanan bir bağlantı, proxy'nin yükseltme işlemini gerçekleştirmediği anlamına gelir.
Diğer container'larınız için halihazırda Traefik kullanıyorsanız, AFFiNE'i normal bir servis olarak ekleyebilirsiniz. ports: bloğunu affine servisinden silin ve ardından şunları ekleyin:
networks:
- default
- proxy
labels:
- 'traefik.enable=true'
- 'traefik.docker.network=proxy'
- 'traefik.http.routers.affine.rule=Host(`affine.example.com`)'
- 'traefik.http.routers.affine.entrypoints=websecure'
- 'traefik.http.routers.affine.tls.certresolver=letsencrypt'
- 'traefik.http.services.affine.loadbalancer.server.port=3010'Dosyanın en altına, services: ile aynı hizaya şunları ekleyin:
networks:
proxy:
external: trueSertifika çözümleyici ismi, Traefik yapılandırmanızda tanımlı olanla eşleşmelidir ve loadbalancer.server.port, host portu değil, container portu olan 3010'dur. Traefik, WebSocket bağlantılarını ek bir yapılandırma gerektirmeden proxy'ler, bu yüzden başka bir işlem yapmanıza gerek yoktur. Eğer yığınınızın geri kalanı halihazırda tek oturum açma için Authentik arkasında duruyorsa, bu router üzerindeki bir forward auth middleware, tarayıcı erişimini kısıtlayacaktır. Ancak tarayıcı oturumu taşımayan ve senkronizasyon hatası verecek olan masaüstü uygulamasını test edene kadar bu özelliği kapalı tutun. Tek bir instance arkasında birden fazla uygulama çalıştırmak birden fazla uygulama için tek bir Traefik başlığında ele alınmıştır.
nginx üzerinde yükseltme işlemini açıkça belirtmeniz gerekir:
location / {
proxy_pass http://127.0.0.1:3010;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 100m;
}client_max_body_size, nginx üzerinde varsayılan olarak 1 MB değerindedir; bu satır olmadan küçük bir fotoğraftan büyük her yükleme 413 durumuyla başarısız olur ve istek hiç ulaşmadığı için AFFiNE günlüklerinde hiçbir şey görünmez. Caddy ise sadece reverse_proxy http://127.0.0.1:3010 satırına ihtiyaç duyar; sertifikaları ve WebSocket yükseltmelerini kendisi yönetir.
Self-hosted kurulumun eksikleri
Bir ekibi bu sisteme geçirmeden önce kendinize karşı dürüst olun.
Gerçek zamanlı iş birliği mevcuttur ve boyutlandırma tavsiyelerinin tamamı bu özellik üzerine kuruludur; çünkü AFFiNE dokümantasyonu bellek kullanımını senkronizasyon sistemine ve belge birleştirme işlemlerine bağlamaktadır. Çevrim dışı düzenleme, birçok kişinin yerel öncelikli (local-first) bir araç istemesinin temel nedenidir ve masaüstü uygulaması, self-hosted sunucunuzu çalışma alanı listenize ekleyerek giriş yapmanıza olanak tanır. Sisteme geçiş yapmadan önce ekibinizin ihtiyaç duyduğu çevrim dışı davranışları mutlaka test edin: ağ bağlantısı kapalıyken masaüstü uygulamasında düzenleme yapın, ardından bağlantıyı kurup sonucu ikinci bir cihazda kontrol edin. Özellik listeleri kanıt niteliği taşımaz; bu liste de buna dahildir.
Sunucu taraflı tam metin arama özelliği, sunucu ve migration işi üzerinde AFFINE_INDEXER_ENABLED=false ayarı yapılmış olan varsayılan compose dosyasında kapalıdır. Bu özelliği açmak, beşinci bir servis olan Manticore Search container'ının eklenmesi ve dolayısıyla daha fazla bellek kullanımı anlamına gelir. 2 GB belleğe sahip bir sunucuda, sistemi sınırın ötesine taşıyacak olan değişiklik budur. İstemci tarafındaki arama özelliği, açık olan çalışma alanınızda çalışmaya devam eder.
Kullanıcıları davet etmeden önce iki sınırlamayı bilmekte fayda var. Self-hosted bir çalışma alanı en fazla 10 kullanıcıya izin verir; bu sayının aşılması durumunda AFFiNE üzerinden bir Team lisansı alınması gerekir. Self-hosted kurulumlar için sınırsız blob depolama ve sınırsız blob boyutu özellikleri, dokümantasyonda hedeflenen ancak Ağustos 2026 itibarıyla henüz tam olarak uygulanmamış özellikler olarak belirtilmiştir. Bu durum, ev kullanımı veya küçük ekipler için bir sorun teşkil etmez. Ancak kırk kişilik bir ekibi taşımayı planlıyorsanız, her iki sınırlama da önem arz eder.
Yükseltmeler
Özellikle 0.26 sürümünden 0.27 sürümüne geçiş gibi, köklü değişikliklerin yer aldığı ara sürüm yükseltmelerinde öncelikle sürüm notlarını okuyun. Herhangi bir işlem yapmadan önce veritabanını ve depolama dizinini yedekleyin; çünkü geçiş işlemi bir sonraki başlatmada şemanızı değiştirir ve bu işlemin geri dönüşü yoktur. Ardından sabitlenmiş digest değerini değiştirin, docker compose pull komutunu ve ardından docker compose up -d komutunu çalıştırın. İşlem sorunsuz bir şekilde tamamlanana kadar docker compose logs -f affine_migration üzerinden süreci izleyin. docker image prune komutu, işlem sonrasında eski katmanları temizler. Çok eski bir kurulum kullananlar için tarihsel bir not: 0.23.0 sürümünden itibaren imaj adı affine-graphql yerine affine olarak değiştirilmiştir. Bu nedenle, o sürümden daha eski bir compose dosyası kullanıyorsanız, bir çekme (pull) işleminin sonuç vermesi için imaj satırlarının yeniden yazılması gerekir.
FAQ
AFFiNE container'ı neden hiçbir zaman başlamıyor?
affine servisi, affine_migration işi üzerinde condition: service_completed_successfully tanımlar; bu nedenle migrasyon işlemi 0 dışında bir durum koduyla sonlanırsa sunucu hiçbir zaman başlatılmaz ve web arayüzü görüntülenmez. Hangi adımın durduğunu görmek için docker compose logs affine_migration komutunu çalıştırın. Elle düzenlenmiş bir compose dosyasındaki en yaygın hata, pgvector/pgvector:pg16 yerine standart postgres imajının kullanılmasıdır; çünkü AFFiNE şeması pgvector eklentisini bildirir ve standart Postgres'in oluşturamadığı vector(1024) sütunlarına sahip tablolar yaratır.
Self-hosted AFFiNE ne kadar RAM'e ihtiyaç duyar?
AFFiNE gereksinimler sayfası en az 4 CPU çekirdeği ve 2 GB RAM talep eder; dokümanlar 10.000 kelimeyi geçtiğinde bu ihtiyaç 4 GB'a çıkar. 10.000 değişiklik içeren bir dokümanı birleştirmenin 1 GB'lık bir tepe noktası oluşturabileceği belirtilir. 2 GB'lık bir sunucuda sistemi çökerten boşta çalışma yükü değil, bu ani yükseliştir: çekirdeğin out-of-memory killer mekanizması AFFiNE sürecini durdurur ve restart: unless-stopped onu tekrar başlatır; bu nedenle kullanıcılar hata yerine sayfa yenilenmesi görür. Durumu docker inspect affine_server --format '{{.State.OOMKilled}}' ve sudo dmesg -T | grep -i 'out of memory' ile doğrulayın, ardından ani yükselişlerin ölümcül değil yavaş gerçekleşmesi için 2 GB'lık bir swap dosyası ekleyin.
AFFiNE verilerimi nerede saklar ve neyi yedeklemeliyim?
Compose dizininiz altındaki üç yol her şeyi barındırır: veritabanı için ./data/postgres, yüklenen dosyalar için ./data/storage ve config.json için ./config. Çalışan bir Postgres kopyalanamayacağı için veritabanını dosyaları kopyalamak yerine docker compose exec -T postgres pg_dump --format c --username affine affine > affine.dump ile yedekleyin. Yüklemeler için ./data/storage dizinini tar ile arşivleyin ve config.json dosyasını elle saklayın; zira yönetici panelinden yapılandırma dışa aktarma özelliği Ağustos 2026 itibarıyla henüz uygulanmamıştır.
Self-hosted AFFiNE üzerinde gerçek zamanlı iş birliği çalışıyor mu?
Evet, bunun için herhangi bir ayar yapılması gerekmez. Tek gereksinim reverse proxy yapılandırmanızdır, çünkü senkronizasyon WebSocket bağlantıları üzerinden gerçekleşir. Nginx üzerinde bu, proxy_http_version 1.1 ile birlikte Upgrade ve Connection: upgrade başlıklarının ayarlanması anlamına gelir; Traefik ve Caddy ise bu bağlantıları ek bir yapılandırma gerektirmeden iletir. Bağlantıları yükseltmeyen bir proxy'nin belirtisi, çalışma alanının normal şekilde yüklenip giriş yapılmasına rağmen bir tarayıcıda yapılan düzenlemelerin diğerinde asla görünmemesidir.
AFFiNE'i standart bir Postgres imajı ile çalıştırabilir miyim?
Hayır. AFFiNE'in schema.prisma dosyası extensions = [pgvector(map: "vector")] bildirir ve vector(1024) tipinde bir embedding sütununa sahip dört tablo tanımlar; migrasyon işi, AI özellikleri kapalı olsa bile bu tabloları oluşturur. Bu eklentinin derlenmiş olduğu Postgres 16 sürümü olan pgvector/pgvector:pg16 kullanın. Eğer AFFiNE'i harici bir Postgres sunucusuna yönlendiriyorsanız, migrasyonu çalıştırmadan önce sunucuya pgvector eklentisini kurun ve hedef veritabanında eklentiyi oluşturun.