生产环境部署
将 PocketBase 部署到生产环境需要仔细规划安全性、可靠性和可扩展性。本文档提供一个完整的部署检查清单。
部署前检查清单
Section titled “部署前检查清单”- 修改默认管理员密码
- 配置正确的环境变量
- 设置合适的日志级别
- 配置 CORS 白名单
- 设置请求大小限制
- 启用 HTTPS
- 配置防火墙规则
- 启用请求限流
- 配置邮件服务(SMTP)
- 审查所有集合规则
- 启用邮箱验证(如需要)
- 设置自动备份
- 配置异地存储
- 测试恢复流程
- 设置备份保留策略
- 配置服务监控
- 设置磁盘空间告警
- 配置错误日志告警
- 设置性能监控
SSL/HTTPS 配置
Section titled “SSL/HTTPS 配置”使用 Caddy(推荐)
Section titled “使用 Caddy(推荐)”Caddy 是最简单的选择,自动处理 HTTPS 证书:
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:
sudo systemctl enable caddysudo systemctl start caddy使用 Nginx
Section titled “使用 Nginx”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 重定向到 HTTPSserver { listen 80; server_name your-domain.com; return 301 https://$server_name$request_uri;}使用 Apache
Section titled “使用 Apache”<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>系统服务配置
Section titled “系统服务配置”Systemd 服务
Section titled “Systemd 服务”创建 /etc/systemd/system/pocketbase.service:
[Unit]Description=PocketBase ServiceAfter=network.target
[Service]Type=simpleUser=pocketbaseGroup=pocketbaseWorkingDirectory=/opt/pocketbaseExecStart=/opt/pocketbase/pocketbase serve --http=127.0.0.1:8090Restart=alwaysRestartSec=5sStandardOutput=journalStandardError=journalSyslogIdentifier=pocketbase
# 安全加固NoNewPrivileges=truePrivateTmp=trueProtectSystem=strictProtectHome=trueReadWritePaths=/opt/pocketbase/pb_data
# 资源限制LimitNOFILE=65535MemoryLimit=512M
[Install]WantedBy=multi-user.target启用服务:
# 创建专用用户sudo useradd -r -s /bin/false pocketbasesudo chown -R pocketbase:pocketbase /opt/pocketbase
# 启用服务sudo systemctl daemon-reloadsudo systemctl enable pocketbasesudo systemctl start pocketbase
# 查看状态sudo systemctl status pocketbaseDocker 部署
Section titled “Docker 部署”# DockerfileFROM alpine:latest
RUN apk add --no-cache ca-certificates curl
WORKDIR /pb
# 下载 PocketBaseARG PB_VERSION=0.22.0RUN 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数据备份策略
Section titled “数据备份策略”完整备份脚本
Section titled “完整备份脚本”#!/bin/bash# 配置BACKUP_DIR="/backups/pocketbase"PB_DATA_DIR="/opt/pocketbase/pb_data"RETENTION_DAYS=30S3_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"设置定时任务:
# 编辑 crontabcrontab -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"#!/bin/bashBACKUP_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 pocketbaseSQLite 优化
Section titled “SQLite 优化”创建 pb_data/sqlite_optimizer.sql:
PRAGMA journal_mode = WAL;PRAGMA synchronous = NORMAL;PRAGMA cache_size = -64000; -- 64MBPRAGMA temp_store = MEMORY;PRAGMA mmap_size = 30000000000;在启动时应用:
sqlite3 pb_data/data.db < sqlite_optimizer.sql// 在 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=falsePrometheus 监控
Section titled “Prometheus 监控”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) } })}#!/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 1fi
echo "Health check passed"# UFW 配置sudo ufw default deny incomingsudo ufw default allow outgoingsudo ufw allow 22/tcp # SSHsudo ufw allow 80/tcp # HTTPsudo ufw allow 443/tcp # HTTPSsudo 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;}CORS 配置
Section titled “CORS 配置”// 启动时设置允许的来源./pocketbase serve --http.cor.origins=https://your-frontend.com,https://www.your-frontend.com加密环境变量
Section titled “加密环境变量”# 设置加密密钥(用于敏感数据)export POCKETBASE_ENCRYPTION_KEY="your-32-character-encryption-key"Q: 如何处理数据库锁定?
Section titled “Q: 如何处理数据库锁定?”# 检查 WAL 文件ls -la pb_data/*.db*
# 如果需要,执行检查点sqlite3 pb_data/data.db "PRAGMA wal_checkpoint(TRUNCATE);"Q: 如何迁移数据到新服务器?
Section titled “Q: 如何迁移数据到新服务器?”# 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/pocketbasetar -xzf pb_data_backup.tar.gz
# 5. 启动服务systemctl start pocketbaseQ: 如何实现零停机部署?
Section titled “Q: 如何实现零停机部署?”# 使用蓝绿部署# 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部署检查清单
Section titled “部署检查清单”- 修改所有默认密码
- 配置 HTTPS
- 设置自动备份
- 配置监控告警
- 审查集合规则
- 测试恢复流程
- 验证所有 API 端点
- 测试实时连接
- 验证文件上传
- 检查日志错误
- 性能基准测试
- 安全扫描