从踩坑到稳定运行,一个开发者的 Web 终端部署实战记录

为什么需要云端终端?

作为一名开发者,我经常遇到这样的场景:

  • 🌙 深夜突发故障:躺在床上,手机收到告警,需要紧急登录服务器
  • ✈️ 机场候机:只带了 iPad,突然想验证一个技术方案
  • 🏢 客户现场:公司电脑权限受限,无法安装开发工具
  • 👥 技术分享:需要给团队实时演示 Linux 命令,但不是每个人都有环境
  • 🔧 快速测试:临时需要一个干净的 Linux 环境测试脚本

传统方案的痛点:

  • 虚拟机太重,占用大量本地资源
  • WSL 仅限 Windows,且需要管理员权限
  • 云服务器成本高,配置复杂
  • SSH 客户端在移动设备上体验差

有没有一个方案,能让我随时随地,打开浏览器就能用?

技术选型:为什么选择 ttyd?

在经历了一周的折腾后,我尝试了多个方案:

方案对比

方案 优点 缺点 结论
Wetty 功能丰富 镜像 160MB,经常出现前端模块加载失败 ❌ 放弃
GoTTY 轻量 项目已不维护,安全问题 ❌ 不推荐
ttyd 轻量、稳定、活跃维护 功能相对简单 最终选择

为什么 Wetty 不行?

刚开始我选择了流行的 Wetty,但踩了几个大坑:

问题 1:前端资源加载失败

Uncaught TypeError: Failed to resolve module specifier 
"@fortawesome/fontawesome-svg-core"

这个错误困扰了我好几天。问题出在 npm install -g wetty 的打包机制上,前端模块路径配置有问题。

问题 2:连接频繁断开

transport error
[reconnect]

bash 进程会莫名其妙地退出,导致需要频繁重连。

问题 3:镜像体积大

  • Wetty 镜像:~160MB
  • 包含大量 Node.js 依赖
  • 构建时间长

ttyd 的优势

经过对比测试,ttyd 完胜:

✅ 镜像仅 50MB(Alpine + ttyd)
✅ 无前端模块问题(C 语言编写)
✅ 连接稳定,无莫名断开
✅ 资源占用低(内存 < 100MB)
✅ 启动速度快(< 2 秒)
✅ 活跃维护(GitHub 13k+ stars)

性能对比实测

指标 ttyd Wetty
镜像大小 50MB 160MB
内存占用 80MB 150MB
启动时间 1.5s 4s
页面加载 稳定 偶尔失败
连接稳定性 ⭐⭐⭐⭐⭐ ⭐⭐⭐

完整部署方案

架构设计

┌─────────────────┐
│   用户浏览器    │  ← 任何设备(PC/iPad/手机)
└────────┬────────┘
         │ HTTPS (TLS 1.3)
         ▼
┌─────────────────┐
│    Fly.io CDN   │  ← 全球加速
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  Docker 容器    │
│  Alpine Linux   │
│   + ttyd        │  ← 轻量级终端
│   + bash        │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  Shell (yys)    │  ← 你的工作环境
└─────────────────┘

第一步:环境准备

安装 Fly.io CLI:

macOS/Linux:

curl -L https://fly.io/install.sh | sh

# 添加到 PATH
echo 'export PATH="$HOME/.fly/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

Windows (PowerShell 管理员模式):

iwr https://fly.io/install.ps1 -useb | iex

验证安装:

flyctl version
# flyctl v0.x.x linux/amd64 Commit: xxx BuildDate: xxx

登录 Fly.io:

flyctl auth login
# 浏览器会自动打开,完成授权

💡 提示:Fly.io 免费额度足够个人使用,无需信用卡即可开始(但建议绑定以获得更多额度)

第二步:项目初始化

创建项目目录:

mkdir ttyd-cloud-terminal
cd ttyd-cloud-terminal

第三步:编写 Dockerfile

这是整个项目的核心,我精心优化了工具集和配置:

FROM alpine:latest

# 一次性安装所有依赖(减少镜像层)
RUN apk add --no-cache \
    # 核心工具
    ttyd \
    bash \
    sudo \
    shadow \
    # 编辑器
    vim \
    nano \
    # 网络工具
    curl \
    wget \
    openssh-client \
    net-tools \
    iputils \
    bind-tools \
    # 开发工具
    git \
    python3 \
    py3-pip \
    nodejs \
    npm \
    build-base \
    # 系统工具
    htop \
    tmux \
    tree \
    # 压缩工具
    unzip \
    tar \
    gzip

# 创建工作用户(非 root,更安全)
RUN adduser -D -s /bin/bash yys && \
    echo "yys ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers && \
    echo "yys:ChangeMe123" | chpasswd

# 配置 bash 环境
RUN echo 'export PS1="\[\e[1;32m\]\u@cloud\[\e[0m\]:\[\e[1;34m\]\w\[\e[0m\]\$ "' >> /home/yys/.bashrc && \
    echo 'alias ll="ls -lah"' >> /home/yys/.bashrc && \
    echo 'alias gs="git status"' >> /home/yys/.bashrc

# 创建启动脚本
RUN echo '#!/bin/bash' > /start.sh && \
    echo 'exec ttyd -p 3000 -W -t fontSize=16 su - yys' >> /start.sh && \
    chmod +x /start.sh

EXPOSE 3000

CMD ["/start.sh"]

配置说明

  • ttyd 参数详解

    • -p 3000: 监听端口
    • -W: 允许写入(可以执行命令)
    • -t fontSize=16: 设置舒适的字体大小
    • su - yys: 以普通用户登录(安全最佳实践)
  • 工具选择逻辑

    • 编辑器:vim(强大)+ nano(简单)
    • 语言:Python、Node.js(覆盖大部分场景)
    • 网络:curl、wget、SSH 客户端
    • 开发:git、编译工具链

第四步:配置 Fly.io

创建 fly.toml

app = 'my-cloud-terminal'  # 改成你的唯一应用名
primary_region = 'lax'      # 美国洛杉矶(也可选 'hkg' 香港、'nrt' 东京)

[build]

[http_service]
  internal_port = 3000
  force_https = true           # 强制 HTTPS,安全第一
  auto_stop_machines = 'stop'  # 无流量时休眠(省钱)
  auto_start_machines = true   # 访问时自动唤醒
  min_machines_running = 0     # 最少 0 台运行

[[vm]]
  memory = '512mb'  # 512MB 足够日常使用
  cpus = 1          # 1 核 CPU

配置优化建议

# 如果需要 24/7 在线(会消耗更多免费额度)
[http_service]
  min_machines_running = 1
  auto_stop_machines = false

# 如果需要更多性能
[[vm]]
  memory = '1024mb'  # 升级到 1GB
  cpus = 2           # 2 核

第五步:一键部署

# 初始化并部署
flyctl launch

# 按照提示操作:
# 1. 检测到 Dockerfile? Yes
# 2. 应用名称? 使用 fly.toml 中的名称
# 3. 立即部署? Yes

部署过程:

==> Building image
==> Pushing image to fly
==> Creating app resources
==> Deploying
--> v0 deployed successfully

Visit your newly deployed app at https://my-cloud-terminal.fly.dev/

整个过程大约 2-3 分钟

第六步:验证部署

# 查看应用状态
flyctl status

# 输出示例:
# App
#   Name     = my-cloud-terminal
#   Owner    = your-email
#   Hostname = my-cloud-terminal.fly.dev
#   Platform = nomad
#   Image    = my-cloud-terminal:deployment-xxx
#
# Machines
# PROCESS  ID      VERSION REGION  STATE   CHECKS  CREATED
# app      a1b2c3  v0      lax     started         2m ago
# 实时查看日志
flyctl logs -f
# 打开应用
flyctl open

浏览器会自动打开:https://my-cloud-terminal.fly.dev/ 🎉

实战案例

案例 1:半夜紧急修复服务器

场景:凌晨 2 点,告警短信把我惊醒 —— 生产环境 Nginx 挂了。

设备:只有手机在身边

操作流程

# 1. 手机浏览器打开云终端
https://my-cloud-terminal.fly.dev/

# 2. SSH 连接到生产服务器
ssh -i ~/.ssh/prod_key admin@prod-server.com

# 3. 检查 Nginx 状态
sudo systemctl status nginx
# ● nginx.service - A high performance web server
#    Loaded: loaded
#    Active: failed (Result: exit-code)

# 4. 查看错误日志
sudo journalctl -u nginx -n 50

# 5. 发现配置文件错误,修复
sudo vim /etc/nginx/sites-enabled/myapp.conf
# 修复了一个缺失的分号

# 6. 测试配置
sudo nginx -t
# nginx: configuration file /etc/nginx/nginx.conf test is successful

# 7. 重启 Nginx
sudo systemctl restart nginx

# 8. 验证服务恢复
curl -I https://myapp.com
# HTTP/2 200 OK

# 总耗时:6 分钟
# 设备:手机
# 成本:0 元

关键优势:

  • ✅ 无需笔记本电脑
  • ✅ 手机浏览器完成所有操作
  • ✅ 完整的 SSH 客户端支持
  • ✅ Vim 操作流畅

案例 2:iPad 上写代码

场景:周末在咖啡厅,带了 iPad + 蓝牙键盘,突然想实现一个创意。

工作流程

# 1. iPad Safari 打开云终端

# 2. 克隆项目
git clone https://github.com/myname/idea-project.git
cd idea-project

# 3. 创建功能分支
git checkout -b feature/awesome-idea

# 4. 编写代码
vim src/main.py

# Python 脚本内容
#!/usr/bin/env python3
import requests
from bs4 import BeautifulSoup

def scrape_tech_news():
    url = 'https://news.ycombinator.com/'
    response = requests.get(url)
    soup = BeautifulSoup(response.text, 'html.parser')
    
    stories = soup.select('.titleline > a')
    for story in stories[:10]:
        print(f"• {story.text}")
        print(f"  {story['href']}\n")

if __name__ == '__main__':
    scrape_tech_news()

# 5. 安装依赖
pip3 install requests beautifulsoup4

# 6. 测试运行
python3 src/main.py
# ✓ 成功抓取 Hacker News 前 10 条

# 7. 提交代码
git add .
git commit -m "Add Hacker News scraper"
git push origin feature/awesome-idea

# 8. 在 GitHub 上创建 Pull Request
# 使用 iPad 浏览器完成

体验

  • ⭐⭐⭐⭐⭐ 完全不输本地开发
  • 响应延迟 < 100ms(洛杉矶节点)
  • Vim 操作无卡顿
  • 代码高亮正常

案例 3:远程协助同事调试

场景:同事的 Python 环境有问题,视频通话也说不清楚。

解决方案

# 1. 分享云终端 URL 和临时密码给同事
# 2. 同事在浏览器打开,实时看到我的操作

# 3. 诊断问题
python3 --version  # Python 3.11.x

# 检查依赖
pip3 list | grep flask
# flask                2.0.1  # 版本太旧了

# 4. 解决方案
pip3 install --upgrade flask

# 5. 验证修复
python3 app.py
# ✓ Running on http://127.0.0.1:5000

# 问题解决,同事学会了操作

优势

  • 无需远程桌面
  • 双方看到完全一致的界面
  • 可以录屏保存操作步骤

案例 4:快速原型验证

场景:有一个技术想法,需要快速验证可行性。

# 创建临时项目目录
mkdir /tmp/prototype && cd /tmp/prototype

# 快速搭建 HTTP 服务器
cat > server.py << 'EOF'
from http.server import HTTPServer, BaseHTTPRequestHandler
import json

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type', 'application/json')
        self.end_headers()
        
        data = {'message': 'Hello from cloud!', 'timestamp': '2026-01-20'}
        self.wfile.write(json.dumps(data).encode())

httpd = HTTPServer(('0.0.0.0', 8080), Handler)
print('Server running on port 8080...')
httpd.serve_forever()
EOF

# 运行服务
python3 server.py &

# 测试
curl http://localhost:8080
# {"message": "Hello from cloud!", "timestamp": "2026-01-20"}

# 验证成功!记录下来,明天继续完善

进阶技巧

1. 持久化工作环境

默认情况下,容器重启后数据会丢失。配置 Volume 持久化:

# 创建 1GB 存储卷
flyctl volumes create terminal_data --region lax --size 1

修改 fly.toml

[mounts]
  source = "terminal_data"
  destination = "/data"

在 Dockerfile 中配置权限:

RUN mkdir -p /data && chown yys:yys /data

现在 /data 目录中的文件会永久保存。

使用示例

# 克隆项目到持久化目录
cd /data
git clone https://github.com/myproject/app.git

# 即使容器重启,项目代码还在

2. 使用 tmux 保持会话

# 安装 tmux
sudo apk add tmux

# 创建命名会话
tmux new -s work

# 在 tmux 中工作
# ...做各种操作...

# 分离会话(保持后台运行)
# 快捷键:Ctrl+B, 然后按 D

# 关闭浏览器
# 几小时后回来...

# 重新打开云终端,连接回会话
tmux attach -t work

# 🎉 所有工作状态都还在!

常用 tmux 快捷键

  • Ctrl+B %:左右分屏
  • Ctrl+B ":上下分屏
  • Ctrl+B 方向键:切换窗格
  • Ctrl+B D:分离会话
  • Ctrl+B C:创建新窗口

3. 添加密码保护

修改 Dockerfile 启动脚本:

# 添加基本认证
RUN echo '#!/bin/bash' > /start.sh && \
    echo 'exec ttyd -p 3000 -W -c admin:SecurePass2026 -t fontSize=16 su - yys' >> /start.sh && \
    chmod +x /start.sh

重新部署后,访问时需要输入:

  • 用户名:admin
  • 密码:SecurePass2026

安全建议

  • 使用强密码
  • 定期更换密码
  • 考虑使用 Fly.io Secrets 存储密码

4. 自定义开发环境

根据你的主要技术栈定制工具:

前端开发者

RUN apk add --no-cache \
    nodejs \
    npm \
    yarn \
    && npm install -g \
    pnpm \
    vite \
    @vue/cli \
    create-react-app

后端开发者

RUN apk add --no-cache \
    python3 \
    py3-pip \
    go \
    && pip3 install \
    django \
    flask \
    fastapi \
    requests \
    pytest

DevOps 工程师

RUN apk add --no-cache \
    docker-cli \
    kubectl \
    helm \
    terraform \
    ansible

数据科学

RUN apk add --no-cache \
    python3 \
    py3-numpy \
    py3-pandas \
    py3-matplotlib \
    jupyter

5. 美化终端

安装 Oh My Bash:

bash -c "$(curl -fsSL https://raw.githubusercontent.com/ohmybash/oh-my-bash/master/tools/install.sh)"

自定义提示符(编辑 ~/.bashrc):

# Git 状态显示
export PS1='\[\e[1;32m\]\u@cloud\[\e[0m\]:\[\e[1;34m\]\w\[\e[0m\]\[\e[1;33m\]$(__git_ps1 " (%s)")\[\e[0m\]\$ '

# 彩色 ls
alias ls='ls --color=auto'
alias ll='ls -lah --color=auto'
alias grep='grep --color=auto'

# 常用快捷方式
alias g='git'
alias d='docker'
alias k='kubectl'
alias tf='terraform'

效果:

yys@cloud:~/project (main)$ 

6. 配置 SSH 代理转发

在本地 ~/.ssh/config 中配置:

Host cloud-terminal
    HostName my-cloud-terminal.fly.dev
    User yys
    ForwardAgent yes

然后可以通过云终端 SSH 到其他服务器,复用本地的 SSH 密钥。

7. 设置定时任务

# 安装 cronie
sudo apk add cronie

# 启动 cron 服务
sudo crond

# 编辑 crontab
crontab -e

# 添加定时任务(每天凌晨 2 点备份)
0 2 * * * /data/scripts/backup.sh

# 查看任务列表
crontab -l

性能优化

冷启动优化

由于配置了 auto_stop_machines = 'stop',首次访问需要等待 3-5 秒唤醒。

优化方案

方案 1:保持常驻(消耗更多免费额度)

[http_service]
  min_machines_running = 1
  auto_stop_machines = false

方案 2:多区域部署(就近访问,减少延迟)

flyctl regions add hkg nrt  # 添加香港、东京

方案 3:定期保活(使用 cron job 定期访问)

# 在本地电脑设置 cron
*/10 * * * * curl https://my-cloud-terminal.fly.dev/ > /dev/null 2>&1

资源监控

实时监控资源使用:

# CPU 和内存
htop

# 磁盘使用
df -h

# 网络连接
netstat -tuln

# 进程树
ps auxf

镜像体积优化

当前大小:~50MB

进一步优化(如果不需要某些工具):

# 精简版 - 只保留核心工具
RUN apk add --no-cache \
    ttyd \
    bash \
    git \
    vim \
    curl
    
# 镜像大小降至 ~30MB

安全最佳实践

1. 强密码策略

# 在云终端中修改密码
passwd yys

# 输入强密码(至少 16 位,包含大小写字母、数字、特殊字符)
# 例如:Xy9#mK2$pL7@qR5&

2. SSH 密钥管理

# 生成 ED25519 密钥(更安全)
ssh-keygen -t ed25519 -C "your_email@example.com"

# 查看公钥
cat ~/.ssh/id_ed25519.pub

# 添加到 GitHub/GitLab/服务器

3. 定期更新

# 更新系统包
sudo apk update && sudo apk upgrade

# 重新部署以获取最新镜像
flyctl deploy

4. 日志审计

# 查看最近的访问日志
flyctl logs --filter app

# 设置日志告警(Fly.io Dashboard)

5. IP 白名单(企业版功能)

如果升级到 Fly.io 企业版,可以限制访问 IP:

[services]
  [[services.http_checks]]
    allowed_ips = ["1.2.3.4/32", "10.0.0.0/8"]

成本分析

Fly.io 免费额度(2026)

  • 3 个共享 CPU 虚拟机(256MB RAM)
  • 每月 160GB 出站流量
  • 3GB 持久化存储

我们的配置

  • 1 台虚拟机(512MB RAM)
  • 预计流量:< 10GB/月(正常使用)
  • 持久化存储:1GB

结论:完全在免费额度内!💰

成本对比

方案 月费用 配置
AWS EC2 t3.micro $8.50 1核 1GB
DigitalOcean Droplet $6.00 1核 1GB
Linode Nanode $5.00 1核 1GB
Fly.io(本方案) $0.00 1核 512MB

即使超出免费额度,Fly.io 的价格也很有竞争力:

  • 额外内存:$0.00024/MB/小时
  • 额外流量:$0.02/GB

故障排查指南

问题 1:页面打不开

症状:浏览器显示"无法访问此网站"

排查步骤

# 1. 检查应用状态
flyctl status

# 2. 检查机器列表
flyctl machine list

# 3. 查看日志
flyctl logs

# 4. 检查 DNS
nslookup my-cloud-terminal.fly.dev

# 5. 手动重启
flyctl machine restart <machine-id>

常见原因

  • 机器自动休眠(等待 3-5 秒即可)
  • DNS 未生效(等待传播)
  • 部署失败(查看日志)

问题 2:连接速度慢

症状:输入命令有明显延迟

优化方案

# 1. 检查当前区域
flyctl status | grep Region

# 2. 添加更近的区域
flyctl regions add hkg  # 香港
flyctl regions add nrt  # 东京
flyctl regions add sin  # 新加坡

# 3. 测试延迟
ping my-cloud-terminal.fly.dev

延迟参考

  • 洛杉矶(lax):200-300ms(中国大陆)
  • 香港(hkg):30-50ms(中国大陆)
  • 东京(nrt):50-80ms(中国大陆)

问题 3:内存不足

症状KilledOut of memory

解决方案

升级内存配置(fly.toml):

[[vm]]
  memory = '1024mb'  # 从 512MB 升级到 1GB

重新部署:

flyctl deploy

问题 4:需要安装新软件

# 搜索软件包
apk search redis

# 查看包详情
apk info redis

# 安装
sudo apk add redis

# 卸载
sudo apk del redis

常见软件包名称

  • MySQL客户端:mysql-client
  • PostgreSQL客户端:postgresql-client
  • Redis:redis
  • Docker CLI:docker-cli
  • MongoDB客户端:mongodb-tools

问题 5:中文显示乱码

# 安装中文字体
sudo apk add font-noto-cjk

# 设置语言环境
echo 'export LANG=zh_CN.UTF-8' >> ~/.bashrc
source ~/.bashrc

与其他方案对比

vs. 本地虚拟机

特性 云终端方案 本地虚拟机
安装时间 5 分钟 30 分钟+
资源占用 0(在云端) 2-4GB RAM
启动速度 3-5 秒 30-60 秒
移动设备 ✅ 完美支持 ❌ 不支持
随时随地 ✅ 任何地点 ❌ 仅本地
成本 免费 占用本地资源
数据同步 自动(云端) 手动

vs. GitHub Codespaces

特性 云终端方案 Codespaces
免费额度 无限制 60 小时/月
启动速度 3-5 秒 30-60 秒
配置自由 ⭐⭐⭐⭐⭐ ⭐⭐⭐
用途 通用终端 主要用于开发
IDE 终端 VS Code
学习曲线

vs. AWS Cloud9

特性 云终端方案 Cloud9
价格 免费 按 EC2 计费
配置复杂度
性能
适用场景 个人、小团队 企业

扩展应用

1. 团队共享开发环境

场景:为整个团队提供统一的开发环境

实现

# 1. 部署多个实例
flyctl apps create team-dev-alice
flyctl apps create team-dev-bob
flyctl apps create team-dev-carol

# 2. 每个实例独立配置
# 3. 分配独立的 URL 和密码

2. CI/CD 工具

场景:作为轻量级的 CI Runner

# 在云终端中运行测试
git clone https://github.com/project/app.git
cd app
npm install
npm test

# 构建
npm run build

# 部署
fly deploy

3. 临时演示环境

场景:快速搭建演示环境给客户

# 克隆项目
git clone https://github.com/demo/product.git

# 启动服务
cd product
python -m http.server 8000 &

# 分享云终端 URL 给客户
# 客户可以实时看到效果

4. 学习平台

场景:教学、培训

优势

  • 学员无需配置环境
  • 统一的学习环境
  • 实时观察学员操作
  • 可以录屏保存教程

常见问题 FAQ

Q: 数据会永久保存吗?

A: 默认不会。需要配置 Volume 持久化存储(参见"持久化工作环境"章节)。

Q: 可以运行 Docker 吗?

A: Fly.io 容器内无法运行 Docker daemon,但可以使用 Docker CLI 连接远程 Docker。

或者使用 Podman:

sudo apk add podman
podman run hello-world

Q: 支持多人同时访问吗?

A: 单个实例同时只能一个人使用。多人需要部署多个实例。

Q: 会话超时吗?

A: 不会主动超时,但如果 2 小时无操作,机器可能休眠。使用 tmux 可以保持会话。

Q: 可以上传/下载文件吗?

A: 可以通过以下方式:

  • 使用 curl/wget 下载
  • 使用 Git 同步代码
  • 配置 rz/sz(zmodem 协议)

Q: 如何备份数据?

A: 定期将重要数据 push 到 Git 仓库,或使用 Volume 快照功能。

Q: 延迟高怎么办?

A: 选择距离更近的区域(flyctl regions add hkg),或考虑升级到付费套餐使用专用 IP。

总结与展望

实现了什么

真正的随时随地:手机、iPad、任何电脑,打开浏览器就能用
完整的 Linux 环境:预装 50+ 常用工具
零成本运行:Fly.io 免费额度完全够用
3 秒启动:比虚拟机快 10 倍
稳定可靠:ttyd 久经考验,无前端加载问题
安全加密:HTTPS + 可选密码保护

适用人群

  • 🧑‍💻 开发者:需要随时随地访问 Linux 环境
  • 👨‍🏫 教育工作者:为学生提供统一的实验环境
  • 🛠️ 运维工程师:紧急情况下的救急工具
  • 📱 移动工作者:经常出差,只带 iPad/手机
  • 🎓 学生:学习 Linux,无需本地安装虚拟机

下一步

  1. 立即动手:跟着教程部署你的第一个云终端(15 分钟)
  2. 定制化:根据自己的技术栈添加常用工具
  3. 分享给团队:提升团队协作效率
  4. 持续优化:根据使用情况调整配置

未来展望

随着技术发展,未来可能实现:

  • 🌐 WebAssembly:完全在浏览器本地运行 Linux(无需服务器)
  • 🎨 图形界面:支持运行 GUI 应用
  • 🤝 多人协作:实时共享终端,远程结对编程
  • 🚀 更强性能:GPU 加速,支持机器学习任务
  • 🔌 插件生态:社区开发的各种扩展功能

项目资源

致谢

感谢以下开源项目: