自托管笔记应用AppFlowy安装与部署

一.了解介绍

首先介绍一下appflowy,这款软件是我在今年10月份的时候想找oneNote平替软件注意到的,我的主要需求是自托管,那会看官网介绍还没自托管的部署,在12月底的时候想看下appflowy的安卓端是否出来了(咕咕咕);安卓端没找到,倒是看到了自托管的Appflowy Cloud出来了,当即决定部署,经过两天摸索,将安装的步骤整理如下。


自托管的Appflowy Cloud采用Docker compose进行部署,一共有11个容器服务,其中5个服务是可选部署;11个服务如下:

  • nginx:代理服务,用于代理各个服务的地址
  • minio:一个开源的对象存储服务器,它兼容Amazon S3服务接口。用于数据存储。
  • postgres:数据库服务
  • redis:缓存中间件
  • gotrue:身份验证服务器
  • appflowy_cloud:appflowy的核心业务服务
  • admin_frontend(可选):管理登陆授权的web页面服务,官方建议是安装,便于新增用户和登陆。因为不使用第三方的oauth的时候,只能通过web页面登陆然后跳转到appflowy。没看明白的话建议先安装,后续使用就明白了。
  • tunnel(可选):提供将 appflowy 连接到 Cloudflare 的安全方式,无需公共可路由 IP 地址。
  • portainer、portainer_init(可选):两个服务是便于Docker管理的WEB UI。
  • pgadmin(可选):管理postgres 数据库的WEB UI。
    部署的服务架构图如下:

    📌
    可以看到有很多的服务非Appflowy本身的,可以与其他的共用;但是因为docker-compose的配置内容都是默认的,如果使用自己部署的minio、postgres、redis的话注意需要修改docker-compose.yml文件里面的地址并注释掉对应的服务,其中postgres还需要手工打脚本。经过折腾后还是强烈建议不要使用自己部署的minio、postgres、redis,可以省了很多麻烦。

二.部署准备

本着最小化原则,本次部署的教程去除了tunnel、portainer、portainer_init、pgadmin的部署。如果都需部署可以跳过我修改的配置信息。

  • 端口 80/443 可用,这点很重要!!!因为哪怕服务改了端口,但是Appflowy客户端在websocket访问的时候默认的80端口会导致数据无法同步,🥴疯狂踩坑。
  • 运行内存最低2GB,建议4GB
  • 本次教程部署的服务器系统为Debian 11

三.程序部署

1.部署Docker

官网教程地址:https://docs.docker.com/engine/install/debian/
a.运行一下命令卸载相关可能导致冲突的包

for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done

b.设置Docker apt存储库

# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

c.安装Docker

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

d.通过运行hello-world镜像验证运行是否成功

sudo docker run hello-world

2.部署AppFlowy-Cloud

a.登陆服务器拉取最新代码

mkdir appflowy && cd appflowy
git clone https://github.com/AppFlowy-IO/AppFlowy-Cloud
cd AppFlowy-Cloud

b.修改.env配置文件
首先复制一份模板命名为.env

cp deploy.env .env

修改.env的配置信息

# 设置一个加密的密码 任意都可
GOTRUE_JWT_SECRET=benzhu666

#如果设置为true,将自动确认用户注册。
#如果设置了OAuth2或配置了smtp,则可以将其设置为false
#以强制执行电子邮件确认或OAuth2登录。
#如果设置为false,则需要设置SMTP
GOTRUE_MAILER_AUTOCONFIRM=false

# 设置邮箱的stmp
GOTRUE_SMTP_HOST=smtp.exmail.qq.com
GOTRUE_SMTP_PORT=465
GOTRUE_SMTP_USER=
GOTRUE_SMTP_PASS=
GOTRUE_SMTP_ADMIN_EMAIL=

# gotrue管理员账号 
GOTRUE_ADMIN_EMAIL=my@benzhu.xyz
GOTRUE_ADMIN_PASSWORD=6666666

# 应用的地址
API_EXTERNAL_URL=http://127.0.0.1

