MoreRSS

site iconLala | 荒岛修改

一个应用分享、教程类的博客,主要是那些需要自部署的。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

Lala | 荒岛的 RSS 预览

部署MoonTVPlus二开增强版+LogVar弹幕API

2025-12-09 06:10:37

MoonTVPlus是基于MoonTV v100二次开发的增强版影视聚合播放器。它在原版基础上新增了外部播放器支持、视频超分、弹幕系统、评论抓取等实用功能,提供更强大的观影体验。

相对原版新增内容:

🎮 外部播放器跳转:支持 PotPlayer、VLC、MPV、MX Player、nPlayer、IINA 等多种外部播放器
✨ 视频超分 (Anime4K):使用 WebGPU 技术实现实时视频画质增强(支持 1.5x/2x/3x/4x 超分)
💬 弹幕系统:完整的弹幕搜索、匹配、加载功能,支持弹幕设置持久化、弹幕屏蔽
📝 豆瓣评论抓取:自动抓取并展示豆瓣电影短评,支持分页加载
🪒自定义去广告:你可以自定义你的去广告代码,实现更强力的去广告功能

安装Docker:

apt -y update
apt -y install curl
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

创建目录新建compose文件:

mkdir /opt/moontvplus && cd /opt/moontvplus && nano docker-compose.yml

写入如下内容,需要修改的地方写了注释:

services:
  moontv-core:
    image: ghcr.io/mtvpls/moontvplus:latest
    container_name: moontv-core
    restart: on-failure
    ports:
      - '10300:3000'
    environment:
      - USERNAME=admin
      - PASSWORD=yourpasswd # 设置moontvplus管理员密码
      - NEXT_PUBLIC_STORAGE_TYPE=kvrocks
      - KVROCKS_URL=redis://moontv-kvrocks:6666
    depends_on:
      - moontv-kvrocks

  moontv-kvrocks:
    image: apache/kvrocks
    container_name: moontv-kvrocks
    restart: unless-stopped
    volumes:
      - kvrocks-data:/var/lib/kvrocks

  danmu-api:
    image: logvar/danmu-api:latest
    container_name: danmu-api
    restart: unless-stopped
    ports:
      - "9321:9321"
    environment:
      - TOKEN=89641937 # 设置访问token
      - ADMIN_TOKEN=19378964 # 设置管理员访问token
    volumes:
      - ./.chche:/app/.cache

volumes:
  kvrocks-data:

启动:

docker compose up -d

配置Ferron反向代理:

nano /etc/ferron.kdl

写入如下内容:

moontvplus.example.com {
    proxy "http://127.0.0.1:10300/"
}

重载Ferron:

systemctl reload ferron

弹幕配置,弹幕API地址填写:http://danmu-api:9321,弹幕APIToken填写你设置的TOKEN=值(默认89641937)

配置订阅(视频源),这里推荐这个项目LunaTV-config。将这个URL填写上去保存即可。

效果:

如果你不想公开danmu-api服务器,可以删掉端口映射的配置,改为如下内容:

...
  danmu-api:
    image: logvar/danmu-api:latest
    container_name: danmu-api
    restart: unless-stopped
    ports:
      - "9321:9321"
    expose:
      - "9321"
    environment:
      - TOKEN=89641937 # 设置访问token
      - ADMIN_TOKEN=19378964 # 设置管理员访问token
    volumes:
      - ./.chche:/app/.cache
...

Ferron:一个用Rust编写的快速、内存安全的Web服务器

2025-12-08 13:18:44

Ferron是一个用Rust编写的高性能Web服务器。Ferron特点(摘自项目页面):

High performance – built with Rust’s async capabilities for optimal speed.
Memory-safe – built with Rust, which is a programming language offering memory safety.
Extensibility – modular architecture for easy customization.
Secure – focus on robust security practices and safe concurrency.

我安装用了一段时间,觉得各方面非常不错,所以特地写篇入门的文章,顺便也算是推荐一下吧。目前我已经把多台服务器的NGINX换成这个了。初次用Ferron给人最大的感觉就是配置起来特别简单,有点Caddy那味,甚至比Caddy还简单。

除了配置简单以外,很多特性或者说功能都是开箱即用的,比如HTTP3、PROXY Protocol、WebSocket、GRPC反代、FastCGI、自动申请TLS证书等等。废话就不多说了,下面一起来体验一下。

安装Ferron,这里我的系统是Debian 13,使用官方的存储库来安装:

