AFFiNE is an open-source workspace platform combining docs, whiteboards, and databases in one interface including notes, tasks, and team projects together. This guide deploys it via Docker Compose with PostgreSQL, Redis, and Traefik-managed TLS, then builds a workspace, writes a doc, and tries the Edgeless canvas.
Prerequisites: a Linux server (4 vCPU / 2GB RAM minimum), Docker + Docker Compose, a domain A record (e.g.
affine.example.com).
Set Up the Project
$ mkdir -p ~/affine-server/{letsencrypt,redis}
$ cd ~/affine-server
$ openssl rand -hex 64
Environment file — replace domain, email, DB password, and secret key:
$ nano .env
DOMAIN=affine.example.com
ACME_EMAIL=admin@example.com
AFFINE_SERVER_HTTPS=true
AFFINE_SERVER_HOST=affine.example.com
AFFINE_SERVER_EXTERNAL_URL=https://affine.example.com
AFFINE_SERVER_SECRET=GENERATED_SECRET_KEY
AFFINE_REVISION=stable
PORT=3010
DB_DATA_LOCATION=./postgres
UPLOAD_LOCATION=./storage
CONFIG_LOCATION=./config
DB_USERNAME=affine
DB_PASSWORD=STRONG_PASSWORD
DB_DATABASE=affine
Deploy with Docker Compose
$ nano docker-compose.yaml
name: affine
services:
traefik:
image: traefik:v3.7
container_name: traefik
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
- "--certificatesresolvers.myresolver.acme.email=${ACME_EMAIL}"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./letsencrypt:/letsencrypt"
restart: unless-stopped
affine:
image: ghcr.io/toeverything/affine:${AFFINE_REVISION:-stable}
container_name: affine_server
depends_on:
redis:
condition: service_healthy
postgres:
condition: service_healthy
affine_migration:
condition: service_completed_successfully
volumes:
- ${UPLOAD_LOCATION}:/root/.affine/storage
- ${CONFIG_LOCATION}:/root/.affine/config
env_file:
- .env
environment:
- REDIS_SERVER_HOST=redis
- DATABASE_URL=postgresql://${DB_USERNAME}:${DB_PASSWORD}@postgres:5432/${DB_DATABASE:-affine}
- AFFINE_INDEXER_ENABLED=false
labels:
- "traefik.enable=true"
- "traefik.http.routers.affine.rule=Host(`${DOMAIN}`)"
- "traefik.http.routers.affine.entrypoints=websecure"
- "traefik.http.routers.affine.tls.certresolver=myresolver"
- "traefik.http.services.affine.loadbalancer.server.port=3010"
restart: unless-stopped
affine_migration:
image: ghcr.io/toeverything/affine:${AFFINE_REVISION:-stable}
container_name: affine_migration_job
volumes:
- ${UPLOAD_LOCATION}:/root/.affine/storage
- ${CONFIG_LOCATION}:/root/.affine/config
command: ['sh', '-c', 'node ./scripts/self-host-predeploy.js']
env_file:
- .env
environment:
- REDIS_SERVER_HOST=redis
- DATABASE_URL=postgresql://${DB_USERNAME}:${DB_PASSWORD}@postgres:5432/${DB_DATABASE:-affine}
- AFFINE_INDEXER_ENABLED=false
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
redis:
image: redis
container_name: affine_redis
volumes:
- ./redis:/data
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:
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
environment:
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_DATABASE:-affine}
POSTGRES_INITDB_ARGS: '--data-checksums'
healthcheck:
test: ['CMD', 'pg_isready', '-U', "${DB_USERNAME}", '-d', "${DB_DATABASE:-affine}"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
affine_migration runs the schema setup once before affine starts; affine waits on Postgres/Redis health plus migration completion.
$ docker compose up -d
$ docker compose ps
$ docker compose logs --tail=50
All containers should show running, with traefik listing ports 80/443.
First-Run Setup
Visit https://affine.example.com:
- Enter Name, Email Address, Password to create the admin account.
- Continue to the dashboard.
Build a Workspace
1. Create a workspace: open the default Demo Workspace → Create Workspace → name it (e.g. Team Knowledge Base) → type AFFiNE SelfHosted Cloud → Create.
2. Write a doc: inside the workspace, + in the sidebar → title it (e.g. Project Planning Notes) → add headings (Project Overview, Key Objectives) and a numbered list for tasks.
3. Switch to Edgeless view: open the doc, click the Edgeless View icon top-left — the canvas toolbar gives you shapes, connectors, drawing tools, and text annotations.
4. Link content: in Edgeless view, add a text block (e.g. Project Resources), then use the connector tool to visually link it back to the doc.
Next Steps
AFFiNE is running with persistent PostgreSQL/Redis storage and automatic HTTPS. From here:
- Invite team members to the self-hosted cloud workspace for shared editing
- Explore database blocks for structured, Notion-style data within docs
- Combine doc and whiteboard views for project planning that needs both text and visual layout
For the full guide, visit the original article on Vultr Docs.
Top comments (0)