# 设置oathu2登录  建议可以设置一个github的 也很方便 参考链接如下:
# https://github.com/AppFlowy-IO/AppFlowy-Cloud/blob/main/doc/AUTHENTICATION.md#github
# Google OAuth2
GOTRUE_EXTERNAL_GOOGLE_ENABLED=false
GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID=
GOTRUE_EXTERNAL_GOOGLE_SECRET=
GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI=http://your-host/callback
# GitHub OAuth2
GOTRUE_EXTERNAL_GITHUB_ENABLED=true
GOTRUE_EXTERNAL_GITHUB_CLIENT_ID=
GOTRUE_EXTERNAL_GITHUB_SECRET=
GOTRUE_EXTERNAL_GITHUB_REDIRECT_URI=http://127.0.0.1/gotrue/callback
# Discord OAuth2
GOTRUE_EXTERNAL_DISCORD_ENABLED=false
GOTRUE_EXTERNAL_DISCORD_CLIENT_ID=
GOTRUE_EXTERNAL_DISCORD_SECRET=
GOTRUE_EXTERNAL_DISCORD_REDIRECT_URI=http://your-host/callback
# File Storage
USE_MINIO=true
# MINIO_URL=http://localhost:9000 # change this if you are using a different address for minio
# 下面的配置无需更改 
AWS_ACCESS_KEY_ID=minioadmin
AWS_SECRET_ACCESS_KEY=minioadmin
AWS_S3_BUCKET=appflowy
AWS_REGION=us-east-1

RUST_LOG=info

# 下面这些服务我都没有部署 可以直接注释掉
# PgAdmin
#PGADMIN_DEFAULT_EMAIL=admin@example.com
#PGADMIN_DEFAULT_PASSWORD=password

# Portainer (username: admin)
#PORTAINER_PASSWORD=password1234

# Grafana Dashboard
#GF_SECURITY_ADMIN_USER=admin
#GF_SECURITY_ADMIN_PASSWORD=password

# Cloudflare tunnel token
#CLOUDFLARE_TUNNEL_TOKEN=

c.修改docker-compose.yml
因为有些服务不需要,因此需要修改docker-compose.yml。

version: '3'
services:
  nginx:
    restart: on-failure
    image: nginx
    ports:
      - 80:80
      - 443:443
    depends_on: # If you did not deploy any of the services below, comment those out
      - minio
      - appflowy_cloud
      - gotrue
      - admin_frontend
