DEV Community

Cover image for Deploying AFFiNE – Open-Source Knowledge Management Platform
Sanskriti Harmukh for Vultr

Posted on • Originally published at docs.vultr.com

Deploying AFFiNE – Open-Source Knowledge Management Platform

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
Enter fullscreen mode Exit fullscreen mode

Environment file — replace domain, email, DB password, and secret key:

$ nano .env
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode

Deploy with Docker Compose

$ nano docker-compose.yaml
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

All containers should show running, with traefik listing ports 80/443.


First-Run Setup

Visit https://affine.example.com:

  1. Enter Name, Email Address, Password to create the admin account.
  2. Continue to the dashboard.

Build a Workspace

1. Create a workspace: open the default Demo WorkspaceCreate Workspace → name it (e.g. Team Knowledge Base) → type AFFiNE SelfHosted CloudCreate.

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)