×

一、备份

先把当前状态记录下来(有助于回滚):

 # 查看容器
 docker ps -a
 ​
 # 查看 affine 相关镜像、标签
 docker images | grep affine
 ​
 # 导出每个容器的配置(备份)
 cd /root
 mkdir affine_backup
 docker inspect affine_server > /root/affine_backup/inspect_affine_server.json
 docker inspect postgres > /root/affine_backup/inspect_postgres.json
 docker inspect redis > /root/affine_backup/inspect_redis.json
 ​
 # docker-compose文件位置——compose.yml
 cd /home/affine

(用当前日期替换下面示例中的 2025-09-08

1、备份 Postgres(推荐用 pg_dumpallpg_dump

先查看 Postgres 容器名(现有的是 postgres),然后:

 # 在宿主机生成 SQL 转储(推荐)
 docker exec -t postgres bash -lc 'pg_dumpall -U "${POSTGRES_USER:-postgres}"' > /root/affine_backup/affine_pg_dumpall_2025-09-08.sql
 # 或备份单库(如果知道数据库名,例如 affine)
 docker exec -t postgres pg_dump -U "${POSTGRES_USER:-postgres}" -d affine -Fc -f /tmp/affine_db_2025-09-08.dump
 docker cp postgres:/tmp/affine_db_2025-09-08.dump /root/

如果 POSTGRES_USER/POSTGRES_DB 不确定,可先用 docker inspect postgresdocker exec -it postgres env | grep POSTGRES 查看环境变量。 注意:如果将来需要升级 Postgres 的 major 版本(例如 pg16→pg17),官方特别警告:不能直接改镜像 tag,需要 dump/restore(也就是说备份是必须的)。docs.affine.pro

2、备份 Redis

 # 触发 RDB 写入
 docker exec redis redis-cli SAVE
 # 将 rdb 拷贝到宿主机
 docker cp redis:/data/dump.rdb /root/affine_backup/affine_redis_dump_2025-09-08.rdb

(如果使用 AOF 或者自定义数据目录,请根据实际 mount 点拷贝相应文件)

3、备份上传文件 / 存储(AFFiNE 的 storage)

先找出 affine 容器的挂载点(host path):

 docker inspect affine_server --format '{{range .Mounts}}{{println .Source " -> " .Destination}}{{end}}'

返回 /home/affine/self-host/storage -> /root/.affine/storage,那么备份为:

 tar -czf /root/affine_backup/affine_storage_backup_2025-09-08.tar.gz -C /home/affine/self-host/storage .

附:实际返回(记住此路径,后面会用到 docker-compose.yml 中)

 /home/affine/self-host/config  ->  /root/.affine/config
 /home/affine/self-host/storage -> /root/.affine/storage

如果数据是 docker volume,可以这样备份:(此处不采用)

 # 列出卷
 docker volume ls
 # 用临时容器将卷打包到宿主机
 docker run --rm -v affine_volume_name:/data -v /root:/backup alpine \
  sh -c "cd /data && tar czf /backup/affine_volume_affine_volume_name_2025-09-08.tar.gz

4、备份配置(.env / docker-compose.yml / 自定义配置)

把现有 .env、compose 文件、副本全部备份到 /root/affine_backup/backup_affine_configs_2025-09-08/。如果没有 .env 文件,可从容器环境导出:

 docker exec affine_server printenv > /root/affine_backup/affine_server_env_2025-09-08.txt

二、升级 AFFiNE 的生产环境操作步骤

以下基于当前环境 /home/affine/compose.yml,路径 /home/affine/self-host/{config,storage}

1. 准备升级目录

 mkdir -p /root/affine_upgrade
 cd /root/affine_upgrade
 ​
 # 下载最新 compose 文件(以官方 release 链接为准)
 # 此文件源文件已经拉取到192.168.201.202(升级测试机)/home/yunweizu/affine_upgrade_2025_09_08/目录下备份用,如无外网环境到此处cp
 wget -O docker-compose.yml https://github.com/toeverything/AFFiNE/releases/latest/download/docker-compose.yml
 ​
 # 同步示例 env(可能有新增参数)
 wget -O .env.example https://raw.githubusercontent.com/toeverything/AFFiNE/main/.github/deployment/self-host/.env.example || true
 ​
 # 对比配置
 diff -u /home/affine/compose.yml /root/affine_upgrade/docker-compose.yml | less

👉 在 docker-compose.yml.env 中确认以下几点:

  • Postgres 数据卷 映射到 /home/affine/self-host/config
  • storage 卷 映射到 /home/affine/self-host/storage
  • Redis 保持不变
  • 端口仍然是 80:3010
  • 新增的环境变量(比如 ENABLE_MERMAID=true)要补到 .env

🔑 docker-compose.yml 关键变化点

  1. 镜像名称
    • 旧:ghcr.io/toeverything/affine-graphql
    • 新:ghcr.io/toeverything/affine 👉 必须改。因为官方已经弃用 affine-graphql 镜像,新版本统一用 affine
  2. 端口映射
    • 旧:固定 80:3010
    • 新:${PORT:-3010}:3010 👉 更灵活,推荐改成新写法。但如果你原本就在 Nginx 前做反代,实际没区别。
  3. 新增环境变量
    • 新增 AFFINE_INDEXER_ENABLED=false 👉 建议跟随官方模板加上。这个控制是否启用索引功能(全文检索/AI 相关)。生产环境如果暂时不用,可以保持 false
  4. Redis
    • 旧:container_name: redis + 暴露 6379 端口
    • 新:container_name: affine_redis,不再暴露宿主机端口 👉 生产环境如果没有外部应用要直连 Redis,建议用新版(不暴露 6379,更安全)。
  5. Postgres
    • 旧:image: postgres:16container_name: postgres,端口 5432
    • 新:image: pgvector/pgvector:pg16container_name: affine_postgres,不暴露端口 👉 升级点最重要!AFFiNE 新版推荐用带 pgvector 扩展的镜像(支持向量搜索 / AI 功能)。 ⚠️ 风险点:容器名变更 → .env 或依赖中 DATABASE_URL 需要同步,否则连不上。

📋 升级时你要做的决策

  1. 镜像名称 → 必须改成新版本 ghcr.io/toeverything/affine:${AFFINE_REVISION:-stable}
  2. 容器名
    • 如果你不想修改 .env(里面写了 postgresredis),可以保持旧名字: container_name: postgres
       container_name: redis
    • 如果你愿意完全跟随新模板,就需要:
      • .envDATABASE_URL 改成 affine_postgresaffine_redis
      • 现有数据卷要确认是否能直接迁移到新容器。
    👉 生产环境建议保留旧名字,否则要做额外迁移。
  3. Postgres 镜像
    • 如果你需要用 AFFiNE 的新 AI/向量功能 → 换成 pgvector/pgvector:pg16
    • 如果你只是普通文档协作,不依赖向量搜索 → 可以先继续用 postgres:16,降低风险。
  4. Redis 端口
    • 如果没有外部依赖,推荐取消暴露(用内部网络通信即可)。
    • 如果外部还有调试或监控工具需要直连,就保留 6379:6379

确认无误后,用更新过的新 compose 文件替换生产目录:

 cp /root/affine_upgrade/docker-compose.yml /home/affine/compose.yml

修改已有用户密码(不删除数据)

原密码为空,会报错,建议修改密码为affine

进入 PostgreSQL 容器:

 docker exec -it postgres psql -U affine -d affine

修改密码:

 ALTER USER affine WITH PASSWORD 'affine';

退出 psql:

 \q
  1. 确认 .env 里的 DB_PASSWORD 与新密码一致,然后再运行迁移:
 docker-compose up --no-deps --exit-code-from affine_migration affine_migration

compose.yml 参考 /home/affine/compose.yml

 name: affine
 services:
  affine:
    image: ghcr.io/toeverything/affine:${AFFINE_REVISION:-stable}
    container_name: affine_server
    ports:
      - '${PORT:-3010}:3010'
    depends_on:
      redis:
        condition: service_healthy
      postgres:
        condition: service_healthy
      affine_migration:
        condition: service_completed_successfully
    volumes:
      # custom configurations
      - ${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_INDEXER_ENABLED=false
    restart: unless-stopped
 ​
  affine_migration:
    image: ghcr.io/toeverything/affine:${AFFINE_REVISION:-stable}
    container_name: affine_migration_job
    volumes:
      # custom configurations
      - ${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_INDEXER_ENABLED=false
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
 ​
  redis:
    image: redis
    container_name: 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: 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'
      # you better set a password for you database
      # or you may add 'POSTGRES_HOST_AUTH_METHOD=trust' to ignore postgres security policy
      POSTGRES_HOST_AUTH_METHOD: trust
    healthcheck:
      test:
        ['CMD', 'pg_isready', '-U', "${DB_USERNAME}", '-d', "${DB_DATABASE:-affine}"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

.env 参考 /home/affine/.env

如果主机有迁移,IP地址有变化,AFFINE_SERVER_HOST 和 AFFINE_SERVER_EXTERNAL_URL 要对应修改

注意:把 DB_PASSWORD=安全考虑已清理 这行 DB_PASSWORD=affine 设置一个新密码

 # select a revision to deploy, available values: stable, beta, canary
 AFFINE_REVISION=stable
 
 # set the port for the server container it will expose the server on
 PORT=80
 
 # set the host for the server for outgoing links
 AFFINE_SERVER_HTTPS=false
 AFFINE_SERVER_HOST=192.168.201.202
 # or
 AFFINE_SERVER_EXTERNAL_URL=http://192.168.201.202
 
 # position of the database data to persist
 DB_DATA_LOCATION=/home/affine/self-host/postgres/pgdata
 # position of the upload data(images, files, etc.) to persist
 UPLOAD_LOCATION=/home/affine/self-host/storage
 # position of the configuration files to persist
 CONFIG_LOCATION=/home/affine/self-host/config
 
 # database credentials
 DB_USERNAME=affine
 DB_PASSWORD=affine
 # 此处设置一个密码affine,否则升级报错,处理较麻烦
 DB_DATABASE=affine
 ​
 MAILER_HOST=smtp.exmail.qq.com
 MAILER_PORT=465
 MAILER_USER=devops@akuvox.com
 MAILER_PASSWORD=knGnfce3ALz8kUm6
 MAILER_SENDER=devops@akuvox.com

安装独立版 Docker Compose(推荐,兼容老系统)

 # 1. 下载 docker-compose 二进制(v2.27.0 为例,官方最新稳定版)
 curl -L "https://github.com/docker/compose/releases/download/v2.27.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
 ​
 # 2. 添加执行权限
 chmod +x /usr/local/bin/docker-compose
 ​
 # 3. 建立软链接(有些系统只认这个名字)
 ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
 ​
 # 4. 验证
 docker-compose version

2. 拉取最新镜像

进入生产目录,拉取新版本镜像:

 cd /home/affine
 docker-compose pull

3. 停止旧 affine 容器(保留数据库和 redis)

 docker stop affine_server || true
 docker rm affine_server || true

不要停 Postgres、Redis,因为它们是数据依赖。

4. 运行 migration job

新版本通常需要迁移数据库 schema,必须跑 migration job:

 docker-compose up --no-deps --exit-code-from affine_migration affine_migration

如果没有 affine_migration 服务,可以这样跑:(已有服务,不采用) 

docker run --rm \
  --network=host \
  -e DATABASE_URL="postgresql://<user>:<pass>@127.0.0.1:5432/<db>" \
  -e REDIS_SERVER_HOST="127.0.0.1" \
  -v /home/affine/self-host/storage:/root/.affine/storage \
  -v /home/affine/self-host/config:/root/.affine/config \
  ghcr.io/toeverything/affine-graphql:stable \
  sh -c "node ./scripts/self-host-predeploy.js"

观察日志,确认返回码是 0,否则停止操作。

5. 启动新 affine 服务

 docker-compose up -d affine

查看日志:

 docker logs -f affine_server

6. 验证服务

  1. 浏览器访问 http://192.168.201.202 (或绑定域名),能正常打开。
  2. 登录原有账号,检查页面内容是否完整。
  3. 新建文档,插入一个 mermaid 代码块测试渲染。
  4. 上传文件、搜索功能、协作是否正常。
  5. docker ps 检查所有容器健康状态。

7. 升级完成后清理

等确认 24~48 小时无异常,再清理旧镜像:

 docker image prune -a

升级后会发生的情况

  • affine_server 容器会被替换(镜像更新),但数据不会丢失,因为你保留了 Postgres/Redis/storage 的 volume 映射。
  • 数据库 schema 被迁移,旧版本无法再直接读取,回滚时必须用备份恢复。
  • 配置文件若未合并新增变量,可能导致新功能不可用(例如 mermaid 渲染)。
  • Redis 缓存可能被清空,但这不会影响持久化数据。

修改密码

方法一:

把一个用户的密码覆盖到另一个用户users 表里密码是 argon2id 哈希,假设将zhongping.wei密码覆盖到Kidd,可以直接把 zhongping.wei 的 password 拷贝过去。

psql 里执行:

 UPDATE users
 SET password = (
    SELECT password FROM users WHERE name = 'zhongping.wei'
 )
 WHERE name = 'Kidd';

然后检查一下:

 SELECT name, password FROM users WHERE name IN ('zhongping.wei', 'Kidd');

看到 Kiddpassword 已经和 zhongping.wei 一样了。 此时,Kidd 就能用 zhongping.wei 的密码登录。

方法二:

Affine 的 users 表里密码字段是 bcrypt 哈希。所以需要:

  1. 生成 bcrypt 哈希
  2. 用 SQL 更新 users

1. 本地生成 bcrypt 哈希

直接在宿主机上生成,步骤如下:

 # 安装 Python 的 bcrypt 库
 pip install bcrypt

新建一个脚本 gen_bcrypt.py

 import bcrypt, os
 ​
 password = os.environ.get("NEWPASS", "Akuvox@2025")
 hashed = bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt())
 print(hashed.decode())

运行:

 NEWPASS='Akuvox@2025' python3 gen_bcrypt.py

会输出类似:

 $2b$12$KpYcD93S8Y/4b3G5XjNw/.rQx5rNw7DD0k5b6d0Q6C4pTQqp6SNCW

这个就是 Affine 数据库接受的哈希值

2. 更新数据库

进入 PostgreSQL:

 docker exec -it postgres psql -U affine -d affine

找到你要改的用户 ID 或邮箱(举例查邮箱):

 SELECT id, email FROM users;

假设要修改 admin@example.com 这个用户:

 UPDATE users 
 SET "password" = '$2b$12$KpYcD93S8Y/4b3G5XjNw/.rQx5rNw7DD0k5b6d0Q6C4pTQqp6SNCW'
 WHERE email = 'admin@example.com';

📍 在 AFFiNE 里怎么用 Mermaid?

  1. 在编辑器中新建一个代码块(和写代码一样)。
  2. 把语言指定为 mermaid
  3. 输入 Mermaid 语法。

例子(直接复制到 AFFiNE 代码块里):

 graph TD
 A[Start] --> B{Is AFFiNE upgraded?}
 B -->|Yes| C[Enjoy Mermaid 🎉]
 B -->|No| D[Upgrade first]

渲染后,你会看到一张流程图。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

作者

fffff@xf.nn

文章推荐