apt update
apt install curl gnupg2 ca-certificates lsb-release debian-archive-keyring
curl https://deb.ferron.sh/signing.pgp | gpg --dearmor | tee /usr/share/keyrings/ferron-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/ferron-keyring.gpg] https://deb.ferron.sh $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/ferron.list
apt update
apt install ferron

管理Ferron服务:

systemctl stop ferron
systemctl restart ferron
systemctl reload ferron

重要的目录和文件:

/var/log/ferron/access.log # 访问日志
/var/log/ferron/error.log # 错误日志
/var/www/ferron # Ferron的网站根目录
/etc/ferron.kdl # Ferron的主配置文件

默认使用的用户和主目录:

ferron:x:1000:1000::/var/lib/ferron:/usr/sbin/nologin

编辑主配置文件:

nano /etc/ferron.kdl

在主配置文件添加如下内容可以包含(include)其他配置文件:

include "/var/lib/ferron/*.kdl"

在主配置文件添加如下内容以支持HTTP3、PROXY Protocol(默认未启用)、自动申请TLS证书功能:

* {
    protocols "h1" "h2" "h3"
    protocol_proxy #false
    auto_tls
    auto_tls_contact "[email protected]"
    auto_tls_cache "/var/lib/ferron/letsencrypt-cache"
    auto_tls_letsencrypt_production
    auto_tls_challenge "http-01"
}

现在简单说一下最常见的用例:反向代理。在主配置文件或者包含(include)一个新的配置文件写入如下内容:

example.com {
    proxy "http://127.0.0.1:3000/"
}

这就完成了一个反向代理的配置,并且Ferron直接就支持WebSocket,不需要额外的配置。我们需要注意的是Ferron默认会将请求发送到后端服务器之前重写“Host”标头,并在“X-Forwarded-Host”标头中保留原始的“Host”标头值。然而,有些Web应用程序可能无法在这种配置下正常工作,这可能会导致主机头不匹配以及其他问题。在这种情况下,你可以将“Host”标头设置为原始值(保留完整的“Host”标头):

example.com {
    proxy "http://127.0.0.1:3000/"
    proxy_request_header_replace "Host" "{header:Host}"
}

Ferron还支持多域名(virtual host)、IP(virtual host):

example.com,www.example.com {
    ...
}

"192.168.1.1" {
    ...
}

自动重定向,将不带“www”的URL重定向到带“www”的URL:

example.com {
    wwwredirect #true
}

每当配置文件发生更改,只需要Reload即可使Ferron使用新的配置:

systemctl reload ferron

除了反代,Ferron还支持通过FastCGI运行PHP程序,例如这里我要配置一个Laravel:

example.com {
    root "/var/www/laravel/public"
    rewrite "^/(.*)" "/index.php/$1" file=#false directory=#false last=#true
    fcgi_php "unix:///run/php/php8.4-fpm.sock"
}

这里要特别注意,Debian系统默认的Unix套接字(php8.4-fpm.sock)所有者和组是www-data,我们需要将其修改为ferron,编辑如下配置文件:

nano /etc/php/8.4/fpm/pool.d/www.conf

找到如下内容将其修改为ferron:

listen.owner = ferron
listen.group = ferron

重启PHP-FPM:

systemctl restart php8.4-fpm.service

重载Ferron:

systemctl reload ferron

完整的配置和文档请参考官方网站:https://ferron.sh/docs

PigeonPod:随时随地收听YouTube

2025-12-03 06:33:05

PigeonPod是一款可以将YouTube的任意频道、播放列表转换成播客的程序,支持自托管。开始部署前,你需要创建一个YouTube Data API v3的API key创建步骤可参考这里

安装Docker和NGINX:

apt -y update
apt -y install curl nginx python3-certbot-nginx
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

创建目录新建compose文件:

mkdir /opt/pigeon-pod && cd /opt/pigeon-pod && nano docker-compose.yml

写入如下内容(将pigeonpod.example.com替换成你的域名):

services:
  pigeon-pod:
    image: ghcr.io/aizhimou/pigeon-pod:latest
    restart: unless-stopped
    container_name: pigeon-pod
    ports:
      - '127.0.0.1:8834:8080'
    environment:
      - 'PIGEON_BASE_URL=https://pigeonpod.example.com'
      - 'PIGEON_AUDIO_FILE_PATH=/data/audio/'
      - 'PIGEON_COVER_FILE_PATH=/data/cover/'
      - 'SPRING_DATASOURCE_URL=jdbc:sqlite:/data/pigeon-pod.db' # set to your database path
    volumes:
      - data:/data
