SSD Nodes Learn 🎉 VPS $5.50/महिन्यापासून
मार्गदर्शक Matt Connorद्वारे Matt Connor · अपडेटेड 2026-08-13

AFFiNE स्वतः होस्ट करा: Notion-सदृश workspace

Docker Compose वापरून AFFiNE एकाच VPS वर चालवा. चार containers, pinned image tags, data कुठे साठतो, backups आणि 2 GB RAM ची प्रत्यक्ष मर्यादा जाणून घ्या.

तुम्ही AFFiNE स्वतः होस्ट केल्यावर काय मिळते

AFFiNE स्वतः होस्ट केल्यावर तुमच्या नियंत्रणातील सर्व्हरवर Notion-सदृश workspace मिळते. ते चार कंटेनरमध्ये चालते: application, one-shot migration job, Postgres आणि Redis. Real-time collaboration समाविष्ट आहे. Self-hosted workspace ला default ने मिळणाऱ्या 10 seats पर्यंत ही सुविधा उपलब्ध असते. Installation साठी एक compose file आणि एक JSON config file आवश्यक असते. मात्र image tags, disk layout, memory ceiling आणि समोर ठेवलेला proxy यांचा विचार करणे आवश्यक आहे.

AFFiNE एकाच workspace मध्ये document editor आणि infinite canvas ठेवते. त्यामुळे एकाच page कडे document म्हणून वाचता येते किंवा whiteboard प्रमाणे विस्तारता येते. तुम्ही अद्याप काय चालवायचे हे ठरवत असाल, तर आधी self-hosted Notion पर्यायांची तुलना वाचा. या मार्गदर्शिकेत निवड झालेली आहे असे गृहीत धरले आहे. त्यामुळे पुन्हा तुलना करण्याऐवजी AFFiNE योग्य पद्धतीने कसे चालवायचे यावर येथे भर आहे.

येथील सर्व माहिती 8 August 2026 रोजी AFFiNE च्या self-host documentation आणि प्रकाशित release files यांच्या आधारे तपासली आहे. त्या तारखेला नवीनतम stable release 0.27.3 होती. ती 23 July 2026 रोजी प्रकाशित झाली.

चार कंटेनर प्रत्यक्षात काय करतात

affine हे एकाच image मधील server आणि web client आहे. ते port 3010 वर listening करते.

affine_migration हे one-shot job आहे. ते node ./scripts/self-host-predeploy.js चालवते, database migrations लागू करते आणि नंतर बंद होते. Application या job वर condition: service_completed_successfully घोषित करते. त्यामुळे migration non-zero status ने बंद झाल्यास affine मुळीच सुरू होत नाही. Web interface सुरू होत नसल्यास सर्वप्रथम त्या job चे log वाचा.

postgres मध्ये तुमचे documents, users, workspaces आणि permissions साठवले जातात. वितरित केलेले image pgvector/pgvector:pg16 आहे. त्यात pgvector extension समाविष्ट केलेले सामान्य Postgres 16 आहे. pgvector Postgres मध्ये vector column type जोडते. हा embeddings साठवण्यासाठी वापरला जाणारा numeric प्रकार आहे. त्यामुळे मजकूराच्या अर्थानुसार search करता येतो.

redis ही hard dependency आहे. Server आणि migration job दोन्ही सुरू होण्यापूर्वी तिच्या health check ची प्रतीक्षा करतात. वितरित केलेली compose file Redis ला काय देत नाही, हे लक्षात घ्या: volume. docker compose down नंतर त्यातील काहीही टिकत नाही. यावरून स्पष्ट होते की त्यात तुमचा कोणताही content साठवलेला नाही आणि त्याचा backup आवश्यक नाही.

Postgres image stock postgres ऐवजी pgvector का आहे

ही आवश्यकता कोणत्याही पसंतीमुळे नाही, तर AFFiNE च्या schema मुळे आहे. schema.prisma मध्ये datasource मध्ये extensions = [pgvector(map: "vector")] घोषित केले आहे आणि चार tables मध्ये embedding column चा type vector(1024) आहे. AI features कधीही सुरू न केली तरी migration job हे tables तयार करते. त्यामुळे migration पूर्ण होण्यापूर्वी extension database मध्ये उपलब्ध असणे आवश्यक आहे. postgres:16 वापरल्यास extension निघून जाते. Migration हे columns तयार करू शकत नाही. त्यानंतर server अयशस्वी झालेल्या job ची वाट पाहत राहतो.

AFFiNE ने version 0.21 पासून pgvector image वापरण्यास सुरुवात केली. त्यापेक्षा जुन्या install मध्ये image line संपादित करणे म्हणजे पूर्ण upgrade नाही. त्यामुळे काहीही pull करण्यापूर्वी AFFiNE self-host docs मधील upgrade page वाचा.

त्या tag विषयी आणखी एक महत्त्वाची बाब आहे. pg16 म्हणजे Postgres 16. Postgres major version ही सहज बदलता येणारी संख्या नाही. विद्यमान data directory वर ते pg17 मध्ये बदलल्यास Postgres सुरू होण्यास नकार देते आणि docker compose logs postgres मध्ये The data directory was initialized by PostgreSQL version 16, which is not compatible with this version 17 सारखी line दिसते. Major version बदलण्यासाठी dump घ्या आणि तो नवीन data directory मध्ये restore करा.

self-hosted AFFiNE साठी किती CPU आणि RAM आवश्यक आहे

AFFiNE च्या requirements पेजनुसार किमान 4 CPU cores आणि 2 GB RAM आवश्यक आहे. तुमच्या documents मध्ये 10,000 words पेक्षा जास्त मजकूर असल्यास memory requirement 4 GB पर्यंत वाढते. याच पेजवर memory कुठे वापरली जाते हेही सांगितले आहे: sync system आणि document merging. लक्षात ठेवण्यासारखा एक आकडा दिला आहे: 10,000 modifications असलेला document merge करताना memory वापर 1 GB पर्यंत वाढू शकतो.

आता 2 GB plan वर दोन लोक documents लिहित असतील, तर या आकड्यांचा विचार करा. सरासरी वापरात समस्या येत नाही. Postgres आणि Node process मर्यादेच्या आत राहतात आणि काही memory शिल्लक असते. समस्या peak usage मध्ये आहे. मोठ्या merge साठी आधीच वापरात असलेल्या memory व्यतिरिक्त आणखी 1 GB memory लागू शकते. Swap नसलेल्या 2 GB box वर kernel चा out-of-memory (OOM) killer ही मागणी पूर्ण करण्यासाठी सर्वात मोठी process बंद करतो. ती process AFFiNE server असते.

तुमच्या सहकाऱ्याला error दिसत नाही. त्यांना page reload झालेला दिसतो, कारण restart: unless-stopped काही seconds मध्ये container पुन्हा सुरू करते. याचा अंदाज लावू नका; याची खात्री करा:

docker inspect affine_server --format '{{.State.OOMKilled}} {{.RestartCount}}'
sudo dmesg -T | grep -i -E 'out of memory|killed process'

पहिल्या command मधील true किंवा दुसऱ्या command मधील Killed process मध्ये node चे नाव असलेली line दिसल्यास memory संपली आहे. हा bug नाही. दोन्ही बाजूंनी हा प्रश्न सोडवा. प्रथम swap जोडा, म्हणजे memory spike fatal होण्याऐवजी system slow होईल:

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 -h

free -h मध्ये आता 2.0Gi swap total दिसायला हवे. Swap मुळे AFFiNE वेगवान होत नाही आणि swap चा उद्देशही तो नाही. त्यामुळे एक second टिकणारा spike container बंद करण्याऐवजी काही काळासाठी system slow करतो. उपायाचा दुसरा भाग म्हणजे merge च्या वेळी application ला आवश्यक असलेल्या space मध्ये Postgres cache वाढू न देणे. यासाठी Compose service वरील memory limits वापरता येतात.