# portainer服务没有部署
#      - portainer
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/ssl/certificate.crt:/etc/nginx/ssl/certificate.crt
      - ./nginx/ssl/private_key.key:/etc/nginx/ssl/private_key.key

  # You do not need this if you have configured to use your own s3 file storage
  minio:
    restart: on-failure
    image: minio/minio
    ports:
      - 9000:9000
      - 9001:9001
    environment:
      - MINIO_BROWSER_REDIRECT_URL=http://localhost/minio
    command: server /data --console-address ":9001"
    volumes:
      - minio_data:/data

  postgres:
    restart: on-failure
    image: postgres
    environment:
      - POSTGRES_USER=${POSTGRES_USER:-postgres}
      - POSTGRES_DB=${POSTGRES_DB:-postgres}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-password}
      - POSTGRES_HOST=${POSTGRES_HOST:-postgres}
    ports:
      - 5433:5432
    volumes:
      - ./migrations/before:/docker-entrypoint-initdb.d
      - postgres_data:/var/lib/postgresql/data

  redis:
    restart: on-failure
    image: redis
    ports:
      - 6380:6379

  gotrue:
    restart: on-failure
    build:
      context: .
      dockerfile: docker/gotrue.Dockerfile
    depends_on:
      - postgres
    environment:
      # Gotrue config: https://github.com/supabase/gotrue/blob/master/example.env
      - GOTRUE_SITE_URL=appflowy-flutter://                           # redirected to AppFlowy application
      - URI_ALLOW_LIST=*                                              # adjust restrict if necessary
      - GOTRUE_JWT_SECRET=${GOTRUE_JWT_SECRET}                        # authentication secret
      - GOTRUE_DB_DRIVER=postgres
      - API_EXTERNAL_URL=${API_EXTERNAL_URL}
      - DATABASE_URL=postgres://supabase_auth_admin:root@postgres:5432/postgres
      - PORT=9999
      - GOTRUE_SMTP_HOST=${GOTRUE_SMTP_HOST}                          # e.g. smtp.gmail.com
      - GOTRUE_SMTP_PORT=${GOTRUE_SMTP_PORT}                          # e.g. 465
      - GOTRUE_SMTP_USER=${GOTRUE_SMTP_USER}                          # email sender, e.g. noreply@appflowy.io
      - GOTRUE_SMTP_PASS=${GOTRUE_SMTP_PASS}                          # email password
      - GOTRUE_MAILER_URLPATHS_CONFIRMATION=/gotrue/verify
      - GOTRUE_MAILER_URLPATHS_INVITE=/gotrue/verify
      - GOTRUE_MAILER_URLPATHS_RECOVERY=/gotrue/verify
      - GOTRUE_MAILER_URLPATHS_EMAIL_CHANGE=/gotrue/verify
      - GOTRUE_SMTP_ADMIN_EMAIL=${GOTRUE_SMTP_ADMIN_EMAIL}            # email with admin privileges e.g. internal@appflowy.io
      - GOTRUE_SMTP_MAX_FREQUENCY=${GOTRUE_SMTP_MAX_FREQUENCY:-1ns}   # set to 1ns for running tests
      - GOTRUE_MAILER_AUTOCONFIRM=${GOTRUE_MAILER_AUTOCONFIRM:-false} # change this to true to skip email confirmation
      # Google OAuth config
      - GOTRUE_EXTERNAL_GOOGLE_ENABLED=${GOTRUE_EXTERNAL_GOOGLE_ENABLED}
      - GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID=${GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID}
      - GOTRUE_EXTERNAL_GOOGLE_SECRET=${GOTRUE_EXTERNAL_GOOGLE_SECRET}
      - GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI=${GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI}
      # GITHUB OAuth config
      - GOTRUE_EXTERNAL_GITHUB_ENABLED=${GOTRUE_EXTERNAL_GITHUB_ENABLED}
      - GOTRUE_EXTERNAL_GITHUB_CLIENT_ID=${GOTRUE_EXTERNAL_GITHUB_CLIENT_ID}
      - GOTRUE_EXTERNAL_GITHUB_SECRET=${GOTRUE_EXTERNAL_GITHUB_SECRET}
      - GOTRUE_EXTERNAL_GITHUB_REDIRECT_URI=${GOTRUE_EXTERNAL_GITHUB_REDIRECT_URI}
      # Discord OAuth config
      - GOTRUE_EXTERNAL_DISCORD_ENABLED=${GOTRUE_EXTERNAL_DISCORD_ENABLED}
      - GOTRUE_EXTERNAL_DISCORD_CLIENT_ID=${GOTRUE_EXTERNAL_DISCORD_CLIENT_ID}
      - GOTRUE_EXTERNAL_DISCORD_SECRET=${GOTRUE_EXTERNAL_DISCORD_SECRET}
      - GOTRUE_EXTERNAL_DISCORD_REDIRECT_URI=${GOTRUE_EXTERNAL_DISCORD_REDIRECT_URI}
      # Prometheus Metrics
      - GOTRUE_METRICS_ENABLED=true
      - GOTRUE_METRICS_EXPORTER=prometheus
    ports:
      - 9998:9999

  appflowy_cloud:
    restart: on-failure
    environment:
      - RUST_LOG=${RUST_LOG:-info}
      - APPFLOWY_ENVIRONMENT=production
      - APPFLOWY_DATABASE_URL=postgres://postgres:password@postgres:5432/postgres
      - APPFLOWY_REDIS_URI=redis://redis:6379
      - APPFLOWY_GOTRUE_JWT_SECRET=${GOTRUE_JWT_SECRET}
      - APPFLOWY_GOTRUE_BASE_URL=http://gotrue:9999
      - APPFLOWY_GOTRUE_EXT_URL=${API_EXTERNAL_URL}
      - APPFLOWY_GOTRUE_ADMIN_EMAIL=${GOTRUE_ADMIN_EMAIL}
      - APPFLOWY_GOTRUE_ADMIN_PASSWORD=${GOTRUE_ADMIN_PASSWORD}
      - APPFLOWY_S3_USE_MINIO=${USE_MINIO}
      - APPFLOWY_S3_MINIO_URL=${MINIO_URL:-http://minio:9000}
      - APPFLOWY_S3_ACCESS_KEY=${AWS_ACCESS_KEY_ID}
      - APPFLOWY_S3_SECRET_KEY=${AWS_SECRET_ACCESS_KEY}
      - APPFLOWY_S3_BUCKET=${AWS_S3_BUCKET}
      - APPFLOWY_S3_REGION=${AWS_REGION}
    build:
      context: .
      dockerfile: Dockerfile
    image: appflowyinc/appflowy_cloud:${BACKEND_VERSION:-latest}
    depends_on:
      - redis
      - postgres
      - gotrue
    ports:
      - 8000:8000

  # Optional
  admin_frontend:
    restart: on-failure
    build:
      context: .
      dockerfile: ./admin_frontend/Dockerfile
    image: appflowyinc/admin_frontend:${BACKEND_VERSION:-latest}
    depends_on:
      - gotrue
    ports:
      - 3000:3000

# 下方四个可选的服务不安装  
# Optional
  #tunnel:
    #image: cloudflare/cloudflared
    #restart: unless-stopped
    #command: tunnel --no-autoupdate run
    #environment:
      #- TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}
    #depends_on:
      #- nginx

  # Optional
  #portainer:
    #restart: on-failure
    #image: portainer/portainer-ce:latest
    #ports:
      #- 9442:9000
    #volumes:
     # - /var/run/docker.sock:/var/run/docker.sock

  # Optional
  #portainer_init:
    #depends_on:
      #- portainer
   # image: alpine/curl
  #  restart: on-failure
    #environment:
     # - PORTAINER_PASSWORD=${PORTAINER_PASSWORD}
#    volumes:
  #    - ./docker/portainer/setup.sh:/setup.sh
  #  command: ./setup.sh

  # Optional
#  pgadmin:
 #   restart: on-failure
 #   image: dpage/pgadmin4
  #  depends_on:
  #    - postgres
 #   environment:
#      - PGADMIN_DEFAULT_EMAIL=${PGADMIN_DEFAULT_EMAIL}
   #   - PGADMIN_DEFAULT_PASSWORD=${PGADMIN_DEFAULT_PASSWORD}
#    ports:
#      - 5400:80
#    volumes:
#      - ./docker/pgadmin/servers.json:/pgadmin4/servers.json

volumes:
  postgres_data:
  minio_data:

d.修改nginx配置
不修改的话nginx无法启动,路径nginx/nginx.conf

# Minimal nginx configuration for AppFlowy-Cloud
# Self Hosted AppFlowy Cloud user should alter this file to suit their needs

events {
    worker_connections 1024;
}

http {
    map $http_upgrade $connection_upgrade {
       default upgrade;
       ''      close;
    }

    server {
        listen 8080;

        # https://github.com/nginxinc/nginx-prometheus-exporter
        location = /stub_status {
            stub_status;
        }
    }

    server {
        ssl_certificate /etc/nginx/ssl/certificate.crt;
        ssl_certificate_key /etc/nginx/ssl/private_key.key;

        listen 80;
        listen 443 ssl;

        underscores_in_headers on;

        # GoTrue
        location /gotrue/ {
            rewrite ^/gotrue(/.*)$ $1 break;
            proxy_pass http://gotrue:9999;

            # Allow headers like redirect_to to be handed over to the gotrue
            # for correct redirecting
            proxy_set_header Host $http_host;
            proxy_pass_request_headers on;
        }

        # WebSocket
        location /ws {
            proxy_pass http://appflowy_cloud:8000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_set_header Host $host;
            proxy_read_timeout 86400;
        }

        # AppFlowy-Cloud
        location /api {
            proxy_set_header X-Request-Id $request_id;
            proxy_pass http://appflowy_cloud:8000;
        }

        # Minio Web UI
        # Derive from: https://min.io/docs/minio/linux/integrations/setup-nginx-proxy-with-minio.html
        # Optional Module, comment this section if you are did not deploy minio in docker-compose.yml
        location /minio/ {
            rewrite ^/minio/(.*) /$1 break;
            proxy_set_header Host $http_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;
            proxy_set_header X-NginX-Proxy true;

            ## This is necessary to pass the correct IP to be hashed
            real_ip_header X-Real-IP;

            proxy_connect_timeout 300;

            ## To support websockets in MinIO versions released after January 2023
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            # Some environments may encounter CORS errors (Kubernetes + Nginx Ingress)
            # Uncomment the following line to set the Origin request to an empty string
            # proxy_set_header Origin '';

            chunked_transfer_encoding off;

            proxy_pass http://minio:9001;
        }

     #主要注释Pgadmin和portainer的代理
     # PgAdmin
        # Optional Module, comment this section if you are did not deploy pgadmin in docker-compose.yml
       # location /pgadmin/ {
        #    proxy_set_header X-Script-Name /pgadmin;
         #   proxy_set_header X-Scheme $scheme;
          #  proxy_set_header Host $host;
           # proxy_pass http://pgadmin:80/;
            #proxy_redirect off;
        #}

        # Portainer
    # Optional Module, comment this section if you are did not deploy portainer in docker-compose.yml
       # location /portainer/ {
         #   proxy_pass http://portainer:9000/;
      #  }

        # Admin Frontend
    # Optional Module, comment this section if you are did not deploy admin_frontend in docker-compose.yml
        location / {
            proxy_set_header X-Scheme $scheme;
            proxy_set_header Host $host;

            proxy_pass http://admin_frontend:3000;
        }
    }

}

e.启动服务

docker compose up -d

f.检查服务是否正常

docker ps -a

g.重新配置和重新部署
重新配置和重新启动是很常见的。只需编辑并再次.env执行docker compose up -d

四.客户端安装

1.客户端下载

直接下载appflowy的最新版本即可。
https://github.com/AppFlowy-IO/AppFlowy/tags

2.客户端设置

a.安装点击快速进入,然后进入设置


b.在cloud settings里面开启同步后点击重启,重启后进入填入appflowy cloud的地址

c.登录账号
因为目前应用端是没法直接输入账号密码登录的,要么通过othau2登录,要么通过web管理台登录。
othau2没啥好说,直接唤起登录即可,通过管理台登录的话先打开地址:http://127.0.0.1/web/login,将127.0.0.1修改为自己服务的地址,用配置的账号密码进行登录,然后单击open appflowy:

五.相关问题

1.如何自编译admin_frontend

如果我们采用的自己单独部署的redis和postgrep数据库之类的话需要修改,这里提供一下参考。
下载了appflowy cloud源码后进入admin_frontend目录。将内容修改完毕后执行命令编译自己的镜像:

docker compose up -d --no-deps --build admin_frontend

评论

  1. Kim
    3周前
    2024-4-06 10:41:40

    写的非常好,可惜我是小白,只会有群晖这类简单的部署,这个对我来说太复杂了,谢谢。

    • xiaozhu
      博主
      Kim
      3周前
      2024-4-06 11:44:42

      😊不太建议安装,目前部署方式不太友好,使用起来也挺多bug;版本还在不断迭代,可以关注后续变化稳定后再安装。

      • Kim
        xiaozhu
        3周前
        2024-4-06 12:21:11

        谢谢提醒,那我暂时用Joplin过渡下,随时关注。

  2. 毒萝
    3周前
    2024-4-04 15:11:15

    我想通过volume 把docker里面的数据挂载到外边,但是不知道数据的存储路径在哪里。怎么实现

    • xiaozhu
      博主
      毒萝
      3周前
      2024-4-04 15:34:55

      数据是存储在minio里面,可以通过指定minio镜像挂载的路径来实现。

      • 咨询
        xiaozhu
        3周前
        2024-4-06 9:47:47

        redis跟postgre用来做什么的

        • xiaozhu
          博主
          咨询
          3周前
          2024-4-06 11:41:29

          官方文档我没有找到有关postgre和redis有关详细说明;postgre是个数据库,正常来说会存储用户的信息,minio里面的数据通过postgre与用户关联起来等等;redis一般充当缓存中间件和用于多服务数据共享的。

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