Appwrite 是面向 Web、移动端和后端开发者的开源 Backend-as-a-Service。它把认证、数据库、存储、函数、消息和 API 统一到一个控制台里,适合个人项目、内部工具和小团队产品。自托管的好处是数据、API Key 和用量都掌握在自己的 VPS 上,但也意味着你要自己负责域名、HTTPS、备份、升级和资源规划。
这篇教程使用 Ubuntu 24.04、Docker Compose、Appwrite 1.7.x 和 Caddy,部署一个可长期维护的单机环境。Appwrite 运行前先确认 VPS 配置,1 核 2GB 只适合测试;正式项目建议至少 2 核 4GB、40GB SSD,并根据数据库、上传文件和 Functions 使用量预留磁盘空间。可以先参考 VPS 配置怎么选。
Appwrite 会同时运行 API、Console、MariaDB、Redis、队列和若干 Worker,容器数量比普通 WordPress 多。建议准备:
| 项目 | 测试环境 | 小型生产环境 |
|---|---|---|
| CPU | 2 vCPU | 4 vCPU 起 |
| 内存 | 4 GB | 8 GB 更稳 |
| 磁盘 | 30 GB SSD | 80 GB SSD 起 |
| 系统 | Ubuntu 22.04/24.04 | Ubuntu 24.04 LTS |
| 域名 | appwrite.example.com | 独立子域名 + 邮件域名 |
如果 VPS 上已经运行多个数据库、监控和 AI 服务,先用 free -h、df -h 和 docker stats 看余量。不要在磁盘快满或内存持续接近上限时直接部署,队列积压时 Appwrite 会表现为登录、上传或函数执行随机超时。
sudo apt update
sudo apt install -y ca-certificates curl git
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker "$USER"
newgrp docker
sudo mkdir -p /opt/appwrite
sudo chown -R "$USER":"$USER" /opt/appwrite
cd /opt/appwrite
生产环境不要把 Docker Socket 和 Appwrite 数据目录放在临时目录。先确认 Docker 服务开机启动:
sudo systemctl enable --now docker
docker version
docker compose version
Appwrite 的 Compose 文件会随版本调整,建议从官方仓库获取与当前版本匹配的模板,不要长期复制旧教程中的镜像标签:
cd /opt/appwrite
git clone --depth=1 https://github.com/appwrite/appwrite.git source
cd source
git checkout 1.7.x
cp .env.example .env
编辑 .env 时至少修改以下值,密钥要使用随机字符串,不要提交到 Git:
_APP_ENV=production
_APP_OPENSSL_KEY_V1=replace-with-a-long-random-secret
_APP_DOMAIN=appwrite.example.com
_APP_DOMAIN_TARGET=appwrite.example.com
_APP_DB_HOST=mariadb
_APP_DB_USER=appwrite
_APP_DB_PASS=replace-with-a-database-password
_APP_DB_SCHEMA=appwrite
_APP_REDIS_HOST=redis
[email protected]
_APP_SYSTEM_EMAIL_NAME=Appwrite
生成密钥可以使用 openssl rand -hex 32。Appwrite 的环境变量名称和默认值会因版本变化,启动前检查是否存在重复配置。不要把数据库端口、Redis 端口或内部 API 直接映射到公网。
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 appwrite
第一次启动需要拉取多个镜像并初始化数据库,几分钟内出现重启属于常见现象。重点观察:
mariadb是否持续为 healthy;redis是否能被 Appwrite 连接;appwrite和 Worker 是否不再反复 Restarting;- 磁盘和内存是否在拉取镜像后仍有余量。
浏览器先访问本机端口或临时 SSH 隧道,不要在 DNS 和 HTTPS 尚未完成时公开管理台:
ssh -L 8080:127.0.0.1:80 root@SERVER_IP
Appwrite 的 Console、API、WebSocket 和部分回调都依赖正确的域名。DNS 的 A/AAAA 记录指向 VPS 后,安装 Caddy:
sudo apt install -y caddy
sudo nano /etc/caddy/Caddyfile
最小配置如下,实际上游端口以 Compose 文件暴露的端口为准:
appwrite.example.com {
encode gzip zstd
reverse_proxy 127.0.0.1:80
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
}
}
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
sudo journalctl -u caddy -n 80 --no-pager
如果 VPS 上已经有 Nginx Proxy Manager 或其他反向代理,不要让多个服务同时抢占 80/443。可以把 Appwrite 只绑定到 127.0.0.1,再由现有网关转发;反代和自动 HTTPS 的通用排查方法见 VPS 用 Caddy 反向代理完全指南。
打开 https://appwrite.example.com 后创建管理员账号,再完成以下设置:
- 为 Web、Android、iOS 或服务器端 SDK 创建独立项目和平台;
- 为每个项目设置明确的回调域名,不要使用
*; - API Key 只授予实际需要的 Scope,并按环境拆分;
- 管理员账号启用强密码和 MFA,团队成员按角色分配权限;
- Functions 执行环境不要放入长期有效的主账号密钥;
- 邮件服务使用 SMTP,发件地址使用已配置 SPF、DKIM、DMARC 的域名;
- 通过云防火墙只开放 SSH、80 和 443,数据库、Redis、内部 Worker 端口保持关闭。
如果需要远程维护数据库或后台,优先通过 WireGuard、Tailscale 或 SSH 隧道访问,不要为了方便把 3306、6379 和内部 API 暴露到公网。公网数据库暴露的风险和检查方法可参考 VPS 数据库不要直接暴露公网。
Appwrite 的可恢复性取决于数据库、存储目录和 .env 密钥三部分,少备份任何一项都可能导致账号、文件或加密数据无法恢复。停机窗口内先导出数据库并打包持久化目录:
cd /opt/appwrite/source
mkdir -p /opt/appwrite/backup
docker compose exec -T mariadb mysqldump -uappwrite -p"$APPWRITE_DB_PASS" appwrite | gzip > /opt/appwrite/backup/appwrite-$(date +%F).sql.gz
tar -czf /opt/appwrite/backup/appwrite-data-$(date +%F).tgz .env docker-compose.yml volumes/
备份至少保留一份异地副本,上传前先加密;不要只依赖 VPS 快照。恢复前在干净测试机还原一次,确认登录、文件下载、数据库查询和 Function 执行都正常。完整的恢复流程可以参考 VPS 备份恢复演练。
升级前记录当前镜像版本和配置差异:
docker compose config > /opt/appwrite/backup/compose-$(date +%F).yaml
git fetch --tags
git checkout 1.7.x
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=200
不要直接使用 latest 并自动重启生产环境。先在测试实例验证数据库迁移,再安排维护窗口;升级失败时保留旧镜像和备份,按版本文档执行回滚。
先看 Caddy 和 Appwrite 日志,再确认上游端口:
sudo journalctl -u caddy -n 100 --no-pager
docker compose ps
docker compose logs --tail=200 appwrite
ss -lntp | grep -E ':80|:443'
检查浏览器开发者工具中的 API 域名、HTTPS 证书和 WebSocket 错误;再确认 Redis、MariaDB 和 Worker 没有重启。如果只在大文件上传时失败,还要检查 Caddy、Cloudflare 或云防火墙的请求体限制。
docker compose ps
docker stats --no-stream
docker inspect appwrite --format '{{.State.OOMKilled}} {{.State.ExitCode}}'
sudo dmesg -T | grep -i -E 'oom|killed process'
先释放无用镜像和日志,确认 Swap,再考虑扩容。不要通过盲目限制 Worker 内存掩盖数据库或队列积压问题。
- 域名、HTTPS 和 WebSocket 均正常;
- 管理员 MFA、项目平台和回调域名已配置;
- 3306、6379 等内部端口没有公网监听;
.env、数据库、上传文件和 Functions 均有备份;- 在独立机器完成过一次恢复演练;
- 升级前能记录版本,升级后能查看日志并回滚。
Appwrite 很适合把认证、数据库和文件 API 集中到一台可控的 VPS 上,但它不是装完就不用运维的黑盒。把 HTTPS、权限、备份和恢复演练一起完成,才算真正可上线的自托管后端。