Storage चा अंदाज बांधणे अधिक सोपे आहे. त्याच पेजवर AFFiNE ने दिलेले आकडे पुढीलप्रमाणे आहेत:

ChartPublished AFFiNE storage figures, August 2026
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
  }
]

Server install साठी 1.5 GB लागतात. प्रत्येकी सुमारे एक हजार words असलेले एक हजार documents जोडल्यास Postgres data मध्ये 0.1 GB वाढ होते. हा आकार जवळजवळ नगण्य आहे. एक हजार uploaded files जोडल्यास 10 GB वाढ होते. मुख्य storage वापर यामुळेच होतो. हे आकडे चालू instance वरील measurements नसून प्रकाशित planning figures आहेत. त्यामुळे त्यांना अचूक हमी न मानता एक अंदाजे स्वरूप समजा. महत्त्वाचे म्हणजे database लहान राहतो आणि तुमच्या uploads मुळे disk ची गरज ठरते.

Tags pin करून compose file स्वतः लिहा

दस्तऐवजीकरणातील install प्रक्रिया curl -L -o docker-compose.yml https://github.com/toeverything/AFFiNE/releases/latest/download/docker-compose.yml वापरून तयार file download करते. ते कार्य करते. मात्र त्यावर अवलंबून राहण्यापूर्वी एक तपशील जाणून घेणे आवश्यक आहे: 8 August 2026 रोजी ${UPLOAD_LOCATION}, ${CONFIG_LOCATION} आणि ${DB_DATA_LOCATION} वापरून release 0.27.3 शी जोडलेली file अजूनही तिचे paths .env file मधून वाचते. त्याउलट, documentation च्या reference page वर ./data अंतर्गत सर्वकाही ठेवणारी नवीन layout दाखवली आहे आणि तिला .env ची अजिबात आवश्यकता नाही. दोन्ही पद्धती योग्य आहेत. File स्वतः लिहिल्यास हा प्रश्न सुटतो. तसेच images pin करण्यासाठी आणि database password सेट करण्यासाठी ती file तुम्हाला संपादित करावीच लागते.

mkdir -p ~/affine/config ~/affine/data
cd ~/affine
printf 'DB_PASSWORD=%s\n' "$(openssl rand -hex 24)" > .env
chmod 600 .env

Compose project directory मधून .env आपोआप वाचते आणि तुमच्यासाठी ${DB_PASSWORD} चे substitution करते. त्यामुळे support thread मध्ये paste करायच्या file मध्ये password दिसत नाही. तुम्ही चालवत असलेल्या प्रत्येक stack मध्ये ही पद्धत वापरणे योग्य आहे. यामागील कारण compose file मधून secrets बाहेर ठेवणे येथे दिले आहे.

आता ~/affine/docker-compose.yml लिहा:

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-stopped

Upstream कडून दिलेल्या file पेक्षा चार फरक आहेत. प्रत्येक फरकामागे एक कारण आहे.

  • 127.0.0.1:3010:3010 port फक्त loopback address वर publish करते. त्यामुळे तुम्ही पद्धत ठरवेपर्यंत server च्या बाहेरून AFFiNE पर्यंत कोणीही पोहोचू शकत नाही. Upstream मधील '3010:3010' प्रत्येक interface वर bind करते. बहुतांश VPS images मध्ये public interface देखील त्यात समाविष्ट असतो.
  • POSTGRES_HOST_AUTH_METHOD: trust काढून टाकले आहे आणि त्याऐवजी password सेट केला आहे. Trust authentication मुळे त्या database वरील कोणतेही connection affine user म्हणून, कोणत्याही password शिवाय स्वीकारले जाते. हे private Compose network पुरते मर्यादित असते. मात्र त्या network मध्ये आणखी एक container जोडल्यास किंवा debugging करताना 5432 publish केल्यास ही रचना सुरक्षित राहीलच असे नाही.
  • साध्या redis ऐवजी redis:8-alpine वापरले आहे. साधे redis latest कडे resolve होते. August 2026 नुसार ते Redis 8 आहे. त्यामुळे pin मुळे तपासलेली major version कायम राहते आणि असंबंधित docker compose pull दरम्यान भविष्यात Redis 9 येण्यापासून प्रतिबंध होतो.
  • pgvector/pgvector:pg16 upstream ज्या पद्धतीने सेट करते त्याच पद्धतीने ठेवले आहे. याचे कारण वर दिले आहे.

Postgres प्रथमच data directory तयार करते तेव्हाच POSTGRES_PASSWORD वाचले जाते. Instance आधीपासून अस्तित्वात असल्यास docker compose exec postgres psql -U affine -c "ALTER USER affine WITH PASSWORD 'yourpassword'" वापरून password सेट करा आणि त्यानंतर त्यानुसार DATABASE_URL update करा.

Configuration config/config.json मध्ये असते

AFFiNE आपली सेटिंग्ज config/config.json मधून वाचते. हीच ती directory आहे जी तुम्ही /root/.affine/config येथे mount केली आहे. ही file आपोआप तयार होत नाही. त्यामुळे पहिल्यांदा सुरू करण्यापूर्वी ती तयार करा. Editor मध्ये ~/affine/config/config.json उघडा आणि उदाहरणातील domain ऐवजी तुमचा स्वतःचा domain देऊन पुढील content लिहा:

{
  "$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 हा तुमचे users browser मध्ये प्रत्यक्ष उघडतात तो address असला पाहिजे. AFFiNE share links आणि workspace invitations ही value वापरून तयार करते. त्यामुळे ती http://localhost:3010 वरच राहिल्यास, तुम्ही पाठवलेले invitation प्राप्तकर्त्याच्या स्वतःच्या machine कडे निर्देश करेल आणि तेथे अपयशी ठरेल. पहिल्यांदा सुरू करण्यापूर्वी ती public HTTPS address वर सेट करा. त्यामुळे file आणि admin panel मध्ये या address बाबत विसंगती राहणार नाही.

copilot AI features नियंत्रित करते. copilot.byok.enabled हा bring-your-own-key switch आहे. त्याद्वारे workspace owner workspace settings मध्ये स्वतःच्या model provider ची key paste करू शकतो. AFFiNE self-host केल्याने AI subscription समाविष्ट होत नाही. तुम्हाला AI features नको असल्यास, दोन्ही false ठेवा.

Stack सुरू करा:

docker compose up -d
docker compose ps

docker compose ps मध्ये affine_postgres आणि affine_redis healthy, affine_server running, तसेच affine_migration_job ची state exited (0) अशी दिसली पाहिजे. Migration job साठी याव्यतिरिक्त कोणताही exit code दिसल्यास त्याची चौकशी करा. त्याच्या log मध्ये थांबलेली step नमूद केलेली असते:

docker compose logs affine_migration

तुम्ही विसरण्यापूर्वी image pin करा

stable हा बदलणारा tag आहे. AFFiNE च्या release workflow मध्ये प्रत्येक stable build साठी अनेक tags दिले जातात. त्यापैकी येथे दोन tags महत्त्वाचे आहेत: stable, जो प्रत्येक release वेळी पुन्हा निर्देशित केला जातो, आणि git short hash नंतरचा stable-, जो बदलला जात नाही. stable वर ठेवले असल्यास, सहा महिन्यांनंतरचा docker compose pull वेगळी image fetch करेल आणि तुम्ही ठरवले नसलेल्या वेळी तिचे migrations तुमच्या database वर चालवेल. तुम्ही तपासलेली अचूक image pin करा:

docker compose pull
docker image inspect ghcr.io/toeverything/affine:stable --format '{{index .RepoDigests 0}}'

यामुळे ghcr.io/toeverything/affine@sha256: नंतरचा लांब hash असलेली ओळ दिसते. हा पूर्ण string affine आणि affine_migration या दोन्हींच्या image: line मध्ये paste करा. हे दोन्ही नेहमी जुळले पाहिजेत, कारण तीच image दोन भूमिका बजावते. Mismatch असल्यास database एका schema वर migrate होतो, पण सेवा दुसऱ्या schema सह चालते. त्यानंतर upgrade हा अनपेक्षित बदल न राहता जाणीवपूर्वक केलेला edit ठरतो: digest बदला, backup घ्या, docker compose pull, docker compose up -d.

इतर कोणी करण्यापूर्वी admin खाते तयार करा

नवीन instance वर /admin उघडल्यावर AFFiNE तुम्हाला खाते तयार करण्याच्या पृष्ठावर पाठवते, कारण सर्व्हरवर अद्याप administrator नाही. या प्रक्रियेत invitation code किंवा setup token नसतो. हे पृष्ठ सर्वप्रथम उघडणारी व्यक्ती तुमच्या सर्व्हरची administrator बनते. त्यामुळे तुम्ही नोंदणी करेपर्यंत हा पोर्ट बंद ठेवला पाहिजे.

म्हणूनच वरील compose file 127.0.0.1 शी bind करते. तुमच्या स्वतःच्या मशीनवरून SSH tunnel वापरून त्यावर पोहोचा:

ssh -L 3010:127.0.0.1:3010 you@your-server-ip

ही प्रक्रिया चालू ठेवा आणि तुमच्या स्थानिक browser मध्ये http://127.0.0.1:3010/admin उघडा. नोंदणी करून log in करा आणि त्यानंतर tunnel बंद करा. आता instance ला public name देणे सुरक्षित आहे.

AFFiNE तुमचा डेटा कुठे ठेवते

सर्व डेटा तीन paths मध्ये साठवला जातो. हे paths तुम्ही तयार केलेल्या directory मध्येच आहेत.

  • ./data/postgres ही Postgres ची data directory आहे. येथे documents, users, workspaces आणि permissions साठवल्या जातात.
  • ./data/storage ही container मधील /root/.affine/storage येथे mount केली जाते आणि त्यात upload केलेल्या सर्व files साठवल्या जातात.
  • ./config ही /root/.affine/config येथे mount केली जाते आणि त्यात config.json साठवले जाते.

Upstream येथे named volumes ऐवजी bind mounts वापरते. हा निर्णय जाणीवपूर्वक घेतलेला आहे. Docker ने हे paths कुठे ठेवले आहेत ते शोधण्याची गरज न पडता, तुम्ही नेहमीच्या commands वापरून त्यांचे tar archive तयार करून copy करू शकता. मात्र यामुळे host वरील file ownership ची जबाबदारी तुमच्यावर येते. हाच bind mounts आणि named volumes यांमधील trade-off आहे, ज्याचे वर्णन bind mounts आणि named volumes मध्ये केले आहे.

AFFiNE चा बॅकअप कसा घ्यावा

दोन गोष्टींचा बॅकअप घ्यावा लागतो आणि त्यांच्यासाठी वेगवेगळ्या पद्धती वापराव्या लागतात. Database हा चालू server असतो. त्यामुळे server चालू असताना त्याच्या files कॉपी केल्यास corrupt copy तयार होते. त्याऐवजी dump घ्या:

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/

हा dump container मध्ये त्याच्या local socket द्वारे चालतो. त्यामुळे password विचारला जात नाही. त्या ls output मध्ये आकार तपासा. काहीशे bytes असलेली file म्हणजे dump अयशस्वी झाला, पण shell ने file तयार केली. ही त्रुटी सहा महिन्यांनी लक्षात येते. -T देखील महत्त्वाचे आहे. ते नसल्यास Compose terminal allocate करू शकते आणि binary stream corrupt होऊ शकतो.

Uploaded files या सामान्य files आहेत. त्यामुळे त्यांचे tar archive तयार करा:

tar czf backup/storage-$(date +%F).tgz -C data storage
cp config/config.json backup/config-$(date +%F).json

config.json आपल्या backup मध्ये स्वतः समाविष्ट करा. August 2026 मध्ये तपासलेल्या AFFiNE documentation नुसार admin panel मधून configuration export अद्याप implemented नाही. त्यामुळे disk वरील file हीच आपल्या settings ची एकमेव copy आहे. या तीनही files server च्या बाहेर कॉपी करा. ज्या disk वरील गोष्टीचे संरक्षण करायचे आहे, त्याच disk वर ठेवलेला backup हा backup मानला जात नाही.

प्रकाशित चरणांमधील पुनर्संचयित प्रक्रिया आणि एक महत्त्वाचा सापळा

अधिकृत restore चरणांची गरज भासण्यापूर्वीच ती वाचा आणि बारकाईने समजून घ्या. August 2026 मध्ये प्रकाशित केलेल्या चरणांमध्ये affine.backup नावाची फाइल container मध्ये copy केली जाते आणि त्यानंतर ./pg.backup मधून restore केले जाते. ही दोन वेगवेगळी नावे आहेत. तसेच ते ./postgres directory काढून टाकतात, परंतु सध्याच्या compose file मध्ये data ./data/postgres मध्ये ठेवला जातो. Snippet मधील paths वापरण्याऐवजी तुम्ही प्रत्यक्ष वापरलेले paths वापरा. या guide मधील layout साठी sequence पुढीलप्रमाणे आहे:

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 -d

rm ऐवजी mv वापरल्याचे लक्षात ठेवा. ज्या database ची copy जतन केलेली नाही त्यावर restore करणे म्हणजे एका चुकीच्या command मुळे संपूर्ण data loss होऊ शकतो. जुने directory बाजूला हलवून ठेवण्याला कोणताही खर्च येत नाही. tar xzf backup/storage-2026-08-08.tgz -C data वापरून uploads देखील restore करा. अन्यथा प्रत्येक document मध्ये attachments तुटलेले दिसतील. त्यानंतर login करा आणि image असलेला document उघडा. हीच चाचणी आहे. Browser मध्ये उघडून पाहिलेले नसलेले restore हे backup नसून केवळ एक file आहे.

तुम्ही आधीपासून चालवत असलेल्या proxy मागे AFFiNE ठेवणे

AFFiNE WebSocket वापरते आणि ते ऐच्छिक नाही. AFFiNE ची sync आणि collaboration system WebSocket वर आधारित आहे. त्यामुळे WebSocket connections upgrade न करणाऱ्या proxy मुळे editing quietly sync होणे थांबते. पेज load होते आणि login कार्य करते; पण एका browser मध्ये केलेला edit दुसऱ्या browser पर्यंत पोहोचत नाही. तुमच्या browser च्या developer tools मध्ये Network tab उघडा आणि WS वर filter करा. वारंवार उघडणारे आणि बंद होणारे connection म्हणजे proxy upgrade पुढे पाठवत नाही याचे लक्षण आहे.

तुम्ही इतर containers साठी Traefik आधीपासून चालवत असल्यास, AFFiNE ही त्यातील सामान्य service म्हणून जोडता येते. affine service मधील ports: block हटवा आणि पुढील मजकूर जोडा:

    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'

तसेच, file च्या शेवटी services: च्या बाजूला पुढील मजकूर जोडा:

networks:
  proxy:
    external: true

Certificate resolver चे नाव तुमच्या Traefik configuration मध्ये परिभाषित केलेल्या नावाशी जुळले पाहिजे. loadbalancer.server.port हा container port 3010 आहे; host port नाही. Traefik WebSocket connections साठी अतिरिक्त configuration शिवाय proxy करते. त्यामुळे आणखी काही जोडण्याची गरज नाही. तुमच्या stack मधील इतर सेवा single sign-on साठी Authentik मागे आधीपासून असल्यास, या router वर forward auth middleware लावल्याने AFFiNE साठी browser access नियंत्रित करता येईल. परंतु desktop app ची चाचणी होईपर्यंत ते बंद ठेवा. Desktop app कडे browser session नसते आणि त्यामुळे sync अपयशी ठरते. एका instance मागे अनेक apps चालवण्याची माहिती अनेक apps समोर एकच Traefik येथे दिली आहे.

nginx मध्ये upgrade स्पष्टपणे सांगावे लागते:

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;
}

nginx मध्ये client_max_body_size चे default मूल्य 1 MB असते. त्यामुळे ही line नसल्यास छोट्या photo पेक्षा मोठे प्रत्येक upload 413 status सह अपयशी ठरते. AFFiNE logs मध्ये काहीही दिसत नाही, कारण request तेथे पोहोचलेलीच नसते. Caddy साठी reverse_proxy http://127.0.0.1:3010 ही एक line पुरेशी आहे. Certificates आणि WebSocket upgrades Caddy स्वतः हाताळते.

self-hosted build मध्ये काय समाविष्ट नाही

टीमचे स्थलांतर करण्यापूर्वी या मर्यादांबाबत स्वतःशी प्रामाणिक रहा.

Real-time collaboration उपलब्ध आहे. sizing संबंधी सर्व सूचना याच feature वर केंद्रित आहेत, कारण AFFiNE च्या स्वतःच्या documentation नुसार memory वापर sync system आणि document merging यामुळे होतो. अनेकांना local-first tool हवे असण्याचे कारण offline editing हे आहे. desktop application मध्ये तुमचा self-hosted server workspace list मध्ये जोडता येतो आणि त्यावर login करता येतो. तुम्ही अवलंबून असलेले अचूक offline behaviour commit करण्यापूर्वी तपासा: network बंद असताना desktop app मध्ये edit करा, पुन्हा connect करा आणि नंतर दुसऱ्या device वर result तपासा. Feature lists पुरावा नाहीत. ही list देखील त्याला अपवाद नाही.

शिप केलेल्या compose file मध्ये server-side full-text search बंद आहे. त्यात AFFINE_INDEXER_ENABLED=false server वर आणि migration job वर set केलेले आहे. ते सुरू करण्यासाठी Manticore Search container जोडावा लागतो. त्यामुळे पाचवा service आणि अधिक memory आवश्यक होते. 2 GB box वर हीच वाढ तुम्हाला मर्यादेपलीकडे नेते. Client मधील search तुम्ही उघडलेल्या workspace मध्ये तरीही कार्यरत राहतो.

लोकांना invite करण्यापूर्वी दोन मर्यादा माहीत असणे आवश्यक आहे. self-hosted workspace ला जास्तीत जास्त 10 seats दिल्या जातात. त्यापेक्षा अधिक seats साठी AFFiNE कडून Team license घ्यावा लागतो. self-hosted instances साठी unlimited blob storage आणि unlimited blob size अपेक्षित आहेत, असे documentation मध्ये वर्णन केले आहे; परंतु August 2026 मध्ये तपासल्यावर ते अद्याप पूर्णपणे implemented नव्हते. घरगुती वापरासाठी किंवा छोट्या team साठी यापैकी कोणतीही मर्यादा महत्त्वाची नाही. मात्र चाळीस लोकांचे स्थलांतर करण्याचा विचार असल्यास दोन्ही मर्यादा महत्त्वाच्या ठरतात.

अपग्रेड

प्रथम release notes वाचा. विशेषतः 0.26 ते 0.27 सारखे minor version bump करताना हे महत्त्वाचे आहे, कारण अशा बदलांमध्ये breaking changes येऊ शकतात. कोणतीही कृती करण्यापूर्वी database आणि storage directory चा backup घ्या. पुढील start वेळी migration job तुमच्या schema मध्ये बदल करते आणि हे बदल पूर्ववत करता येत नाहीत. त्यानंतर pinned digest बदला, docker compose pull चालवा आणि त्यानंतर docker compose up -d चालवा. प्रक्रिया स्वच्छपणे पूर्ण होईपर्यंत docker compose logs -f affine_migration monitor करा. नंतर docker image prune जुन्या layers हटवते. अतिशय जुन्या install साठी एक ऐतिहासिक नोंद: version 0.23.0 पासून image name affine-graphql वरून affine असे बदलले. त्यामुळे त्यापूर्वीच्या compose file मधील image lines pull ला योग्य image सापडण्यापूर्वी पुन्हा लिहाव्या लागतात.

FAQ

AFFiNE कंटेनर कधीच सुरू का होत नाही?

affine सेवा affine_migration job वर condition: service_completed_successfully घोषित करते. त्यामुळे migration कोणत्याही status ने 0 व्यतिरिक्त exit झाल्यास server सुरू होत नाही आणि web interface अजिबात दिसत नाही. कोणत्या step वर प्रक्रिया थांबली हे पाहण्यासाठी docker compose logs affine_migration चालवा. हाताने संपादित केलेल्या compose file मध्ये सर्वात सामान्य कारण म्हणजे pgvector/pgvector:pg16 ऐवजी stock postgres image वापरणे. AFFiNE schema मध्ये pgvector extension घोषित केलेले आहे आणि vector(1024) columns असलेले tables तयार केले जातात. Plain Postgres हे columns तयार करू शकत नाही.

