Appearance
七、生产环境部署 (Deployment)
本章提供完整的从零开始部署 TodoApp 后端服务的操作手册,适用于 Ubuntu 24.04 VPS 环境。
7.1 服务器要求
| 项目 | 最低要求 | 推荐配置 |
|---|---|---|
| 操作系统 | Ubuntu 22.04 LTS | Ubuntu 24.04 LTS |
| CPU | 1 核 | 1 核 |
| 内存 | 512 MB | 1 GB |
| 磁盘 | 10 GB | 20 GB |
| 网络 | IPv4 公网地址 | IPv4 + IPv6 双栈 |
| 域名 | 必须(申请 SSL 证书需要) | 已解析的二级域名 |
7.2 目录结构
~/todo_backend/
├── bin/
│ └── server.dart ← 后端入口
├── lib/ ← 后端源码
├── Dockerfile
├── docker-compose.yml
├── pubspec.yaml
├── .env ← 敏感配置(不进仓库)
├── .env.example ← 配置模板(进仓库)
└── logs/ ← 日志文件目录(不进仓库)
└── server_YYYY-MM-DD.log7.3 环境变量配置清单
在 ~/todo_backend/ 目录下创建 .env 文件,参考以下模板填写:
env
# ── 服务器 ────────────────────────────────────────────────
PORT=8080
HOST=::
# ── JWT 认证 ──────────────────────────────────────────────
JWT_SECRET=<用 openssl rand -hex 32 生成>
ACCESS_TOKEN_EXPIRE_HOURS=1
REFRESH_TOKEN_EXPIRE_DAYS=30
# ── PostgreSQL ────────────────────────────────────────────
DB_NAME=todo_db
DB_USER=todo_user
DB_PASSWORD=<强密码>
# ── 邮件服务(Resend)────────────────────────────────────
RESEND_API_KEY=<your-resend-api-key>
# ── 日志查看接口认证 ──────────────────────────────────────
LOG_USER=<管理员用户名>
LOG_PASS=<强密码>
LOG_SECRET=<用 openssl rand -hex 32 生成>生成随机密钥:
bash
openssl rand -hex 327.4 安装依赖环境
安装 Docker 和 Docker Compose
bash
# 更新包索引
sudo apt update
# 安装 Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
newgrp docker
# 验证安装
docker --version
docker compose version安装 Nginx
bash
sudo apt install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx安装 Certbot(Let's Encrypt 证书)
bash
sudo apt install -y certbot python3-certbot-nginx7.5 Docker Compose 部署
克隆代码
bash
git clone <your-repo-url> ~/todo_backend
cd ~/todo_backend创建日志目录
bash
mkdir -p ~/todo_backend/logs构建并启动服务
bash
docker compose up -d --build查看运行状态
bash
# 查看容器状态
docker compose ps
# 实时查看后端日志
docker compose logs -f api
# 查看数据库日志
docker compose logs -f db正常启动后应看到:
todo_api | 2026-05-20 10:00:00.123 [INFO ] [Logger] ServerLogger 初始化完成
todo_api | 2026-05-20 10:00:00.456 [INFO ] [DB ] 数据库初始化完成
todo_api | 2026-05-20 10:00:00.789 [INFO ] [Server] 启动成功,监听 ::80807.6 Nginx 配置
创建配置文件
bash
sudo vim /etc/nginx/sites-available/todo-api写入以下内容(将 api.todo.wangpudev.com 替换为你的域名):
nginx
# HTTP → HTTPS 重定向
server {
listen 80;
listen [::]:80;
server_name api.todo.wangpudev.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
# HTTPS 主配置
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name api.todo.wangpudev.com;
ssl_certificate /etc/letsencrypt/live/api.todo.wangpudev.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.todo.wangpudev.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
add_header Strict-Transport-Security "max-age=63072000" always;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
# 普通 API 请求
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# SSE 长连接(关闭缓冲,保持长连接)
location /events/ {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection '';
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
gzip off;
}
# 日志查看接口
location /logs/ {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}启用配置
bash
sudo ln -s /etc/nginx/sites-available/todo-api /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx7.7 配置 Resend 邮件服务
TodoApp 的密码重置功能通过 Resend 发送验证码邮件。Resend 是一个面向开发者的邮件发送服务,免费套餐每月可发送 3000 封邮件,对个人项目完全够用。
注册并获取 API Key
- 访问 resend.com 注册账号
- 进入 Dashboard → API Keys → Create API Key
- 权限选择 Sending access,复制生成的 Key(格式为
re_xxxxxxxxxx) - 将 Key 填入
.env:
env
RESEND_API_KEY=re_xxxxxxxxxx验证发件域名
免费套餐可以直接用 Resend 提供的测试域名发送,但建议绑定自己的域名,邮件送达率更高且更专业。
第一步:进入 Dashboard → Domains → Add Domain,输入你的域名(如 todo.wangpudev.com)。
第二步:Resend 会提供几条 DNS 记录,在你的 DNS 控制台(Cloudflare 等)添加:
| 类型 | 名称 | 值 |
|---|---|---|
| TXT | resend._domainkey | <Resend 提供的 DKIM 值> |
| MX | send | feedback-smtp.us-east-1.amazonses.com |
| TXT | send | v=spf1 include:amazonses.com ~all |
第三步:等待 DNS 生效(通常几分钟),Resend 控制台显示 Verified 后即可使用。
配置发件地址
本项目的发件地址在后端代码中配置,默认为 todo@todo.wangpudev.com。如需修改,编辑 lib/utils/email_util.dart:
dart
static Future<void> sendVerificationCode({
required String to,
required String code,
}) async {
await _send(
from: 'todo@todo.wangpudev.com', // ← 修改为你的发件地址
to: to,
subject: '【待办】密码重置验证码',
html: '''
<p>你的密码重置验证码为:</p>
<h2 style="letter-spacing:4px;">$code</h2>
<p>验证码 10 分钟内有效,请勿泄露给他人。</p>
''',
);
}注意:发件地址的域名必须与 Resend 中已验证的域名一致,否则邮件会被拒绝发送。
验证邮件功能
部署完成后,在应用的「忘记密码」页面输入你的注册邮箱,点击发送验证码,确认能正常收到邮件。
如果收不到,检查以下几点:
bash
# 查看后端日志中的邮件发送记录
docker compose logs api | grep -i email[Email] 邮件发送失败:检查RESEND_API_KEY是否正确填入.env并重启容器- 域名未验证:Resend 控制台确认域名状态为 Verified
- 邮件进了垃圾箱:域名 DNS 记录未正确配置 SPF / DKIM
7.8 申请 SSL 证书
确保域名已解析到 VPS 的公网 IP,然后执行:
bash
sudo certbot --nginx -d api.todo.wangpudev.com按提示操作,选择强制重定向 HTTP 到 HTTPS。证书申请成功后 Certbot 会自动修改 Nginx 配置。
验证自动续期:
bash
sudo certbot renew --dry-run7.9 客户端构建
Windows 桌面端
powershell
flutter build windows --release产物位于 build\windows\x64\runner\Release\,将整个 Release 文件夹打包分发即可。
Android APK
针对 arm64 架构单独打包,体积更小(约为全架构包的 1/3):
powershell
flutter build apk --release --target-platform android-arm64产物位于 build\app\outputs\flutter-apk\app-arm64-v8a-release.apk。
注意:Release 包需要在
AndroidManifest.xml中声明INTERNET权限,否则网络请求全部失败。Debug 模式会自动注入此权限,Release 不会。
7.10 日常运维命令速查
后端服务管理
bash
# 查看所有容器状态
docker compose ps
# 重启后端服务
docker compose restart api
# 更新代码后重新构建并启动
docker compose down
docker compose build
docker compose up -d
# 查看实时日志(Ctrl+C 退出)
docker compose logs -f api
# 查看最近 100 行日志
docker compose logs --tail=100 api数据库管理
bash
# 进入数据库容器
docker exec -it todo_db psql -U todo_user -d todo_db
# 查看所有表
\dt
# 退出
\q日志管理
bash
# 查看今天的日志文件
ls ~/todo_backend/logs/
# 实时监控日志文件
tail -f ~/todo_backend/logs/server_$(date +%Y-%m-%d).log
# 搜索 ERROR 级别日志
grep "ERROR" ~/todo_backend/logs/server_$(date +%Y-%m-%d).log
# 通过接口查看日志(需要替换 TOKEN)
curl -u 'LOG_USER:LOG_PASS' \
'https://api.todo.wangpudev.com/logs/?level=error&limit=50'Nginx 管理
bash
# 检查配置语法
sudo nginx -t
# 重载配置(不中断服务)
sudo systemctl reload nginx
# 查看 Nginx 错误日志
sudo tail -f /var/log/nginx/error.logSSL 证书管理
bash
# 查看证书有效期
sudo certbot certificates
# 手动续期
sudo certbot renew