跳转到内容

生产环境部署

将 PocketBase 部署到生产环境需要仔细规划安全性、可靠性和可扩展性。本文档提供一个完整的部署检查清单。

  • 修改默认管理员密码
  • 配置正确的环境变量
  • 设置合适的日志级别
  • 配置 CORS 白名单
  • 设置请求大小限制
  • 启用 HTTPS
  • 配置防火墙规则
  • 启用请求限流
  • 配置邮件服务(SMTP)
  • 审查所有集合规则
  • 启用邮箱验证(如需要)
  • 设置自动备份
  • 配置异地存储
  • 测试恢复流程
  • 设置备份保留策略
  • 配置服务监控
  • 设置磁盘空间告警
  • 配置错误日志告警
  • 设置性能监控

Caddy 是最简单的选择,自动处理 HTTPS 证书:

/etc/caddy/Caddyfile
your-domain.com {
reverse_proxy 127.0.0.1:8090
# 日志
log {
output file /var/log/caddy/pocketbase-access.log
}
}
# 管理后台使用不同子域名(可选)
admin.your-domain.com {
reverse_proxy 127.0.0.1:8090
}

启动 Caddy:

Terminal window
sudo systemctl enable caddy
sudo systemctl start caddy
/etc/nginx/sites-available/pocketbase
server {
listen 443 ssl http2;
server_name your-domain.com;
# SSL 证书(使用 Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
# 现代 SSL 配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
# 安全头部
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header X-XSS-Protection "1; mode=block";
# 上传文件大小限制
client_max_body_size 10M;
# WebSocket 支持
location / {
proxy_pass http://127.0.0.1:8090;
proxy_http_version 1.1;
# WebSocket 头部
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 标准代理头部
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;
}
}
# HTTP 重定向到 HTTPS
server {
listen 80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}
/etc/apache2/sites-available/pocketbase.conf
<VirtualHost *:443>
ServerName your-domain.com
# SSL 配置
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/your-domain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/your-domain.com/privkey.pem
# 代理配置
ProxyPreserveHost On
ProxyRequests Off
# WebSocket 支持
RewriteEngine On
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) "ws://127.0.0.1:8090/$1" [P,L]
# 标准 HTTP 代理
ProxyPass / http://127.0.0.1:8090/
ProxyPassReverse / http://127.0.0.1:8090/
# SSL 配置
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
</VirtualHost>

创建 /etc/systemd/system/pocketbase.service

[Unit]
Description=PocketBase Service
After=network.target
[Service]
Type=simple
User=pocketbase
Group=pocketbase
WorkingDirectory=/opt/pocketbase
ExecStart=/opt/pocketbase/pocketbase serve --http=127.0.0.1:8090
Restart=always
RestartSec=5s
StandardOutput=journal
StandardError=journal
SyslogIdentifier=pocketbase
# 安全加固
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/pocketbase/pb_data
# 资源限制
LimitNOFILE=65535
MemoryLimit=512M
[Install]
WantedBy=multi-user.target

启用服务:

Terminal window
# 创建专用用户
sudo useradd -r -s /bin/false pocketbase
sudo chown -R pocketbase:pocketbase /opt/pocketbase
# 启用服务
sudo systemctl daemon-reload
sudo systemctl enable pocketbase
sudo systemctl start pocketbase
# 查看状态
sudo systemctl status pocketbase
# Dockerfile
FROM alpine:latest
RUN apk add --no-cache ca-certificates curl
WORKDIR /pb
# 下载 PocketBase
ARG PB_VERSION=0.22.0
RUN curl -L \
"https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_amd64.zip" \
-o pocketbase.zip && \
unzip pocketbase.zip && \
rm pocketbase.zip
EXPOSE 8090
# 挂载数据目录
VOLUME ["/pb/pb_data"]
CMD ["./pocketbase", "serve", "--http=0.0.0.0:8090"]

docker-compose.yml:

version: "3.8"
services:
pocketbase:
build: .
container_name: pocketbase
restart: unless-stopped
ports:
- "127.0.0.1:8090:8090"
volumes:
- ./pb_data:/pb/pb_data
- ./pb_hooks:/pb/pb_hooks
- ./pb_public:/pb/pb_public
environment:
- POCKETBASE_ENCRYPTION_KEY=your-encryption-key
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8090/api/health"]
interval: 30s
timeout: 10s
retries: 3
/opt/scripts/backup-pocketbase.sh
#!/bin/bash
# 配置
BACKUP_DIR="/backups/pocketbase"
PB_DATA_DIR="/opt/pocketbase/pb_data"
RETENTION_DAYS=30
S3_BUCKET="s3://your-backup-bucket/pocketbase"
# 创建备份目录
mkdir -p "$BACKUP_DIR"
# 备份文件名
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/pocketbase_$DATE.tar.gz"
# 创建备份
tar -czf "$BACKUP_FILE" -C "$PB_DATA_DIR" .
# 上传到 S3(可选)
# aws s3 cp "$BACKUP_FILE" "$S3_BUCKET/pocketbase_$DATE.tar.gz"
# 删除旧备份
find "$BACKUP_DIR" -name "pocketbase_*.tar.gz" -mtime +$RETENTION_DAYS -delete
echo "Backup completed: $BACKUP_FILE"

设置定时任务:

Terminal window
# 编辑 crontab
crontab -e
# 每天凌晨 2 点备份
0 2 * * * /opt/scripts/backup-pocketbase.sh >> /var/log/pb-backup.log 2>&1
#!/bin/bash
# 仅备份数据库文件(不含上传文件)
BACKUP_DIR="/backups/pocketbase/db"
DB_FILE="/opt/pocketbase/pb_data/data.db"
mkdir -p "$BACKUP_DIR"
# 使用 SQLite 备份命令
sqlite3 "$DB_FILE" ".backup '$BACKUP_DIR/data_$(date +%Y%m%d_%H%M%S).db'"
# 或直接复制
cp "$DB_FILE" "$BACKUP_DIR/data_$(date +%Y%m%d_%H%M%S).db"
/opt/scripts/restore-pocketbase.sh
#!/bin/bash
BACKUP_FILE="$1"
PB_DATA_DIR="/opt/pocketbase/pb_data"
# 停止服务
systemctl stop pocketbase
# 备份当前数据
mv "$PB_DATA_DIR" "$PB_DATA_DIR.backup.$(date +%Y%m%d_%H%M%S)"
# 创建目录
mkdir -p "$PB_DATA_DIR"
# 恢复备份
tar -xzf "$BACKUP_FILE" -C "$PB_DATA_DIR"
# 启动服务
systemctl start pocketbase

创建 pb_data/sqlite_optimizer.sql

PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;
PRAGMA cache_size = -64000; -- 64MB
PRAGMA temp_store = MEMORY;
PRAGMA mmap_size = 30000000000;

在启动时应用:

Terminal window
sqlite3 pb_data/data.db < sqlite_optimizer.sql
hooks/main.go
// 在 hooks 中配置
func OnBootstrap() error {
app.Dao().DB().Exec("PRAGMA journal_mode = WAL")
app.Dao().DB().Exec("PRAGMA synchronous = NORMAL")
return nil
}
// 使用 Redis 作为缓存层
import Redis from "ioredis";
const redis = new Redis({
host: "localhost",
port: 6379,
});
// 缓存查询结果
async function getCachedPosts() {
const cached = await redis.get("posts:all");
if (cached) return JSON.parse(cached);
const posts = await pb.collection("posts").getList(1, 50);
await redis.setex("posts:all", 300, JSON.stringify(posts));
return posts;
}
// 启动时设置日志级别
./pocketbase serve --http=0.0.0.0:8090 --debug=false
hooks/metrics.go
package main
import (
"github.com/pocketbase/pocketbase/core"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"net/http"
)
var (
requestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "pocketbase_requests_total",
Help: "Total number of requests",
},
[]string{"method", "endpoint"},
)
)
func init() {
prometheus.MustRegister(requestsTotal)
}
func OnServe(e *core.ServeEvent) error {
// 指标端点
e.Router.GET("/api/metrics", func(e *core.RequestEvent) error {
promhttp.Handler().ServeHTTP(e.Response.ResponseWriter, e.Request)
return nil
})
// 记录指标
e.Router.GET("/*", func(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
requestsTotal.WithLabelValues(r.Method, r.URL.Path).Inc()
next(w, r)
}
})
}
health-check.sh
#!/bin/bash
# 检查服务是否响应
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8090/api/health)
if [ "$response" != "200" ]; then
echo "Health check failed!"
# 发送告警
# systemctl restart pocketbase
exit 1
fi
echo "Health check passed"
Terminal window
# UFW 配置
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw enable
# Nginx 限流
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
location /api/ {
limit_req zone=api_limit burst=20;
proxy_pass http://127.0.0.1:8090;
}
// 启动时设置允许的来源
./pocketbase serve --http.cor.origins=https://your-frontend.com,https://www.your-frontend.com
Terminal window
# 设置加密密钥(用于敏感数据)
export POCKETBASE_ENCRYPTION_KEY="your-32-character-encryption-key"
Terminal window
# 检查 WAL 文件
ls -la pb_data/*.db*
# 如果需要,执行检查点
sqlite3 pb_data/data.db "PRAGMA wal_checkpoint(TRUNCATE);"
Terminal window
# 1. 停止服务
systemctl stop pocketbase
# 2. 备份数据
tar -czf pb_data_backup.tar.gz pb_data/
# 3. 传输到新服务器
scp pb_data_backup.tar.gz user@new-server:/opt/pocketbase/
# 4. 在新服务器恢复
cd /opt/pocketbase
tar -xzf pb_data_backup.tar.gz
# 5. 启动服务
systemctl start pocketbase
Terminal window
# 使用蓝绿部署
# 1. 启动新版本实例
./pocketbase serve --http=127.0.0.1:8091
# 2. 切换代理
# nginx: upstream -> 127.0.0.1:8091
# 3. 验证新版本
# 4. 停止旧版本
./pocketbase serve --http=127.0.0.1:8090
  • 修改所有默认密码
  • 配置 HTTPS
  • 设置自动备份
  • 配置监控告警
  • 审查集合规则
  • 测试恢复流程
  • 验证所有 API 端点
  • 测试实时连接
  • 验证文件上传
  • 检查日志错误
  • 性能基准测试
  • 安全扫描