Self-hosted AFFiNE साठी किती RAM आवश्यक आहे?

AFFiNE च्या requirements page नुसार किमान 4 CPU cores आणि 2 GB RAM आवश्यक आहे. Documents मध्ये 10,000 words पेक्षा जास्त असल्यास ही गरज 4 GB पर्यंत वाढते. तसेच 10,000 modifications असलेला document merge करताना वापर 1 GB पर्यंत वाढू शकतो, असे त्यात नमूद आहे. 2 GB server वर idle load समस्या निर्माण करत नाही; ही peak memory वापरच समस्या निर्माण करते. Kernel out-of-memory killer AFFiNE process थांबवतो आणि restart: unless-stopped तो पुन्हा सुरू करते. त्यामुळे users ना error ऐवजी page reload दिसतो. docker inspect affine_server --format '{{.State.OOMKilled}}' आणि sudo dmesg -T | grep -i 'out of memory' वापरून याची खात्री करा. त्यानंतर 2 GB swap file जोडा, जेणेकरून memory spike fatal न होता प्रक्रिया फक्त धीमी होईल.

AFFiNE माझा data कुठे साठवते आणि मी कोणत्या गोष्टींचा backup घ्यावा?

तुमच्या compose directory अंतर्गत तीन paths मध्ये सर्व data असतो: database साठी ./data/postgres, uploaded files साठी ./data/storage आणि config.json साठी ./config. Files copy करण्याऐवजी docker compose exec -T postgres pg_dump --format c --username affine affine > affine.dump वापरून database चा backup घ्या. चालू असलेला Postgres सुरक्षितपणे copy करता येत नाही. Uploads साठी ./data/storage चे tar archive तयार करा. config.json ची copy manually जतन करा, कारण August 2026 पर्यंत admin panel मधून configuration export करणे उपलब्ध नाही, असे नमूद आहे.

Self-hosted AFFiNE वर real-time collaboration चालते का?

होय. यासाठी कोणतीही setting enable करण्याची गरज नाही. तुमचा reverse proxy योग्य प्रकारे configured असणे ही एकमेव आवश्यकता आहे, कारण sync WebSocket connections वर चालते. nginx वर यासाठी proxy_http_version 1.1 तसेच Upgrade आणि Connection: upgrade headers आवश्यक असतात. Traefik आणि Caddy ही connections अतिरिक्त configuration शिवाय forward करतात. Proxy या connections upgrade करत नसल्यास workspace सामान्यपणे load होते आणि login देखील होते. मात्र एका browser मध्ये केलेले edits दुसऱ्या browser मध्ये दिसत नाहीत.

मी AFFiNE stock Postgres image सोबत चालवू शकतो का?

नाही. AFFiNE चे schema.prisma extensions = [pgvector(map: "vector")] घोषित करते आणि vector(1024) type च्या embedding column सह चार tables define करते. AI features बंद असतानाही migration job हे tables तयार करते. pgvector/pgvector:pg16 वापरा. हा त्या extension सह compile केलेला Postgres 16 आहे. त्याऐवजी AFFiNE ला external Postgres server शी जोडत असल्यास त्या server वर pgvector install करा. Migration चालवण्यापूर्वी target database मध्ये extension तयार करा.