这是使用 Docker Compose 工具来安装和运行 Misskey(一个开源的去中心化社交平台)的标准化操作流程。
很久前就一直想弄个二次元氛围爆满的网站,博客也是用动漫主题,奈何使用起来各种体验并不太满意,毕竟都不是原生的二次元风,唯一了解到的开源免费套件就是去中心化的社交平台 Misskey ,一个充满二次元味道的微博网站,正巧我也一直很想弄个微博网站,WordPress 发短文还是感觉差点意思,无论是排版方面,还是发布方面都不太原生,发个说说都像是发文章那样。
不过 Misskey 需要的配置还挺高的,不是一般 VPS 能承受得起的,以我的经验部署完后占用 1.5G 内存左右,也就是说至少要 2G 内存的主机才够用,所以我一直没弄,直到看到吃灰许久的迷你主机……于是我把迷你主机装上 Debian 无桌面环境版本,部署上 Misskey ,通过内网穿透的方式使用,总算是发挥了一丢丢作用(功耗低7x24小时开着应该没啥问题→_→),部署过程中发现网上教程要不就太复杂,要不就是不够详细,故此将自己的部署过程以及遇到的一些问题记录下来。
部署完成效果确实挺二次元的,如图:


核心警告:请务必注意!
对于一个已经投入使用的网站,绝对不要重新执行“初始化数据库”的步骤!
这样做会清空你所有的数据,包括用户、帖子、文件等。初始化是且仅是第一次安装时才需要执行的操作。
第一步:准备工作 (在 Debian 系统上安装 Docker Engine)
在开始之前,请确保您的服务器已经安装好了 Docker 和 Docker Compose 这两个核心软件。本指南的所有操作都依赖于它们。
如果你连 Debian 系统都还没有,需要先进行安装,这个安装过程应该没有不会的吧?如果有,我再补充。
简单来说就是到 Debian 官网下载一个类似“debian-12.11.0-amd64-DVD-1.iso”的安装镜像,放到写入了引导的U盘里面,然后开机启动后安装提示一步步安装即可。因为我是在无网络环境下安装的,所以用了这个 DVD 版本——我的情况比较特殊,在方便接显示器的地方没有网线,在放服务器主机的地方有网络但没有显示器……
在无网络的情况下安装无显示器的服务器,建议先在有条件的环境下,配置好静态或动态IP地址。这样,当将服务器移至最终位置并接通网线后,它就可以使用指定的IP地址稳定地连接到网络,方便之后通过SSH等方式进行远程管理,但我在安装过程中不懂直接就跳过了网络配置。
补救方法是在有显示器的条件下:
1、识别网络接口名称:
首先,你需要找到你的网络接口名称。通过以下命令可以列出所有的网络接口:
ip a
或者
ls /sys/class/net/
常见的接口名称有 eth0, ens33, enp0s3 等。请记下您要配置的那个接口的名称。
2、编辑配置文件:
使用文本编辑器(如 nano 或 vim)打开网络配置文件 /etc/network/interfaces:
sudo nano /etc/network/interfaces
3、配置网络:
动态IP (DHCP): 如果您的网络环境支持DHCP自动分配IP地址,添加以下内容:
auto <接口名>
allow-hotplug <接口名>
iface <接口名> inet dhcp
请将 <接口名> 替换为您在上一步中找到的实际接口名称。
静态IP: 对于服务器,更推荐使用静态IP。添加如下配置,并根据您的实际网络情况修改IP地址、子网掩码和网关:
auto <接口名>
iface <接口名> inet static
address 192.168.1.100
netmask 255.255.255.0
gateway 192.168.1.1
dns-nameservers 8.8.8.8 114.114.114.114
请将 <接口名> 以及IP地址、子网掩码、网关和DNS服务器地址替换为您的实际信息。
4、重启网络服务:
保存文件后,重启网络服务以使配置生效:
sudo systemctl restart networking.service
例如,我在使用 ip a 命令中看到 lo 和 enp1s0 分别是:
lo: 这是环回接口 (Loopback Interface),是每台Linux机器上都有的虚拟网络接口,用于本机进程间的通信。它的IP地址通常是127.0.0.1。您不需要对它进行任何配置。enp1s0: 这就是您的物理网卡接口 (Ethernet card)。根据命名规则,这很可能是一个PCI Express插槽上的网卡。您需要配置的就是这个接口。
我选择使用DHCP,因为这样配置起来最简单。当我把服务器挪到有网络的地方并开机后,系统会通过 enp1s0 这个网卡向网络中的DHCP服务器(通常是路由器)请求IP地址。
以下是在有显示器的环境下,需要为 enp1s0 接口配置动态IP的方法:
这是在Debian上最经典的方法,兼容性最好。
1、编辑配置文件:
用 nano 或 vim 编辑器打开配置文件:
sudo nano /etc/network/interfaces
2、修改或添加配置:
确保文件中有以下内容,用于配置 enp1s0 接口。如果文件是空的或者有其他关于此接口的静态配置,可以先将其注释掉(在行首加 #)或删除。
# The primary network interface
auto enp1s0
allow-hotplug enp1s0
iface enp1s0 inet dhcp
auto enp1s0: 表示在系统启动时自动激活enp1s0接口。allow-hotplug enp1s0: 表示在检测到网线插入时自动激活enp1s0接口。iface enp1s0 inet dhcp: 表示enp1s0接口通过DHCP来获取IPv4地址。
3、保存并重启网络服务:
保存文件后,可以重启网络服务来使配置立即生效,或者直接重启服务器。
sudo systemctl restart networking.service
1、安装 Docker 前的准备工作
在开始安装之前,必须完成以下准备步骤,以确保安装过程顺利且系统环境干净。
1. 确认系统要求
- 操作系统: 必须是 64 位版本的以下 Debian 系统之一:
- Debian 13 (Trixie) - 测试版
- Debian 12 (Bookworm) - 稳定版 (推荐)
- Debian 11 (Bullseye) - 旧稳定版
- 架构: 支持
x86_64(也叫amd64),armhf,arm64等主流架构。
2. 卸载旧版本或冲突的软件包
您的系统可能通过 Debian 自带的软件源安装了非官方的 Docker 包,或者存在其他冲突软件。必须先将它们卸载。
需要卸载的包包括: docker.io, docker-doc, docker-compose, podman-docker, containerd, runc。
使用以下命令一键卸载所有可能冲突的包:
# 循环遍历并卸载列表中的每一个包
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done
- 提示: 如果系统提示某个包未安装,这是正常现象,直接忽略即可。
- 注意: 此操作不会删除您已有的 Docker 镜像、容器或卷(数据存储在
/var/lib/docker/目录下)。
3. 理解防火墙的特殊情况(重要警告)
- 如果您使用
ufw或firewalld来管理防火墙,请注意:当 Docker 映射容器端口时,会绕过这些防火墙规则! - 这意味着,即使您在
ufw中禁止了某个端口,如果 Docker 将其映射出来,该端口依然可以被外界访问。这是 Docker 网络机制的一个重要特性,需要特别留意其安全影响。
2、安装 Docker Engine (推荐方法)
官方提供了多种安装方法,但最推荐的是使用 Docker 官方的 apt 软件仓库进行安装。这样做的好处是,您可以轻松地进行安装和后续的升级。
步骤 1: 设置 Docker 的官方 apt 仓库
这个过程是为了让您的系统信任并知道从哪里下载官方的 Docker 软件包。
# 1. 更新现有的包列表并安装必要的工具
sudo apt-get update
sudo apt-get install ca-certificates curl
# 2. 创建用于存放 GPG 密钥的目录
sudo install -m 0755 -d /etc/apt/keyrings
# 3. 下载 Docker 的官方 GPG 密钥(用于验证软件包的真实性)
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
# 4. 更改密钥文件的权限,确保 apt 可以读取它
sudo chmod a+r /etc/apt/keyrings/docker.asc
# 5. 将 Docker 的软件源添加到系统的 apt 源列表中
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 6. 再次更新 apt 包列表,以包含新添加的 Docker 软件包信息
sudo apt-get update
步骤 2: 安装 Docker 相关软件包
现在,您可以直接从刚刚配置好的 Docker 仓库中安装最新版本的 Docker 了。
# 安装 Docker Engine, 命令行工具, containerd, 以及 buildx 和 compose 插件
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
docker-ce: Docker 社区版(核心引擎)。docker-ce-cli: Docker 命令行工具。containerd.io: 容器运行时。docker-buildx-plugin,docker-compose-plugin: 官方推荐的插件,让您可以使用docker buildx和docker compose命令。
步骤 3: 验证安装是否成功
通过运行一个经典的 hello-world 镜像来测试 Docker 是否已正确安装并运行。
sudo docker run hello-world
如果安装成功,您会看到一条来自 hello-world 容器的欢迎信息,其中包含 "Hello from Docker!"。这表明 Docker 已成功下载镜像、启动容器并正确执行。
3、安装后的重要配置(推荐)
将当前用户添加到 docker 用户组,实现免 sudo 执行 Docker 命令
默认情况下,您必须使用 sudo 才能运行 Docker 命令。为了方便,可以把当前用户加入 docker 组。
1、执行添加命令:
# 将您当前的用户($USER)添加到 docker 用户组中
sudo usermod -aG docker $USER
2、重新登录或激活配置:
这一步至关重要! 您必须退出当前的终端会话并重新登录(或者重启系统),这样新的用户组权限才会生效。之后,您就可以直接运行 docker ps 等命令,而无需再加 sudo。
4、其他操作
如何升级 Docker Engine
如果您是按照前面推荐的方法安装的,升级非常简单:
# 1. 更新软件包列表
sudo apt-get update
# 2. 直接运行安装命令即可安装到最新版本
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
如何彻底卸载 Docker Engine
1、卸载软件包:
sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
使用 purge 会同时移除相关的配置文件。
2、删除所有 Docker 数据(危险操作):
卸载软件包并不会删除镜像、容器、卷等数据。如果您想彻底清理,请手动删除以下目录:
# 警告:此操作会删除您所有的容器和镜像数据,且不可恢复!
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
3、清理软件源和密钥:
sudo rm /etc/apt/sources.list.d/docker.list
sudo rm /etc/apt/keyrings/docker.asc
附录:其他安装方法简介
- 手动安装
.deb包: 适用于无法连接 Docker 官方仓库的离线环境。您需要去官网手动下载所有containerd,docker-ce,cli等deb包,然后使用sudo dpkg -i ...命令进行安装。升级和管理会比较繁琐。 - 使用便捷脚本 (
get.docker.com): 官方提供了一键安装脚本。但不推荐在生产环境中使用,因为它会自动执行许多操作,缺乏控制。它更适合用于快速搭建测试环境。
第二步:获取 Misskey 源代码
此步骤的目的是从 GitHub(一个代码托管平台)上将 Misskey 的最新版源代码下载到您的服务器上。
# 从官方仓库下载 Misskey 的主分支代码
git clone -b master https://github.com/misskey-dev/misskey.git
# 进入刚刚下载好的 misskey 文件夹
cd misskey
# 确保当前在主分支上(这步是为确保万无一失)
git checkout master
第三步:创建并编辑配置文件
程序需要配置文件才能知道如何运行,比如您的域名是什么,数据库密码是多少。此步骤就是从官方提供的模板文件复制出我们自己要用的配置文件。
1、执行复制命令:
# 复制 Misskey 主配置文件
cp .config/docker_example.yml .config/default.yml
# 复制 Docker 环境变量文件(通常用于存放密码等敏感信息)
cp .config/docker_example.env .config/docker.env
# 复制 Docker Compose 的部署文件
cp ./compose_example.yml ./compose.yml
2、编辑配置文件(这是关键步骤):
您需要使用文本编辑器(如 nano 或 vim)打开并修改以下两个文件:
default.yml: 这是 Misskey 的核心配置文件。您必须根据文件内的注释说明,修改以下必填项:url: 填写您准备给这个网站使用的完整域名,例如https://example.com。
docker.env: 这个文件专门存放数据库密码。请务必修改里面的密码,设置一个足够复杂的密码以保证安全。
另外,compose.yml 文件定义了需要启动哪些服务。一般情况下您不需要修改它,除非您想更改对外服务的端口(默认为 3000)。
第四步:构建应用并初始化数据库
此步骤包含两个重要操作:编译打包应用和创建数据库结构。
# 1. 构建镜像:Docker 会根据代码和配置,打包成一个独立的、可运行的应用镜像。
# 这个过程需要下载大量依赖,会花费很长时间,请耐心等待。
sudo docker compose build
# 2. 初始化数据库:运行一个临时容器来执行初始化脚本。
# 这个脚本会连接到数据库,并创建运行 Misskey 所需的各种数据表。
# --rm 参数意味着命令执行完后会自动删除这个临时容器。
sudo docker compose run --rm web pnpm run init
再次强调:第二条 init 命令是一次性操作,请勿在日后重复执行。
第五步:启动 Misskey 服务
恭喜!完成以上步骤后,就可以正式启动您的网站了。
# 使用 up 命令启动所有服务,-d 参数表示在后台持续运行。
sudo docker compose up -d
执行后,稍等片刻,您就可以通过 http://你的服务器IP:3000 或您在 default.yml 中配置的域名来访问您的 Misskey 实例了。
日常维护操作
如何更新 Misskey 版本
重要:更新前,请务必抽空阅读官方的更新日志 (CHANGELOG.md),确认新版本是否有重大变更或需要额外的手动操作。
在服务器的 misskey 目录下,依次执行以下命令:
# 暂存您对配置文件的修改,以防与新代码冲突
git stash
# 切换到主分支并拉取最新的代码
git checkout master
git pull
# 更新项目的子模块依赖
git submodule update --init
# 恢复您之前暂存的配置
git stash pop
# 根据新代码重新构建应用镜像
sudo docker compose build
# 停止旧服务,然后用新镜像启动服务,完成更新
sudo docker compose stop && sudo docker compose up -d
如何执行后台管理命令 (CLI)
有时您可能需要执行一些特殊管理任务(如重置用户密码、清理数据等),这需要通过后台命令行工具 (CLI) 完成。
执行语法:
# 格式为:sudo docker compose run --rm web [具体命令]
# 文档中的示例是执行一个名为 foo 的工具,并传入 bar 参数
sudo docker compose run --rm web node packages/backend/built/tools/foo bar
您只需将示例中的 node ... foo bar 部分替换为您实际需要执行的管理命令即可。
可能会遇到的一些问题
上传图片时报错 Internal Server Error
文件夹权限问题,需在 Misskey 根文件夹运行 sudo chown -R 991:991 files
通过内网穿透访问网站一直加载中,但局域网内可以打开正常
是套了 Cloudflare CDN 的问题,登录 Cloudflare 主面板,进入 Speed -> Optimization,Rocket Loader™: 确保这个功能是关闭的。它非常容易破坏 Web 应用。
对于任何复杂的、基于现代 JavaScript 框架的 Web 应用(不仅仅是 Misskey),一个通用的最佳实践是:在 Cloudflare 或任何类似的 CDN 服务中,务必禁用任何会自动重排或延迟加载 JavaScript 的“性能优化”功能,特别是像 Rocket Loader™ 这样的。
这些现代应用本身已经通过构建工具(如 Vite, Webpack)进行了高度优化,外部工具的再次“优化”往往会适得其反。
在 Docker 及 Cloudflare Tunnel 环境下无法联合(关注外站用户失败)
一、问题背景与症状
在通过 Docker 部署 Misskey 实例,并使用 Cloudflare Tunnel(cloudflared)进行内网穿透后,遇到了以下几个核心问题:
- 联合失败:尝试关注任何外部 Misskey 服务器的用户(例如
@[email protected])时,立即提示错误。 - 搜索失效:站内搜索功能无法搜索到任何外部实例的用户或内容。
- 全局时间轴(GTL)空空如也:即使已经配置好,全局时间轴上也没有任何外部内容。
这些症状共同指向一个根本原因:我的 Misskey 服务器无法与外部世界进行出站(Outbound)网络通信。
二、排查之旅:从现象到本质
Step 1: 初步诊断 - 查看应用日志
任何问题排查的第一步,都是听听应用程序自己怎么说。我们通过 Docker 日志来获取第一手信息。
操作:
# 实时跟踪 Misskey web 服务的日志
sudo docker compose logs -f web
在跟踪日志的同时,在浏览器中尝试进行一次失败的“关注”操作。
关键发现:
日志中出现了明确的错误信息:
ERR * [remote resolve-user] Failed to ... reason: Blocked address: 198.18.3.114
分析与讲解:
Blocked address:这不是一个网络连接错误(如ETIMEDOUT),而是 Misskey 出于安全考虑(防止SSRF攻击)主动阻止了这次请求。198.18.3.114:这是一个用于网络基准测试的保留IP地址段。- 初步结论:当 Misskey 尝试查找外部域名(如
misskey.io)时,DNS 解析返回了一个奇怪的、被列入黑名单的内部 IP。这强烈暗示了 DNS 解析过程受到了干扰。
Step 2: 验证推论 - 进入容器内部测试网络
为了验证 DNS 是不是真的出了问题,我们需要直接进入容器的“肚子”里,以它的视角来访问外部网络。
操作:
# 进入 web 容器的命令行环境
sudo docker compose exec web bash # 或 sh
# 在容器内部尝试用 curl 访问外部网站
curl -v https://misskey.io
关键发现:curl 命令的输出带来了两个重磅消息:
* Trying 198.18.3.115:443...:验证了 DNS 劫持。在容器内部,所有对公网域名的请求都被解析到了198.18.x.x这个奇怪的地址段。这通常是cloudflared服务接管了宿主机的 DNS 所导致的。curl: (77) error setting certificate file: /etc/ssl/certs/ca-certificates.crt:发现了第二个问题。即使 DNS 问题解决了,容器内部也缺少用于验证 HTTPS 连接的根证书文件,导致所有https://请求都会失败。
分析:
我们现在面临两个独立的问题:
- DNS 问题:Docker 默认使用了被
cloudflared干扰的宿主机 DNS。 - 证书问题:Misskey 的 Docker 镜像过于精简,没有包含
ca-certificates包。
Step 3: 解决 DNS 问题 - 配置 Docker 全局 DNS
我们首先解决最主要的问题。我们需要强制所有 Docker 容器使用可靠的公共 DNS 服务器,绕过宿主机的干扰。
操作:
1、创建或编辑 Docker 的配置文件 daemon.json。
```bash
sudo nano /etc/docker/daemon.json
2、在文件中写入以下内容:
{
"dns": ["8.8.8.8", "1.1.1.1"]
}
3、重启 Docker 服务使配置生效。
sudo systemctl restart docker
4、重启 Misskey 服务以应用新的网络配置。
sudo docker compose down && sudo docker compose up -d
验证:
再次进入容器内部执行 curl -v https://misskey.io,此时 * Trying ... 后面已经变成了真实的公网 IP。第一个问题成功解决! 但 curl: (77) 证书错误依然存在。
Step 4: 解决证书问题 - 尝试通过 Dockerfile 安装
我们尝试通过修改 Dockerfile,在镜像构建时就将证书包装进去。
操作(这是一个尝试,但最终证明在复杂的多阶段构建中无效):
- 编辑
Dockerfile,在构建最终运行镜像的runner阶段,为apt-get install命令添加ca-certificates包。 - 执行
sudo docker compose up -d --build进行重建。
关键发现:
问题依旧。通过 sudo docker compose exec web bash 进入容器内部,使用 ls -l /etc/ssl/certs/ca-certificates.crt 和 ls -l /etc/ssl/certs/ | head -n 10 以及 dpkg -l | grep ca-certificates 命令检查后发现,/etc/ssl/certs 目录、/etc/ssl/certs/ca-certificates.crt 文件和 ca-certificates 包在最终的运行环境中根本不存在。
分析:
Misskey 使用的先进的多阶段构建 Dockerfile 非常复杂,它将构建环境和运行环境严格分离。我们在一个阶段安装的东西,可能并不会被拷贝到最终的运行阶段。直接修改 Dockerfile 的方法在此场景下失效。
Step 5: 最终解决方案 - 在容器启动时动态修复环境
既然无法在“出厂前”(构建时)修复,那我们就在“每次开机时”(启动时)进行动态修复。我们将利用 compose.yml 的 command 和 user 指令,实现一个“自检修复”的启动脚本。
操作:
1、编辑 compose.yml 文件。
2、找到 web: 服务,添加/修改 user 和 command 两个指令,将其替换为以下内容:
```yaml
# ... web 服务其他配置 ...
user: root # 1. 强制以 root 身份启动,获得权限
command: > # 2. 覆盖默认启动命令,执行我们的修复脚本
bash -c "
# 3. 检查证书包是否已安装
if ! dpkg -l | grep -q ca-certificates; then
echo '>>>> Certificate package not found. Installing now...'
# 4. 如果未安装,就以 root 权限进行安装
apt-get update && apt-get install -y ca-certificates
fi &&
echo '>>>> Starting Misskey as user misskey...' &&
# 5. 修复完成后,切换回低权限的 misskey 用户,再安全地启动程序
su misskey -c 'pnpm run migrateandstart'
"
3、应用新的配置并重启服务。
sudo docker compose down && sudo docker compose up -d
最终验证:
再次进入容器内部 sudo docker compose exec web curl -v https://misskey.io,命令成功返回网页内容。回到浏览器,关注功能恢复正常。问题解决。
三、结论与总结
这次问题的根源是 cloudflared 服务的 DNS 劫持 和 Misskey 官方 Docker 镜像的极度精简 两个因素叠加造成的。通过层层递进的诊断,我们最终绕过了复杂的 Docker 构建过程,采用在容器启动时动态注入修复逻辑的方式,一劳永逸地解决了问题。经测试,可以联合(关注外站用户)成功:

这个案例告诉我们,在处理容器化应用的网络问题时:
- 日志是永远的起点。
docker exec是深入现场、验证推论的终极武器。- 当构建时修复(Dockerfile)过于复杂或无效时,在运行时修复(compose.yml command)往往是更直接、更有效的降维打击。
Misskey 搜索提示“帖子检索不可用”
搜索功能一直提示“帖子检索不可用”,最后发现是默认没有开搜索功能导致的。需要用超级管理员账号(即部署后创建的第一个账号),路径:控制面板-角色-基本角色,在下拉列表中找到“是否可以搜索帖子”,设置为“是”,重新加载/切换一下账号即可解决。这个地方还可以设置各种细节,真是个完善的去中心化平台。
Comments NOTHING