volumes:
  data:

启动:

docker compose up -d

配置NGINX反向代理:

nano /etc/nginx/sites-available/pigeonpod

写入如下内容(将pigeonpod.example.com替换成你的域名):

server {
    listen 80;
    server_name pigeonpod.example.com;
    client_max_body_size 0;

    location / {
        proxy_pass http://127.0.0.1:8834;
        proxy_set_header Host $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;
    }
}

启用站点:

ln -s /etc/nginx/sites-available/pigeonpod /etc/nginx/sites-enabled/pigeonpod

签发SSL证书:

certbot --nginx --email [email protected] --agree-tos --no-eff-email

访问pigeonpod.example.com,默认的管理员账号:root,密码:Root@123

登录进去,添加你刚创建的YouTube Data API Key:

效果:

VPS配置LotSpeed单边加速

2025-12-02 10:29:06

我第一眼看到这个名字还以为是锐速,卧槽文艺复兴了??说起来还挺怀念那段时间的,那段时间是折腾小鸡最快乐的时候,现在已经电子阳痿了。。完全提不起兴趣,今年黑5,总共消费0元= =

找了台灵车落地鸡试了一下,没想到药效出乎意料的好,本来晚高峰只能跑0.几MBps的鸡,吃上这个后能跑150MBps了,白天能跑150MBps的,现在能跑650MBps了。。

LotSpeed作者一共提供了3个版本,我全部都试了一遍,发现zeta-tcp版本的效果最好,所以这里我就只记录下zeta-tcp版本的配置步骤。

系统我使用的是Debian13,先更新系统、重启,确保系统当前运行的内核是最新版:

apt update
apt full-upgrade

安装需要用到的软件包:

apt install build-essential git
apt install linux-headers-$(uname -r)

克隆项目存储库、编译lotspeed内核模块:

git clone -b zeta-tcp https://github.com/uk0/lotspeed.git
cd lotspeed
make

安装lotspeed内核模块:

cp lotspeed.ko /lib/modules/$(uname -r)/kernel/net/ipv4/
depmod -a

加载lotspeed内核模块:

modprobe lotspeed

确保加载成功:

lsmod | grep lotspeed

[可选]配置开机自动加载lotspeed内核模块:

echo "lotspeed" >> /etc/modules-load.d/lotspeed.conf

这个开机自动加载配不配其实不重要,因为只要你后续把拥塞控制算法设置成lotspeed,系统就会自动加载lotspeed内核模块。配置这个的效果就是即便你的系统拥塞控制算法不是lotspeed,系统也自动加载lotspeed内核模块。换句话说就是无论你用不用这个模块,系统都先给你加载起来。

设置拥塞控制算法为lotspeed:

nano /etc/sysctl.d/10-lotspeed.conf

写入如下内容:

net.ipv4.tcp_congestion_control = lotspeed
net.ipv4.tcp_no_metrics_save = 1

使其生效:

sysctl --system

查看拥塞控制算法是否生效:

sysctl net.ipv4.tcp_congestion_control

这样就配置好了,注意不要随意更新系统内核,如果内核更新了,你就需要重新编译一遍,作者要是能搞个dkms出来就好了。

openSUSE Tumbleweed配置Mihomo裸核

2025-11-11 06:33:55

如果你因为种种原因不想再使用各类基于mihomo内核的GUI客户端了,那么可以尝试一下直接用裸核,裸核除了第一次配置的时候会麻烦一点(搓配置文件),后续使用是很爽的。

openSUSE Tumbleweed是我主要使用的Linux发行版,实际上下面的这些配置步骤应该适用于大部分使用systemd的Linux系统。

下载mihomo内核/解压/给执行权限:

wget https://github.com/MetaCubeX/mihomo/releases/download/v1.19.16/mihomo-linux-amd64-v3-go123-v1.19.16.gz
gzip -d mihomo-linux-amd64-v3-go123-v1.19.16.gz
sudo chmod +x mihomo-linux-amd64-v3-go123-v1.19.16

重命名并移动到/usr/local/bin:

sudo mv mihomo-linux-amd64-v3-go123-v1.19.16 /usr/local/bin/mihomo

创建运行时的目录和配置文件:

sudo mkdir /etc/mihomo
sudo nano /etc/mihomo/config.yaml

我的配置如下:

mixed-port: 7890
allow-lan: true
tcp-concurrent: true
find-process-mode: strict
mode: rule
log-level: info
ipv6: false
keep-alive-interval: 30
unified-delay: true

profile:
  store-selected: true
  store-fake-ip: false

external-controller: 127.0.0.1:9090
external-controller-cors:
  allow-origins:
    - '*'
  allow-private-network: true
secret: "89641937"             
external-ui: "./ui"                      
external-ui-name: zashboard
external-ui-url: "https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip"

tun:
  enable: true
  stack: mixed
  auto-route: true
  auto-redirect: false
  auto-detect-interface: true
  dns-hijack:
    - any:53
  strict-route: true
  mtu: 1500

dns:
  enable: true
  cache-algorithm: arc
  prefer-h3: false
  use-hosts: true
  use-system-hosts: true
  listen: 127.0.0.1:6868
  ipv6: false
  enhanced-mode: redir-host
  default-nameserver:
    - 223.5.5.5
    - 119.29.29.29
  nameserver:
    - https://cloudflare-dns.com/dns-query
    - https://dns.google/dns-query
  proxy-server-nameserver:
    - https://dns.alidns.com/dns-query
    - https://doh.pub/dns-query
  direct-nameserver:
    - https://dns.alidns.com/dns-query
    - https://doh.pub/dns-query
  respect-rules: true

sniffer:
  enable: true
  force-dns-mapping: true
  parse-pure-ip: true
  sniff:
    HTTP:
      ports:
        - 80
        - 8080-8880
      override-destination: true
    TLS:
      ports:
        - 443
        - 8443

proxies:
  - name: proxy1
    type: vless
    server: 89.64.19.37
    port: 443
    network: tcp
    udp: true
    tls: true
    servername: www.cloudflare.com
    reality-opts:
      public-key: xxxx
      short-id: "xxxx"
    client-fingerprint: chrome
    uuid: uuid
    packet-encoding: xudp
    flow: xtls-rprx-vision
  - name: proxy2
    type: ss
    server: 89.64.19.37
    port: 8080
    network: tcp
    udp: true
    password: xxxx
    cipher: chacha20-ietf-poly1305

proxy-groups:
  - name: 🌍 VPN
    icon: https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Hijacking.png
    type: select
    proxies:
      - ⚡️ Fastest
      - 🎲 Random
      - proxy1
      - proxy2
  - name: ⚡️ Fastest
    icon: https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Auto.png
    type: url-test
    tolerance: 150
    url: https://cp.cloudflare.com/generate_204
    interval: 300
    proxies:
      - proxy1
      - proxy2
  - name: 🎲 Random
    icon: https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Filter.png
    type: fallback
    url: https://cp.cloudflare.com/generate_204
    interval: 300
    proxies:
      - proxy1
      - proxy2

rule-providers:
  torrent-trackers:
    type: http
    behavior: domain
    format: mrs
    url: https://github.com/legiz-ru/mihomo-rule-sets/raw/main/other/torrent-trackers.mrs
    path: ./rule-sets/torrent-trackers.mrs
    interval: 86400
    proxy: ⚡️ Fastest
  torrent-clients:
    type: http
    behavior: classical
    format: yaml
    url: https://github.com/legiz-ru/mihomo-rule-sets/raw/main/other/torrent-clients.yaml
    path: ./rule-sets/torrent-clients.yaml
    interval: 86400
    proxy: ⚡️ Fastest
  geosite-cn:
    type: http
    behavior: domain
    format: mrs
    url: https://github.com/MetaCubeX/meta-rules-dat/raw/meta/geo/geosite/cn.mrs
    path: ./rule-sets/geosite-cn.mrs
    interval: 86400
    proxy: ⚡️ Fastest
  geoip-cn:
    type: http
    behavior: ipcidr
    format: mrs
    url: https://github.com/MetaCubeX/meta-rules-dat/raw/meta/geo/geoip/cn.mrs
    path: ./rule-sets/geoip-cn.mrs
    interval: 86400
    proxy: ⚡️ Fastest
  geosite-private:
    type: http
    behavior: domain
    format: mrs
    url: https://github.com/MetaCubeX/meta-rules-dat/raw/meta/geo/geosite/private.mrs
    path: ./rule-sets/geosite-private.mrs
    interval: 86400
    proxy: ⚡️ Fastest
  geoip-private:
    type: http
    behavior: ipcidr
    format: mrs
    url: https://github.com/MetaCubeX/meta-rules-dat/raw/meta/geo/geoip/private.mrs
    path: ./rule-sets/geoip-private.mrs
    interval: 86400
    proxy: ⚡️ Fastest

