一.了解介绍
首先介绍一下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
写的非常好,可惜我是小白,只会有群晖这类简单的部署,这个对我来说太复杂了,谢谢。
😊不太建议安装,目前部署方式不太友好,使用起来也挺多bug;版本还在不断迭代,可以关注后续变化稳定后再安装。
谢谢提醒,那我暂时用Joplin过渡下,随时关注。
我想通过volume 把docker里面的数据挂载到外边,但是不知道数据的存储路径在哪里。怎么实现
数据是存储在minio里面,可以通过指定minio镜像挂载的路径来实现。
redis跟postgre用来做什么的
官方文档我没有找到有关postgre和redis有关详细说明;postgre是个数据库,正常来说会存储用户的信息,minio里面的数据通过postgre与用户关联起来等等;redis一般充当缓存中间件和用于多服务数据共享的。