Fluxer 2026.1025.41605 Docker Compose 部署指南
用官方 compose bundle 手工部署 Fluxer 2026.1025.41605 全栈 20 服务,含 .env 密钥生成、数据持久化、运维命令与常见问题实测。
Fluxer 2026.1025.41605 Docker Compose 部署指南
一、环境信息
本文演示环境为一台 Ubuntu 22.04 LTS 服务器,配置 4 vCPU / 8 GB 内存 / 40 GB SSD 磁盘;Docker Engine 29.1.3,Docker Compose v2.40.3;目标部署版本为 Fluxer 2026.1025.41605,访问地址 http://fluxer.test:8080。
1.1 演示环境配置表
| 项目 | 配置 |
|---|---|
| 服务器 | Ubuntu 22.04 LTS(4 vCPU / 8 GB / 40 GB SSD) |
| Docker Engine | 29.1.3 |
| Docker Compose | v2.40.3 |
| 软件版本 | Fluxer 2026.1025.41605(官方 compose bundle 2026.1025.41605) |
| 部署目录 | /opt/fluxer |
| 服务数量 | 20 个 |
| 访问地址 | http://fluxer.test:8080(私有域名 .test,反向代理模式) |
官方文档给出的生产建议为 2 vCPU / 4 GB / 40 GB 磁盘起步,语音频道建议 4 核;官方安装器实测预检为内存低于 2 GB、磁盘低于 20 GB 直接拒绝安装。20 个常驻服务的服务器内存低于 4 GB 时体验很差,请勿用 1C2G 小机器硬扛。
二、部署形态与镜像选型说明
Fluxer 官方只提供容器化交付,compose 编排是它的原生形态。官方发布渠道同时提供三种等价入口:
- rexctl 安装器:
rexctl install下载官方 bundle 并按交互/参数生成配置后启动编排,再叠加一个rexctl start/stop/status的 systemd 生命周期封装,适合单服务器快速上线(详见《Ubuntu 22.04 安装 Fluxer 2026.1025.41605 指南》)。 - 官方 compose bundle(本文方式):从发布资产直接下载
fluxer-compose-<版本>.tar.gz,手工解压、填写.env、docker compose up。不引入 rexctl,部署单元完全由 Docker Compose 直管,适合已有 compose 运维体系(配置入库、CI 下发、统一监控)的团队。 - Helm Chart:源码仓
deploy/helm/附带,面向 Kubernetes 集群,不在本文范围。
2.1 镜像清单
整栈 20 个服务使用 19 个镜像,分两类:
- Fluxer 自研服务镜像(12 个,
ghcr.io/fluxerapp/fluxer-*,按 sha256 摘要锁定,不可变):api(api 与 worker 两个服务共用)、gateway、media-proxy、admin、push、static(static-proxy 服务)、app-proxy-self-hosted、snowflakes、users、gifs、messages、unfurl。 - 第三方基础镜像(7 个,compose 中用
${FLUXER_*_IMAGE:-默认}参数化,可指向内部镜像仓库):postgres:16-alpine、valkey/valkey:9.1-alpine、nats:2.14-alpine、getmeili/meilisearch:v1.53、chrislusf/seaweedfs:4.47、livekit/livekit-server:v1.12.0、caddy:2.11-alpine。
自研镜像按摘要锁定意味着:升级 = 换新版 bundle 的 compose 文件,而不是改 tag。第三方镜像可用
FLUXER_POSTGRES_IMAGE、FLUXER_CADDY_IMAGE等环境变量覆盖(离线/内网环境指向内部 registry)。
2.2 端口规划
| 端口 | 用途 | 说明 |
|---|---|---|
| 8080 | edge 对内监听(反代模式) | 宿主反代/隧道连进来的入口,由 .env 的 FLUXER_EDGE_BIND 决定 |
| 80 / 443 TCP+UDP | edge 直接服务模式 | 默认 compose 文件(Fluxer 自管 HTTPS 证书,h3 需要 443/udp) |
| 7881 TCP / 7882 UDP | 语音(LiveKit RTC) | compose 默认直接发布到宿主机 |
三、前置条件
- Ubuntu 22.04(或其他主流 Linux 发行版)64 位;Docker ≥ 24.0(或 Podman ≥ 5.4)+ Compose v2;内存 ≥ 4 GB、磁盘 ≥ 20 GB。
- 一个域名(公网 DNS 指向服务器,或内部域名/私有后缀
.test用于测试)。 - 能访问
ghcr.io与 Docker Hub(拉取镜像);国内网络为宿主 Docker 配置代理。 - 安装 curl、GNU tar。
四、部署步骤
4.1 安装 Docker Engine 与 Compose 插件
root@fluxer:~# apt-get update && apt-get install -y docker.io docker-compose-v2
root@fluxer:~# docker version && docker compose version
Client:
Version: 29.1.3
API version: 1.52
Go version: go1.26.0
Git commit: fbf34ed
Built: Fri Dec 12 21:21:44 2025
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 29.1.3
API version: 1.52 (minimum version 1.44)
Go version: go1.25.5
Git commit: fbf34ed
Built: Fri Dec 12 21:21:44 2025
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v2.2.0
GitCommit: 1c4457e00facac03ce1d75f7b6777a7a851e5c41
runc:
Version: 1.3.4
GitCommit: v1.3.4-0-gd6d73eb8
docker-init:
Version: 0.19.0
GitCommit: de40ad0
Docker Compose version v2.40.3
如果你的环境拉取镜像需要走代理,为 dockerd 配置 systemd 代理后重启 Docker:
mkdir -p /etc/systemd/system/docker.service.d cat > /etc/systemd/system/docker.service.d/proxy.conf <<'EOF' [Service] Environment="HTTP_PROXY=http://192.168.1.62:7897" Environment="HTTPS_PROXY=http://192.168.1.62:7897" Environment="NO_PROXY=localhost,127.0.0.1" EOF systemctl daemon-reload && systemctl restart docker
4.2 下载并解压官方 compose bundle
从 releases.fluxer.app 下载与目标版本对应的 bundle(文件名带构建号),解压到部署目录 /opt/fluxer:
root@fluxer:~# mkdir -p /opt/fluxer && cd /opt/fluxer
root@fluxer:/opt/fluxer# curl -fsSLO https://releases.fluxer.app/2026.1025.41605/fluxer-compose-2026.1025.41605.tar.gz
root@fluxer:/opt/fluxer# tar xzf fluxer-compose-2026.1025.41605.tar.gz && rm fluxer-compose-2026.1025.41605.tar.gz
root@fluxer:/opt/fluxer# ls -la
total 92
drwxr-xr-x 4 root root 4096 Oct 25 07:33 .
drwxr-xr-x 3 root root 4096 Oct 25 07:28 ..
-rw-r--r-- 1 root root 1247 Oct 25 07:33 .env
-rw-r--r-- 1 root root 534 Oct 25 04:24 .env.example
-rw-r--r-- 1 root root 1453 Oct 25 04:24 Caddyfile
drwxr-xr-x 2 root root 4096 Oct 25 04:24 caddy.d
drwxr-xr-x 2 root root 4096 Oct 25 04:24 certs
-rw-r--r-- 1 root root 265 Oct 25 04:24 docker-compose.proxy.yml
-rw-r--r-- 1 root root 45568 Oct 25 04:24 docker-compose.yml
-rw-r--r-- 1 root root 297 Oct 25 04:24 external-object-store.compose.yml
-rw-r--r-- 1 root root 42 Oct 25 04:24 ipv6.compose.yml
-rw-r--r-- 1 root root 259 Oct 25 04:24 tunnel.compose.yml
(上表中 .env 是下一步生成的,刚解压时不存在。)bundle 内容一览:
| 文件 | 作用 |
|---|---|
docker-compose.yml | 主编排文件(20 个服务全定义,45 KB) |
.env.example | 环境变量模板(所有密钥都在这里) |
Caddyfile | edge(Caddy)唯一配置文件,站点地址/TLS 等全部由环境变量驱动 |
caddy.d/ | 自定义 Caddy 片段目录,挂载到 /etc/caddy/conf.d,被 Caddyfile import |
certs/ | 自定义证书目录,挂载到 /certs(配合 FLUXER_EDGE_TLS 使用内部证书) |
docker-compose.proxy.yml | 覆盖文件:反向代理模式(edge 只监听 FLUXER_EDGE_BIND,不办证书) |
tunnel.compose.yml | 覆盖文件:隧道模式(cloudflared 类隧道回源到 80) |
ipv6.compose.yml | 覆盖文件:为 stack 网络启用 IPv6 |
external-object-store.compose.yml | 覆盖文件:停用内置 SeaweedFS,改用外部 S3 兼容对象存储 |
4.3 编写 .env(全部密钥一次生成)
.env.example 列出了必须填写的全部变量——1 个开关、2 个实例参数(域名 + 首次设置令牌)、5 个组件口令,以及 12 个应用级密钥:
root@fluxer:/opt/fluxer# cat .env.example
FLUXER_SETTINGS_LOADED=true
FLUXER_DOMAIN=
FLUXER_SETUP_TOKEN=
FLUXER_S3_ACCESS_KEY=fluxer
LIVEKIT_API_KEY=fluxer
POSTGRES_PASSWORD=
MEILI_MASTER_KEY=
FLUXER_S3_SECRET_KEY=
FLUXER_SUDO_MODE_SECRET=
FLUXER_CONNECTION_INITIATION_SECRET=
FLUXER_PROFILE_PSEUDONYM_SECRET=
FLUXER_GATEWAY_RPC_AUTH_TOKEN=
FLUXER_ERLANG_COOKIE=
FLUXER_MEDIA_PROXY_SECRET_KEY=
FLUXER_ADMIN_SECRET_KEY_BASE=
FLUXER_ADMIN_OAUTH_CLIENT_SECRET=
LIVEKIT_API_SECRET=
FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64=
FLUXER_VAPID_PUBLIC_KEY=
FLUXER_VAPID_PRIVATE_KEY=
除了 FLUXER_SETUP_TOKEN(32 字符,浏览器首次设置用的一次性令牌)外,十六进制密钥都可以用 OpenSSL 生成;FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64 是 base64;VAPID 密钥对(Web Push)必须用 ECDSA P-256 算法生成,不能用随机串。一条命令生成整套密钥并写入 .env(本文用反代模式,绑定 0.0.0.0:8080,域名用私有后缀 fluxer.test):
root@fluxer:/opt/fluxer# python3 - <<'EOF'
import secrets, base64
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
def h(n=32): return secrets.token_hex(n)
def b64url(b): return base64.urlsafe_b64encode(b).rstrip(b"=").decode()
key = ec.generate_private_key(ec.SECP256R1())
priv = key.private_numbers().private_value.to_bytes(32, "big")
pub = key.public_key().public_bytes(Encoding.X962, PublicFormat.UncompressedPoint)
env = f"""FLUXER_SETTINGS_LOADED=true
FLUXER_DOMAIN=fluxer.test
FLUXER_SETUP_TOKEN={secrets.token_hex(16)}
FLUXER_S3_ACCESS_KEY=fluxer
LIVEKIT_API_KEY=fluxer
POSTGRES_PASSWORD={h()}
MEILI_MASTER_KEY={h()}
FLUXER_S3_SECRET_KEY={h()}
FLUXER_SUDO_MODE_SECRET={h()}
FLUXER_CONNECTION_INITIATION_SECRET={h()}
FLUXER_PROFILE_PSEUDONYM_SECRET={h()}
FLUXER_GATEWAY_RPC_AUTH_TOKEN={h()}
FLUXER_ERLANG_COOKIE={h()}
FLUXER_MEDIA_PROXY_SECRET_KEY={h()}
FLUXER_ADMIN_SECRET_KEY_BASE={h(64)}
FLUXER_ADMIN_OAUTH_CLIENT_SECRET={h()}
LIVEKIT_API_SECRET={h()}
FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64={base64.b64encode(secrets.token_bytes(32)).decode()}
FLUXER_VAPID_PUBLIC_KEY={b64url(pub)}
FLUXER_VAPID_PRIVATE_KEY={b64url(priv)}
FLUXER_PUBLIC_SCHEME=http
FLUXER_PUBLIC_PORT=8080
FLUXER_EDGE_BIND=0.0.0.0:8080
"""
open(".env", "w").write(env)
print("ok")
EOF
ok
root@fluxer:/opt/fluxer# chmod 600 .env && cat .env
FLUXER_SETTINGS_LOADED=true
FLUXER_DOMAIN=fluxer.test
FLUXER_SETUP_TOKEN=ce4e0b00850a218cb09a2a4ec4f884d6
FLUXER_S3_ACCESS_KEY=fluxer
LIVEKIT_API_KEY=fluxer
POSTGRES_PASSWORD=1e3cb7e45ed9d087da7a809f0c3bf45e
MEILI_MASTER_KEY=7269f247d87958bee1ed20bb1003e933
FLUXER_S3_SECRET_KEY=0113babb9cc7baea2e3b4a9a0e9d309a
FLUXER_SUDO_MODE_SECRET=616b62fdcde50f89113112524d00d0f8
FLUXER_CONNECTION_INITIATION_SECRET=aba59fc8df0aeb552a575fd72e981824
FLUXER_PROFILE_PSEUDONYM_SECRET=c652c196b47dbb7a52522b843077aa8b
FLUXER_GATEWAY_RPC_AUTH_TOKEN=4e5a77ab74c45f4dee80930847aaae2e
FLUXER_ERLANG_COOKIE=8a67af7a8d1c955caca3e3bb26c74de8
FLUXER_MEDIA_PROXY_SECRET_KEY=df74bc35e3fee7659346acda56452aa6
FLUXER_ADMIN_SECRET_KEY_BASE=e2b17afc99ab8aacefd7d4b9331e7eecca409caa943d2285cbab4ce7d4fe61bc
FLUXER_ADMIN_OAUTH_CLIENT_SECRET=366badbf95e63bb6d8da4a31b40a965b
LIVEKIT_API_SECRET=0d6669e686faf1839f9f25641453864e
FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64=vGXQjI5Iz0YCWB2iQy7uUIOxMpNZtBZJHWaELFr5RM0=
FLUXER_VAPID_PUBLIC_KEY=BIpjEgHwBmNpMSSAnWH-7wxcApZfd5i7QTd5rSSoPBeoi7Wh2S0G38HQI1uF2L9dgQZ-WfXthxZ1p0P0z_b_zLk
FLUXER_VAPID_PRIVATE_KEY=X32Ol8wEo26352aI_M2UonKTgIV8NpYRy_urHLr8w6Y
FLUXER_PUBLIC_SCHEME=http
FLUXER_PUBLIC_PORT=8080
FLUXER_EDGE_BIND=0.0.0.0:8080
三个补充变量不在
.env.example里,但反代模式下很常用:FLUXER_PUBLIC_SCHEME/FLUXER_PUBLIC_PORT告诉实例「用户最终看到的地址 scheme 与端口」(生成邀请链接、发现端点都靠它);FLUXER_EDGE_BIND是docker-compose.proxy.yml里 edge 发布端口用的宿主绑定地址(默认127.0.0.1:8080,即只接受本机反代回源)。
FLUXER_VAPID_PUBLIC_KEY/FLUXER_VAPID_PRIVATE_KEY不能留空也不能用随机字符串:这两个是 Web Push 的 VAPID 密钥对,必须是 ECDSA P-256(prime256v1)曲线生成的 base64url 编码密钥,留空会导致 push 服务异常。上面的 Python 片段用cryptography库生成,与官方安装器内部生成方式等价。
4.4 拉取镜像并启动整栈
先拉取镜像(首次约 20 个镜像、1.9 GB,需要几分钟;以下回显为镜像已在本地缓存时的重复执行结果,秒级完成):
root@fluxer:/opt/fluxer# docker compose -p fluxer-20261025-stack -f docker-compose.yml -f docker-compose.proxy.yml --env-file .env pull
meilisearch Pulling
edge Pulling
seaweedfs Pulling
unfurl Pulling
livekit Pulling
app-proxy Pulling
unfurl Pulled
gateway Pulled
users Pulled
gifs Pulled
static-proxy Pulled
snowflakes Pulled
admin Pulled
api Pulled
push Pulled
media-proxy Pulled
messages Pulled
app-proxy Pulled
valkey Pulled
nats Pulled
postgres Pulled
meilisearch Pulled
seaweedfs Pulled
livekit Pulled
edge Pulled
启动(-p 指定项目名,避免与其他 compose 栈混淆;-f 叠加反代模式覆盖文件):
root@fluxer:/opt/fluxer# docker compose -p fluxer-20261025-stack -f docker-compose.yml -f docker-compose.proxy.yml --env-file .env up -d
启动过程有严格的依赖编排:postgres / valkey / nats / meilisearch / seaweedfs-init 先 healthy,api、worker、gateway 等应用服务才启动,edge 最后起。整栈 ready 后再次执行 up -d 的回显如下(所有服务已在运行):
Container fluxer-20261025-stack-nats-1 Healthy
Container fluxer-20261025-stack-api-1 Healthy
Container fluxer-20261025-stack-gateway-1 Healthy
Container fluxer-20261025-stack-edge-1 Waiting
Container fluxer-20261025-stack-edge-1 Healthy
4.5 验证运行状态
root@fluxer:/opt/fluxer# docker compose -p fluxer-20261025-stack -f docker-compose.yml -f docker-compose.proxy.yml --env-file .env ps --format "table {{.Name}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"
NAME IMAGE STATUS PORTS
fluxer-20261025-stack-admin-1 ghcr.io/fluxerapp/fluxer-admin@sha256:d50cc677050e51bd0e68eeb7eb5d9cc352786dfe4921de50207be348fa7e299a Up 18 minutes (healthy) 8080/tcp
fluxer-20261025-stack-api-1 ghcr.io/fluxerapp/fluxer-api@sha256:8b34480e0c085c6b5873dc6c16989d60f4b94cad713b9ead7714a400ea40d544 Up 18 minutes (healthy) 8080/tcp
fluxer-20261025-stack-app-proxy-1 ghcr.io/fluxerapp/fluxer-app-proxy-self-hosted@sha256:984b58c9676822d58858958bc60410156b589324698d13af02c65624d174d8cc Up 18 minutes (healthy) 8080/tcp
fluxer-20261025-stack-edge-1 caddy:2.11-alpine Up 18 minutes (healthy) 80/tcp, 443/tcp, 2019/tcp, 443/udp, 0.0.0.0:8080->8080/tcp
fluxer-20261025-stack-gateway-1 ghcr.io/fluxerapp/fluxer-gateway@sha256:7da9bbf12263132973281855cef7b7e1ce40623784e92dea17ffe7e32b709562 Up 18 minutes (healthy) 4369/tcp, 8080-8081/tcp
fluxer-20261025-stack-gifs-1 ghcr.io/fluxerapp/fluxer-gifs@sha256:1b90610660264f548cd835d62c9a400806f5491b7a02ecf3ef189702da355427 Up 18 minutes (healthy) 8090/tcp
fluxer-20261025-stack-livekit-1 livekit/livekit-server:v1.12.0 Up 19 minutes (healthy) 0.0.0.0:7881->7881/tcp, [::]:7881->7881/tcp, 0.0.0.0:7882->7882/udp, [::]:7882->7882/udp
fluxer-20261025-stack-media-proxy-1 ghcr.io/fluxerapp/fluxer-media-proxy@sha256:5718fac76560b380934252f7b1525d41ea4120262d57a861c7f80370a1c3b94d Up 18 minutes (healthy) 8080/tcp
fluxer-20261025-stack-meilisearch-1 getmeili/meilisearch:v1.53 Up 19 minutes (healthy) 7700/tcp
fluxer-20261025-stack-messages-1 ghcr.io/fluxerapp/fluxer-messages@sha256:92ccae001d54914637de4d1d4431e5860ecf7869ec028de0afbbca5f1d5cedb8 Up 18 minutes (healthy) 8090/tcp
fluxer-20261025-stack-nats-1 nats:2.14-alpine Up 19 minutes (healthy) 4222/tcp, 6222/tcp, 8222/tcp
fluxer-20261025-stack-postgres-1 postgres:16-alpine Up 19 minutes (healthy) 5432/tcp
fluxer-20261025-stack-push-1 ghcr.io/fluxerapp/fluxer-push@sha256:1f435ffbc08d7e9ee4bc2585dbc412820ea44f1ea4b319af7df1f3ba19dadf56 Up 18 minutes (healthy) 8126-8127/tcp
fluxer-20261025-stack-seaweedfs-1 chrislusf/seaweedfs:4.47 Up 19 minutes (healthy) 7333/tcp, 8080/tcp, 8333/tcp, 8888/tcp, 9333/tcp, 18080/tcp, 18888/tcp, 19333/tcp
fluxer-20261025-stack-snowflakes-1 ghcr.io/fluxerapp/fluxer-snowflakes@sha256:53593ff4709df185678c9d54bd3d4e039943a0c7bf8d26019822a2517b472376 Up 18 minutes (healthy) 8090/tcp
fluxer-20261025-stack-static-proxy-1 ghcr.io/fluxerapp/fluxer-static@sha256:568d0232fd4779934c0cfe92edaafedbbcc43a44398ec7d84a741f07f3dd9e9c Up 19 minutes (healthy) 8080/tcp
fluxer-20261025-stack-unfurl-1 ghcr.io/fluxerapp/fluxer-unfurl@sha256:06295aeed77f015912523b9a3337813127108451cad59862cfb1d91a1cd47683 Up 18 minutes (healthy) 8090/tcp
fluxer-20261025-stack-users-1 ghcr.io/fluxerapp/fluxer-users@sha256:3df3edaa475bce10f197e43c6ffcc5e09f7417bbe8c510d28bf0da487f16a071 Up 18 minutes (healthy) 8090/tcp
fluxer-20261025-stack-valkey-1 valkey/valkey:9.1-alpine Up 19 minutes (healthy) 6379/tcp
fluxer-20261025-stack-worker-1 ghcr.io/fluxerapp/fluxer-api@sha256:8b34480e0c085c6b5873dc6c16989d60f4b94cad713b9ead7714a400ea40d544 Up 18 minutes (healthy) 8080/tcp
20 个服务全部 healthy。验证 HTTP 入口与 edge 健康检查:
root@fluxer:/opt/fluxer# curl -s -o /dev/null -w "%{http_code}\n" http://fluxer.test:8080/
root@fluxer:/opt/fluxer# curl -s -o /dev/null -w "%{http_code}\n" http://fluxer.test:8080/_health
200
200
再验证实例发现端点(Fluxer 客户端用它发现实例能力与各服务地址):
root@fluxer:/opt/fluxer# curl -s http://fluxer.test:8080/.well-known/fluxer
{"api_code_version":1,"endpoints":{"api":"http://fluxer.test:8080/api","api_client":"http://fluxer.test:8080/api","api_public":"http://fluxer.test:8080/api","gateway":"ws://fluxer.test:8080/gateway","media":"http://fluxer.test:8080/media","upload_relay":"http://fluxer.test:8080/media","static_cdn":"http://fluxer.test:8080","marketing":"http://fluxer.test:8080","admin":"http://fluxer.test:8080/admin","invite":"http://fluxer.test:8080/invite","gift":"http://fluxer.test:8080/gift","webapp":"http://fluxer.test:8080"},"captcha":{"provider":"altcha"},"features":{"voice_enabled":true,"stripe_enabled":false,"premium_enabled":false,"stripe_serviceable":false,"self_hosted":true,"presigned_attachment_uploads":true,"emails_enabled":false,"phone_verification_enabled":false,"discovery_enabled":true,"account_identity":"username","tag_style":"none","identifier_first":false,"instant_accounts":false,"email_codes":false,"date_of_birth_step":true,"instant_account_availability":"disabled","interaction_tier":"enforced","guild_join_gate":"always","email_delivery_state":"off_username_mode","verification_basis":"local_credential"},"gif":{"provider":"klipy","display_name":"Klipy","attribution_required":false},"sso":{"enabled":false,"enforced":false,"display_name":null,"button_label":null,"redirect_uri":"http://fluxer.test:8080/auth/sso/callback"},"registration":{"mode":"open","admin_registration_urls_enabled":true},"community":{"single_community":false,"direct_messages_disabled":false,"friends_disabled":false,"guild_create_access":true},"services":{"gif_enabled":false,"youtube_enabled":false,"bluesky_enabled":false},"limits":{"version":2,"traitDefinitions":[],"rules":[{"id":"default","overrides":{"feature_animated_avatar":1,"feature_animated_banner":1,"feature_custom_discriminator":1,"feature_early_access":1,"feature_global_expressions":1,"feature_higher_video_quality":1,"feature_per_guild_profiles":1,"feature_voice_entrance_sounds":1,"max_bookmarks":300,"max_custom_backgrounds":15,"max_favorite_memes":500,"max_guilds":200,"max_attachment_file_size":524288000,"max_message_length":4000,"max_guild_emojis":500,"max_guild_stickers":500}},{"id":"very_large_guild","filters":{"guildFeatures":["VERY_LARGE_GUILD"]},"overrides":{"max_guild_members":10000000}}],"defaultsHash":"7b8p7j"},"push":{"public_vapid_key":"BIpjEgHwBmNpMSSAnWH-7wxcApZfd5i7QTd5rSSoPBeoi7Wh2S0G38HQI1uF2L9dgQZ-WfXthxZ1p0P0z_b_zLk"},"app_public":{"branding":{"product_name":"Fluxer","icon_url":null,"symbol_url":null,"logo_url":null,"wordmark_url":null,"favicon_url":null,"favicon_dark_url":null,"theme_color":null,"status_page_url":null,"status_page_incident_history_url":null,"premium_product_name":"Premium","premium_info_url":null,"sign_in_backdrop_url":null,"custom_css":null,"upload_limit_message":null,"trusted_domains":[]},"setup":{"configured":false,"admin_url":"http://fluxer.test:8080/admin","account_identity_locked":false,"account_identity_lock_reason":null,"setup_token_required":true},"legal":{"terms_url":null,"privacy_url":null,"guidelines_url":null},"registration":{"collect_date_of_birth":false}},"notice":null,"domain_migration":{"enabled":false,"anonymous_rollout_basis_points":0,"rollout_salt":"domain-migration-v1","standalone_forwarding":false}}
返回 200 且 JSON 中的 endpoints 全部指向你的域名,说明整栈已就绪。注意其中 setup.configured: false 与 setup_token_required: true——实例还在等待首次设置。
4.6 首次浏览器设置
浏览器打开 http://fluxer.test:8080,进入首次设置向导,粘贴 .env 里的 FLUXER_SETUP_TOKEN,按提示创建管理员账号(演示账号:root / q1w2e3r4)、填写实例名称。完成后发现端点中的 setup.configured 变为 true,实例进入正常使用状态。
如果丢了 setup token,直接
grep FLUXER_SETUP_TOKEN /opt/fluxer/.env找回即可。设置完成后它可以留在.env里,不再生效。
五、数据持久化
compose 文件定义了 8 个命名卷(实际名字带项目名前缀 fluxer-20261025-stack_):
| 卷名 | 对应服务 | 内容 | 可重建 |
|---|---|---|---|
postgres-data | postgres | PostgreSQL 数据目录(账号、频道、消息元数据) | 否,必须备份 |
seaweedfs-data | seaweedfs | 对象存储数据(头像、附件、媒体文件) | 否,必须备份 |
nats-data | nats | JetStream 队列数据(待投递任务) | 基本可重建,停机时建议备份 |
valkey-data | valkey | 缓存(RDB 持久化) | 是 |
meilisearch-data | meilisearch | 搜索索引 | 是(重建耗时) |
edge-data | edge | Caddy 证书与状态 | 反代模式下基本为空 |
edge-config | edge | Caddy 自动配置 | 是 |
media-proxy-tmp | media-proxy | 媒体处理临时文件 | 是 |
备份要点:真正不可重建的是 postgres-data 与 seaweedfs-data。最简单可靠的方式是停机冷备:
cd /opt/fluxer
docker compose -p fluxer-20261025-stack -f docker-compose.yml -f docker-compose.proxy.yml --env-file .env stop
tar czf fluxer-backup-$(date +%F).tar.gz -C /var/lib/docker/volumes \
fluxer-20261025-stack_postgres-data fluxer-20261025-stack_seaweedfs-data
docker compose -p fluxer-20261025-stack -f docker-compose.yml -f docker-compose.proxy.yml --env-file .env start
.env 文件(含全部密钥)必须随备份一起保存,否则恢复后会话签名与推送凭据全部失效。
六、环境变量表
.env.example 中必须提供的变量如下(compose 文件里还有大量 ${FLUXER_*:-默认} 形式的可选调优变量,如各服务内存上限 FLUXER_API_MEMORY_LIMIT、worker 副本数 FLUXER_WORKER_REPLICAS、第三方镜像覆盖 FLUXER_*_IMAGE 等,见 bundle 内注释):
| 变量 | 必填 | 示例 | 说明 |
|---|---|---|---|
FLUXER_SETTINGS_LOADED | 是 | true | 置 true 表示「设置已加载」,跳过引导检查 |
FLUXER_DOMAIN | 是 | fluxer.test | 实例域名 |
FLUXER_SETUP_TOKEN | 是 | 32 字符 hex | 首次浏览器设置的令牌 |
POSTGRES_PASSWORD | 是 | 32 字符 hex | PostgreSQL 口令 |
MEILI_MASTER_KEY | 是 | 32 字符 hex | Meilisearch 主密钥 |
FLUXER_S3_ACCESS_KEY / FLUXER_S3_SECRET_KEY | 是 | fluxer / 32 字符 hex | 内置 SeaweedFS 的 S3 凭据 |
FLUXER_SUDO_MODE_SECRET | 是 | 32 字符 hex | 管理员 sudo 模式会话签名 |
FLUXER_CONNECTION_INITIATION_SECRET | 是 | 32 字符 hex | 连接初始化签名 |
FLUXER_PROFILE_PSEUDONYM_SECRET | 是 | 32 字符 hex | 用户资料假名化密钥 |
FLUXER_GATEWAY_RPC_AUTH_TOKEN | 是 | 32 字符 hex | 网关内部 RPC 令牌 |
FLUXER_ERLANG_COOKIE | 是 | 32 字符 hex | Erlang 分布式 cookie(gateway 与 Rust 服务间) |
FLUXER_MEDIA_PROXY_SECRET_KEY | 是 | 32 字符 hex | 媒体代理签名密钥 |
FLUXER_ADMIN_SECRET_KEY_BASE | 是 | 64 字符 hex | 管理面板会话密钥 |
FLUXER_ADMIN_OAUTH_CLIENT_SECRET | 是 | 32 字符 hex | 管理面板 OAuth 客户端密钥 |
LIVEKIT_API_KEY / LIVEKIT_API_SECRET | 是 | fluxer / 32 字符 hex | LiveKit API 凭据 |
FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64 | 是 | base64 | 媒体上传中继密钥(base64 编码) |
FLUXER_VAPID_PUBLIC_KEY / FLUXER_VAPID_PRIVATE_KEY | 是 | base64url | Web Push VAPID 密钥对(必须 ECDSA P-256 生成) |
FLUXER_PUBLIC_SCHEME | 反代模式建议 | http | 用户访问地址的 scheme |
FLUXER_PUBLIC_PORT | 反代模式建议 | 8080 | 用户访问地址的端口 |
FLUXER_EDGE_BIND | 反代模式建议 | 0.0.0.0:8080 | edge 发布到宿主机的绑定地址(proxy/tunnel 覆盖文件使用,默认 127.0.0.1:8080) |
密钥轮换:修改 .env 中任意密钥后 docker compose ... up -d 即会重建相关服务。注意 POSTGRES_PASSWORD、MEILI_MASTER_KEY 这类数据组件口令一旦初始化完成再改会连不上已有数据(口令已固化在数据卷里),需要同步改组件内的口令或重建数据卷。
七、配置参数说明
compose 形态下有两层配置:
- 部署层(本文
.env+ compose 文件):域名、监听地址、密钥、镜像、资源限额。改这些需要up -d重建对应服务。 - 实例行为层(注册策略、品牌、登录方式、清理策略等 170+ 项):首次设置完成后存于数据库,通过管理面板(
http://fluxer.test:8080/admin)调整,多数即时生效、无需重启。发现端点.well-known/fluxer返回的 JSON(见 4.5)就是这些行为参数的对外投影。
实例行为层各项参数的详解见《Fluxer 2026.1025.41605 配置参数详解》;rexctl 的手工编排交还与接管用法见《Fluxer 2026.1025.41605 常用 CLI 命令与工具详解》。
八、配置文件挂载
edge(Caddy)是挂载本地配置最多的服务,compose 中的挂载如下:
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./certs:/certs:ro
- ./caddy.d:/etc/caddy/conf.d:ro
- edge-data:/data
- edge-config:/config
Caddyfile 是主配置,站点地址、TLS 指令、信任代理全部用环境变量占位,三种模式(直接服务/反代/隧道)的差异由 compose 覆盖文件注入不同的 FLUXER_EDGE_SITE_ADDRESS、FLUXER_EDGE_TLS_DIRECTIVE 实现,而不是换 Caddyfile:
root@fluxer:/opt/fluxer# cat Caddyfile
{
servers {
trusted_proxies static {$FLUXER_EDGE_TRUSTED_PROXIES:private_ranges}
trusted_proxies_strict
protocols {$FLUXER_EDGE_PROTOCOLS:h1 h2 h3}
}
{$FLUXER_EDGE_GLOBAL_OPTIONS}
}
(upstream) {
reverse_proxy {args[0]} {
header_up X-Forwarded-For {client_ip}
header_up X-Real-IP {client_ip}
header_up -Forwarded
}
}
{$FLUXER_EDGE_SITE_ADDRESS} {
{$FLUXER_EDGE_TLS_DIRECTIVE}
import /etc/caddy/conf.d/*.caddy
encode {$FLUXER_EDGE_ENCODE:zstd gzip}
handle /_health {
respond "OK" 200
}
handle /_edge {
header Cache-Control no-store
respond "{system.hostname}" 200
}
handle_path /api/* {
import upstream api:8080
}
handle /gateway {
rewrite * /
import upstream gateway:8080
}
handle_path /gateway/* {
import upstream gateway:8080
}
handle_path /media/* {
import upstream media-proxy:8080
}
handle_path /livekit/* {
import upstream livekit:7880
}
handle {$FLUXER_ADMIN_BASE_PATH:/admin} {
rewrite * /
import upstream admin:8080
}
handle_path {$FLUXER_ADMIN_BASE_PATH:/admin}/* {
import upstream admin:8080
}
@staticAssets path /web/* /emoji/* /libs/* /avatars/* /badges/* /desktop/*
handle @staticAssets {
import upstream static-proxy:8080
}
handle /.well-known/fluxer {
import upstream api:8080
}
handle {
import upstream app-proxy:8080
}
}
:8088 {
handle /.well-known/fluxer {
import upstream api:8080
}
handle /_edge {
respond "{system.hostname}" 200
}
}
如需自定义路由(限流、额外请求头、IP 白名单),把 .caddy 片段放进 caddy.d/ 即可被 import /etc/caddy/conf.d/*.caddy 收进去,不必改主 Caddyfile。改完重启 edge:
docker compose -p fluxer-20261025-stack -f docker-compose.yml -f docker-compose.proxy.yml --env-file .env restart edge
九、等价 docker run 示例(了解用)
compose 文件是唯一定义来源,不建议手工 docker run。以下为帮助理解单个服务的等价写法(以 api 服务为例,实际请用 compose 管理):
docker run -d \
--name fluxer-api \
--network fluxer-20261025-stack_fluxer \
--env-file /opt/fluxer/.env \
-e FLUXER_API_PORT=8080 \
--restart unless-stopped \
ghcr.io/fluxerapp/fluxer-api@sha256:8b34480e0c085c6b5873dc6c16989d60f4b94cad713b9ead7714a400ea40d544
注意 20 个服务之间存在严格的启动依赖与健康检查编排(postgres/valkey/nats/meilisearch 必须先 healthy、seaweedfs-init 必须跑完,api/worker/gateway 才会启动),手工维护这些依赖得不偿失——这也是官方只发布 compose/helm 两种形态的原因。
十、常用运维命令
以下命令都在 /opt/fluxer 下执行,为节省篇幅把项目名与文件参数定义为 shell 别名:
root@fluxer:~# cd /opt/fluxer
root@fluxer:/opt/fluxer# alias dc='docker compose -p fluxer-20261025-stack -f docker-compose.yml -f docker-compose.proxy.yml --env-file .env'
查看状态:dc ps(输出见 4.5)。查看某个服务的日志(以 api 为例):
root@fluxer:/opt/fluxer# dc logs --tail 4 api
api-1 | {"level":"info","time":"2026-10-25T07:54:16.675Z","service":"fluxer-api","env":"production","method":"POST","path":"/internal/rpc","status":200,"durationMs":1,"msg":"Request completed"}
api-1 | {"level":"info","time":"2026-10-25T07:54:27.800Z","service":"fluxer-api","env":"production","method":"POST","path":"/internal/rpc","status":200,"durationMs":0,"msg":"Request completed"}
api-1 | {"level":"info","time":"2026-10-25T07:54:30.724Z","service":"fluxer-api","env":"production","method":"GET","path":"/.well-known/fluxer","status":200,"durationMs":11,"msg":"Request completed"}
api-1 | {"level":"info","time":"2026-10-25T07:54:30.727Z","service":"fluxer-api","env":"production","method":"GET","path":"/.well-known/fluxer","status":200,"durationMs":9,"msg":"Request completed"}
重启单个服务 / 整栈:
dc restart api # 重启单个服务
dc restart # 整栈滚动重启
dc stop && dc start # 整栈停止再启动(不删容器)
修改 .env 或 caddy.d 片段后使生效:
dc up -d # 自动重建受影响的服务
查看资源占用(compose 文件为每个服务预设了内存上限,如 api 2560mb、edge 384mb,可用 FLUXER_*_MEMORY_LIMIT 调整):
root@fluxer:/opt/fluxer# docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}" | head -10
NAME CPU % MEM USAGE / LIMIT
fluxer-20261025-stack-app-proxy-1 0.00% 3.844MiB / 256MiB
fluxer-20261025-stack-edge-1 0.00% 21.15MiB / 384MiB
fluxer-20261025-stack-push-1 0.00% 1.918MiB / 256MiB
fluxer-20261025-stack-admin-1 0.00% 10.21MiB / 256MiB
fluxer-20261025-stack-api-1 0.01% 166.8MiB / 2.5GiB
fluxer-20261025-stack-worker-1 0.01% 143.1MiB / 2.5GiB
fluxer-20261025-stack-media-proxy-1 0.00% 34.78MiB / 1GiB
fluxer-20261025-stack-users-1 0.01% 1.41MiB / 256MiB
fluxer-20261025-stack-messages-1 0.01% 3.066MiB / 256MiB
升级到新构建号:自研镜像按 sha256 摘要锁定,升级方式是下载新版 bundle,用新版 docker-compose.yml 替换旧文件(.env 沿用),然后:
dc pull && dc up -d
整栈服务会按新摘要重建,数据库迁移由 api 启动时自动执行。升级前务必备份(见第五节)。
十一、常见问题
Q1:docker compose pull 时某镜像拉取失败,报超时或 failed to resolve reference?
Docker Hub 与 ghcr.io 连通性问题。先确认 dockerd 代理已配置(见 4.1),再单独重试该镜像。内网环境用 FLUXER_POSTGRES_IMAGE 等变量把第三方镜像指向内部 registry,自研镜像批量搬运后修改 compose 文件中的 image 字段。
Q2:启动后 api 一直 unhealthy,日志报数据库连接失败?
.env 中 POSTGRES_PASSWORD 在首次初始化后被改动过。PostgreSQL 的口令已固化在 postgres-data 卷里,.env 改了但卷里没改。两种解法:把 .env 口令改回初始值;或者进数据库改口令:
dc exec postgres psql -U postgres -c "ALTER USER postgres PASSWORD '新口令';"
Q3:浏览器打开提示「Invalid setup token」或一直停在设置页?
粘贴的 FLUXER_SETUP_TOKEN 与 .env 不一致(多空格/换了行),用 grep FLUXER_SETUP_TOKEN .env 精确复制。若发现端点显示 setup.configured: true,说明设置已完成过,设置页会关闭,这是正常现象。
Q4:推送通知不工作,客户端收不到 Web Push?
FLUXER_VAPID_PUBLIC_KEY / FLUXER_VAPID_PRIVATE_KEY 未按 ECDSA P-256 生成或留空。按 4.3 的 Python 片段重新生成密钥对,dc up -d 重建 push 服务。
Q5:dc ps 显示 healthy 但访问 8080 超时?
检查 FLUXER_EDGE_BIND:proxy 覆盖文件默认绑定 127.0.0.1:8080,只有本机能访问;要让局域网/反代服务器从外部连进来,需显式设 FLUXER_EDGE_BIND=0.0.0.0:8080 并 dc up -d。另外确认宿主防火墙放行了该端口。
Q6:想换域名怎么办?
改 .env 的 FLUXER_DOMAIN(反代模式连同 FLUXER_PUBLIC_SCHEME/FLUXER_PUBLIC_PORT),dc up -d。实例行为层的域名迁移(domain_migration.* 参数,灰度切换)见《Fluxer 2026.1025.41605 配置参数详解》。
Q7:磁盘占用增长快,主要是哪个卷?
seaweedfs-data(附件/媒体对象)与 postgres-data(消息)。用 docker system df -v | grep fluxer 看各卷大小;附件衰减清理策略(media.attachment_decay.*)见《Fluxer 2026.1025.41605 配置参数详解》第五节。
十二、参考链接
- Fluxer 官方文档站:https://docs.fluxer.app(查询日期:2026-10-25)
- Self-hosting 指南(rexctl 与 bundle 下载地址):https://docs.fluxer.app/self-hosting(查询日期:2026-10-25)
- Fluxer GitHub 仓库(compose bundle 与 Helm Chart 源码):https://github.com/fluxerapp/fluxer(查询日期:2026-10-25)
- 系列文档:《Fluxer 2026.1025.41605 介绍与选型指南》、《Ubuntu 22.04 安装 Fluxer 2026.1025.41605 指南》、《Fluxer 2026.1025.41605 配置参数详解》、《Fluxer 2026.1025.41605 常用 CLI 命令与工具详解》