rules:
  - RULE-SET,torrent-clients,DIRECT 
  - RULE-SET,torrent-trackers,DIRECT
  - RULE-SET,geosite-private,DIRECT
  - RULE-SET,geosite-cn,DIRECT
  - RULE-SET,geoip-private,DIRECT
  - RULE-SET,geoip-cn,DIRECT
  - MATCH,🌍 VPN

简单说下这个配置的效果:

1.使用zashboard作为Web控制面板,访问:http://127.0.0.1:9090/ui/zashboard/ 密码:89641937

2.DNS模式使用realip+嗅探。(我不喜欢用FakeIP)我用了很多测试DNS泄露的网站均没有检测到漏(没有在本机抓包验证,不能百分百肯定,应该是不会漏=-=)

3.我自己的使用习惯是Tun,所以默认启用Tun模式,如果要使用系统代理也可以用端口7890。

4.分流规则全部使用rule-set,并且规则很简单,没有搞一大堆乱七八糟的规则在里面,除了geosite/geoip外,就只加了和bt下载相关的(个人使用习惯:下小姐姐必备)

5.出站代理的只配置了vless/ss,仅用作演示。如果你要添加其他协议的节点请参考官方的“出站代理”文档

我自己是不使用公共机场服务的,所有的节点都是自建,所以上面的配置没有涉及到proxy-providers(代理集合或者叫代理供应商)但是我最近一直在使用remnawavepanel,所以也可以把remnawavepanel提供的订阅链接配置上:

proxy-providers:
  remnawave:
    type: http
    url: "https://sub.example.com/xxxx"
    path: ./proxy_providers/remnawave.yaml
    interval: 3600
    size-limit: 0

然后在proxy-groups里面使用刚才配置的proxy-providers:

proxy-groups:
  - name: 🌍 VPN
    icon: https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Hijacking.png
    type: select
    proxies:
      - ⚡️ Fastest
      - 🎲 Random
      - proxy1
      - proxy2
    use:
      - remnawave
  - name: ⚡️ Fastest
    icon: https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Auto.png
    type: url-test
    tolerance: 150
    url: https://cp.cloudflare.com/generate_204
    interval: 300
    proxies:
      - proxy1
      - proxy2
    use:
      - remnawave
  - name: 🎲 Random
    icon: https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Filter.png
    type: fallback
    url: https://cp.cloudflare.com/generate_204
    interval: 300
    proxies:
      - proxy1
      - proxy2
    use:
      - remnawave

创建systemd服务:

sudo nano /etc/systemd/system/mihomo.service

写入如下配置:

[Unit]
Description=mihomo Daemon, Another Clash Kernel.
After=network.target NetworkManager.service systemd-networkd.service iwd.service

[Service]
Type=simple
LimitNPROC=500
LimitNOFILE=1000000
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE
Restart=always
ExecStartPre=/usr/bin/sleep 1s
ExecStart=/usr/local/bin/mihomo -d /etc/mihomo
ExecReload=/bin/kill -HUP $MAINPID

[Install]
WantedBy=multi-user.target

启动并设置开机自启:

sudo systemctl enable --now mihomo

效果:

部署AppFlowy-Cloud笔记软件

2025-11-10 10:03:09

AppFlowy是Notion的开源替代品,你可以简单理解成这就是一个笔记软件。然后官方提供了一个自托管(self-host)版本:AppFlowy-Cloud,可以部署在自己的服务器上,无需使用官方的付费服务。

其实我半年前就部署过一次,试用了一会儿,当时就觉得这个程序的客户端UI真的太粗糙了,就没用下去,也懒得写文章记录部署的步骤,这回又故地重游了一次属于是。。心里想着半年过去了,这程序会不会变好一些?结果你猜怎么着?越来越拉了。。说句实话,我觉得这个AppFlowy-Cloud不值得我花这么长时间去部署,看看这个自托管版本的限制就知道了:

AI功能直接不让用,用户数量也限制只允许1个。。还有一堆其他的限制。。想赚钱能理解,但是你搞个自托管的版本限制成这个屌样,未免也有点太那啥了吧。。最TM骚的是这些限制在部署前找不到任何地方有说明,这是我部署好了后在管理员后台看到的。。你要在醒目的位置标明这些限制我压根就不会去部署了。

