Appwrite:开源全栈 BaaS,Firebase 之外的第三条路
当你在构建一个新的 Web 或移动应用时,总会面临一个重复性的工作:从零搭建用户认证、数据库 CRUD、文件存储、消息推送......这些基础设施每次都要重新来过,耗费大量时间。Firebase 解决了这个痛点,但它是 Google 的闭源服务,数据掌握在别人手中,定价也随时可能变化。Supabase 虽然是开源替代品,但它以 PostgreSQL 为核心,更偏向关系型数据库场景。
Appwrite 则走了另一条路:它是一个完全开源的 Backend-as-a-Service(BaaS),提供文档数据库、身份认证、文件存储、云函数、实时订阅等全套后端服务,通过 REST API 和官方 SDK 供前端直接调用。本文带你在自己的服务器上完整部署 Appwrite 1.5.7,并演示从创建项目到前端集成的全流程。
Appwrite vs Supabase vs Firebase
| 对比项 | Appwrite | Supabase | Firebase |
|---|---|---|---|
| 数据库类型 | 文档型(自研) | PostgreSQL(关系型) | Firestore(文档型) |
| 开源 | 完全开源 | 开源 | 闭源 |
| 自托管 | 支持 | 支持 | 不支持 |
| 实时订阅 | 支持 | 支持 | 支持 |
| 云函数 | 支持(多语言) | 支持(Deno/TypeScript) | 支持(Node.js 为主) |
| 适用场景 | 全栈应用、移动 App | 数据密集型、复杂查询 | 快速原型 |
如果你的应用更像文档存储(类似 MongoDB 的使用方式),或者需要一个覆盖前端开发所有需求的一站式方案,Appwrite 是比 Supabase 更自然的选择。
服务器配置
Appwrite 内部运行了多个 worker 进程(处理函数执行、邮件发送、文件处理等),对内存有一定要求。推荐使用 2 核 4GB 机型 作为开发/测试环境,生产环境建议升级到 4 核 8GB。
推荐使用 雨云服务器 rainyun-com 来部署 Appwrite,注册填 2026off 可领取 5 折券。雨云支持按需扩容,非常适合从小规模起步、逐步增长的项目。
环境要求:
- 操作系统:Ubuntu 22.04 LTS
- CPU:2 核及以上
- 内存:4GB 及以上(生产环境 8GB+)
- 磁盘:40GB 及以上(文件存储)
- 开放端口:80、443
安装 Docker 和 Docker Compose
bash
sudo apt update && sudo apt upgrade -y
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
newgrp docker
# 验证安装
docker --version
docker compose version
Docker Compose 部署 Appwrite
Appwrite 官方提供了一个交互式安装脚本,通过单条 Docker 命令拉起安装程序,自动生成完整的 docker-compose.yml 配置:
bash
docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
appwrite/appwrite:1.5.7
安装程序会以交互方式询问以下配置:
? Choose your server HTTP port: 80
? Choose your server HTTPS port: 443
? Enter your Appwrite hostname: appwrite.yourdomain.com
? Enter a secret API key: (自动生成,直接回车即可)
? Enter your Appwrite database password: (设置一个强密码)
? Enter your Appwrite Redis password: (设置一个强密码)
回答完成后,安装程序会自动生成 appwrite/docker-compose.yml 和 .env 文件,并启动所有容器。
Appwrite 内部服务架构
appwrite # 主 API 服务(PHP + Swoole)
appwrite-worker-audits # 审计日志 worker
appwrite-worker-databases # 数据库操作 worker
appwrite-worker-deletes # 数据删除 worker
appwrite-worker-functions # 云函数执行 worker
appwrite-worker-mails # 邮件发送 worker
appwrite-worker-messaging # 消息推送 worker
appwrite-worker-migrations # 数据迁移 worker
appwrite-worker-webhooks # Webhook worker
appwrite-traefik # 反向代理(内置)
appwrite-mariadb # 主数据库
appwrite-redis # 缓存 + 队列
appwrite-influxdb # 指标存储
appwrite-telegraf # 指标采集
Caddy 反代配置
Appwrite 默认使用内置的 Traefik 处理 HTTPS,如果你希望统一用 Caddy 管理域名,需要修改 .env 文件关闭 Traefik 的 80/443 绑定,再配置 Caddy 代理到 Appwrite 内部端口。
安装 Caddy:
bash
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install caddy
修改 appwrite/.env,将端口改为非 80/443(如 8080/8443),并在 /etc/caddy/Caddyfile 中添加:
caddy
appwrite.yourdomain.com {
reverse_proxy localhost:8080
}
重载 Caddy:
bash
sudo systemctl reload caddy
初始设置:创建账号与项目
访问 https://appwrite.yourdomain.com,首次打开会进入注册页面,创建管理员账号后进入控制台。
创建项目
- 点击 Create project
- 输入项目名称(如
my-todo-app) - 记录 Project ID(后续 SDK 初始化需要)
创建数据库与集合(Collection)
Appwrite 的数据库使用文档模型:数据库(Database)→ 集合(Collection,类似表)→ 文档(Document,类似行)。
在控制台进入 Databases → Create database → 命名为 main。
然后创建集合 todos,添加以下属性(Attributes):
| 属性名 | 类型 | 必填 |
|---|---|---|
| title | String(255) | 是 |
| completed | Boolean | 是 |
| userId | String(255) | 是 |
在 Settings → Permissions 中配置权限规则(如允许已登录用户读写自己的文档)。
前端集成:Web SDK 示例
安装 SDK
bash
npm install appwrite
初始化 SDK
javascript
// lib/appwrite.js
import { Client, Databases, Account, Storage, ID, Query } from 'appwrite';
const client = new Client()
.setEndpoint('https://appwrite.yourdomain.com/v1')
.setProject('YOUR_PROJECT_ID');
export const account = new Account(client);
export const databases = new Databases(client);
export const storage = new Storage(client);
export { ID, Query };
用户注册与登录
javascript
import { account, ID } from './lib/appwrite';
// 注册新用户
async function register(email, password, name) {
try {
const user = await account.create(ID.unique(), email, password, name);
// 注册成功后自动登录
await account.createEmailPasswordSession(email, password);
return user;
} catch (error) {
console.error('注册失败:', error.message);
}
}
// 登录
async function login(email, password) {
try {
const session = await account.createEmailPasswordSession(email, password);
return session;
} catch (error) {
console.error('登录失败:', error.message);
}
}
// 获取当前用户信息
async function getCurrentUser() {
try {
return await account.get();
} catch {
return null;
}
}
// 登出
async function logout() {
await account.deleteSession('current');
}
数据库 CRUD 操作
javascript
import { databases, ID, Query } from './lib/appwrite';
const DATABASE_ID = 'main';
const COLLECTION_ID = 'todos';
// 创建文档
async function createTodo(title, userId) {
return await databases.createDocument(
DATABASE_ID,
COLLECTION_ID,
ID.unique(),
{ title, completed: false, userId }
);
}
// 查询当前用户的所有 Todo
async function listTodos(userId) {
const response = await databases.listDocuments(
DATABASE_ID,
COLLECTION_ID,
[
Query.equal('userId', userId),
Query.orderDesc('$createdAt')
]
);
return response.documents;
}
// 更新文档
async function completeTodo(documentId) {
return await databases.updateDocument(
DATABASE_ID,
COLLECTION_ID,
documentId,
{ completed: true }
);
}
// 删除文档
async function deleteTodo(documentId) {
return await databases.deleteDocument(DATABASE_ID, COLLECTION_ID, documentId);
}
文件存储(Storage)
创建存储桶
在控制台进入 Storage → Create bucket ,命名为 avatars,配置允许的文件类型(如 image/*)和最大文件大小。
上传与获取文件
javascript
import { storage, ID } from './lib/appwrite';
const BUCKET_ID = 'avatars';
// 上传文件(浏览器 File 对象)
async function uploadAvatar(file) {
const response = await storage.createFile(BUCKET_ID, ID.unique(), file);
return response.$id;
}
// 获取文件预览 URL
function getAvatarUrl(fileId) {
return storage.getFilePreview(BUCKET_ID, fileId, 200, 200);
}
// 下载文件
function getAvatarDownload(fileId) {
return storage.getFileDownload(BUCKET_ID, fileId);
}
云函数(Functions)
Appwrite Functions 支持 Node.js、Python、PHP、Ruby、Dart 等多种运行时。
创建一个 Node.js 函数
在控制台进入 Functions → Create function ,选择 Node.js 18.0 运行时。
函数代码示例(src/index.js):
javascript
import { Client, Databases } from 'node-appwrite';
export default async ({ req, res, log, error }) => {
const client = new Client()
.setEndpoint(process.env.APPWRITE_FUNCTION_API_ENDPOINT)
.setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
.setKey(req.headers['x-appwrite-key'] ?? '');
const databases = new Databases(client);
// 执行业务逻辑
const body = JSON.parse(req.body || '{}');
log(`Processing request for user: ${body.userId}`);
return res.json({ success: true, message: 'Function executed!' });
};
触发函数
javascript
import { Functions } from 'appwrite';
const functions = new Functions(client);
const execution = await functions.createExecution(
'YOUR_FUNCTION_ID',
JSON.stringify({ userId: 'user123' }),
false // async: false 表示同步等待结果
);
console.log(execution.responseBody);
实时订阅(Realtime)
javascript
import { Client } from 'appwrite';
const client = new Client()
.setEndpoint('https://appwrite.yourdomain.com/v1')
.setProject('YOUR_PROJECT_ID');
// 订阅集合变化
const unsubscribe = client.subscribe(
`databases.main.collections.todos.documents`,
(response) => {
if (response.events.includes('databases.*.collections.*.documents.*.create')) {
console.log('新文档创建:', response.payload);
}
if (response.events.includes('databases.*.collections.*.documents.*.update')) {
console.log('文档更新:', response.payload);
}
}
);
// 取消订阅
// unsubscribe();
功能使用:OAuth 登录配置
Appwrite 支持 30+ 种 OAuth 提供商(GitHub、Google、Discord 等)。以 GitHub 为例:
- 在 GitHub 创建 OAuth App,回调 URL 设为
https://appwrite.yourdomain.com/v1/account/sessions/oauth2/callback/github/YOUR_PROJECT_ID - 在 Appwrite 控制台 → Auth → Settings → 启用 GitHub,填入 Client ID 和 Client Secret
- 前端代码:
javascript
account.createOAuth2Session(
'github',
'https://yourapp.com/dashboard', // 成功回调
'https://yourapp.com/login' // 失败回调
);
结语
Appwrite 将原本需要数周才能搭建的后端基础设施压缩成了几小时的工作------一次部署,获得认证、数据库、存储、函数、实时功能的全套解决方案。对于独立开发者和小团队来说,这是快速验证产品想法、减少重复造轮子的利器。