返回列表 发布新帖

[源码] Pocketbase-GO语言高并发单文件api数据库

439 3
阿白 发表于 2026-1-4 12:51:49 | 查看全部 阅读模式 来自:Error

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
<p><img src="data/attachment/forum/202601/04/124813e3zq9f9bjlfbo83v.webp" alt="QQ20260104-124324.webp" title="QQ20260104-124324.webp" /></p>
) F) x/ S, r  K/ J6 v<h1>PocketBase 基于 Debian 12 的详细使用指南</h1>8 L7 P/ F; N8 v  f, m# g" p
<h2>一、核心需求确认</h2>4 D4 l: C- j6 I" X" C# F8 @* t
<p>你需要一份面向 Debian 12 系统的 PocketBase 完整操作手册,涵盖从环境准备、安装部署到日常运维的全流程,并以 Markdown 格式整理,方便查阅和使用。</p>
$ V- ^2 S5 |; Z4 e: O/ m0 b<h2>二、PocketBase 详细操作指南</h2>
; @" t% r, \& [6 l1 y<h3>1. 什么是 PocketBase</h3>
2 W/ H) b8 z( e0 F  V' C9 h( [<p>PocketBase 是一个开源的、轻量级的后端即服务(BaaS),集成了实时数据库、认证系统、文件存储和 REST API,单二进制文件运行,无需额外依赖,非常适合小型项目、原型开发或个人项目。</p>4 f) A9 |# N8 N# v4 i. Q4 U. n1 n
<h3>2. 环境准备(Debian 12)</h3>
" m7 y4 m7 Q4 e* O- ~<h4>2.1 系统基础检查与更新</h4>; Y6 c& i8 u8 ~( |% Z
<p>首先确保 Debian 12 系统为最新状态,执行以下命令:</p>. V, Y5 _  q8 ]) E3 a& S
<pre><code class="language-bash"># 更新软件包索引
3 ?% i; f- M" H/ j- u- c" z1 M% M3 }sudo apt update -y  @* u* ~: l# I7 [% ^7 F/ U

5 Z: T3 {3 F' ?( K3 X8 T) I# 升级已安装的软件包
- A3 \8 j2 M. d8 G3 B* [sudo apt upgrade -y
& A. O3 L: C) R% W2 N) Y4 D
5 r$ _" u( @& t. Q5 z# 安装必要的基础工具(curl、unzip、wget)
  h# F3 t+ F) nsudo apt install curl unzip wget -y
# {7 {0 W9 i$ s: b5 z' q8 U0 S
" R1 V3 ~/ m2 m5 G' Y" u% s& D# 检查系统架构(PocketBase 需匹配架构下载)
# c- ^" M6 R" iuname -m( ^9 e% R/ U2 B9 V: x) Y, a, v
# 常见输出:x86_64(amd64)、aarch64(arm64). {/ N% f8 e+ f
</code></pre>$ n4 U$ `  T3 t% L+ u
<h4>2.2 防火墙配置(可选但推荐)</h4>9 h3 p" ?# H  q  H6 X
<p>PocketBase 默认使用 8090 端口,需开放该端口:</p>
' M1 J# c8 |) o! X<pre><code class="language-bash"># 查看防火墙状态
+ U3 P1 q/ @& H( A" ^; w: z8 k) Xsudo ufw status
/ O5 i. S0 M+ v( t# q+ {5 n3 T
8 y" j# c- v! H/ _# 若未启用,先启用防火墙4 c% z- c# \8 n" K% i
sudo ufw enable* _9 x5 r. K/ g# Z% b- n3 u% b! N
8 }1 n  n# |: X- R  E0 E8 d
# 开放 8090 端口
3 z$ K, @: u9 O. E9 N0 N4 g( j8 e5 dsudo ufw allow 8090/tcp0 I1 d/ X/ }( a% V+ @7 {

2 y4 V6 B7 f$ n7 z# 重载防火墙规则
# e+ U: f, `* l& u3 s$ ~sudo ufw reload% d: p; l- m  O- c* Y; W5 G
</code></pre>
& h* F7 A5 g- j/ Y' a<h3>3. PocketBase 安装</h3>
% Q% R% K+ y/ c5 N4 x( J3 x2 O! X0 k<h4>3.1 下载 PocketBase 二进制文件</h4>
, N5 p2 H9 \/ e" U' }9 i<p>根据系统架构下载对应版本(以最新稳定版为例):</p>1 u( q) r/ l% V4 y6 K
<pre><code class="language-bash"># 创建 PocketBase 工作目录(推荐)
4 G& v0 v5 `" imkdir -p /opt/pocketbase
, Z6 U. t; |  Z/ g0 dcd /opt/pocketbase# n3 k( S$ M( y7 n! L  U0 [, D

: [% F3 ^3 h9 ?/ S# N# 下载 amd64 架构版本(Debian 12 服务器主流架构)& N) t' w2 W5 m4 A' P! E, E$ E4 A7 g) }
wget https://github.com/pocketbase/pocketbase/releases/latest/download/pocketbase_linux_amd64.zip
& D* A9 R  G$ w5 o- `
. l9 A1 N: P9 M% g7 O2 A# 若为 arm64 架构,替换为:+ s9 l. e; J- A: \" b: D7 b& N) X
# wget https://github.com/pocketbase/pocketbase/releases/latest/download/pocketbase_linux_arm64.zip+ l: g# z3 r- S9 o" ^$ z

2 h3 A1 @3 P$ r% s. D$ Y) k# 解压文件* m% b) @$ l* ^- `. @7 X; _
unzip pocketbase_linux_*.zip
8 {1 O! ?* t) X! b3 l8 z! _* i1 J5 Q, I4 h
# 删除压缩包
3 `) K, ^3 G1 S8 f% K: \3 Qrm pocketbase_linux_*.zip
- V1 n- R. ?3 m0 ]5 F% M0 O' m, t$ S* o
# 添加执行权限9 v! f+ w2 {- ]$ H" }% u" k# S
chmod +x pocketbase
1 G# G) v& q; J5 n# {) D) `* T
9 C$ w. H5 P# R  J+ h# 验证安装(查看版本)( x3 B% o4 p3 M$ B( x, z$ ~
./pocketbase version. t8 c6 V& l" k! a5 p& C  \5 B) K! y6 s
</code></pre>
" d/ n( H" a+ l8 ]1 S! [) m<h4>3.2 测试运行</h4>
; k3 f% k3 G2 K) T3 g0 K<pre><code class="language-bash"># 首次运行 PocketBase% \5 @; t5 e3 @. X) t
./pocketbase serve
0 U* V8 P  h( G8 f0 J* p
0 A( `2 Q& x& H  p# 运行成功后,终端会输出:& C+ I* M! N' e
# &gt; Server started at http://0.0.0.0:80909 B' o, R' B. r, S& G. q1 g! ]1 Y
# &gt; REST API: http://0.0.0.0:8090/api/
# T! S  c) I8 B4 F% x7 n# &gt; Admin UI: http://0.0.0.0:8090/_/
! A$ e5 }9 `: G</code></pre>
5 B1 V2 K" C. X$ t<p>此时可通过 <code>http://你的服务器IP:8090/_/</code> 访问管理后台,首次访问会要求创建管理员账号(用户名/密码)。</p>
! P) ~" S( m# Z<h3>4. PocketBase 基础使用</h3>8 {+ c- }5 S$ e% R
<h4>4.1 管理员后台操作</h4>3 g( t9 w- D3 }( t
<ol>
  X. S9 Z7 X- _/ v+ `; J<li>访问 <code>http://服务器IP:8090/_/</code>,输入首次创建的管理员账号登录;</li>
% c( ^3 {0 Q! z: ^" I<li><strong>创建数据集合(Collections)</strong>:
3 B3 g- K) q+ t<ul>0 D' y, X5 X. U/ p9 {8 k
<li>点击左侧「Collections」→「New collection」;</li>2 _8 {: J+ o2 t! {. O9 W2 V
<li>填写集合名称(如 <code>users</code>)、类型(Base model);</li>
" b( x7 d0 K/ i; g$ O<li>添加字段(如 <code>username</code>(Text)、<code>email</code>(Email)、<code>age</code>(Number));</li>$ |: T0 K5 r* {) k! x( L
<li>保存后即可通过 API 操作该集合数据。</li>
$ F3 B1 P) M% i0 c</ul>1 q! O$ Q6 [5 T
</li>1 Y$ }  [' G) j! o3 v3 n
<li><strong>权限配置</strong>:可针对集合设置「Create/Read/Update/Delete」权限(如开放匿名只读、仅管理员可写等)。</li>
4 s# s, G* \8 y+ w+ h</ol>
, B& @, v/ G/ h5 J% l" j* b<h4>4.2 基础 API 使用</h4>7 B8 m& k: y& m3 Y
<p>以 <code>users</code> 集合为例,通过 curl 测试 API:</p>
# u+ H6 v1 }1 N; h<pre><code class="language-bash"># 1. 创建一条用户数据(需管理员认证,先获取 token)% e3 V% `+ O& \% K" ]0 X
# 获取管理员 token
' y3 w' j4 t3 AADMIN_TOKEN=$(curl -X POST http://服务器IP:8090/api/admins/auth-with-password \, t9 @0 M$ r, ^0 L9 [
  -H &quot;Content-Type: application/json&quot; \
. \: T0 S; z, d* E, o8 q/ ^. f  -d '{&quot;identity&quot;:&quot;你的管理员邮箱&quot;,&quot;password&quot;:&quot;你的管理员密码&quot;}' | jq -r '.token'). l$ A& d7 \$ H

' \7 e' z9 ~- X: i8 ~/ X# 创建用户
/ s& ?6 Z& R8 fcurl -X POST http://服务器IP:8090/api/collections/users/records \
0 s$ Y$ K' ]( B( n  -H &quot;Content-Type: application/json&quot; \7 t8 D' h1 O2 l: f* B& Y
  -H &quot;Authorization: Admin $ADMIN_TOKEN&quot; \$ T# {. i: |# Q1 M
  -d '{&quot;username&quot;:&quot;testuser&quot;,&quot;email&quot;:&quot;test@example.com&quot;,&quot;age&quot;:25}'
3 ?. k  S" G& }- }# X8 J  T" c" ]2 a( n$ ^
# 2. 查询所有用户数据(匿名访问,需先开放 users 集合的 Read 权限)% |; D% P9 @4 j# n/ y7 X; I  y
curl http://服务器IP:8090/api/collections/users/records8 Z4 S1 S# ?7 h
</code></pre>' \* k% Z$ r0 h) l2 V  o) W
<h3>5. 进阶配置(生产环境必备)</h3>
) h8 ^: O9 [3 s<h4>5.1 将 PocketBase 配置为系统服务(开机自启)</h4>* K; g/ t2 r2 V3 W# ?
<p>创建 systemd 服务文件,确保 PocketBase 后台运行且开机自启:</p>
3 P9 o& A1 C5 K7 G<pre><code class="language-bash"># 创建服务文件
& H6 w% s2 D/ I7 W3 Z* e0 A+ Jsudo nano /etc/systemd/system/pocketbase.service6 Z7 p1 f; d, T0 W) D0 z3 h' k
</code></pre>: Y2 j5 J( u; V* ^
<p>粘贴以下内容(修改 <code>User</code> 和 <code>WorkingDirectory</code> 为实际路径):</p>8 I8 G- E6 B. s  X$ l% k
<pre><code class="language-ini">[Unit]
) {+ s% [6 N7 O, H% n. `) hDescription=PocketBase Service
: m& k, Z( p0 X8 @% Z* o3 v$ {5 cAfter=network.target3 O; C0 m+ `3 |5 }, m. E* T/ J: {

  B5 i' Q) B7 P$ I0 w$ B[Service]
% y8 y! T- {. n0 b& w/ ~Type=simple
3 }9 R2 n. y% T+ v' C% bUser=root  # 推荐使用非 root 用户,如创建 pocketbase 用户9 v; v* S0 C, K% \
WorkingDirectory=/opt/pocketbase% W; U8 Y, x/ |1 A- @0 ?2 M
ExecStart=/opt/pocketbase/pocketbase serve --http=0.0.0.0:8090* k# t' T( D. r  U) O( V
Restart=always
% J% Y9 x. F9 u& ]RestartSec=5
4 l) v4 X/ M3 B+ N4 D) j  y% Q( |1 \8 NStandardOutput=journal+console. f8 y+ H$ A8 F* }* c/ E
StandardError=journal+console9 U  v, C% j) v! x' U. c5 y

. v+ H# r0 i+ |[Install]
) v9 m0 ]1 E+ x/ z# U( ZWantedBy=multi-user.target
4 L5 l# M0 E; v  z8 P0 w* B</code></pre>
. u8 j/ ~# S% c/ A: N, z- _7 t<p>保存后执行以下命令启用服务:</p>' N9 }, `9 W8 H
<pre><code class="language-bash"># 重新加载 systemd 配置
* o. c8 {& r7 {5 Dsudo systemctl daemon-reload5 p  H2 R4 G; S
3 t$ |4 V) A- m& @
# 启动 PocketBase 服务
! ~) I7 T2 t$ e/ J; ]: Csudo systemctl start pocketbase
( B4 n) c) O" g. v; A! W6 k& T+ z$ a+ ^7 m
# 设置开机自启% \( c* A5 G' E7 ~' ]3 b1 I
sudo systemctl enable pocketbase
" E% a; o  A8 R- G4 _& z, _& w1 K1 \
# 查看服务状态
) @$ y. l: j. W, l1 l1 G2 Nsudo systemctl status pocketbase) z5 }' ?2 p* [$ B/ p
</code></pre>
7 z8 A5 B# l  H2 T4 f4 e# t<h4>5.2 配置 HTTPS(推荐)</h4>
7 j: m# f1 Z  s! s' e: v# s3 `<p>PocketBase 本身不直接支持 HTTPS,需通过 Nginx 反向代理实现:</p>
& J, Z9 G/ D+ k7 k! t<ol>0 w/ K( C+ L$ S* W2 ~2 O
<li>安装 Nginx:6 x' b# F2 W% I% Z
<pre><code class="language-bash">sudo apt install nginx -y; ~. w' G% Q& l# F
</code></pre>2 U  j6 ~/ y. T8 R# ~$ f
</li>$ Y- N! p( q. G8 P" U5 [5 E
<li>创建 Nginx 配置文件:% o: v3 A" z; X( [: B
<pre><code class="language-bash">sudo nano /etc/nginx/sites-available/pocketbase. V3 C% a. A1 y
</code></pre>
# }& p9 D- l" d2 H- b</li>0 M1 A# i1 X1 {+ J# M7 ?
<li>粘贴以下配置(替换 <code>your-domain.com</code> 为你的域名):
: e# M' Q9 Y( y1 N& c  M<pre><code class="language-nginx">server {. h" o) M% ~2 Q4 z' y2 f+ n
    listen 80;
8 S. n7 C- w' K    server_name your-domain.com;
4 h9 K9 Y' e3 c    # 重定向 HTTP 到 HTTPS) X" C  t/ }1 u2 |- Z
    return 301 https://$host$request_uri;9 q4 a9 y* c1 r7 o
}
" v$ g- R, F( V5 w" U; \9 p# K) e# w9 O: H2 `+ \
server {
' ]4 X: k4 L; z4 x- n3 V7 {8 I2 K    listen 443 ssl http2;
8 C- `+ ]8 A6 K    server_name your-domain.com;
7 z: E7 `3 X8 s% l
9 J; G) @* R% l# m' ?    # SSL 证书配置(推荐使用 Let's Encrypt)
* Q0 L( H9 O% A2 \+ A" E3 [    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
) R4 P( x) m6 W" y, U    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
+ N9 i& m9 Z5 |9 K% v1 T3 S) P    ssl_protocols TLSv1.2 TLSv1.3;: U% y5 z: c9 C4 ^
    ssl_prefer_server_ciphers on;, C3 W/ K3 M/ Y" c$ M( p9 z- M
% v; ~' K( A  W5 e
    # 反向代理到 PocketBase) t( n, x' e0 w) G- n
    location / {
4 [4 Q$ f& C% l0 W' \/ ]# S        proxy_pass http://127.0.0.1:8090;' ^3 ~1 x* h: E6 x" g7 x7 d
        proxy_set_header Host $host;
8 p8 i4 @# n) }; A6 L        proxy_set_header X-Real-IP $remote_addr;
  O4 L2 X+ H" J5 i+ f        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;0 T9 |1 |# R: M$ T- r$ A
        proxy_set_header X-Forwarded-Proto $scheme;4 M" x4 [+ d/ B3 r. [3 E
    }
$ Q# X8 x/ R* E7 S( ~}
3 s5 i! e! N  |* l</code></pre>
% g  ?0 A0 ~6 m" J" M' [</li>
# U& k/ f2 E3 b& v<li>启用配置并重启 Nginx:
' o, M8 }* v! e% @<pre><code class="language-bash"># 启用配置8 f9 g7 t9 e" x0 _: |6 [4 ?
sudo ln -s /etc/nginx/sites-available/pocketbase /etc/nginx/sites-enabled/
5 b& |/ z8 |9 c9 U6 ?" Y# E& r- ]% k" A, B6 V& L) d  C
# 检查配置语法
3 W+ u0 u' P' n$ W6 o3 B6 ksudo nginx -t
% Z  I. a, d; T' q2 z$ W
3 F$ _6 |7 U  p) a- A- y# 重启 Nginx+ O- d/ e1 w! K7 D( T
sudo systemctl restart nginx
4 ?% W0 q3 B8 j5 ^% o6 R5 R' w</code></pre>$ z+ G7 X/ F" C
</li>
3 B  {! G; r9 r! z2 M# g<li>申请 Let's Encrypt 免费证书(可选):" u+ w, s" ~2 }+ \% m
<pre><code class="language-bash"># 安装 certbot5 A# n" `7 _$ @( u7 v
sudo apt install certbot python3-certbot-nginx -y
3 v2 `7 V3 J" p. y
% s" q: R9 d' [) z( ?! H# 申请证书
  x; I1 t0 b0 R$ ~( Nsudo certbot --nginx -d your-domain.com
9 P! D" Y5 w) d1 Z" z. l/ i- _; y</code></pre>5 F, V0 s2 s+ w
</li>* A+ V5 ^' R- S6 Q8 j6 Z+ d! ?1 m& b
</ol>
" b8 J6 u( B1 _0 x' K) J<h4>5.3 自定义 PocketBase 配置</h4>
3 p; J1 b; z7 l' N1 k* n<p>PocketBase 的配置文件为 <code>pb_data/pb_config.json</code>(运行后自动生成),可修改以下核心参数:</p>
; r- e* L3 ?3 O4 K8 w7 _" Q1 o<ul>) J" H- Y5 B6 r+ Y8 ^; P
<li><code>appName</code>:应用名称;</li>
( C; p& A* B  T<li><code>api.allowedOrigins</code>:跨域允许的域名;</li>
; m& B. r" `/ p4 ^' C& ?7 U<li><code>mailer</code>:邮件配置(用于密码重置、验证等);</li>
, x' j/ u" L* O: J6 @" D<li><code>storage</code>:文件存储配置(默认本地,可配置 S3 等)。</li>; A- x3 I3 F5 V/ C/ _5 [
</ul>2 N& k# p, i) `  T$ w: K
<p>修改配置后需重启 PocketBase 服务:</p>2 ?% f9 Z% C6 G- K8 ]2 a8 b; W1 Z
<pre><code class="language-bash">sudo systemctl restart pocketbase
% j8 K8 i( S6 R1 g6 `</code></pre>! r0 h5 `0 T5 h; W3 a: W# }7 r
<h3>6. 日常运维</h3>4 u  [/ T1 X) [6 x4 U' W7 V- |
<h4>6.1 数据备份</h4>
0 D; I9 {; b& d/ o; [<p>PocketBase 的所有数据(数据库、文件、配置)都在 <code>pb_data</code> 目录,备份该目录即可:</p>5 n4 O" `* l8 u4 ^: i' s/ j8 z* s; m3 T) c
<pre><code class="language-bash"># 创建备份脚本+ |% Z% P* o' [3 _  E0 k
nano /opt/pocketbase/backup.sh6 _1 H2 s8 d, ^& @, c8 M3 |
</code></pre>/ g% ]+ V/ P4 v( q
<p>粘贴以下内容:</p>- T7 v4 ]' N9 [1 o
<pre><code class="language-bash">#!/bin/bash
" n1 c+ U0 m+ b+ |! s! B" |BACKUP_DIR=&quot;/opt/pocketbase/backups&quot;; Y: _: H+ |& U. w* x) L5 M
DATE=$(date +%Y%m%d_%H%M%S)
% h: |/ {8 P! cmkdir -p $BACKUP_DIR9 y% N; q6 E% G# N. ]

# G4 i& s; L$ C) ~& b# 停止服务(可选,避免备份时数据写入)- l& W& V2 I# H! e8 r
sudo systemctl stop pocketbase4 _& j) q9 u! x% J8 F- ^
& \- K1 u: Q* s# x& \8 v: J6 ]
# 压缩 pb_data 目录
6 ]: f8 B. d6 C1 x* U) O. czip -r $BACKUP_DIR/pocketbase_backup_$DATE.zip /opt/pocketbase/pb_data
6 U3 ]6 @: G  G( }/ @
- u2 [$ \9 ?  ~5 @. S# 启动服务
+ b! ~1 [! X' }; L( U3 \sudo systemctl start pocketbase
2 m2 \- N2 n% D4 G! A$ _
# Z5 a  V/ h( U0 g# 删除 7 天前的备份(可选)9 M1 z1 z+ w. }1 s1 W; j' L
find $BACKUP_DIR -name &quot;pocketbase_backup_*.zip&quot; -mtime +7 -delete1 W+ b# B7 d0 y/ k8 e& N& ]
</code></pre>6 Y, S9 l: H* t+ z: _0 g
<p>添加执行权限并定时执行:</p>
0 F0 @  s/ T3 m<pre><code class="language-bash">chmod +x /opt/pocketbase/backup.sh
' y* O% ]  ]4 g* _
8 m1 |* `# x1 ?/ J, C# 添加到 crontab,每天凌晨 2 点备份7 y8 d: U. N) y) Z) \
sudo crontab -e
3 v5 J) D; w7 w  }  G. ]. V  T# J# 粘贴:0 2 * * * /opt/pocketbase/backup.sh' p  D: R9 ~$ z- F+ Z
</code></pre>
4 ]* L6 T6 \# @; V+ b+ Y<h4>6.2 PocketBase 更新</h4>; S! b3 ]. y0 U# k/ a
<pre><code class="language-bash"># 停止服务
0 t1 s2 s! S1 \) q. S8 Osudo systemctl stop pocketbase
: q' e0 j  `# V
8 v% ]1 I" k1 G9 R# 备份 pb_data(保险)
; T6 G7 d4 Q8 v" m& g5 Rcp -r /opt/pocketbase/pb_data /opt/pocketbase/pb_data_backup3 x5 }8 U; [/ W9 S3 T& y
  t% N# b" n/ `: h4 |: X
# 下载最新版本2 M' e, Z% O2 ~0 s6 N
cd /opt/pocketbase
9 J1 A  q) `; G6 n3 Cwget https://github.com/pocketbase/pocketbase/releases/latest/download/pocketbase_linux_amd64.zip/ ]0 V8 Y- r1 N; [+ t; Y4 p3 ~
unzip -o pocketbase_linux_amd64.zip  # -o 覆盖原有文件3 E( a* A' l0 `
rm pocketbase_linux_amd64.zip2 c$ c2 ]4 D6 D2 M0 X3 s

' ]  O& P) ~% [+ Y$ p3 m& J) Y# 启动服务; J  V; f$ M; R6 X2 p& G9 p8 v2 T
sudo systemctl start pocketbase# \' x6 K4 @* s3 X4 }

( |& h7 a, H3 p: q; H" M& U! x# 验证版本
1 D4 p2 ]/ k2 `8 M/opt/pocketbase/pocketbase version
$ r$ ^5 m1 Y4 M</code></pre>/ Y1 Q2 I# S- ]; A
<h4>6.3 查看日志</h4>
2 N! y$ v: }% _. ?$ }<pre><code class="language-bash"># 实时查看 PocketBase 日志! R4 b' {3 E' y3 x, i
sudo journalctl -u pocketbase -f- u% s' e1 E3 H/ w6 c4 P8 Y: `

; H; l" e4 e1 }: y9 d# 查看最近 100 行日志
& d, I4 T8 n3 H  bsudo journalctl -u pocketbase -n 100" ?7 ^* Y7 Z# G9 }
</code></pre>
) x2 K- I, L- J' I. d* c<h3>7. 常见问题解决</h3>
, [$ L3 d) W$ K5 R/ i$ e+ e4 N<ol>
4 d% J! {$ F1 G% _  P# W9 e& t/ N<li><strong>无法访问管理后台</strong>:
# _) @: K5 |( @<ul>$ n5 _; q1 l6 \( @2 y* ]8 t' a2 R
<li>检查防火墙是否开放 8090 端口(<code>sudo ufw status</code>);</li>
# a, B2 j& m, s<li>检查 PocketBase 服务是否运行(<code>sudo systemctl status pocketbase</code>);</li>
$ ?" g+ W0 d  g  s4 a! i+ N0 ?<li>检查服务器安全组(云服务器需开放对应端口)。</li>
: D% C0 n% S3 y. {( P, k</ul>: T8 Z. O' t, f  z1 Y
</li>
/ ~+ o5 V& N; S' H<li><strong>API 调用返回 403</strong>:1 T0 A2 F6 _' o# ?
<ul>5 k* F7 [5 @" {/ Z9 a
<li>检查集合的权限配置(管理员后台→Collections→对应集合→Rules);</li>7 e1 Z9 Z) ~+ `7 T
<li>确认请求头是否携带正确的认证信息(Admin/User Token)。</li>
  r2 E" y; u& [7 Z0 X. E</ul>  W& r1 F& j* b& \# Y
</li>$ ]7 W' V! _3 `( s; E5 ~% ^. g4 g
<li><strong>服务启动失败</strong>:0 L) [* D+ l7 D8 x
<ul>
4 [4 Y6 b" \# E9 ^<li>检查 <code>pocketbase.service</code> 文件语法是否正确;</li>
& B$ {  B, |% q$ u% l, M+ j<li>检查 <code>pb_data</code> 目录权限(<code>chmod -R 755 /opt/pocketbase/pb_data</code>)。</li>
" G: l0 W3 I: u</ul>
) Q  \# h4 V9 Z3 m$ X1 b5 r' {9 y' `1 C</li>) |. \2 ]7 X6 s, }. N, b8 J
</ol>; k, o6 K) Q# i4 Y8 G( m" R
QQ20260104-124324.webp
匠心独运,千锤百炼,品质非凡。
回复 转播

使用道具 举报

评论3

阿白楼主Lv.1 发表于 2026-1-4 12:54:05 | 查看全部 来自:Error
<h1>PocketBase 在堡塔(宝塔)面板下配置进程守护与端口转发</h1>
- C, A/ B& f) n2 z& s<h2>一、核心需求确认</h2>
0 X4 E! T. |+ K) v  r. g+ q<p>你希望在堡塔(宝塔)面板中为 Debian 12 服务器上的 PocketBase 配置<strong>进程守护</strong>(确保 PocketBase 持续后台运行、崩溃自动重启),并设置<strong>端口转发(反向代理)</strong>,让 PocketBase 可通过 80/443 端口或域名访问(替代默认的 8090 端口)。</p>
9 q, C+ i( o+ j, p4 ]<h2>二、前置条件</h2>8 v8 R8 w* h9 G& e( `
<ol>9 W! v% p& u, m- [1 c
<li>堡塔面板已成功安装在 Debian 12 服务器(若未安装,可执行官方脚本:<code>curl -sSO https://download.bt.cn/install/install_panel.sh &amp;&amp; bash install_panel.sh</code>);</li>
) t8 n5 N2 E! h1 g3 p/ M6 R; t<li>PocketBase 已按之前的教程安装在服务器(推荐路径:<code>/opt/pocketbase</code>);</li>5 ]9 H! p: E" @. Z# c
<li>服务器已开放 80/443 端口(堡塔面板默认会开放,可在「安全」模块确认);</li>1 v  n) a& b! t0 Y
<li>若需域名访问,需提前将域名解析到服务器公网 IP。</li>3 x- [: Y/ ?4 N' g$ U
</ol>) ^) k1 C5 I: J0 B$ W4 }
<h2>三、配置 PocketBase 进程守护(堡塔面板)</h2>0 M6 B( d% ?/ H' S  M: e) K. O2 p/ N* ]
<p>堡塔面板的「进程守护」功能可替代手动配置 systemd 服务,可视化操作更简单,核心是让 PocketBase 后台运行且崩溃自动重启。</p>9 z" C9 x  J/ z0 r3 J' M
<h3>步骤 1:登录堡塔面板</h3>! @  V, @# C$ a% ~
<p>通过浏览器访问 <code>http://服务器IP:8888</code>(默认端口),输入堡塔面板的账号密码登录。</p>
$ _7 i2 ?  z# R# O3 D  c" x<h3>步骤 2:进入「进程守护」模块</h3>
$ ~7 T  e/ s" y, ^8 \6 l<ol>3 [1 m7 v2 b% [- h9 b" s
<li>点击左侧菜单栏的「软件商店」→ 「系统工具」,确认「进程守护」插件已安装(默认已安装,若未安装则点击「安装」);</li>/ ~+ P/ A: i5 t' p
<li>安装完成后,点击左侧菜单栏的「进程守护」,进入守护进程管理页面。</li>/ L, C# a  c6 B' H8 |
</ol>6 o0 Y1 }; @$ o
<h3>步骤 3:添加 PocketBase 守护进程</h3>
- l% W3 f0 l4 H8 V1 ?2 Z<ol>4 M) G) w5 I0 J
<li>6 I0 |, h0 F6 Y) B/ F0 n
<p>点击页面右上角的「添加守护进程」,弹出配置窗口;</p>
$ s8 m5 m  a& n6 f9 G% N</li>+ U" {- A0 [  H2 C) a1 n; [0 Z) X
<li>
( @1 @. k, R0 u) e' F0 |+ B<p>按以下参数填写(关键项标红):</p>
' I3 e" j" I! Q0 r0 |7 X<table>8 U5 e5 o/ z, W2 h9 d& w! h) p! ^; Z
<thead>
& f% g8 s: C9 h, {( I2 O- y. i+ i<tr>
, K3 {$ \) V. ^0 e<th>配置项</th>
! _( O5 |( V: H. n! A: V8 x! p<th>填写内容</th>
" Y: ]: k$ T  Q</tr>' S2 \  b8 {- \; |3 }, r
</thead>- I2 C: x- o( d8 h
<tbody>+ w' D- h, S9 K) X  }2 d8 Z
<tr>! n  b7 D% r1 @' c
<td>进程名称</td>& i+ y$ K  t+ ?7 _) j  U6 Y# C
<td>PocketBase(自定义,便于识别)</td>) @& m5 r" H% K' N6 O# e
</tr>
; z8 A5 [) k$ ~& _<tr>
2 X; ^9 B2 V& [) ]6 f1 {<td>运行目录</td>
. L: u4 P, c, k# G: t1 e0 a<td><code>/opt/pocketbase</code>(PocketBase 二进制文件所在目录,需和实际路径一致)</td>
2 Y: [+ |2 a% C: D# o+ S</tr>
/ C0 E9 |4 `, n" k<tr>: C% R# `, e, F9 j
<td>启动命令</td>
  k3 S% G& h( }+ S' O<td><code>./pocketbase serve --http=127.0.0.1:8090</code>(绑定本地回环地址,更安全)</td>
7 X3 ~4 J( V4 A7 M& m5 l</tr>
: y3 p* H, l3 {+ D; C4 a<tr>
1 L: B  r8 M# j) K5 C<td>停止命令</td>& m/ J$ a7 L- X) L7 F
<td><code>pkill pocketbase</code>(可选,用于手动停止进程)</td>
9 O, c: u. u* ?2 K& m2 Q</tr>' j8 B1 ~) }; w! l/ r1 i
<tr>. Y" H+ `' F+ G3 p
<td>日志文件</td>
( ]2 F. l( N' J; m# Q5 K<td><code>/opt/pocketbase/pocketbase.log</code>(自定义日志路径,便于排查问题)</td>
. `* P/ l* Y; h, v: I% [</tr>
6 q3 j- T4 U% u<tr>
/ U/ S5 ^7 c1 j9 Y! {+ Z( e/ ?1 ?<td>错误日志文件</td>
- m# V% h' Z% K2 p<td><code>/opt/pocketbase/pocketbase_error.log</code>(可选,单独记录错误日志)</td>
  w& y0 }6 b/ g! K6 ]! f; a</tr>
, B/ e6 g. t  ]& t( ^<tr>  d% W% }! f) v/ g/ m. u* X  M
<td>自动重启</td>
3 f$ [  ?' Z2 _( {<td>开启(必选,进程崩溃后自动重启)</td>
1 u# j. U* E; i</tr>( {- H( ?% ^+ V9 o) S
<tr>
) t$ C7 s1 D: p7 c7 t<td>重启间隔</td>7 ^" e" G, v( }' o7 ^3 w
<td>5 秒(默认即可)</td>+ h( O. a: u/ b8 `+ Y' I
</tr>
, I% d' E, }/ ^- a! y+ y' A6 G<tr>
% t. g4 e  g& Z, Z% s<td>启动用户</td>7 y; Y' a0 X  H, V2 V- f) C
<td>root(或你创建的非 root 用户,需确保该用户有 <code>/opt/pocketbase</code> 目录权限)</td>9 {# M$ f- C8 p9 _& l( w6 R
</tr>/ T7 t+ }7 t8 q  G% ~& ]
</tbody>
, k. R0 i; {& H& S/ ^</table>
7 s4 A, ], N$ t% n$ }$ X</li>- Q: F+ b/ M- J" z
<li>( l; I0 x1 h$ m4 [& a2 t: L& i
<p>点击「提交」,完成守护进程创建。</p>( Y% }  }( y6 T
</li>
& `- {% U, u: J+ [; l</ol>
! E6 V3 _5 ^, u/ H% H<h3>步骤 4:启动并验证守护进程</h3>
& H6 D' M  \) P0 }<ol>
. i+ i. i: q- r/ ~3 O7 {' M<li>在「进程守护」列表中找到刚创建的「PocketBase」进程,点击右侧的「启动」;</li>
' O8 D. W$ U- p; t<li>启动后,进程状态会显示「运行中」,可点击「日志」查看运行日志:
3 k& {0 O; J8 ^6 v. G* [<ul>. Q' |5 D& l9 |- r  _+ J( e8 Y
<li>若日志中显示 <code>Server started at http://127.0.0.1:8090</code>,说明 PocketBase 已通过守护进程成功运行;</li>" l& N# e4 a2 O# A
<li>若启动失败,检查「运行目录」「启动命令」是否正确,或查看「错误日志」定位问题(如权限不足可执行 <code>chmod -R 755 /opt/pocketbase</code>)。</li>" ~1 }, O  u5 p/ i
</ul>
- A& e. o3 |0 c/ q4 L1 K</li>9 ]. V; B8 D5 P' A4 O5 _6 m; s
</ol>
' O5 B( _- U+ S* c<h2>四、配置端口转发(反向代理)</h2>
: e# J: d7 }9 O! d0 m$ D<p>PocketBase 默认监听 8090 端口,直接暴露该端口不够友好,通过堡塔面板的「反向代理」可实现:</p>
  i" z7 A& i8 S7 D1 t% T3 z: D2 ~<ul>) X  N: [1 z9 g6 W4 x
<li>域名访问(如 <code>https://your-domain.com</code>)→ 转发到 <code>127.0.0.1:8090</code>;</li>3 I# l4 W+ G/ Z- F% h3 N# h8 Y# I: z
<li>80/443 端口(默认 HTTP/HTTPS 端口)→ 转发到 8090 端口;</li>
9 H+ \) R, V% P1 p0 b6 _: A<li>同时可一键配置 SSL 证书,实现 HTTPS 访问。</li>3 |7 \) ~$ S. ^/ R
</ul>* A/ j, c0 T% J) [+ F
<h3>步骤 1:添加站点(域名绑定)</h3>$ Z0 _0 ~; w6 F4 c: v6 u
<ol>& L, n7 e) J, @2 Z
<li>
, T5 F" t: J. T0 t* {6 j# s: V<p>点击堡塔面板左侧菜单栏的「网站」→「添加站点」;</p>
6 a0 y; F" i  ?+ L2 i5 n( B: a</li>
  q% L* v; c" n' O<li>
3 D9 l& a( G9 n5 b: e<p>填写站点配置:</p>* O0 m, S/ Z6 ?% X3 s0 S9 \* u
<table>
: p0 _+ s% t) x* q& }% }& X: S4 d<thead>7 _+ A% J7 Q8 V$ \$ w% \$ W: n
<tr>$ \4 G+ M6 H7 k( r4 J
<th>配置项</th>
! V8 g7 i" k. k0 b% b<th>填写内容</th>! X0 G0 {* j+ Z
</tr>1 n: u; v! t7 T6 K3 T7 |) M% e
</thead>
; ^* N  o. a4 I<tbody>8 |- K( U0 R0 B& s' J
<tr>$ u2 U' b9 [: T; ?: ~
<td>域名</td>
$ G! i* `* f/ @8 ^1 \( p<td>你的域名(如 <code>pb.example.com</code>,若无需域名可填服务器 IP)</td>) g, h+ Y: E+ c" S( y
</tr>, O0 b3 P. v3 k* M+ ?
<tr>: q+ q7 [/ Z9 c/ R
<td>备注</td>2 c9 {! z" W) k$ t
<td>PocketBase 反向代理(自定义)</td>
8 \& p8 F5 S/ ^- }</tr>9 N, Z  A7 Y' b2 i) V
<tr>) Z/ t& c$ Z/ O9 H
<td>根目录</td># v5 X7 ^1 b' e7 {) r) m9 g
<td>任意(反向代理无需实际网站文件,如 <code>/www/wwwroot/pocketbase</code>)</td>
/ B, }% m1 a6 i+ O, R- K* [</tr>
% Z* }+ x) ^# ~) E  _( ]- F! r<tr>+ {% u; E; \; V- P# y/ J
<td>PHP 版本</td>7 e( `0 u0 x! v0 L' D8 I4 o, |
<td>纯静态(无需 PHP,选择此项)</td>% w3 ]/ W5 t- C% [; T. b; h3 w
</tr>! U' D/ W+ h) {! {# }9 H
<tr>
) V1 {7 ~% @3 k$ d: ^) Q7 ?<td>数据库</td>
2 M% U% H* T6 |! J# ^4 g/ R<td>不创建(无需)</td>1 @: Q6 c/ ?4 t! ]0 O
</tr>( W/ M; i) z1 q9 T' X
<tr>
" t  v! o" ]+ N  O- Q$ v) g<td>FTP</td>
2 \* ^; Y4 T7 A1 L; H% l$ a<td>不创建(无需)</td>8 J9 H8 d" A$ G- _7 {: A  F( I
</tr>+ z! c8 [5 B4 s6 W+ C7 S6 h' u
</tbody>" m% V( {5 e& D3 Y& m  s2 b. G; Z! M. w
</table>4 u0 Q- f$ e0 J7 o8 l8 L: F
</li>
, u% A9 b* j% r. c: V<li>
+ X! s5 }' u% p6 d! O7 z6 t6 L<p>点击「提交」,完成站点创建。</p>7 C8 a' h& W! S3 D
</li>; U2 x$ g: w: d; e
</ol>+ ?& m+ m6 P, U$ u* m
<h3>步骤 2:配置反向代理(端口转发)</h3>, Q. k6 C6 y+ ?3 ]! }. P
<ol>+ b$ {7 g& o% w( S1 G# E. s
<li>
$ i/ \9 R/ a( U/ c<p>在「网站」列表中找到刚创建的站点,点击右侧的「设置」;</p>( _- d# b: l7 y/ y1 X
</li>
4 G+ l- z8 W4 [/ X, |  ]4 |<li>) p4 M* S- H# q9 ]& Q' r& o" o
<p>点击左侧的「反向代理」→「添加反向代理」;</p>  A" ]8 C  ]; q3 t, E
</li>) N; _: F" h0 ?9 q5 z
<li>6 X& r2 x# m( C
<p>填写反向代理配置:</p>7 m1 V/ Q2 c- Z7 D2 L
<table>' B" a4 u/ ]* U- [& T! A
<thead>2 M/ E6 a6 K) q$ x& P. @
<tr>2 U5 a+ |+ S' H2 W, @. l0 w
<th>配置项</th>) B6 f" o: v5 o0 ]+ L7 H* P2 z
<th>填写内容</th>9 a- u& c% @7 ?  `  J
</tr>
4 u. \3 O7 h  @; c% H</thead>
; c  r: h, Z8 ~) r) w<tbody>
0 G8 K+ l  o2 d/ A/ @$ _. }7 X<tr>6 P; I/ J8 y- A, C0 A* C
<td>代理名称</td>( S& f! L$ e4 j+ L# K/ m% Y
<td>PocketBase(自定义)</td>
3 s8 s6 A3 p5 R, b4 S7 X7 h) n</tr>' {6 e% N1 Y& d+ P
<tr>- K* H/ A4 g5 S+ b' S
<td>代理目录</td>
0 U$ N: n9 _& m/ Q$ L; v<td>/(根目录,转发所有请求)</td>
+ z- @: I1 Z  O0 C  O% S  R</tr>
# |( S$ G+ G* E/ g: e# C: j1 u<tr>: b0 Z0 `3 {  o% _2 ?7 R: b/ }; c
<td>目标URL</td>
5 i) V; m- E$ s- g+ U' z" v<td><code>http://127.0.0.1:8090</code>(PocketBase 运行地址,和守护进程启动命令一致)</td>' S1 d4 l8 N4 O3 k: U- P5 c' u$ o+ q6 f
</tr>8 \% S2 ?$ Y+ X7 p; W/ Q5 }
<tr>
( e: @$ I2 {  I# Y8 Q( T<td>缓存</td>  s& c) U& f: M3 G5 u" I2 o
<td>关闭(避免 API 数据缓存)</td>" z9 d/ p, K" }/ P! |/ n" X
</tr>
$ @- X! }* r; _3 P) p$ V$ \2 k2 i/ ?<tr>
+ P6 i* h! s/ Y$ |4 X<td>反向代理参数</td>
. U4 B8 `- n! V1 O% u- }3 }, b<td>点击「添加自定义参数」,新增以下参数(解决跨域/Header 传递问题):<code>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;</code></td>
2 o) ^8 ?# P  c- H9 O" V</tr>
9 y! b$ s7 X3 |2 x</tbody>
9 ^& ^' {, S( q' A( L# A</table>5 M* u$ Z" |9 D# @: ]" c
</li>2 I' Y" s% h; i) R0 W
<li>
& g6 l  v3 m( J9 a/ K<p>点击「提交」,反向代理配置生效。</p>
. ?, o: }5 Q( X3 R. L  r/ J0 ?! V1 Z  f</li>/ {$ O& K' Z; {( x
</ol>
- W9 |% d7 S0 b) q3 p( Q9 _<h3>步骤 3:配置 SSL 证书(可选,推荐)</h3>0 A% k) D) x) A& ?8 [' |
<p>为了安全访问,建议给域名配置 SSL 证书(堡塔面板支持一键申请 Let's Encrypt 免费证书):</p>5 _- Z" H4 r/ m. o+ o( G$ l  j
<ol>% {) U3 G* ^3 p2 u) B- N! R, l) ^
<li>在站点「设置」页面,点击左侧的「SSL」;</li>; a4 c7 |4 ^0 m; s# a+ T7 G% K/ L
<li>选择「Let's Encrypt」→ 勾选需要申请证书的域名 → 点击「申请」;</li>
2 y1 @. Z- F. @3 E" M4 d2 Y<li>申请成功后,开启「强制 HTTPS」(自动将 HTTP 请求重定向到 HTTPS);</li>
7 w9 A8 ?8 j  ^' D6 m7 v4 ?+ ^$ V0 D( Z<li>点击「保存」,SSL 配置生效。</li>
: t  D0 b+ `' z3 g9 c1 g4 ]</ol>
: D3 D3 R% Z( |0 f, p<h3>步骤 4:验证端口转发</h3>
9 i9 Y- J. [6 F3 q3 M+ m. M6 A! }. G<ol>
! @: m/ {5 [" _$ ], d<li>访问配置的域名/IP:
- J5 o* u% z! C$ p3 Y5 T; {) v! F( u<ul>) G6 Z( D+ F% \, i& V  H
<li>管理后台:<code>https://你的域名/_/</code>(替代 <code>http://服务器IP:8090/_/</code>);</li>
. }  \8 O% g8 v8 b5 }$ p7 C<li>API 接口:<code>https://你的域名/api/collections/users/records</code>(替代 8090 端口);</li>
7 g8 r8 o4 `. G+ L' Y9 w. J</ul>3 ^; z) A' r8 i3 i8 z2 i
</li>
5 ?! ~" U% h; k+ ~; `* y7 i  W( r: @<li>若能正常访问 PocketBase 管理后台或 API,说明端口转发配置成功。</li>
/ o0 B  ]& e6 @6 V</ol>2 R! `5 `2 l  e8 d! o4 H
<h2>五、常见问题排查</h2>; |( |# a0 F4 l' u2 j
<ol>
; w8 @9 b% _: u! S) ?<li><strong>守护进程启动失败</strong>:. m8 j3 t4 n6 [: O  \  {
<ul>
6 n0 L  L6 g( ^<li>检查「运行目录」是否为 PocketBase 二进制文件所在目录;</li>
( x; l- {1 m4 N% I2 W% ?<li>检查启动命令是否正确(如 <code>./pocketbase</code> 路径是否存在,可在堡塔面板「终端」执行 <code>ls /opt/pocketbase</code> 验证);</li>
# m" n* w+ Z7 b- K4 J- K<li>查看「错误日志」,若提示权限不足,执行 <code>chmod +x /opt/pocketbase/pocketbase</code> 赋予执行权限。</li>& |- \* d+ _% o$ Y$ p
</ul>1 j% X9 `: |9 \( x# A) o: f0 k
</li>
( i* p% }$ f; h4 F<li><strong>反向代理访问 404/502</strong>:4 g+ q" [  [9 s1 o+ D+ K+ `( m
<ul>% T0 C  B* M3 c, \
<li>502 错误:PocketBase 守护进程未运行,先确认进程状态为「运行中」;</li>, S+ Z2 \) q% W# t- f: s- M( P+ ^
<li>404 错误:反向代理「目标URL」填写错误(需为 <code>127.0.0.1:8090</code>,而非服务器公网 IP);</li>
1 @4 L2 s0 f7 v0 J9 C' t6 `4 i<li>跨域错误:检查反向代理「自定义参数」是否添加完整的 Header 配置。</li>
: \! d8 j6 j% O/ e6 L/ H) v</ul>
+ q/ q7 _+ N+ _" a2 T0 O</li>7 \. ]9 a+ P/ \
<li><strong>域名无法访问</strong>:. [# B1 S  ~3 J. q
<ul>
; y3 R8 Y& r0 Z3 r! _" C- @- F7 q- A<li>确认域名已解析到服务器公网 IP(可通过 <code>ping 你的域名</code> 验证);</li>. u% V6 d8 _) `  t5 R
<li>确认服务器安全组/堡塔面板「安全」模块已开放 80/443 端口。</li>1 {' }  ~1 i( p. U7 D
</ul>! Q$ C8 p  G$ X" U$ O% k' K
</li>
+ i: e' [5 o' {* w! e6 U) j  N</ol>9 ]) {/ z* o7 f5 K! I
匠心独运,千锤百炼,品质非凡。
回复

使用道具 举报

diggerLv.9 发表于 2026-1-4 12:57:08 | 查看全部 来自:Error
<h1>PocketBase 保留目录说明 &amp; 钩子(Hook)调用方式与示例</h1>6 _7 W7 x3 u  {3 c' @4 t, {5 _/ c
<h2>一、核心需求确认</h2>/ w' }: `* K& Q! H, E
<p>你希望了解 PocketBase 运行过程中自动生成/识别的<strong>保留目录</strong>的名称和具体作用,同时掌握 PocketBase 钩子(Hook)的调用方式,并通过实际示例理解钩子在业务场景中的应用(如数据校验、事件触发、自定义逻辑等)。</p>
/ }( J2 o! z) h% [3 t0 m& k: N# N<h2>二、PocketBase 保留目录详解</h2>( m3 V0 x: v2 k3 @
<p>PocketBase 运行时会在其工作目录(如 <code>/opt/pocketbase</code>)自动生成/识别多个保留目录(文件名固定,PocketBase 会优先读取),所有核心数据、配置、自定义逻辑都集中在这些目录中。以下是所有保留目录的名称、作用及关键细节:</p>1 ~; i$ f; e7 U/ b0 v5 T; j
<table>( d( Z. J' H5 z3 S! J
<thead>
9 d' A7 e8 i, E% N8 W* D<tr>3 P0 F" d3 t7 }: H* v
<th>目录名称</th>2 Y- i6 ~/ ^" s
<th>核心作用</th>  G1 b4 ^8 K+ B; r$ [$ E) T6 e
<th>关键文件/子目录</th>4 a; B0 W9 a- n# U/ M1 }  V
<th>适用场景</th>
' [+ C  \3 @7 W( R: ]</tr>; y" n6 b& _% h' F: s3 k
</thead>
/ X0 R5 g$ e  r0 W) O<tbody>
  R/ u7 o! g, J6 j% C9 C1 _' G<tr>
* W, V% L% z3 A8 y5 d3 k8 l3 [<td><code>pb_data/</code></td>
8 p0 a+ T$ i# g" G9 ^" }<td><strong>最核心目录</strong>,存储所有持久化数据(数据库、配置、文件、日志等)</td>
/ ?$ M( T! e1 `5 [$ [! {2 a<td>- <code>pb.db</code>:SQLite 核心数据库(存储集合、记录、用户等)- <code>pb_config.json</code>:全局配置文件(应用名称、跨域、邮件等)- <code>storage/</code>:文件存储目录(上传的图片/文件)- <code>logs/</code>:运行日志(可选)- <code>pb_auth.json</code>:认证相关配置</td>
( ^7 ~' X9 m' ^8 R<td>数据备份、配置修改、文件存储管理</td>% r- m* }' S+ ^5 M2 B6 @1 K
</tr>4 x% f: I! Q3 @/ c  C0 F' i
<tr>
* l4 Y2 D: c# Y: U1 x<td><code>pb_hooks/</code></td>
5 C0 N: x/ Y" d+ x8 p+ t4 J4 {<td>存放 JS/TS 钩子脚本,PocketBase 启动时自动加载,用于扩展业务逻辑</td>
' {" p, E% d* X+ f" K3 |3 M2 P<td><code>*.js</code>/<code>*.ts</code>(如 <code>users.hooks.js</code>)</td>
2 ^2 b- G! u7 z) y1 p<td>数据校验、事件触发、自定义认证、请求拦截</td>% n/ Q# x2 G7 ~
</tr>
% L2 D5 R# v( u) b$ w<tr>
0 Z9 M3 G3 Q( F$ a" R<td><code>pb_migrations/</code></td>. X9 |& `4 u/ T& D. m
<td>数据库迁移脚本目录,用于管理集合结构变更(版本升级/手动修改表结构)</td>" ^5 [$ c' x; s/ }5 ~, S+ I
<td><code>*.js</code>/<code>*.ts</code>(如 <code>20240104120000_init.js</code>)</td>
% B& `- C& Y' m% \/ {$ `<td>生产环境集合结构变更、版本迭代</td>
* E. l5 i( s& h0 s9 q$ ]3 T( m</tr>
+ `8 d3 @% o& N' S# M: _. d<tr>
% H/ d1 ^! l$ [6 `<td><code>pb_public/</code></td>3 l/ X9 Z! {, z& T) N4 V# `
<td>静态文件托管目录,可通过 URL 直接访问(无需认证)</td>
( C/ ~5 o, t1 g8 G<td>任意静态文件(如 <code>index.html</code>、<code>logo.png</code>)</td>
/ v$ L/ N# X8 `& E6 ~- l<td>托管前端静态页面、公共资源(如图片、JS)</td>" ^9 x- ?% W) ~. Q. v: _5 u( }
</tr>
' g0 ]$ a+ \2 y</tbody>
9 D8 |, i0 }/ N! l  I& d3 D7 R* {) [</table>
# M6 E; u  t$ R/ W* `' \' }1 m+ W6 v<h3>各目录详细说明</h3>
* }8 W3 l& V8 c, _! J% ]<h4>1. <code>pb_data/</code>(核心数据目录)</h4>
4 W! }, E7 s/ e- r9 u  I! B<ul>
7 @* l# t+ |2 n8 [4 b& E<li><strong>不可删除</strong>:删除该目录会丢失所有数据(数据库、配置、上传文件);</li>* t6 e: y0 J6 K+ g) _
<li><strong>备份优先级</strong>:日常运维只需备份该目录即可完整恢复 PocketBase 所有数据;</li>
0 `8 c# }* y4 G4 ?<li><strong>关键文件说明</strong>:
9 m7 A$ n$ D9 r* u8 x<ul>% s: G/ Q8 Q; m7 o
<li><code>pb.db</code>:SQLite 数据库文件,存储集合定义、记录数据、管理员/用户账号等核心数据;</li>
3 D/ h1 M7 l$ O+ v<li><code>pb_config.json</code>:自动生成的配置文件,可手动修改(如跨域允许的域名、邮件服务器配置),修改后需重启 PocketBase;</li>
5 n& \- M% H& Y<li><code>storage/</code>:默认存储用户上传的文件(如集合中「File」类型字段的文件),路径对应 API 返回的 <code>fileUrl</code>;</li>/ C& e9 _; L$ W' g4 e' q
<li>权限要求:运行 PocketBase 的用户需有该目录的读写权限(如 <code>chmod -R 755 pb_data/</code>)。</li>
7 N2 g  k$ K& ^9 V1 E9 L! r( {</ul>
3 G* i0 B1 I7 Q  a% N</li>
1 h' ~! `7 v* E6 i9 x</ul>
( M8 g1 L% N& J- G/ G; v6 N<h4>2. <code>pb_hooks/</code>(钩子脚本目录)</h4>$ V1 `* M7 ?3 t" D% n4 U1 K# |  }0 i
<ul>9 Z7 q! L+ q( T; T9 l% I0 k
<li><strong>自动加载</strong>:PocketBase 启动时会扫描该目录下所有 <code>.js</code>/<code>.ts</code> 文件并执行,无需手动配置;</li>
4 o  q4 w8 l( `% u8 I; U4 k) ^7 R<li><strong>运行环境</strong>:基于 Go 内置的 ESModule 运行时,支持大部分 ES6+ 语法,可直接使用 <code>console.log</code> 调试;</li>% }7 m+ a+ P) n, H( ~
<li><strong>无依赖</strong>:暂不支持 npm 包,需用原生 JS/TS 编写逻辑。</li>! J1 Q+ r- K7 {
</ul>
" |5 S. v, O$ S5 d- P4 Q<h4>3. <code>pb_migrations/</code>(数据库迁移目录)</h4>
. z) m, \9 y4 f' Z% p<ul>2 V$ L, H0 f7 a3 v+ `! c& S
<li><strong>自动生成</strong>:在管理后台修改集合结构(如添加字段)时,会自动生成迁移脚本;</li>
( c8 {; l1 R/ l; c9 a; s( P% k<li><strong>手动执行</strong>:可通过命令 <code>./pocketbase migrate up</code> 执行未应用的迁移脚本;</li>
! h- b8 w4 y4 t! v7 F7 l<li><strong>回滚</strong>:支持 <code>./pocketbase migrate down</code> 回滚最近一次迁移(需脚本支持)。</li># O( V3 G+ d" @- w# `' O
</ul>1 K& x0 C: u7 |& {
<h4>4. <code>pb_public/</code>(静态文件目录)</h4>; V( {9 o1 D) k
<ul>
& q5 O; A/ c+ M, r' w/ M<li><strong>访问方式</strong>:文件路径对应 URL 路径,如 <code>pb_public/logo.png</code> 可通过 <code>http://域名/public/logo.png</code> 访问;</li>: e0 P( O0 I* B: Q; b. y4 V9 r
<li><strong>权限</strong>:所有文件无需认证即可访问,适合存放公共静态资源(不建议存放敏感文件)。</li>
% U! a, Y# b  J  {) b6 Q( V. ~/ I</ul>/ P) h/ [! `# y0 [  h% h
<h2>三、PocketBase 钩子(Hook)调用方式与示例</h2>2 b. J! k' R, ~% f
<h3>1. 钩子核心概念</h3>: z+ d% ?2 q& u0 v" I& B( D2 Y0 y
<p>PocketBase 钩子是<strong>服务端事件驱动脚本</strong>,可拦截/处理系统核心事件(如数据创建/更新、用户认证、服务启动等),实现自定义业务逻辑(如数据校验、自动填充字段、日志记录、权限控制)。</p>) i# k) V& `2 M% b2 S; H. ?: b% ?  l
<p>钩子分为两类:</p>, t! I' ]6 j2 E
<ul>
/ _. a. ?) H- ^<li><strong>集合钩子(Collection Hooks)</strong>:针对特定集合的操作(如 <code>users</code> 集合的创建/更新),最常用;</li>4 H# S! A4 o, g: T) b0 j
<li><strong>全局钩子(App Hooks)</strong>:针对全局事件(如服务启动、HTTP 请求拦截、用户登录)。</li>
& t' h7 V8 c4 i1 h1 M8 z3 h1 M1 j</ul>
% E5 C) i8 f) }0 {<h3>2. 钩子基本使用步骤</h3>
  p* P/ x8 L8 a5 ?- h, ~1 i5 I<ol>. ~  h" N' [8 x+ q
<li>在 PocketBase 工作目录(如 <code>/opt/pocketbase</code>)创建 <code>pb_hooks</code> 目录:
9 p8 Q: e' X* x8 N* Z8 w5 R<pre><code class="language-bash">mkdir -p /opt/pocketbase/pb_hooks  d( v8 a8 s) x" k  q
</code></pre>2 @" v- ~/ s1 w, P# I0 |$ t
</li>
$ w- }* |. G! ~/ T$ r<li>在 <code>pb_hooks</code> 目录下创建 <code>.js</code> 文件(如 <code>users.hooks.js</code>);</li>
: R- {. m7 R; D. t<li>编写钩子逻辑,保存后重启 PocketBase 守护进程(堡塔面板「进程守护」→ 重启);</li>
2 s& U2 K6 l" o- J% P' |<li>测试触发条件(如创建一条用户记录),验证钩子是否生效。</li>
- n) M0 X& M8 w</ol>
5 B0 f1 H" W* `<h3>3. 常用钩子示例</h3>
) Q4 A' m3 p; e" w0 h7 y<h4>示例 1:集合钩子 - 数据创建前校验(必填字段+格式校验)</h4>
3 E+ c" A8 {7 U$ ^& I<p>场景:<code>users</code> 集合创建记录时,强制校验「email」字段格式,且「username」字段不能为空。</p>
0 ]: N: k7 T- \8 N, z1 s<p>创建 <code>pb_hooks/users.hooks.js</code>:</p>( i/ l! c+ U+ q
<pre><code class="language-javascript">// 监听 users 集合的 beforeCreate 事件(创建记录前触发)$ G7 a6 M' b9 T4 ^: v
onRecordBeforeCreate((e) =&gt; {0 C6 z# H6 B9 m) @) d
  // 仅针对 users 集合生效- u* p, I% i8 \- b9 ?( U
  if (e.record.collectionName !== &quot;users&quot;) {; p6 L: K* l9 P& J+ |
    return;
, m' B3 P; ]& Q) Q  }  m8 ^  a- W3 R& D
3 t- T/ O  C0 U1 G- [
  // 1. 校验 username 不能为空
* T. M0 t+ w. |  const username = e.record.get(&quot;username&quot;);
; w  v! n9 ]: l) v5 O  if (!username || username.trim() === &quot;&quot;) {  T' T5 n5 J- `/ Z
    throw new Error(&quot;用户名不能为空!&quot;); // 抛出错误会终止创建操作,前端会收到该错误信息, w2 B- m6 f2 P' z  Z5 p
  }7 p4 a8 |2 T1 [. A$ F5 e
( i5 e) P+ c) i, M  q
  // 2. 校验 email 格式
/ P+ Y6 {! x1 G4 e5 h/ Z! @! a  const email = e.record.get(&quot;email&quot;);- U- Y8 I6 ?  V* ], z
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;2 t6 @0 _/ \) E, B, s$ l
  if (!emailRegex.test(email)) {
3 s  l+ B- \/ F% h  `9 z& m    throw new Error(&quot;邮箱格式不正确!&quot;);
. ~$ f- J6 }" B, X6 u) F  }
$ N0 L3 p# W) E- x3 c1 b4 p2 B4 @/ p  o
  // 3. 自动填充创建时间(无需前端传参)
' b" Z- V2 Q% V& e( Y' v; c  L  e.record.set(&quot;created_at&quot;, new Date().toISOString());
# p" ?# N4 r" T" C3 T1 H% P$ \  p});0 o" W# v: A/ G
</code></pre>
+ `0 p$ z7 t; g* V+ t, d6 Q) @<p><strong>触发方式</strong>:调用 <code>users</code> 集合的创建 API 时自动触发:</p>
0 e, I5 u6 r. q% O<pre><code class="language-bash"># 测试:传入错误邮箱,会返回「邮箱格式不正确」2 }  V: w5 ^3 t$ T# _1 o, [
curl -X POST http://域名/api/collections/users/records \& f! x! u9 F2 N3 F6 M4 A# F
  -H &quot;Content-Type: application/json&quot; \4 l7 s+ i1 ?0 O" x, V" F. `2 ?, }
  -d '{&quot;username&quot;:&quot;test&quot;,&quot;email&quot;:&quot;invalid-email&quot;,&quot;age&quot;:25}'
9 z; {# e' n7 [. K5 x" C</code></pre>
8 H* ^$ e" ?$ e8 P2 j. l<h4>示例 2:集合钩子 - 数据更新后记录日志</h4>
: `. n+ S- H( C; D' \' Y<p>场景:<code>users</code> 集合记录更新后,自动将操作日志写入 <code>user_logs</code> 集合(需先创建该集合,包含 <code>user_id</code>、<code>operation</code>、<code>update_time</code> 字段)。</p>" q5 P1 `) a% J9 U% g+ Z4 _
<p>创建 <code>pb_hooks/users.hooks.js</code>:</p>% c. r; I3 b; l' ?
<pre><code class="language-javascript">// 监听 users 集合的 afterUpdate 事件(更新记录后触发)6 r4 [6 K5 O& c- [" G. [. X' P0 I1 I
onRecordAfterUpdate(async (e) =&gt; {
3 @: B6 W3 O3 m# i) h; B# W! \6 k$ I  if (e.record.collectionName !== &quot;users&quot;) {
/ H) T8 e- X, _  P5 ^    return;% b+ ]" E/ }  W4 z: B
  }# H1 a4 n! [" ^

( z; b9 J* w/ J. r: Y% w9 |  // 获取更新的用户ID和操作时间
' Z3 D/ Q  t" n2 B0 Q4 ~  const userId = e.record.id;7 I+ ]' w* I3 d( S- R/ o& A% ]
  const updateTime = new Date().toISOString();
* U( C0 V' u: J' k" {! Z. S  B( S1 s" P8 t3 ]0 z: _: Y% _/ w1 t* @- q* v
  // 写入日志到 user_logs 集合* V) a% F6 y9 X- r' x$ F+ n1 Q- A
  await $app.dao().createRecord(9 j& c  h& j5 v& j/ h1 y2 |
    $app.dao().findCollectionByNameOrId(&quot;user_logs&quot;),& }8 T  J0 L# y. A' `, H+ a# `
    {
3 a7 r/ ?( v9 V- Y2 E% A4 i) F      user_id: userId,
) P  [; h$ c3 A) t      operation: &quot;用户信息更新&quot;,, l/ p" D) l1 J7 }
      update_time: updateTime,7 \& `' ~& D/ U" Q* R
    }/ m8 I2 M8 s( x% }! U7 y
  );
$ ^% |4 H0 m/ X$ ~! Y& f; s  u- K" C/ [- A/ d; J
  console.log(`用户 ${userId} 信息已更新,日志已记录`); // 日志会输出到 PocketBase 运行日志
2 S1 `' F" d! L; u});1 n0 Q% D- E. }/ j* ~
</code></pre>
  Z) @% Q  m, g+ N2 m<h4>示例 3:全局钩子 - 服务启动时初始化</h4>3 u7 }2 F; I1 `  n) ~
<p>场景:PocketBase 启动时,自动检查 <code>settings</code> 集合是否存在默认配置,不存在则创建。</p>" t8 }4 e: h5 V; i/ @
<p>创建 <code>pb_hooks/app.hooks.js</code>:</p>& u7 m4 ]. v5 J' h, l' H+ a
<pre><code class="language-javascript">// 监听服务启动后事件
% u% J# l5 K! ?/ g. T0 yonAppAfterServe((e) =&gt; {
' z8 M6 W& B& A$ p' I* X  console.log(&quot;PocketBase 服务已启动,开始初始化默认配置&quot;);
" b& O0 ~& {' G- e  u
& |! B- \3 l. y6 w* `0 ?  [5 G  // 获取 settings 集合( U3 D7 Z- Q% X; o. c6 a; C
  const settingsCollection = $app.dao().findCollectionByNameOrId(&quot;settings&quot;);
. \3 {+ }( C3 C, Y! _4 @  if (!settingsCollection) {
) I8 w* b4 r9 k$ R  g5 G  \    console.log(&quot;settings 集合不存在,跳过初始化&quot;);& A& \) D* |) [; _. L
    return;
- p# F3 H6 w  e$ j5 @  }
' A7 Y2 Q6 g0 B/ |% S1 S
( |# p* W( u& p0 K5 H/ y( i  // 检查是否已有默认配置' D3 X  U9 w" Z: {
  const defaultSettings = $app.dao().findFirstRecordByFilter(( |' @3 ?  V# B: ^& O8 d
    &quot;settings&quot;,
3 p2 e3 F8 G( o8 s: K/ P( F1 n    &quot;key = 'site_name'&quot;,
0 ^: t; ?9 \1 J: Z    &quot;&quot;
) K' H* ^  Y$ ~% {  );- A$ |% N+ c1 e3 H) j2 }' M
% B" }& Q( m1 V5 L+ Y! }5 X
  // 无默认配置则创建$ @5 g' U  X9 g0 p, x+ Z: T
  if (!defaultSettings) {% R5 U" n+ I0 B9 o3 c2 b# R* H
    const record = new Record(settingsCollection);2 u3 B0 _7 \4 |3 n* q' F, T
    record.set(&quot;key&quot;, &quot;site_name&quot;);
3 Q# d. y! i6 c# d0 v    record.set(&quot;value&quot;, &quot;我的 PocketBase 应用&quot;);9 X, S& {( _  R, ?1 ~3 X' \
    $app.dao().saveRecord(record);
; ?. e: w" W, {+ M  u. _    console.log(&quot;默认站点名称已创建&quot;);5 @8 B& l! P* x* J4 R1 M' z! x1 S
  }: L6 I9 o5 G& C1 p
});
4 z, V* N4 U/ k9 S6 u3 P/ P6 K</code></pre>0 ~, a- Q; |: g. ~
<h4>示例 4:全局钩子 - 拦截 HTTP 请求添加跨域头</h4>
9 l  A* c" @. q; c<p>场景:自定义跨域配置(替代 <code>pb_config.json</code> 中的跨域设置),允许指定域名的跨域请求。</p>
4 J% `! [  a# N5 \1 i7 ~<p>创建 <code>pb_hooks/app.hooks.js</code>:</p>8 c; c- Y- F* r/ W3 \! t+ A9 H! D
<pre><code class="language-javascript">// 监听所有 HTTP 请求
! }/ o0 \, r+ X2 TonHttpRequest((e) =&gt; {
; ^; g6 `, a# [+ S, G  // 获取请求的 Origin 头9 u' l$ E" j% S/ S% c3 w* W: d
  const origin = e.request.headers.get(&quot;Origin&quot;);
) U+ j( J: s* P4 K( {' n  // 允许的跨域域名列表
& E! @; ^; a1 }2 [, s) j  const allowedOrigins = [&quot;https://your-domain.com&quot;, &quot;http://localhost:3000&quot;];, J/ Z& j$ x7 {( C
6 q4 v% Q. B% b) v4 }; r6 h
  // 若 Origin 在允许列表中,添加跨域头- o9 N1 v; M! \# p+ p
  if (allowedOrigins.includes(origin)) {( w, j- K) i0 m; Z3 ^- V1 ^
    e.response.headers.set(&quot;Access-Control-Allow-Origin&quot;, origin);$ F! ^! f. l( [& B, ^' g+ x
    e.response.headers.set(&quot;Access-Control-Allow-Methods&quot;, &quot;GET, POST, PUT, DELETE, OPTIONS&quot;);: j, ^# y* R0 ~0 |7 X9 N. I
    e.response.headers.set(&quot;Access-Control-Allow-Headers&quot;, &quot;Content-Type, Authorization&quot;);
. w6 H5 y9 P% ^7 E1 V$ M6 }5 K; F  }( N) `. ~) g7 L+ N+ p! ]( i
3 I, G: \7 ^6 R/ c
  // 处理 OPTIONS 预检请求" V- g! {) a9 M- J1 K, F
  if (e.request.method === &quot;OPTIONS&quot;) {
- r9 ^" a4 O9 T1 ]0 ?    e.response.status = 204;
. F0 F7 ~9 Z& t' u    e.response.body = &quot;&quot;;6 R, Y( y" Z% U  u( k- h1 R
  }
& O3 i+ v7 `; |* V; w+ v; }});0 l1 r" t) g5 {' o0 S8 v
</code></pre>. @, {, t3 U0 f1 i# k) _* a. Y
<h4>示例 5:认证钩子 - 自定义用户登录逻辑</h4>
2 k! c3 C6 r, Z) ]. X( C- M<p>场景:用户登录时,额外校验「账号是否禁用」(<code>users</code> 集合需添加 <code>is_disabled</code> 布尔字段)。</p>3 B" c. Z1 k8 G* j
<p>创建 <code>pb_hooks/auth.hooks.js</code>:</p>
5 |2 K/ F, {4 e9 \/ K<pre><code class="language-javascript">// 监听用户密码登录事件
0 V; Z; W- e  H1 M, X1 o8 eonRecordAuthWithPassword((e) =&gt; {
: i0 @' u& g& Z, @/ [, f6 V  // 仅针对 users 集合的登录. y# |7 @, O7 E- W
  if (e.record.collectionName !== &quot;users&quot;) {. j* B/ [% D! t5 |# z( c0 v
    return;
+ I. i2 i4 x4 ~  }
9 l) b5 Z6 P1 c0 G$ C, B
4 M& d* C5 \" J1 c0 J  // 检查用户是否被禁用
9 \2 b" J4 ^' |& s# U* S! K4 G  const isDisabled = e.record.get(&quot;is_disabled&quot;);
/ N! A" Y5 q7 t. ?% Q5 m2 |, J$ f6 U  if (isDisabled) {* f  m& N, ~* M* I7 \1 U" O) b
    throw new Error(&quot;该账号已被禁用,请联系管理员!&quot;); // 终止登录
( a# y# J4 x' [9 v" y! K! m  }/ V4 k, M: ]3 Z& K! h5 K! _

) L9 A% ~2 e- E) f; R$ u  // 登录成功后,记录最后登录时间' b/ o3 C5 Q, r! A& L
  e.record.set(&quot;last_login_at&quot;, new Date().toISOString());' u& G9 I# V8 z" o
  await $app.dao().saveRecord(e.record);
5 K; F  J3 J+ o; M- y- H- o
9 H3 v, \1 r# }+ R3 N3 V  console.log(`用户 ${e.record.id} 登录成功,最后登录时间已更新`);
' E5 k1 P, O1 c" _});
& x6 }) h; F* E9 q  D6 x" W</code></pre>* Y& Y/ L' {" @7 e
<h3>4. 钩子调试技巧</h3>
& F' a. G4 L: t# X<ul>
/ \$ s) N; T5 M1 |) P, `2 h# n<li><strong>日志输出</strong>:使用 <code>console.log(xxx)</code> 输出调试信息,日志会写入 PocketBase 运行日志(堡塔面板「进程守护」→「日志」可查看);</li>
& u* K1 o# [, y6 t7 Z; d<li><strong>错误排查</strong>:钩子脚本语法错误会导致 PocketBase 启动失败,可在终端手动运行 <code>./pocketbase serve</code> 查看具体错误信息;</li>5 o; e( o9 ]0 v
<li><strong>参数打印</strong>:触发钩子时,打印事件对象 <code>e</code> 查看可用参数(如 <code>console.log(JSON.stringify(e.record))</code>)。</li>
8 Q# Z: M2 X/ [+ g. n</ul>
" p8 S' b% c: y, l5 j' N, Q<h2>四、总结</h2>
$ A$ k3 a8 |0 Z. J<ol>
$ y6 L1 E  X- v: K* d- |' z" |<li><strong>保留目录核心要点</strong>:
# A. s$ {' h7 g' ^7 F<ul>
% X; f' K5 s% ^; ]<li><code>pb_data/</code> 是核心数据仓,备份该目录即可恢复所有数据;</li>7 n+ `7 G4 p; {" r/ {
<li><code>pb_hooks/</code> 存放自定义钩子脚本,启动时自动加载;</li>4 ]; E; J/ n6 r  q: q" @" j
<li><code>pb_public/</code> 托管无需认证的静态文件,<code>pb_migrations/</code> 管理数据库结构变更。</li>
+ N# z1 ?; {/ B/ _6 g</ul>
; B0 q+ V: H) X% X$ I6 A</li>
6 u" Z. B' ^, F8 u0 I; ~<li><strong>钩子使用核心要点</strong>:
1 f1 Q+ M; w5 {( B2 r1 X<ul>  O6 _9 l/ P, \9 C) a1 k
<li>钩子分「集合钩子」(针对数据操作)和「全局钩子」(针对系统事件),放在 <code>pb_hooks/</code> 目录自动加载;</li>
' u+ `2 s, O/ E# o<li>常用钩子:<code>onRecordBeforeCreate</code>(数据校验)、<code>onRecordAfterUpdate</code>(日志记录)、<code>onHttpRequest</code>(跨域配置);</li>& T7 u/ i- B0 I2 g" M0 g
<li>钩子中抛出错误会终止原操作,适合做数据校验;可通过 <code>$app.dao()</code> 操作数据库(如创建/更新记录)。</li>
+ Z4 {1 N' w- E* @( J# o( O: v</ul>
5 e. m( \/ m. L0 v! H</li>
# o0 e5 |$ m. @5 m6 I) \1 \5 ~0 Z<li><strong>实战建议</strong>:
5 j# _5 [& A* [8 w, P1 f<ul>
. r  L+ U, M% w6 L- y' b( J5 H<li>钩子脚本优先实现核心业务逻辑(校验、自动填充),避免复杂计算;</li>7 U* t# F. l" t5 x3 {
<li>修改钩子后需重启 PocketBase 才能生效;</li>
) `. z3 g, H. c" D0 _" j<li>生产环境需备份 <code>pb_hooks/</code> 目录,避免钩子脚本丢失。</li>/ T& z& i7 Y1 z9 Z! U  A3 `
</ul>
" w  o4 M( d- @8 P3 \</li>% s! M) r, x$ Y7 A0 Q) b( k* ~3 T
</ol>0 ?) N; k& z0 Q6 T! q
[!luckypost!]: digger 被钱袋砸中进医院,看病花了 1 匠币. !lucky_goodrank! / !lucky_badrank!
匠心独运,千锤百炼,品质非凡。
回复

使用道具 举报

打工日常 发表于 2026-1-4 13:00:20 | 查看全部 来自:Error
<h1>Debian 12 下 PocketBase 全维度配置指南</h1>% c8 I2 ^3 c  x  ]
<h2>一、核心需求确认</h2>
5 B& c8 z9 x: S7 g  e<p>你需要在 Debian 12 系统中完成 PocketBase 的<strong>全场景配置</strong>,包括基础网络(端口、绑定地址)、邮件(SMTP)、存储(本地/S3)、安全(跨域、认证)、应用基础(日志、时区)等核心配置,同时掌握配置的生效方式、备份与问题排查方法,适配生产环境的实际需求。</p>
+ |. Q/ E+ q# k<h2>二、PocketBase 配置的核心入口(Debian 12 环境)</h2>- N. C, Q; r" Q1 H
<p>PocketBase 的配置主要通过 4 种方式实现(优先级:命令行参数 &gt; 管理后台 &gt; 配置文件 &gt; 钩子脚本),所有配置最终会落地到 <code>pb_data/pb_config.json</code>(运行后自动生成),以下是各入口的适用场景:</p>
+ w- ]4 w$ T$ p1 t* j1 j0 U<table>" M3 }) j" {+ ?& e7 b" b
<thead>
# ?* m. d! P, o$ |* D) m  ~<tr>
/ T0 E3 d7 N  c. W8 c- Z7 O+ F<th>配置方式</th>
: y" H, m" C$ P; G9 z' [+ O<th>操作路径</th>. Q" v+ Q' z. H5 I! o
<th>适用场景</th>" |) J: v9 A0 u8 W; n0 x
</tr>+ F  s0 I3 \. `- I0 q0 D7 R+ z/ a
</thead>' t& g6 V" D" F$ {3 j$ G
<tbody>! d4 b! X7 S/ d% b0 \) i
<tr>
& X( m9 H5 d" B2 `) h$ V<td>配置文件</td>
% s) O& I6 m; @# G1 S# j$ }2 ^<td><code>/opt/pocketbase/pb_data/pb_config.json</code>(手动编辑)</td>. O, s& k" f0 M& F1 k
<td>所有基础配置(网络、邮件、存储、安全)</td>& ~5 c: o  ?+ Y9 x# X' K( }+ X
</tr>
, o& O2 e. O! V7 Q& u<tr>
% Z7 z8 m: F' c, _: M6 U5 l1 p<td>命令行启动参数</td>4 G8 q9 v& g* H! T0 m
<td>启动时追加参数(如 <code>./pocketbase serve --http=0.0.0.0:8080</code>)</td>
; m7 c% m! Q" _$ m$ `<td>临时覆盖配置(如测试端口、调试模式)</td>
- }2 T, Q! L1 e3 B1 i9 q# z! W6 q" X</tr>$ J) Z  W- e2 j! \
<tr>
8 H+ R& E; S% J2 l<td>管理后台</td>/ ]! A; X6 B" e& w) g1 `
<td><code>http://域名/_/</code> → 设置(Settings)</td># I9 g5 w4 _1 c3 [( J: W0 Y5 s
<td>可视化配置(邮件、跨域、认证策略)</td>9 k% n; H9 a6 ^% Q1 A7 J' i" O
</tr>0 u1 h: F4 Z" y- |2 ?
<tr>2 x+ i- Y3 C0 @" c1 A+ _
<td>钩子脚本</td>8 }" t. S0 }1 C8 G8 k! M3 @" e
<td><code>pb_hooks/</code> 下的 JS 脚本</td>% ?6 q# S% _3 @7 u3 \: A: W) w
<td>自定义配置(如动态跨域、自定义认证规则)</td>
/ e+ p% ^7 F6 c' J* L</tr>4 l; {/ ^2 x# T/ D: [# x: R
</tbody>
- V# T0 q9 A" `5 C( @3 X) s</table>/ G; L& A1 o! A  ^& W: l' H8 K+ K+ E. h
<h3>前置操作(Debian 12)</h3>
- r; P  ~6 N0 ]<ol>
7 b. Y: j9 t& k6 _. e# X( w<li>确认 PocketBase 工作目录(默认 <code>/opt/pocketbase</code>),若路径不同需替换下文所有路径;</li>
- ^7 }( C. t' R$ `9 ~9 l<li>确保对 <code>pb_data/</code> 目录有读写权限:- g) m7 `9 P/ Y. l
<pre><code class="language-bash">sudo chmod -R 755 /opt/pocketbase/pb_data
1 p9 V# d- x) u: z3 o& Isudo chown -R root:root /opt/pocketbase/pb_data  # 或你的运行用户
! |( P+ l- U2 m) \8 |& p# ^</code></pre>% J  Y' g# J: h  _+ f1 B  G  \
</li>
! X: c4 n3 ?' e/ J- q</ol>
& M# `; L( U" l4 E' v* I) k9 D<h2>三、核心配置模块(Debian 12 实操)</h2>
+ m% X5 [* X! q# G4 H<h3>1. 基础网络配置(端口、绑定地址、HTTPS)</h3>
" |! a3 Y( U1 M# b<h4>1.1 修改默认端口/绑定地址(3种方式)</h4>( f) @1 z+ ]( M( {2 N, {8 I
<p>PocketBase 默认监听 <code>0.0.0.0:8090</code>,以下是修改方式:</p>( N- S# T5 }5 @0 p, U
<h5>方式1:命令行参数(临时生效,重启后失效)</h5>
3 I: \+ U% |  [# Y9 l6 ?- p<pre><code class="language-bash"># 切换到 PocketBase 目录
; M3 z6 _6 W! ?6 g# a! Vcd /opt/pocketbase4 v. G5 K1 `9 ?3 |. _/ {

( d7 P) J; e$ p! A# 监听 8080 端口,仅绑定本地回环地址(仅服务器内部访问)
! n/ h% F$ R: \  e./pocketbase serve --http=127.0.0.1:8080) V! H5 y5 m! e) M
3 Z5 }+ V( A5 @+ m1 v" i% `
# 监听 80 端口(需 root 权限),绑定所有网卡
0 o5 H+ C- Y' U5 a9 y& @& ysudo ./pocketbase serve --http=0.0.0.0:80
) {# L. f3 W2 n4 I: ^3 d7 e, D</code></pre>. _% E- A  Y8 z- b  y8 F
<h5>方式2:配置文件(永久生效)</h5># z( B+ E% z8 U; ?
<ol>0 {$ K5 |0 u2 o
<li>编辑配置文件:
- S0 c( N/ W, ]0 X3 B; S- c% k3 C2 g<pre><code class="language-bash">nano /opt/pocketbase/pb_data/pb_config.json
, z3 q' D1 q. ~9 e" k. M% e8 \: v" x6 r</code></pre>0 {) |, m- Q5 o$ B
</li>
5 E& O% Z! k9 A/ [( ?! J" \<li>添加/修改 <code>api</code> 节点(无则新增):
2 K  s& O( A- P* T( K<pre><code class="language-json">{$ h' W' ~, G9 c' J& O
  &quot;api&quot;: {  }7 g3 P9 ]* i: c: [
    &quot;httpAddr&quot;: &quot;0.0.0.0:8080&quot;,  // 绑定地址+端口
; J3 G9 E7 x  ~  P& d8 ~/ n/ k    &quot;httpTimeout&quot;: 30           // 请求超时时间(秒)
5 ?: h5 y2 r0 R  }
" I# @) W" ~  n/ B/ {' u' F}
* L6 o2 H; D  h8 G% o</code></pre>
' j# c& |7 }* u) g</li>
" j% {* ?( X  F$ m) r; X2 S  b<li>保存后重启 PocketBase:
% u8 k8 h4 q  u" j; Q5 [<pre><code class="language-bash"># systemd 服务方式: B" w: R( e) d* G0 U0 _
sudo systemctl restart pocketbase
9 k4 r1 d/ T; y  e( R' h% r* F& Y( k. |4 P4 _
# 堡塔面板方式:进程守护 → 重启 PocketBase
3 p5 ?6 ]8 ?1 @1 m! U: E2 _( c</code></pre>* h& t, Y% g6 K/ c0 D
</li>
, e! Y. j% V. L* |; u- J</ol>. n+ P3 j5 s/ |, |, o0 ?' L/ J6 Z1 Z
<h5>方式3:堡塔面板进程守护(永久生效)</h5>
0 l; x/ w7 h: ~2 e<ol>
  m0 V' b3 y- s0 H<li>登录堡塔面板 → 进程守护 → 找到 PocketBase 进程 → 编辑;</li>3 X) @) e- O2 ^
<li>修改「启动命令」为:
8 D, ?: @6 s' H+ V+ k<pre><code class="language-bash">./pocketbase serve --http=0.0.0.0:8080
1 u5 O, D$ p1 W# Y0 z</code></pre>
% d9 h! H6 a1 _. s</li>
  J- K( Z# w6 O$ w" y<li>保存并重启进程。</li>! h! X% w6 j; B3 ?4 F
</ol>
& J% b5 X3 b5 V<h4>1.2 配置 HTTPS(Debian 12 推荐 Nginx 反向代理)</h4>
' ]2 P$ h$ u4 z0 g( ]<p>PocketBase 自身不直接支持 HTTPS,Debian 12 下推荐通过 Nginx 配置(替代 PocketBase 内置的 HTTPS 方式,更稳定):</p>
7 ]! J# ~4 j& W! t<ol>$ Y* l! {4 H/ r0 V: X
<li>安装 Nginx(Debian 12):: N6 D: ^3 L" g/ ~
<pre><code class="language-bash">sudo apt install nginx -y
/ a3 i/ N$ b, O0 o  T0 c</code></pre>
/ U8 s: P$ L" W6 ]6 v</li>% U, }0 u$ G& F; x0 ]5 Q- a" a
<li>创建 Nginx 配置文件:0 T: b- Q" c$ L4 o; N
<pre><code class="language-bash">sudo nano /etc/nginx/sites-available/pocketbase-https) \5 }2 L: W# m( u3 h: q: K2 ^
</code></pre>6 z$ Q( P8 {% a! Q( U0 a$ }% f
</li>- U; _6 p6 a% \9 i( x. w" |& j( i
<li>粘贴以下配置(替换 <code>your-domain.com</code> 为你的域名):
2 p* l% F) b/ Y+ H. T/ B' O& t<pre><code class="language-nginx">server {* q. g- U0 K! x3 h
    listen 80;
  V1 l# F+ S; m% y' j- ~    server_name your-domain.com;
* Q+ G6 c# }; r0 z5 Y/ m: ^: E    # 重定向 HTTP 到 HTTPS5 U% P  K. [% X2 E7 \/ o# ?/ A; e! T
    return 301 https://$host$request_uri;
4 S8 y% A7 T1 L4 {1 i% v! j1 Q& z}
2 S) q/ N7 y+ m8 B) g) Z/ [" J. n
3 H: W4 F" T" Q# v1 userver {
' I7 T- z2 Y# Z  g6 C  ]+ {$ q; W    listen 443 ssl http2;
! q4 i7 p+ R# s. U    server_name your-domain.com;' V8 l" V* ^5 i% K1 J5 ]

  {9 [" K0 H. w    # SSL 证书(Let's Encrypt 免费证书)% l: }+ P7 M" k" t
    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
7 u3 v* |' V' Z( z- p/ j    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;7 N- ^1 m, j4 O9 T# @
    ssl_protocols TLSv1.2 TLSv1.3;0 j2 X: h- p6 P3 b8 k: K5 U. x

5 p" I1 ?. p$ M6 N% z- Y. G    # 反向代理到 PocketBase
6 ?) s% e! ]% n6 [$ P; w+ X    location / {6 @: R: ]- d8 o2 p
        proxy_pass http://127.0.0.1:8090;2 N4 `+ p  N5 v/ p4 n9 l
        proxy_set_header Host $host;( x! O0 d9 F  S' [$ J4 M: L" ^/ B  |" D
        proxy_set_header X-Real-IP $remote_addr;2 i0 e6 B# s% V/ p' A- X
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;/ `5 ]8 }, N' R4 y
        proxy_set_header X-Forwarded-Proto $scheme;
$ \6 O# ~# |$ u7 b$ U6 p+ W    }" o: g$ F6 @' N4 @  W1 B" I
}
' [' @$ W$ Y0 R! i3 [, J  Y, u  j# X</code></pre>
2 k8 c( t' Z; ~9 p. X, O" u</li>' S* k- f# |, |- C- |6 `
<li>启用配置并重启 Nginx:; l9 a9 `2 N! N- ?* j; l6 |
<pre><code class="language-bash">sudo ln -s /etc/nginx/sites-available/pocketbase-https /etc/nginx/sites-enabled/
! W( ]7 Y' H" T" e3 t3 zsudo nginx -t  # 校验配置语法
) B+ H6 E5 z  ]$ Usudo systemctl restart nginx
0 X+ j5 X( l% `; R5 `0 {</code></pre>
( {7 D2 B- I* D4 f</li>
- w" r& T7 z1 Q0 k<li>申请 Let's Encrypt 证书(Debian 12):
, \* f; G1 A& d( r<pre><code class="language-bash">sudo apt install certbot python3-certbot-nginx -y
' Z6 N; J: k. Q7 l+ X  ~sudo certbot --nginx -d your-domain.com8 ]1 s% n$ Y$ Y- X( j& C, g
</code></pre>
5 S- l, `4 h2 @9 y) E  M</li>
9 M! ~  C* R1 N% Q$ ?) z3 R</ol>" T/ x0 y. N; o7 L* N  g
<h3>2. 邮件配置(SMTP,用于密码重置/验证)</h3>1 N, b& O' R2 B" t
<p>PocketBase 需配置 SMTP 才能发送邮件(如用户注册验证、密码重置),以下是 Debian 12 下的配置步骤:</p>1 C; J6 N! m. `* F  e* B
<h4>方式1:管理后台可视化配置(推荐)</h4>
, i  I( T- G; l6 ]* ^. Q+ L<ol>2 |( E) U8 X9 R( }
<li>
9 x& _- g: t0 _* f<p>访问 <code>http://域名/_/</code> → 左侧「Settings」→「Mailer」;</p>
  Y2 R+ y+ T( _' i! E</li>: r, p$ j# |4 d8 c4 n  F5 S
<li>' a1 {. `; t9 J# c' R& Y
<p>填写 SMTP 信息(以腾讯企业邮/QQ 邮箱为例):</p>
2 Y5 o" J' z$ [+ Z  z+ s5 P% P<table>: X. ~& R( R" ^) Z
<thead>
( b1 H, f. w: k" ^. W& M; E7 g& I# U( {& _<tr>
. m( q& F3 _3 v8 x$ o/ @<th>配置项</th>& ]- n" ~9 o. ^* h9 x$ ?
<th>填写内容(QQ 邮箱)</th>
) [6 N& W# x+ F3 A$ O4 P# {; Q/ ?+ Y</tr>
5 c5 [: f* p6 F! a6 e4 Y' ~</thead>
5 h: O: g) I1 C  m$ J8 _3 w<tbody>: e% f: g) m% u3 `/ q) q/ y2 j
<tr>
  j- S; [3 n9 a<td>From address</td>
0 O: ~- z4 u. M- d. x  e% y<td>你的邮箱(如 <code>xxx@qq.com</code>)</td>, e# z- I& `1 U% ~
</tr>
4 e1 n4 q- h4 R' e8 H1 c0 P<tr>
) `+ e; o. y  F5 D7 |: t<td>From name</td>
% Z7 q) C) l9 h0 M8 B<td>PocketBase 应用(自定义)</td>
8 p: ?, A- b* v- i6 y</tr>
* o9 i9 ]6 ]$ H<tr>: f5 {* A& V3 A# B0 \
<td>SMTP host</td>; S  y( q! E, e) m' v* h+ Z& `7 e
<td>smtp.qq.com</td>6 s, y# \% `& K0 F2 U
</tr>  ]! r! z; h) |5 A4 X- c
<tr>, A* G* ?: {8 Z
<td>SMTP port</td>
1 }9 r& }$ I4 T- T0 U* }! D$ I<td>465(SSL)/587(TLS)</td>
' g' W0 Q8 {7 J</tr>
2 W' c% G5 g. ?, W<tr>
0 \6 v# k/ Q1 U$ S, F% S<td>SMTP username</td>
9 D# x$ k4 L; o* Y6 s  }<td>你的邮箱(如 <code>xxx@qq.com</code>)</td>' Q& E* _) l- T8 v
</tr>
. D7 r  l  F( ]$ H9 P, Q( _<tr>
6 p, T$ q4 l1 W# P<td>SMTP password</td>7 U. I3 q! ^1 A6 O; c
<td>邮箱授权码(非登录密码)</td>/ X% F7 ?4 `( y
</tr>
4 J7 V" A+ p8 v6 S0 b1 x; s; v% c& F<tr>
6 ~6 ~, G$ n* H1 p  h5 Z" Y1 C<td>SMTP secure</td>; O% Q% s- c! c; K* w( P- g
<td>SSL(对应 465 端口)/TLS(对应 587 端口)</td>/ Y. U! B9 Y% x$ B# f$ E# E
</tr>4 z. K6 [  p/ J/ x; Z1 k) `( N
</tbody>$ ^: N% H8 f5 d/ D" C
</table>8 F6 H& q" y, m: M1 g. a
</li>
2 U5 _# I/ S0 t, ]% B1 f, d$ Y% F/ r<li>$ e' o: i' J  g. S0 F
<p>点击「Test」测试邮件发送,成功后点击「Save」保存。</p>
3 m$ q1 G+ D4 a9 z- ?0 b</li>
. O/ z. ?/ Y( B</ol>! q8 }# i1 ]6 W0 Y
<h4>方式2:手动编辑配置文件(永久生效)</h4>, q$ t0 `' }9 b; A4 v
<ol>! c4 X6 g4 V) x$ t' @
<li>编辑 <code>pb_config.json</code>:4 O# h1 e8 m9 z# D; p3 r) N- Z3 E
<pre><code class="language-bash">nano /opt/pocketbase/pb_data/pb_config.json" [! r4 @& [8 s; T3 y
</code></pre>* M& ~7 R' e2 Y
</li>5 p* H9 J2 q: O" S! A
<li>添加/修改 <code>mailer</code> 节点:
6 j- m! B1 K  ?' I7 R<pre><code class="language-json">{
9 \7 W. z* L" w6 C  &quot;mailer&quot;: {' P+ G0 u( o2 B5 M$ `. x# U* }5 a; |
    &quot;fromAddress&quot;: &quot;xxx@qq.com&quot;,, ^: X9 @" N. Z* G
    &quot;fromName&quot;: &quot;PocketBase 应用&quot;,
4 [3 Z1 F8 X: @0 t- r; t  R; K+ Y    &quot;smtp&quot;: {, J2 P* Z5 @2 i5 _
      &quot;host&quot;: &quot;smtp.qq.com&quot;,% T3 P( o. o- k% k5 E. U3 X
      &quot;port&quot;: 465,
' t" K% b+ w, R) O! E; R      &quot;username&quot;: &quot;xxx@qq.com&quot;,4 H8 Q7 Q8 c% @
      &quot;password&quot;: &quot;你的邮箱授权码&quot;,
( _  _, d  b% E. p2 [      &quot;secure&quot;: true  // true=SSL,false=TLS
! S4 g/ {: B' Q  b$ ^    }7 [* H2 M: C  T# \3 i$ v. x1 y% |
  }
& T2 T% F' m) D4 j! A& H}: |! |- J3 ?! m5 S' L: r* }1 G
</code></pre>& A' m# L# k& \4 J
</li>% E4 f: R: _. z
<li>重启 PocketBase 生效。</li>% l& D- Q- }; D" {- b0 U$ ^
</ol>) C1 N& l5 T: p* D! A
<h3>3. 存储配置(本地/S3 兼容存储)</h3>' P& ?! b* W+ K. q
<p>PocketBase 默认将上传文件存储在 <code>pb_data/storage/</code>,可配置为 S3 兼容存储(如阿里云 OSS、腾讯云 COS)。</p>8 w2 L* s& P2 Z2 o( d) B0 |2 v. O
<h4>3.1 本地存储配置(默认,调整路径)</h4>5 D* n8 n# C6 [6 Y) O
<ol>
' c9 q% Z2 `0 R0 f; h8 b<li>编辑 <code>pb_config.json</code>:* `+ T; y' G( ^8 t8 [" \
<pre><code class="language-bash">nano /opt/pocketbase/pb_data/pb_config.json# \. E! L! G! y8 a& E  T
</code></pre>
; B+ I2 m. U/ ]* s</li># l  \5 U( |, `9 W
<li>修改 <code>storage</code> 节点(自定义本地存储路径):2 e+ Z' K# a1 B, h' }2 B) d: e/ k
<pre><code class="language-json">{
( b: @' ~; w9 b; |- @3 M  &quot;storage&quot;: {! R. k+ Z! t  _: g/ s0 H
    &quot;local&quot;: {9 G& o; Z$ v/ s: H0 y
      &quot;path&quot;: &quot;/data/pocketbase/storage&quot;  // 自定义存储路径(Debian 12 需提前创建)
. B5 j: D# E- \- j% ?7 X7 q, ~    },' L& P5 f- u4 A8 z5 {4 V
    &quot;active&quot;: &quot;local&quot;  // 启用本地存储* Z8 [% Z, F4 d/ @6 C' |* t5 Z
  }* x! k& c8 J. \' U3 k, S; v$ L
}8 Y$ r* g/ y2 I7 c) t" c) Z  ]
</code></pre># l+ c7 |5 W% @7 L& F
</li>
5 a$ U% _* I$ Y' u, |<li>创建自定义路径并授权:& t, {- u2 x8 m% o. F* l
<pre><code class="language-bash">sudo mkdir -p /data/pocketbase/storage
5 {) G# Z7 ^7 E& f: }- u. Ssudo chmod -R 755 /data/pocketbase/storage
6 S/ \$ B8 s' C: b+ Y+ b2 Wsudo chown -R root:root /data/pocketbase/storage3 E+ G# k" ~% G% l
</code></pre>' d0 d/ \0 `9 r' C+ l8 ^+ }
</li>
( \7 w0 u; x: I8 ]$ H. I<li>重启 PocketBase 生效。</li>
# T6 M2 y. h5 W6 ~3 T# T9 Z# \( R</ol>+ U0 V2 h+ g: l3 x2 f$ M& W& Q% c
<h4>3.2 S3 兼容存储配置(阿里云 OSS 示例)</h4># d4 {+ S& T% b+ i& n5 t0 ~
<ol>
% H: ~0 u. t/ Y5 g( ]/ M( J- b& {<li>编辑 <code>pb_config.json</code>:0 x8 A. e4 ?  H9 h
<pre><code class="language-json">{. k6 V! f1 Z! g3 I0 x4 U5 G
  &quot;storage&quot;: {5 O& B! l) U5 q
    &quot;s3&quot;: {
! F3 u5 o1 \$ f2 V      &quot;accessKeyID&quot;: &quot;你的阿里云 AccessKey ID&quot;,! u" c1 h' E3 g* l; L2 O
      &quot;secretAccessKey&quot;: &quot;你的阿里云 AccessKey Secret&quot;,
5 D' P) }& ^' X# J" N% E3 {, d' f; H8 J      &quot;region&quot;: &quot;oss-cn-beijing&quot;,  // 阿里云 OSS 地域
; D* a/ e( F6 {( o) `      &quot;bucket&quot;: &quot;your-bucket-name&quot;,  // OSS 桶名称
: J" q0 V. X1 X. k2 n      &quot;endpoint&quot;: &quot;oss-cn-beijing.aliyuncs.com&quot;,  // OSS 端点
0 D$ a; t9 P* S8 s" e/ R( B      &quot;disableSSL&quot;: false,
. l- B4 \& f* s      &quot;forcePathStyle&quot;: false
: h. R/ |7 W& Y+ l- c$ c    },1 f/ y$ C# L; S: }6 U
    &quot;active&quot;: &quot;s3&quot;  // 启用 S3 存储
4 u% Z# |( w3 X$ O; L* u# P3 X  }
4 M* `$ f0 O8 a0 v% f& c0 i. O}& M- F5 s% w% O: |  ?/ B
</code></pre>
* w% ^9 f9 I8 {0 |) O! h8 Z% v</li>
+ _- E$ |7 l% F; u5 V9 N- f<li>重启 PocketBase 生效,上传文件会自动存储到 OSS 桶。</li>
" z# ~: I5 @, B( ?) @# D; u& U</ol>
6 n$ D) H' b0 n5 j# L+ g% @<h3>4. 安全配置(跨域、认证、密码策略)</h3>
" N& n9 h: j) u, \<h4>4.1 跨域配置(CORS)</h4>5 s. m% p3 q' Z+ k
<h5>方式1:管理后台配置</h5>' k+ E+ `7 C8 \. _, J# G8 A' c
<ol>% Q3 Y2 ?( y: x# l4 e" k+ ~
<li>访问 <code>http://域名/_/</code> →「Settings」→「API」;</li>
5 V! h+ P8 v8 C) E# Y) v6 N<li>在「Allowed origins」中填写允许的跨域域名(如 <code>https://your-domain.com,http://localhost:3000</code>),多个域名用逗号分隔;</li>2 x% E9 ]! \) s4 n" |6 E7 [
<li>可选:开启「Allow credentials」(允许携带 Cookie/Token);</li>% G: o3 [) Y3 u; u5 J; y& ]
<li>保存后立即生效(无需重启)。</li>8 T4 f5 @) c- b7 o
</ol>
! ]* ]1 k, \; C: u<h5>方式2:配置文件配置</h5>
' s" K1 P% q2 ~' {' V: o/ u1 [<ol>
3 \5 j, b; q- w% f0 j. r- V<li>编辑 <code>pb_config.json</code>:- z$ l( c! g+ C8 h: v" N* Q/ f
<pre><code class="language-json">{$ _  ]8 d  o6 P+ I( _# O4 z
  &quot;api&quot;: {
. A9 Q* A' j" ~    &quot;allowedOrigins&quot;: [&quot;https://your-domain.com&quot;, &quot;http://localhost:3000&quot;],- h& C. I3 |3 r: R6 V
    &quot;allowCredentials&quot;: true) ]" S; o  \! G0 C& Z0 ~
  }; C9 K4 W8 v) T. ?; `
}. m5 z; u' y$ j9 f- x6 y
</code></pre>
! K. V6 O1 p5 K/ g</li>
$ h& S, |9 d, u* K: A3 U; j- l: ]' U<li>重启 PocketBase 生效。</li>6 l; A$ o( @9 {5 E& g7 W
</ol>
9 `% c. I7 _! v& }<h4>4.2 认证安全配置(Token 超时、密码策略)</h4># e# F' j# L6 W% P% |( ], e
<ol>( V& D% Z0 l+ I. s4 a6 c
<li>
, Y( m0 o! V- @<p>管理后台配置路径:<code>Settings</code> →「Auth」;</p>
# }/ z: s* d8 ~5 F</li>
: g9 B, G4 X! P6 J9 J<li>
0 l- l! k6 g; W! ^+ M<p>核心配置项:</p>5 D+ b7 l! P$ d
<table>
1 H; b! y$ r) w  L<thead>
" e' I& M" W# E$ S<tr>
# @$ L* T) e* x! S6 L3 C- X& {<th>配置项</th>
& M/ E' n+ D3 |( G8 w2 i. w) h/ R<th>作用</th>& E! c9 q- F7 y9 z: l! J
</tr>0 h2 o. k* Q$ \0 h
</thead>
2 |: M! T5 k' t1 z4 [6 P3 W<tbody>
6 S! ?" P) p9 i( r+ H. G% g5 \$ b8 `<tr>
0 F# h$ v2 `; G( v% f<td>Token duration</td>
* f, G% _) o8 A2 s8 u2 V<td>用户 Token 有效期(如 7d=7 天,1h=1 小时)</td>) ^+ J/ P3 y' o% K) [
</tr>. P! r; Q) m- q1 x! a. v
<tr>
' H+ Y1 h0 s6 m) s+ b6 z/ e6 {/ Z/ I<td>Password min length</td>
$ d* m, j* U" U4 g2 N<td>用户密码最小长度(推荐 ≥8)</td>5 o1 m/ L6 q* B; V
</tr>
! N  T5 [) {5 L9 V( N<tr>
1 }: E. s% R! ~<td>Password require chars</td>
, N" d- r) @5 M: ?8 C+ _3 D' _<td>密码复杂度(是否要求大小写、数字、特殊字符)</td>
- b' s, J8 U4 O! m" L/ B: b) S</tr>
1 W0 b, D' @' ~& i<tr>6 l# D) g+ h3 t. I: D1 P
<td>Max failed attempts</td>
9 c  z! Q& D: b" {! ]<td>登录失败最大次数(超过后锁定账号)</td>
* b* k) q8 k" T8 h, x2 t: T* H5 ]- y</tr>4 ?6 z8 E- @4 W* v4 h4 _& M8 V% {
</tbody>
& Y* m% n" q" ^9 a' m5 U</table>) t3 ^! t! k2 l
</li>
7 y- X: ?3 k: K5 S5 T2 e) D<li>% u1 p7 W  e9 z
<p>保存后立即生效。</p>
6 A3 d3 c- `+ V, @$ Y2 |</li>8 r! A& m# g: d/ \& V3 u
</ol>
# E$ s6 W- T; s+ N! e. ~) o0 V<h4>4.3 管理后台安全配置</h4>
% j) h7 {7 V- u% l8 n<ol>
0 K; g/ X6 V9 D<li>限制管理后台访问 IP(Debian 12 防火墙):
6 a, s" S- m" l' w<pre><code class="language-bash"># 仅允许 192.168.1.100 访问 8090 端口(管理后台)
* P: o7 y- C9 \: N: v7 ]! |sudo ufw allow from 192.168.1.100 to any port 8090" L4 N: J  |9 D5 j' f* g: Z1 a, Y/ q$ G
sudo ufw reload
: }( G$ v) E! z$ D# r% ^* V2 i</code></pre>+ U+ B* O, |* K. [- X4 n0 @
</li>0 u" w2 r) c, L8 E
<li>或通过钩子拦截(推荐,见前文请求拦截示例)。</li>' h+ V2 B) {0 J9 d, z5 R: N
</ol>. S! t* V) l* P( @9 m3 J
<h3>5. 应用基础配置(名称、日志、时区)</h3>
# _) K2 [, ?9 ?5 A2 G: P<h4>5.1 应用名称/描述配置</h4>
9 H: _/ K( u) E1 A8 J% O" `0 h5 I' s<ol>; D# v2 H! P) ^' D
<li>编辑 <code>pb_config.json</code>:& \9 }; r/ J' D3 F8 N
<pre><code class="language-json">{
. [4 Y- a' _1 n- f  &quot;app&quot;: {# `. r5 w* Z4 @
    &quot;name&quot;: &quot;我的 PocketBase 应用&quot;,
) h, o  @7 \; f5 L* J    &quot;url&quot;: &quot;https://your-domain.com&quot;,3 e& o! Y9 w  e+ l! U
    &quot;description&quot;: &quot;基于 PocketBase 的后端服务&quot;( \2 T- ~  I$ ~
  }
6 t; L4 j* \; a0 k$ o; G( \}$ O- ?& D' E7 }. r; s) T
</code></pre>& W) J, ~# j3 k1 f
</li>
' ]% \0 f, l) g$ j5 C6 |7 C<li>重启生效。</li>2 ]( W4 n6 H& p! X" b1 L3 ^+ v" P
</ol>
! ^* h' I5 O1 A/ L$ Z<h4>5.2 日志配置(Debian 12 持久化日志)</h4>5 d  P. P% E+ N0 G. V. D. F6 H
<ol>& R% |! p0 ^- k4 [7 A) H
<li>编辑 <code>pb_config.json</code>:
, X+ g% p$ N3 e! m<pre><code class="language-json">{
, t. M: ~% ?0 b$ |$ }! i  &quot;logs&quot;: {
! e  `/ J! k' U* |2 |/ b: ?    &quot;level&quot;: &quot;info&quot;,  // 日志级别:debug/info/warn/error
8 G0 y! X; r) E+ N+ G& j6 Y    &quot;file&quot;: &quot;/var/log/pocketbase/pb.log&quot;  // 日志文件路径(Debian 12), o4 [2 c: |/ y9 \
  }$ g5 T' `# s2 [$ E4 J: z
}% }6 f  a" q+ h
</code></pre>
! T. `- o; ^! a, R# Z) \# c</li>
1 e6 A, u1 ^. O5 ]* f3 h<li>创建日志目录并授权:
4 \, L: S5 a; P<pre><code class="language-bash">sudo mkdir -p /var/log/pocketbase' @9 L6 ]$ Z; H
sudo chmod -R 755 /var/log/pocketbase8 ?8 V4 o1 z2 T/ e+ s; |( S
sudo chown -R root:root /var/log/pocketbase
8 m( K* s9 ?8 }. G0 l; v& v- F% r</code></pre>$ x+ L+ t1 a1 W- `6 V8 u
</li>
+ X* k0 j1 _. P6 E7 N4 e# T<li>重启 PocketBase 生效,日志会自动写入 <code>/var/log/pocketbase/pb.log</code>。</li>: I9 A( C- p* O- g! O( w
</ol>
0 v- G: q8 U0 O  P<h4>5.3 时区配置(Debian 12 系统时区同步)</h4>
% D5 }* E; _( n% z$ f7 g+ M<ol>& g) B3 F. P* @3 m
<li>先设置 Debian 12 系统时区:
. x1 v; M% A1 @/ v; ?. M<pre><code class="language-bash">sudo timedatectl set-timezone Asia/Shanghai
* t/ Y# I4 u( A/ D</code></pre>
  A) R2 |7 X+ v0 ]( d</li>. T0 u: D! l4 g7 K1 C4 W
<li>PocketBase 会自动同步系统时区,无需额外配置;若需手动指定,可通过启动参数:9 E; {0 U! R2 l6 M& v9 `
<pre><code class="language-bash">./pocketbase serve --timezone=Asia/Shanghai" R0 z9 f! U3 R
</code></pre># E6 _6 Q4 W! L
</li>1 d  n. x6 ^6 G  l) U$ j9 K
</ol>8 M" I2 o$ Y8 i1 Y9 J( q$ k& H" W
<h3>6. 自定义配置(钩子脚本补充)</h3>6 |( g4 u4 ?6 J3 j7 v) ]4 |
<p>对于配置文件无法实现的自定义需求,通过 <code>pb_hooks/</code> 脚本补充:</p>  _. T- t# ~7 `7 M# h7 ~& c
<h4>示例:动态跨域配置(根据请求域名放行)</h4>
$ k- z- c. J: E9 ]<pre><code class="language-javascript">// pb_hooks/cors.hooks.js
& j" y6 m$ m0 b( j  ?7 U  `onHttpRequest((e) =&gt; {% |- O2 r/ t, c7 a. [! ?7 `
  // 动态允许所有子域名跨域
5 z# [, e  b! v3 ^* w  const origin = e.request.headers.get(&quot;Origin&quot;);
; Y4 [6 g9 K2 r2 M  if (origin &amp;&amp; origin.endsWith(&quot;.your-domain.com&quot;)) {
6 E& o0 j9 v' e6 K. v* c    e.response.headers.set(&quot;Access-Control-Allow-Origin&quot;, origin);2 A  F: c( |$ z* Y
    e.response.headers.set(&quot;Access-Control-Allow-Credentials&quot;, &quot;true&quot;);
0 J# B% L+ ]* t1 N# D: u  }
# b% X' ?0 H$ H  e.next();, X4 f4 y% t! Q9 u' `5 ~# G9 ]
});' A: m( P1 ~' v: c# Z) i
</code></pre>
% {; u% ^* a7 f8 O7 Y9 L! v<h2>四、配置的备份、恢复与生效方式</h2>
/ }/ t- H& z0 o/ q<h3>1. 配置生效方式</h3>
3 m) p1 @1 ^% p/ U<table>
  \' C4 Y# }2 `$ b  \! ~<thead>9 I. o- L( }- t
<tr>
: c' t0 c' c0 ^<th>配置类型</th>% y# f" g! \1 }0 b' n, p$ j# p
<th>生效方式</th>' b  J* x, w/ D2 f$ u5 j
</tr>
. _0 y2 ^( J7 M$ p</thead>
  A( i; c7 m  F" Y& H. F. t<tbody>
. s; q$ x0 I! m  X6 o, ~<tr>
: H" [# C, V" e<td>命令行参数</td>. F/ ?2 s) [- O& P% z
<td>启动时立即生效(临时)</td>! ^0 N' U" R8 g$ `" H
</tr>
& X1 m: O( U) N( ]/ C. y<tr>* f6 m! E& x, D5 _' \9 K9 ]
<td>管理后台配置</td>: }! J! m% L1 w
<td>保存后立即生效(部分需重启,如邮件)</td>
. s" [( S/ r6 a, t$ V& Y3 x% V& _</tr>1 X9 j' |7 ~3 z; ?1 y" T, m+ o) @
<tr>
+ S- G" W5 b% ?  S! g* Q<td>配置文件修改</td>
3 @' U6 i, ?) Z5 Z" N+ I<td>重启 PocketBase 生效</td>
/ ^) \* f5 I/ z( z; m* S; @</tr>" L, E% ^1 @/ ]# H
<tr>
: p4 `( _% O* O* O<td>钩子脚本</td>! @4 l$ Z* x0 j% T2 k8 m1 U
<td>重启 PocketBase 生效</td>
( Q& {6 O) B3 f# U0 T/ n  p</tr>: h# U* x3 O% C$ w' V
</tbody>/ D4 D  A4 j! R# }) @0 j# z
</table>
. ?  _9 s6 h* C3 S6 t: c<h3>2. 配置备份(Debian 12)</h3>8 w* C9 S& [2 R$ m8 M
<pre><code class="language-bash"># 备份 pb_config.json(核心配置文件)# J+ f. ?! |; ]/ j$ K3 b" |3 C
cp /opt/pocketbase/pb_data/pb_config.json /opt/pocketbase/pb_config.backup.json* \! b& x1 X! i3 V
& v4 a' B7 Q. f. M
# 完整备份所有配置+数据(推荐)
% r$ S9 z1 X# b2 fzip -r /opt/pocketbase_backup_$(date +%Y%m%d).zip /opt/pocketbase/pb_data/
6 S. L( y7 _$ s2 ^5 M0 L</code></pre>
& W) `9 U  ^6 \: w<h3>3. 配置恢复</h3>
2 a( P/ ?- R; g( Y7 v<pre><code class="language-bash"># 恢复配置文件1 S8 d/ {4 X" R  N8 w8 M/ h
cp /opt/pocketbase/pb_config.backup.json /opt/pocketbase/pb_data/pb_config.json8 s  n/ O$ U2 D! `! e5 L

5 |+ ^# K. [2 F; W9 O# 重启 PocketBase/ B& K- R, {" F- m: D
sudo systemctl restart pocketbase
$ U; I. A& ?7 i5 f: M</code></pre>
- ^; c. q% d, B" u<h3>4. 常见配置问题排查</h3># s  H! I' J+ U( x0 Q5 R8 W
<h4>问题1:配置修改后不生效</h4>' X8 B4 Y/ O) |4 B* y: l! q  E7 a
<ul>
$ O4 R6 x. K# a3 D! ]% d<li>检查是否重启 PocketBase;</li>
. i, b& T! w1 ?& L0 s0 B! k3 p<li>检查配置文件语法(JSON 格式是否正确,可通过 <code>https://jsonlint.com/</code> 校验);</li>
6 u4 K  h$ H. c$ ]+ q& ?<li>检查配置文件权限(是否可读写)。</li>  D9 P3 b* |# i5 N
</ul>9 ~% [+ v: v6 {; d/ _9 {' O( D
<h4>问题2:邮件发送失败</h4>
8 N6 E* X9 N0 e- i, Y<ul>
% t( R1 u  b, ~% b: ]) ]' W<li>检查 SMTP 端口是否开放(Debian 12 防火墙/云服务器安全组);</li>3 z* R: p9 F: u: X7 j! {2 x2 L
<li>验证 SMTP 账号/授权码是否正确;</li>
+ T: X! {3 }3 E/ _, n. l  C<li>查看 PocketBase 日志:<code>sudo journalctl -u pocketbase -f</code>。</li>- u# \5 t" A6 a, V
</ul>
* d% F8 A/ f' x$ a8 a5 J/ S<h4>问题3:端口无法访问</h4>
  x6 `0 F+ C% L5 e/ i7 ]<ul>
' L8 u0 Q: o2 S$ O1 U9 z/ U<li>检查 Debian 12 防火墙:<code>sudo ufw status</code>;</li>, i  |  i0 d4 u5 N8 a
<li>检查云服务器安全组是否开放端口;</li>: v- U' M; m1 i$ M2 G0 p
<li>检查 PocketBase 绑定地址(是否为 <code>0.0.0.0</code>,而非 <code>127.0.0.1</code>)。</li>
' [* \  R/ o0 \9 [4 }0 W- L1 Z</ul>
; [$ W1 m4 p7 l3 m<h2>五、总结</h2>
& M9 N! T# U( Z% m<ol>
! U0 V  E* r9 f/ L/ C4 C% ]<li><strong>配置核心入口</strong>:
) r* K0 }* V! W0 _' J7 E<ul>
* J0 T; F# l. R6 n' k<li>基础配置(网络、邮件、存储)优先通过 <code>pb_config.json</code> 或管理后台配置(永久生效);</li>
4 A$ Q1 U4 z  L/ d  H<li>临时测试用命令行参数(重启失效);</li>
( u7 L( F6 C" S9 t; @<li>自定义逻辑用钩子脚本补充。</li>0 w2 }; b) B0 l' s& k  o
</ul>9 u8 M0 G9 k5 Y- \/ }" W$ I! j
</li>& B; \- m& ~$ ]+ y& _& f- y7 f
<li><strong>Debian 12 关键操作</strong>:! s2 t( J0 u. {: g) r6 I* B
<ul>' `  U" R& ~) P) z
<li>修改配置文件后需重启 PocketBase(systemctl/堡塔面板);</li>( I# B* B& j7 ^; x' m' _
<li>自定义路径(存储/日志)需提前创建并授权;</li>
" H! |& S3 b3 a<li>HTTPS 推荐用 Nginx 反向代理,而非 PocketBase 内置方式。</li>2 o" _  ^# I$ f! B! `8 m
</ul>1 z* @6 ~) ]' M3 v- S+ H1 z
</li>
7 l9 P1 X! A1 }& {2 W5 ^<li><strong>生产环境必配</strong>:
, W- ]  o4 O. m6 k  U$ J<ul>' |% t' N# G# a4 b
<li>邮件配置(密码重置)、HTTPS(安全访问)、跨域配置(前端访问)、日志持久化(排查问题);</li>. h* L( d: f6 F. g3 W
<li>配置文件定期备份,避免丢失。</li>8 ]2 e9 y2 q7 {! a: p; g: L  E% h
</ul>: X* p! v, J$ X) a$ ?
</li>
9 L5 ^) M& p% |; g! R</ol>
! {/ a  C, f: B# u& _4 S<p>通过以上配置,可完全适配 Debian 12 系统下 PocketBase 的生产环境需求,兼顾安全性、稳定性和自定义性。</p>
3 c+ [9 |' O0 B/ N2 J+ p
匠心独运,千锤百炼,品质非凡。
回复

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

您需要 登录 后才可以回复,轻松玩转社区,没有帐号?立即注册
快速回复
关灯 在本版发帖
扫一扫添加微信客服
QQ客服返回顶部
快速回复 返回顶部 返回列表