替大伙节约时间了,你看到这里可能就已经和我有一样的感受了,估计你也没有部署的欲望了,这东西不花钱真的就像一个大号的文本编辑器。。而且还有很多未知BUG,我刚部署的时候管理员后台直接报错打不开,隔了两天pull了个新的镜像后又能打开了(估计是他们修了BUG)但是还有一个问题是文件上传,只要上传的文件体积稍微大一点(10MB左右)就上传失败。。

遭老罪咯,花这么多时间去折腾这么个玩意,这个程序单说部署步骤也是同类产品中最繁琐的。。我的建议是花钱可以考虑,不花钱就别用了,自托管?搞笑的兄弟!我说的都是非常中肯的评价,好就是好,不好就是不好。

如果你想和我一起受罪,请开始准备工作:

1.一个域名A记录解析到:appflowy.example.com

2.系统的内存至少1GB,以下是我部署的全部服务内存占用情况,供参考:

3.系统的以下端口不能被其他程序占用,其中80/443端口用于给主机的NGINX反向代理:

80/443/3000/3001/8000/9999/9000/9001

我使用的系统是Debian13,安装NGINX/Docker:

apt -y update
apt -y install curl nginx python3-certbot-nginx
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

克隆AppFlowy-Cloud项目仓库:

cd /opt
git clone https://github.com/AppFlowy-IO/AppFlowy-Cloud
cd AppFlowy-Cloud

复制一份环境变量配置文件编辑:

cp deploy.env .env
nano .env

需要修改的内容如下,全部写好了注释。其他没有在这里列出的内容可以保持默认值不做修改:

# 设置你的AppFlowy域名
FQDN=appflowy.example.com
# 使用TLS
SCHEME=https
WS_SCHEME=wss
# 数据库密码
POSTGRES_PASSWORD=dbpassword
# MinIO的管理员账号密码,也用作s3存储桶的访问凭据
AWS_ACCESS_KEY=admin
AWS_SECRET=miniopassword
# AppFlowy管理员账号密码
[email protected]
GOTRUE_ADMIN_PASSWORD=appflowyadminpassword
# 使用命令openssl rand -hex 32生成 
GOTRUE_JWT_SECRET=0a7a5b32d2a28f51a1250d4d68e68aa7133e033b17eeb7a6e2a0d2ab5cb62cdb
# 关闭自动验证用户账户
GOTRUE_MAILER_AUTOCONFIRM=false
# 关闭用户注册功能
GOTRUE_DISABLE_SIGNUP=true
# GOTRUE的SMTP配置:
GOTRUE_SMTP_HOST=mail.example.com
GOTRUE_SMTP_PORT=587
GOTRUE_SMTP_USER=smtp                   
GOTRUE_SMTP_PASS=smtppassword
[email protected]
# AppFlowy的SMTP配置:
APPFLOWY_MAILER_SMTP_HOST=mail.example.com
APPFLOWY_MAILER_SMTP_PORT=587
APPFLOWY_MAILER_SMTP_USERNAME=smtp           
[email protected]  
APPFLOWY_MAILER_SMTP_PASSWORD=smtppassword
APPFLOWY_MAILER_SMTP_TLS_KIND=opportunistic # "none" "wrapper" "required" "opportunistic"
# AI配置
AI_OPENAI_API_KEY=sk-proj-xxxxx
AI_OPENAI_API_SUMMARY_MODEL=gpt-4o-mini
# 性能优化
APPFLOWY_COLLABORATE_MULTI_THREAD=true
# PGadmin的管理员账号密码
[email protected]
PGADMIN_DEFAULT_PASSWORD=pgadminpassword

由于我使用外部(主机)的NGINX来反向代理AppFlowy,所以需要编辑compose文件:

nano docker-compose.yml

注释或者删掉compose内的NGINX配置:

services:
#  nginx:
#    restart: on-failure
#    image: nginx
#    ports:
#      - ${NGINX_PORT:-80}:80   # Disable this if you are using TLS
#      - ${NGINX_TLS_PORT:-443}:443
#    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

将其他服务的端口暴露出来,为安全起见这里全部配置成只监听在本地(127.0.0.1):

services:
...
  minio:
    restart: on-failure
    ...
    ports:
      - "127.0.0.1:9000:9000"
      - "127.0.0.1:9001:9001"
...
  gotrue:
    restart: on-failure
    ...
    ports:
      - "127.0.0.1:9999:9999"
...
  appflowy_cloud:
    restart: on-failure
    ...
    ports:
      - "127.0.0.1:8000:8000"
...
  admin_frontend:
    restart: on-failure
    ...
    ports:
      - "127.0.0.1:3000:3000"
...
  appflowy_web:
    restart: on-failure
    ...
    ports:
      - "127.0.0.1:3001:80"

启动:

docker compose up -d

新建NGINX站点配置文件:

nano /etc/nginx/sites-available/appflowy

写入如下内容:

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

server {
    listen 80;
    server_name appflowy.example.com;
    client_max_body_size 0;
    underscores_in_headers on;

    access_log /var/log/nginx/appflowy_access.log;
    error_log /var/log/nginx/appflowy_error.log;

    set $appflowy_cloud_backend "http://127.0.0.1:8000";
    set $gotrue_backend "http://127.0.0.1:9999";
    set $admin_frontend_backend "http://127.0.0.1:3000";
    set $appflowy_web_backend "http://127.0.0.1:3001";
    set $minio_backend "http://127.0.0.1:9001";
    set $minio_api_backend "http://127.0.0.1:9000";
    set $minio_internal_host "minio:9000";

    # GoTrue
    location /gotrue/ {
        proxy_pass $gotrue_backend;
        rewrite ^/gotrue(/.*)$ $1 break;
        # 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 $appflowy_cloud_backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $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_read_timeout 86400s;
    }

    location /api {
        proxy_pass $appflowy_cloud_backend;
        proxy_set_header X-Request-Id $request_id;
        proxy_set_header Host $http_host;
        location ~* ^/api/workspace/([a-zA-Z0-9_-]+)/publish$ {
            proxy_pass $appflowy_cloud_backend;
            proxy_request_buffering off;
            client_max_body_size 256M;
        }

        # AppFlowy-Cloud
        location /api/chat {
            proxy_pass $appflowy_cloud_backend;
            proxy_http_version 1.1;
            proxy_set_header Connection "";
            chunked_transfer_encoding on;
            proxy_buffering off;
            proxy_cache off;
            proxy_read_timeout 600s;
            proxy_connect_timeout 600s;
            proxy_send_timeout 600s;
        }

        location /api/import {
            proxy_pass $appflowy_cloud_backend;
            # Set headers
            proxy_set_header X-Request-Id $request_id;
            proxy_set_header Host $http_host;
            # Timeouts
            proxy_read_timeout 600s;
            proxy_connect_timeout 600s;
            proxy_send_timeout 600s;
            # Disable buffering for large file uploads
            proxy_request_buffering off;
            proxy_buffering off;
            proxy_cache off;
            client_max_body_size 2G;
        }
    }

    # Minio Web UI
    location /minio/ {
        proxy_pass $minio_backend;
        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 300s;
        ## 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;
    }

    location /minio-api/ {
        proxy_pass $minio_api_backend;
        # Set the host to internal host because the presigned url was signed against the internal host
        proxy_set_header Host $minio_internal_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;
        rewrite ^/minio-api/(.*) /$1 break;
        proxy_connect_timeout 300s;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        chunked_transfer_encoding off;
    }

    # Admin Frontend
    location /console {
        proxy_pass $admin_frontend_backend;
        proxy_set_header X-Scheme $scheme;
        proxy_set_header Host $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;
    }

    # AppFlowy Web
    location / {
        proxy_pass $appflowy_web_backend;
        proxy_set_header X-Scheme $scheme;
        proxy_set_header Host $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;
    }
}

启用站点:

ln -s /etc/nginx/sites-available/appflowy /etc/nginx/sites-enabled/appflowy

签发SSL证书:

certbot --nginx --email [email protected] --agree-tos --no-eff-email

三个WebUI将在如下网址提供访问:

# AppFlowy Web UI
https://appflowy.example.com
# AppFlowy管理员后台
https://appflowy.example.com/console
# MinIO Web UI
https://appflowy.example.com/minio

1.使用GOTRUE_ADMIN_EMAIL/GOTRUE_ADMIN_PASSWORD既可以登录AppFlowy Web UI也可以登录AppFlowy管理员后台。

2.使用AWS_ACCESS_KEY/AWS_SECRET可以登录MinIO Web UI。

效果: