返回列表 发布新帖

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

411 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>6 v+ n9 w: {" m7 j; R
<h1>PocketBase 基于 Debian 12 的详细使用指南</h1>
, x# Q1 Q( |9 x0 K; x9 ~<h2>一、核心需求确认</h2>$ m) A1 e/ M/ g5 i, Q/ M7 D4 |
<p>你需要一份面向 Debian 12 系统的 PocketBase 完整操作手册,涵盖从环境准备、安装部署到日常运维的全流程,并以 Markdown 格式整理,方便查阅和使用。</p>) b% Y$ R/ x. [3 W7 V) D
<h2>二、PocketBase 详细操作指南</h2>. c  @1 O5 ~  y3 z0 R. |( N
<h3>1. 什么是 PocketBase</h3>
& x8 d; b1 n+ ]. r- C<p>PocketBase 是一个开源的、轻量级的后端即服务(BaaS),集成了实时数据库、认证系统、文件存储和 REST API,单二进制文件运行,无需额外依赖,非常适合小型项目、原型开发或个人项目。</p>
8 j! E  A# ?# S* D3 L* i<h3>2. 环境准备(Debian 12)</h3>
5 h; D9 {  W' C$ g* D<h4>2.1 系统基础检查与更新</h4>$ @0 ~! \; r5 M& I6 E# }
<p>首先确保 Debian 12 系统为最新状态,执行以下命令:</p>0 W( ^& t' {% e  H2 Z0 w5 i2 c: {
<pre><code class="language-bash"># 更新软件包索引
% Y: o: k/ }6 B+ isudo apt update -y6 J% }4 k5 O3 j4 l* \0 p) n" j0 {

* y) J3 r% h" i# J6 L8 X( F# 升级已安装的软件包
) o- s- V3 v3 {9 usudo apt upgrade -y
0 b+ P: x+ _# D8 R, C) O, g: ], }3 c' a9 ~& i( e3 N
# 安装必要的基础工具(curl、unzip、wget)
0 e7 g& h2 {4 I+ }% nsudo apt install curl unzip wget -y
3 c+ k% b5 o. p8 _) x# n  E) b7 M( X6 h
# 检查系统架构(PocketBase 需匹配架构下载)" ~! F" p4 V9 ^  q; M
uname -m& t5 |2 H6 {; o, r/ X' s- ^( r5 k
# 常见输出:x86_64(amd64)、aarch64(arm64)  Q7 M7 G1 _, l5 N
</code></pre>$ n1 Q# p6 s+ t0 s& C
<h4>2.2 防火墙配置(可选但推荐)</h4>
" E" v' [- O7 m- `' X+ H<p>PocketBase 默认使用 8090 端口,需开放该端口:</p>
1 M2 [3 @3 I/ S% I! j5 X<pre><code class="language-bash"># 查看防火墙状态
% E  ?5 G; u5 B* u) Q/ c4 H# Osudo ufw status4 o$ B8 e4 \% w2 I% A5 n
$ h0 _& ~$ x  {% M, |" R! B9 ?
# 若未启用,先启用防火墙! o* f( Z7 u( N! F" k4 i0 \( H
sudo ufw enable& G3 B9 A. z' f' b% A+ F' c

  z; ?* u. K, i/ E% c3 O# 开放 8090 端口) \* b3 P  Y9 F/ r0 o/ z6 c
sudo ufw allow 8090/tcp
+ u' ?/ D" i) D- A, ?- p3 k' _1 ]( t1 E- N9 d
# 重载防火墙规则
; U* W% d0 ^. F8 }sudo ufw reload
& _5 g: E7 d  q1 ~8 p" v7 y; j</code></pre>8 }+ G8 O# U7 \- ^" I1 i1 N
<h3>3. PocketBase 安装</h3>
5 O' k# N+ V, J2 D, n1 ~<h4>3.1 下载 PocketBase 二进制文件</h4>
3 p- {: u3 k9 _* k& G/ s<p>根据系统架构下载对应版本(以最新稳定版为例):</p>5 X% S* C, V9 R, v7 n6 F; A) L9 Q
<pre><code class="language-bash"># 创建 PocketBase 工作目录(推荐)
3 D/ F) X) }1 [2 A4 G/ \" T+ y& u) dmkdir -p /opt/pocketbase
  k5 [8 l7 ]1 M) ]; X) }8 [cd /opt/pocketbase# f- L( L1 H2 A! v3 K7 k0 g- [: c
8 q) B4 |, @- ?! c; ?( B
# 下载 amd64 架构版本(Debian 12 服务器主流架构)8 k; l  |0 \; R% c  }. Q" T& {( G
wget https://github.com/pocketbase/pocketbase/releases/latest/download/pocketbase_linux_amd64.zip
: A+ X) x% N* [; j# s2 {4 k9 I% v% t, I
# 若为 arm64 架构,替换为:
+ d0 W. m5 z: }# wget https://github.com/pocketbase/pocketbase/releases/latest/download/pocketbase_linux_arm64.zip8 I& }) n( ]- T8 U9 o

$ p; h/ P1 T+ T% _. t6 |# 解压文件
$ [2 K- m9 i' [- T- r" w( \unzip pocketbase_linux_*.zip
8 l9 l+ x) U6 {8 e' D0 F! }0 Y+ X' G1 g
# 删除压缩包
/ f7 r2 a) h/ J* m" U8 n3 a& v2 D8 Xrm pocketbase_linux_*.zip
3 ]( _, X4 n7 y8 t: s2 F7 L8 @0 U) k. A6 _$ a7 u0 t0 l  \
# 添加执行权限
. {+ Z& e! e2 f5 Z4 {chmod +x pocketbase
+ p) E, p( Z1 @) U" U* ^% F% n  e  D$ O6 M% @' y
# 验证安装(查看版本)# d1 X" D6 s' v1 Y
./pocketbase version+ V1 \+ D( u: l5 R6 w9 i2 y' L
</code></pre>5 k) O# x; b' f6 x% N. U% P' h& k
<h4>3.2 测试运行</h4>7 m) I5 `% l" o) g
<pre><code class="language-bash"># 首次运行 PocketBase
& f7 q( D7 l" X& q% ^./pocketbase serve6 D2 k/ c6 L/ f& y+ V: ^6 q9 e5 e# U
: j' J- Z; `# {+ ?- K# c8 W; `) |
# 运行成功后,终端会输出:0 d) G0 |  k$ C( R
# &gt; Server started at http://0.0.0.0:8090
: K# B/ N4 m' P" C# &gt; REST API: http://0.0.0.0:8090/api/
7 Z) J) C+ O: I" S3 o% s# &gt; Admin UI: http://0.0.0.0:8090/_/* Y6 `0 |# Q( V% g
</code></pre>
& \5 h0 o4 h0 y<p>此时可通过 <code>http://你的服务器IP:8090/_/</code> 访问管理后台,首次访问会要求创建管理员账号(用户名/密码)。</p>
' x- L6 c) C5 T( v8 g2 `1 W<h3>4. PocketBase 基础使用</h3>
) r* t( B9 F; D9 r& q<h4>4.1 管理员后台操作</h4>
7 M& k9 D5 x! x<ol>
$ I- L; |; ^& V: K& k<li>访问 <code>http://服务器IP:8090/_/</code>,输入首次创建的管理员账号登录;</li>
' T4 S( T3 \% F  c1 r$ @3 d" h<li><strong>创建数据集合(Collections)</strong>:$ a: Z" P$ `: Y. s* v1 t0 \& _
<ul>
$ u7 y. W- u, J4 o- f" P! X<li>点击左侧「Collections」→「New collection」;</li>% s. V3 Y- Q5 m# ?/ X3 f. Q
<li>填写集合名称(如 <code>users</code>)、类型(Base model);</li>5 S# h  I! |5 R* k# B; n
<li>添加字段(如 <code>username</code>(Text)、<code>email</code>(Email)、<code>age</code>(Number));</li>3 e' x2 H* A" ~8 ?; f8 D, P% N
<li>保存后即可通过 API 操作该集合数据。</li>
& P2 t9 C. ?( R</ul>2 r" [) g# t. `* ]7 w
</li>9 r  ^; @# Q" J  }% W
<li><strong>权限配置</strong>:可针对集合设置「Create/Read/Update/Delete」权限(如开放匿名只读、仅管理员可写等)。</li>
" X) u* _% K3 I" k) ]' }& T4 k</ol>/ P3 n3 |& V: T5 \1 _
<h4>4.2 基础 API 使用</h4>9 d- x2 E; l5 F6 K" f  k& c: V
<p>以 <code>users</code> 集合为例,通过 curl 测试 API:</p>6 W( t1 p3 l% b* \  _( P
<pre><code class="language-bash"># 1. 创建一条用户数据(需管理员认证,先获取 token)
8 `: x4 Y/ c; _# 获取管理员 token
* u4 w5 J5 @& R, ]4 Z$ j: GADMIN_TOKEN=$(curl -X POST http://服务器IP:8090/api/admins/auth-with-password \
/ V1 R% H0 I* }3 Y. b1 C) M  -H &quot;Content-Type: application/json&quot; \
0 d& h# w5 W- b5 R2 p1 V  -d '{&quot;identity&quot;:&quot;你的管理员邮箱&quot;,&quot;password&quot;:&quot;你的管理员密码&quot;}' | jq -r '.token'): A2 ^4 [! }& G9 [9 G9 G- c
8 U; r$ h9 T; v' r
# 创建用户
$ I  R& z0 Q/ a% Y; _curl -X POST http://服务器IP:8090/api/collections/users/records \. w: P* n, V6 m2 P, C
  -H &quot;Content-Type: application/json&quot; \
/ R8 q- o8 h+ Y2 w6 j  -H &quot;Authorization: Admin $ADMIN_TOKEN&quot; \) W$ z7 r5 |1 [$ g) j6 H; x- j* i$ \
  -d '{&quot;username&quot;:&quot;testuser&quot;,&quot;email&quot;:&quot;test@example.com&quot;,&quot;age&quot;:25}'4 i& M1 R; M3 t2 o1 z' l, b, H. \" D
: B# A$ |; I& h5 e" t/ p
# 2. 查询所有用户数据(匿名访问,需先开放 users 集合的 Read 权限)& L5 S$ K' c+ D9 L' e( v: X
curl http://服务器IP:8090/api/collections/users/records( _3 I# ]2 f) B' s: D6 n/ |$ B
</code></pre>/ U/ h" r% ~* E* a
<h3>5. 进阶配置(生产环境必备)</h3>
  F7 g$ D$ J* S! {<h4>5.1 将 PocketBase 配置为系统服务(开机自启)</h4>
& d3 e0 w5 ~4 w# j+ t: B<p>创建 systemd 服务文件,确保 PocketBase 后台运行且开机自启:</p>
& ]' Y  b, D& O: ~<pre><code class="language-bash"># 创建服务文件# {) L; v! I( U# r) F( s
sudo nano /etc/systemd/system/pocketbase.service# s. L( \" H" v' a& S! G
</code></pre>
, x, I9 y% r. N: r% C# _: k, ~% ^<p>粘贴以下内容(修改 <code>User</code> 和 <code>WorkingDirectory</code> 为实际路径):</p>3 N+ s6 N/ _: R% P
<pre><code class="language-ini">[Unit]
7 V# U% c4 c$ q$ A1 nDescription=PocketBase Service7 a; x; J! C1 V
After=network.target9 ]! W5 K6 ^5 }

4 r0 n7 ^$ Q1 ^6 _. M# N9 W$ c[Service]: S" _$ x1 V: J7 h5 L' A, c
Type=simple, K( Q7 |- x+ b$ Z5 h" k4 ^
User=root  # 推荐使用非 root 用户,如创建 pocketbase 用户  Q+ H1 c/ ?5 f
WorkingDirectory=/opt/pocketbase0 N# ?! e; F  s4 P3 E" T! R5 b* A
ExecStart=/opt/pocketbase/pocketbase serve --http=0.0.0.0:8090
) U/ ~2 T% A$ F: K! ~. `* vRestart=always
( h$ f# @% ]; \3 X; xRestartSec=59 ~$ j, y/ y  r) D3 u0 I
StandardOutput=journal+console2 z6 j" I* Q8 \4 }" B, s0 q
StandardError=journal+console
5 b5 d. V, H- L. b" J, F7 `* g  N3 ^7 E7 ^9 w
[Install]- e7 k- I  U, I
WantedBy=multi-user.target
* R8 o$ b0 o9 O</code></pre>
4 u, _- L0 [/ ]; Z( ^# G% o# P' p<p>保存后执行以下命令启用服务:</p>
: d& |7 a+ D9 [6 W( u% B) X% k0 C<pre><code class="language-bash"># 重新加载 systemd 配置2 N8 v; n0 K0 R4 m) t, z, X
sudo systemctl daemon-reload! @* A8 C/ f$ X2 Y2 R

2 _9 b" q( A, M( g# 启动 PocketBase 服务: g  c7 \+ \' j6 H" \) p
sudo systemctl start pocketbase0 g8 _# S4 v1 P  s5 G' i; q& ]

1 s7 C, u* _( g1 \7 u# 设置开机自启7 p2 v' h6 l+ a3 `% I. G5 q+ X* S1 h
sudo systemctl enable pocketbase
; x1 S$ T9 k; F; z7 f5 }( C
: u9 H* L/ k& c9 B2 A$ E* n# 查看服务状态' F8 ^/ {6 D$ w/ l# d
sudo systemctl status pocketbase
! h7 x% f- Z: J% Q, O</code></pre>
1 r0 E3 j  h- x( c4 h9 |4 i/ ?<h4>5.2 配置 HTTPS(推荐)</h4>
4 M: t  S5 }5 j7 I5 l6 c<p>PocketBase 本身不直接支持 HTTPS,需通过 Nginx 反向代理实现:</p>
7 @4 c) R" ]: N2 Z  {" a<ol>
. |  P2 D# x% t, N5 L2 @<li>安装 Nginx:
* O$ p7 \1 B5 e6 d<pre><code class="language-bash">sudo apt install nginx -y
# W7 U1 p0 W7 q/ e+ f, K. Z" V1 r</code></pre>! {4 C* x: y8 h3 v* H0 ]9 d
</li>! Y9 E+ X5 S' `3 r/ p; O
<li>创建 Nginx 配置文件:
6 w* H; S) w7 T& }5 D<pre><code class="language-bash">sudo nano /etc/nginx/sites-available/pocketbase  v+ w$ y" N' M1 I
</code></pre>
6 O4 ?; Y* ~; T! z5 u</li>7 g' S4 ~+ ]; b3 J
<li>粘贴以下配置(替换 <code>your-domain.com</code> 为你的域名):3 Y. n/ _. v& _" i
<pre><code class="language-nginx">server {7 l& P( G/ l5 l+ C  N6 G
    listen 80;* ~" Y1 }+ ^: |( w, C) d0 U: X5 A
    server_name your-domain.com;
9 b: _' B, {4 {1 s2 L+ w/ r    # 重定向 HTTP 到 HTTPS2 }2 o: b9 z  [) c2 p; ~
    return 301 https://$host$request_uri;
& R& c. B3 o1 x1 n5 L9 v# o}/ S- ?4 d; r. X' }, ^
: W% b; Z8 ?, d: ^9 k6 V. c8 A2 i7 H
server {' t' N( q% \! \" n* R- y9 k2 f! _
    listen 443 ssl http2;  w# E8 u0 B9 V2 Q6 v$ o
    server_name your-domain.com;
  U$ _9 K1 |4 w( W5 q4 k7 O8 |
& K; w5 K) E& a5 S" H. a    # SSL 证书配置(推荐使用 Let's Encrypt)
! I; U+ E0 v( g4 {6 s1 S    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;5 d0 _. e/ K- s9 d2 x( n) e' X
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;% M2 t+ m3 H7 z: y. \  ~
    ssl_protocols TLSv1.2 TLSv1.3;
% r/ l& _' x, d5 r' @    ssl_prefer_server_ciphers on;
0 q' q: B% H0 M. A3 n+ i# k
% r$ s# W8 B8 l; H6 F0 I    # 反向代理到 PocketBase1 Y- V/ {4 T# P5 \) z4 {0 g3 G' }- _
    location / {
6 [. q9 m7 M% Q        proxy_pass http://127.0.0.1:8090;
5 U& x6 Z8 `, W$ O0 t( @+ ]0 n3 B$ P( S+ U        proxy_set_header Host $host;
& O; `1 |: x: w6 A5 v, C5 Z' @        proxy_set_header X-Real-IP $remote_addr;
4 m8 C2 V" _; y        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;8 K/ u6 B/ u! G1 I
        proxy_set_header X-Forwarded-Proto $scheme;
/ U0 [$ N# y! ?# q    }
; z$ I. |1 t$ i7 N, _1 Z. C}2 ]; n9 C, v( B3 X. M* D& F
</code></pre>" V/ V) `  x' U+ @6 M) L
</li>7 o) M2 t4 x0 M( f
<li>启用配置并重启 Nginx:
% c, R$ `( q9 T6 x5 v<pre><code class="language-bash"># 启用配置- Q( B. R5 z' T& v! P# W8 d3 \8 x
sudo ln -s /etc/nginx/sites-available/pocketbase /etc/nginx/sites-enabled/
/ v" I  V( ]: S0 V& t& `4 P# k6 f3 ^' z; z5 ]0 ^( A
# 检查配置语法
* r1 O' b- g, N1 ^- t6 e! Isudo nginx -t
0 s+ X4 |, [/ c! y
, N) Y% a9 f- U9 b# 重启 Nginx
. s9 d! ^. ]: Osudo systemctl restart nginx
9 R) o8 h  L' s2 |</code></pre>& P# j% ^5 A0 y& ^8 N: M
</li>; _# J8 P( [0 l% I* k
<li>申请 Let's Encrypt 免费证书(可选):6 s3 l1 \/ Y  Y7 o; G" [
<pre><code class="language-bash"># 安装 certbot5 A# b8 c  i" `7 a9 G
sudo apt install certbot python3-certbot-nginx -y
9 S" l" {1 G9 P  x7 e+ z. f. |3 J& ^( M
# 申请证书
9 r. t0 f! E- }. f# ?( g0 [0 ?sudo certbot --nginx -d your-domain.com, m2 [- `0 G8 U3 H& C2 j& T
</code></pre>; _& a, N# A- s1 a" Y
</li>
+ w3 {  Y+ s$ \( w</ol>
5 B5 g+ d8 o8 L* s. R8 b# D<h4>5.3 自定义 PocketBase 配置</h4>0 B3 L1 i1 `' b
<p>PocketBase 的配置文件为 <code>pb_data/pb_config.json</code>(运行后自动生成),可修改以下核心参数:</p>
- D% f* J& a! g9 f$ `. f4 Z/ A<ul>0 A4 Q' B, b( G9 G6 f
<li><code>appName</code>:应用名称;</li>4 m9 `: Y8 n  ^6 T
<li><code>api.allowedOrigins</code>:跨域允许的域名;</li>
# {2 f: \9 ?) e, @) F: ^<li><code>mailer</code>:邮件配置(用于密码重置、验证等);</li>% }+ B, [% J$ N* P! Z
<li><code>storage</code>:文件存储配置(默认本地,可配置 S3 等)。</li>
' e, f% n' m- u3 h: f; w- h  x  V</ul>! Q1 ^" k3 u! i, o) i8 {
<p>修改配置后需重启 PocketBase 服务:</p>% I$ m) `0 F' ?2 @% x
<pre><code class="language-bash">sudo systemctl restart pocketbase
& {8 a5 q) C" j$ [</code></pre>& u- f( B8 V/ `! g- K( U3 r5 i
<h3>6. 日常运维</h3>
& r3 j5 ^* E# a; f  b<h4>6.1 数据备份</h4>
% o7 d% ~$ d: }! }  b: `<p>PocketBase 的所有数据(数据库、文件、配置)都在 <code>pb_data</code> 目录,备份该目录即可:</p>; S2 s8 q, f0 e; B4 z1 {8 N
<pre><code class="language-bash"># 创建备份脚本$ u! Y0 V  W2 ^0 a
nano /opt/pocketbase/backup.sh8 p& U7 l# j4 A+ }/ B2 o+ ^
</code></pre>
# Z5 M, u. u' G( V; a# S7 |<p>粘贴以下内容:</p>* S2 p& O. l) [( H  P* g" R
<pre><code class="language-bash">#!/bin/bash
$ H8 u# X* K' V  Z4 B0 FBACKUP_DIR=&quot;/opt/pocketbase/backups&quot;
- C5 x! Q. F9 R: m; K9 T! SDATE=$(date +%Y%m%d_%H%M%S)2 U# B9 j6 w+ q, v8 f& N
mkdir -p $BACKUP_DIR  u5 f7 n( l6 O( Q  U+ Q
: z4 t4 U/ c& Y7 N* |, y% h- @3 a
# 停止服务(可选,避免备份时数据写入)
- ^9 c. y* A) B. z  s$ Vsudo systemctl stop pocketbase
, B: K6 f8 y) `2 a: O
# K% z9 I; h! J8 U9 |# 压缩 pb_data 目录5 l& A8 j* |% T! }1 n1 E1 r, X
zip -r $BACKUP_DIR/pocketbase_backup_$DATE.zip /opt/pocketbase/pb_data; g  y9 I! `, B- I) w
# G# h& I; `# W! ~
# 启动服务
! z7 k, P8 G3 ksudo systemctl start pocketbase
, o7 M- ?4 l* L/ i1 D
  @* V! d" o# E; A5 _2 ]# 删除 7 天前的备份(可选)6 Z1 G* I/ M" q" E2 U
find $BACKUP_DIR -name &quot;pocketbase_backup_*.zip&quot; -mtime +7 -delete7 M) ?$ i5 o* g% ^: C' c3 }& D: i+ L3 W8 \
</code></pre>8 o/ l& g: Y* N) u# y! d
<p>添加执行权限并定时执行:</p>9 r: n4 P" o1 z" K- Q! u# M9 a; m$ x% x
<pre><code class="language-bash">chmod +x /opt/pocketbase/backup.sh
. j; S( y8 c9 y% x1 v9 j$ x) s' J( H6 r" ?
# 添加到 crontab,每天凌晨 2 点备份, q5 k6 p/ L* x, k4 C5 h
sudo crontab -e9 f5 s4 T- b# y$ C+ y* r
# 粘贴:0 2 * * * /opt/pocketbase/backup.sh1 W' z- U/ |: ^3 D1 w
</code></pre>
' {# ^2 G) N3 b- S<h4>6.2 PocketBase 更新</h4>
: p! e6 x  I# _7 Z' y" b. O% v<pre><code class="language-bash"># 停止服务
& T7 p5 Z0 n* r: H% Z" gsudo systemctl stop pocketbase1 e  s* \3 K) @' l4 z2 K
( D* h, }/ {4 t" U
# 备份 pb_data(保险)# B* w! A' G7 `$ [
cp -r /opt/pocketbase/pb_data /opt/pocketbase/pb_data_backup
, @/ j; k4 T/ r
8 {! F+ j) u' u1 E+ B$ w# f# 下载最新版本
7 h0 b0 L& t7 H5 Ecd /opt/pocketbase, ~# R2 V6 ?9 _) |6 c: L% u
wget https://github.com/pocketbase/pocketbase/releases/latest/download/pocketbase_linux_amd64.zip
% t9 B7 n" n# f# C  C7 e3 j4 Zunzip -o pocketbase_linux_amd64.zip  # -o 覆盖原有文件
4 \7 Z' p9 q+ r0 C7 b+ ^rm pocketbase_linux_amd64.zip( @4 \. d; \. l' b0 |5 m" Q

9 w5 ~* Y& r1 h# 启动服务+ A1 E* `0 v5 K, r( a; K; J/ L
sudo systemctl start pocketbase$ a! g7 O: R) E( q8 o
, A7 D( k; {3 o, X  u# ^. C
# 验证版本
1 K& ^! `: m0 l" }* H/opt/pocketbase/pocketbase version1 O" j0 _$ z0 I" C6 }) p+ `6 H" {
</code></pre>
" g# G" R2 A! m2 f) g4 @: p<h4>6.3 查看日志</h4>
4 z5 R. X4 O2 {* u% h+ Q6 C<pre><code class="language-bash"># 实时查看 PocketBase 日志
( R) A1 `2 C* g7 }sudo journalctl -u pocketbase -f3 r3 M( y1 \: B2 g# y  b. F; s9 V
; X7 T% ?4 A' I+ A
# 查看最近 100 行日志
1 C5 b2 e$ w" i# C- W3 `sudo journalctl -u pocketbase -n 100! L& [- u1 q2 e
</code></pre>
# Z' u* a6 y. w<h3>7. 常见问题解决</h3>
. K2 ^* f5 r: `, G/ ~: |<ol>
; [) x% U1 D  E6 D4 p7 `<li><strong>无法访问管理后台</strong>:
! }2 c* {; f: U1 P- t/ R9 D<ul>, M; P* S$ k- @
<li>检查防火墙是否开放 8090 端口(<code>sudo ufw status</code>);</li>: ~, O3 Z/ O- C
<li>检查 PocketBase 服务是否运行(<code>sudo systemctl status pocketbase</code>);</li>$ l$ |; [- [( h* [9 x& E$ \
<li>检查服务器安全组(云服务器需开放对应端口)。</li>
) v0 Y5 e. c3 V& j' a</ul>
# C7 V# N% R5 U, y</li>$ D, Q2 S+ F+ J* f) s8 [" L
<li><strong>API 调用返回 403</strong>:; y! y+ n; |7 B$ f
<ul>' C0 G7 Q+ c9 [% |- F, M# M$ }4 X
<li>检查集合的权限配置(管理员后台→Collections→对应集合→Rules);</li>
+ x' o( a! z, y% w. [<li>确认请求头是否携带正确的认证信息(Admin/User Token)。</li>
8 x% X, K) K* a" I</ul>) h; W6 h/ k$ \( G
</li>0 I; J/ v$ O  Z/ Q. g0 x
<li><strong>服务启动失败</strong>:2 ]  h. k6 ^. a5 K' c
<ul>
  E; n) l$ Z( k* ~7 h<li>检查 <code>pocketbase.service</code> 文件语法是否正确;</li>
( d% t5 l: a# r! W: b<li>检查 <code>pb_data</code> 目录权限(<code>chmod -R 755 /opt/pocketbase/pb_data</code>)。</li>
9 S$ _2 M# I- j6 Q9 u1 b+ b</ul>
4 x1 F, ~* f- i8 V</li>8 x9 v7 w! }  x( Y# z
</ol>
% Z7 B2 h/ d- A+ U6 C$ V3 ~
QQ20260104-124324.webp
匠心独运,千锤百炼,品质非凡。
回复 转播

使用道具 举报

评论3

阿白楼主Lv.1 发表于 2026-1-4 12:54:05 | 查看全部 来自:Error
<h1>PocketBase 在堡塔(宝塔)面板下配置进程守护与端口转发</h1>
: [/ J! F6 y9 x6 G. }5 ~/ |  O' t<h2>一、核心需求确认</h2>1 l& X: S" Q/ @8 N
<p>你希望在堡塔(宝塔)面板中为 Debian 12 服务器上的 PocketBase 配置<strong>进程守护</strong>(确保 PocketBase 持续后台运行、崩溃自动重启),并设置<strong>端口转发(反向代理)</strong>,让 PocketBase 可通过 80/443 端口或域名访问(替代默认的 8090 端口)。</p>
# v& `! W/ l8 M# a5 C- G% A  \, q<h2>二、前置条件</h2>6 M: t7 t& {8 S" `
<ol>+ Y0 a2 D2 C/ C4 ]" n: {! T: W
<li>堡塔面板已成功安装在 Debian 12 服务器(若未安装,可执行官方脚本:<code>curl -sSO https://download.bt.cn/install/install_panel.sh &amp;&amp; bash install_panel.sh</code>);</li>
  E2 a( B) T; Q# {/ s* m" T<li>PocketBase 已按之前的教程安装在服务器(推荐路径:<code>/opt/pocketbase</code>);</li>
5 c' T6 e0 B, ~% G! d( X<li>服务器已开放 80/443 端口(堡塔面板默认会开放,可在「安全」模块确认);</li>+ s0 I# W" h( [7 R9 |
<li>若需域名访问,需提前将域名解析到服务器公网 IP。</li>4 d: B) J5 J% ^) K
</ol>
! Z- I* v6 d( I0 q7 F4 o0 F# g<h2>三、配置 PocketBase 进程守护(堡塔面板)</h2>
5 ?4 @, E# A) g) `% {. A  Z) j<p>堡塔面板的「进程守护」功能可替代手动配置 systemd 服务,可视化操作更简单,核心是让 PocketBase 后台运行且崩溃自动重启。</p>
  ?. T0 e2 ?" Z6 `; ~3 d( H5 f7 ]<h3>步骤 1:登录堡塔面板</h3>0 b& z; i& l) P: |/ A% X
<p>通过浏览器访问 <code>http://服务器IP:8888</code>(默认端口),输入堡塔面板的账号密码登录。</p>5 H+ X: Y( w  s' i: W
<h3>步骤 2:进入「进程守护」模块</h3>
! A( l7 D/ _" b5 N5 D. r. H- k<ol>
7 @8 b2 R. X1 d<li>点击左侧菜单栏的「软件商店」→ 「系统工具」,确认「进程守护」插件已安装(默认已安装,若未安装则点击「安装」);</li>* c) |' a& n4 T7 a2 a$ O
<li>安装完成后,点击左侧菜单栏的「进程守护」,进入守护进程管理页面。</li>
1 _. {: L: v3 \5 F) {</ol>
0 T. k# i/ }4 G  L/ b; b) V<h3>步骤 3:添加 PocketBase 守护进程</h3>
' I" Z2 U) }2 P4 `$ R8 F<ol>* g& l0 ^2 L2 j% _
<li>6 f5 _1 U- o) c5 o; K. z
<p>点击页面右上角的「添加守护进程」,弹出配置窗口;</p>, ~8 f4 n# H5 _# E
</li>/ L  |1 w/ h' K+ m3 W% e7 ?% o
<li>- M- V! m, N5 a5 l
<p>按以下参数填写(关键项标红):</p>7 N1 {7 m0 o) U5 r3 c
<table>+ f+ |4 l( e: q7 A% u! J3 V
<thead>
' P; o/ ]# |8 F2 N& R* J9 |<tr>
' a& p  w, Y$ h8 T% r3 v- B* B<th>配置项</th>
! l4 _/ K) P6 ~- N; K<th>填写内容</th>2 L9 @8 i" g! M3 e9 K' A" \- E
</tr>& X- k7 R- F. ?/ F
</thead>
8 Q5 n! I" U8 Z3 n! i, x9 m<tbody>
8 T( M9 i) Q/ f4 M% y<tr># y( f" S& M1 H2 }) `9 p, w
<td>进程名称</td>1 H& z( j/ S+ C0 f& d/ d: o! l
<td>PocketBase(自定义,便于识别)</td>
' f5 K  c7 ?  C+ Y: b</tr>
8 T/ N. r" q1 m5 S9 b9 Q. Y. }<tr>% T' x$ f0 r2 l$ e
<td>运行目录</td>
. o. Q) I" y: K1 X1 O& b1 h6 y: H<td><code>/opt/pocketbase</code>(PocketBase 二进制文件所在目录,需和实际路径一致)</td>
( {- o. Y4 D& @+ O& n</tr>
2 u) Z- B' r  l2 \, Y<tr>
1 ~$ s7 R* b4 }5 s+ ^7 n0 P* e$ t: U<td>启动命令</td>) N- P- ~' T" a
<td><code>./pocketbase serve --http=127.0.0.1:8090</code>(绑定本地回环地址,更安全)</td>
9 c( |0 l0 X5 B! Y( b! x! D</tr>; }# {7 {+ ^" A  E; G2 E# j1 k
<tr>8 k+ [; s$ `5 `1 {& q/ C, ]
<td>停止命令</td>8 ~: }2 e: {& E8 `5 a
<td><code>pkill pocketbase</code>(可选,用于手动停止进程)</td>
% K8 k1 g9 H/ G$ p; ?</tr>
$ ]; e4 I* {4 u3 ~1 d- a8 ~0 J% G<tr>
' B2 @' \, h2 J4 W6 P<td>日志文件</td>- y3 h5 L6 Z. O! z# K
<td><code>/opt/pocketbase/pocketbase.log</code>(自定义日志路径,便于排查问题)</td>0 Z- ?1 _2 x$ L2 S$ i8 O" h7 Z' i
</tr>7 V- ]$ |; `/ c4 @, ?
<tr>* c) F; t- K- ]. M7 X; n
<td>错误日志文件</td>9 _  Y9 W5 Y1 \
<td><code>/opt/pocketbase/pocketbase_error.log</code>(可选,单独记录错误日志)</td>
2 {+ j( d' y  i0 X- x- y</tr>0 |# S" j7 \) M4 g
<tr>
' F9 ~* d5 N) g4 u3 d<td>自动重启</td>
  t& V, S; K2 V% A' w( s- p<td>开启(必选,进程崩溃后自动重启)</td>
4 K/ |6 _0 l, Y/ t5 v" n) U( \2 L$ j</tr>( u4 `5 l- k; Y% m! f" _
<tr>
. z, i2 Y6 A. K% P; ~0 C* y<td>重启间隔</td>1 T! ?' Q/ b$ F3 w# [
<td>5 秒(默认即可)</td>. p) z' e( G- F- l3 M2 a- ~; I
</tr>
7 C6 V8 p! y3 l' b, b3 n! f. a! I  U<tr>
3 b) e$ N9 i3 r9 P# o4 m) P<td>启动用户</td>$ u% r; w( U* j! D+ y
<td>root(或你创建的非 root 用户,需确保该用户有 <code>/opt/pocketbase</code> 目录权限)</td>9 r* X  Q3 f+ c% m  n; [5 h1 E
</tr>
% j, R; k: h1 _( q</tbody>7 N- x! q4 {: X/ I# H7 l
</table>% v7 h2 l4 X6 [& }( L  b- J& w
</li>' S  X! d0 O# v2 M7 U! Y% S8 _5 j5 l
<li>/ q1 n4 j6 K1 w: V
<p>点击「提交」,完成守护进程创建。</p>
9 C% E7 l4 h& Q</li>
( y) U  k4 P- X/ _$ c0 \5 \</ol>3 `4 H4 }% L7 n$ K
<h3>步骤 4:启动并验证守护进程</h3>
  j& ?3 ~' G- m9 l. ]6 J<ol>
- g6 I; s' j0 o) _8 ]. t, D<li>在「进程守护」列表中找到刚创建的「PocketBase」进程,点击右侧的「启动」;</li>
) D0 t6 q; t# M1 q9 f<li>启动后,进程状态会显示「运行中」,可点击「日志」查看运行日志:8 p5 u. _$ e5 C
<ul>& M/ Z0 \5 @  B/ D1 i+ |
<li>若日志中显示 <code>Server started at http://127.0.0.1:8090</code>,说明 PocketBase 已通过守护进程成功运行;</li>
1 H  b0 ~% y7 E0 p9 g2 q<li>若启动失败,检查「运行目录」「启动命令」是否正确,或查看「错误日志」定位问题(如权限不足可执行 <code>chmod -R 755 /opt/pocketbase</code>)。</li>/ M% ~6 G; s( B
</ul>
9 _  j9 O' I; o7 ]</li>
( }* w1 X9 o4 O* \- o</ol>  D3 N9 P7 v3 v" Y% M; d  ^% _
<h2>四、配置端口转发(反向代理)</h2>, N" ^; d" ^: f8 ]
<p>PocketBase 默认监听 8090 端口,直接暴露该端口不够友好,通过堡塔面板的「反向代理」可实现:</p>
0 u- E7 D- d, t- \, A- m  x5 T<ul>/ C+ ^2 U& S1 R* y* Y
<li>域名访问(如 <code>https://your-domain.com</code>)→ 转发到 <code>127.0.0.1:8090</code>;</li>
( M: \$ {( x( i9 h. L3 c* m0 T. G* Q  n7 {<li>80/443 端口(默认 HTTP/HTTPS 端口)→ 转发到 8090 端口;</li>
) L  ~- a' y* {" ~<li>同时可一键配置 SSL 证书,实现 HTTPS 访问。</li>
( v! K1 \; |+ c+ y: {</ul>
6 h, k5 B3 M" T; W& G. F<h3>步骤 1:添加站点(域名绑定)</h3>
5 G- y5 ^' l( A<ol>% y, ^% }% C+ P4 V, h8 b
<li>
6 H- o4 |0 {# D. r<p>点击堡塔面板左侧菜单栏的「网站」→「添加站点」;</p>; {- p6 w( C( L' U2 \
</li>8 M+ c# h+ t9 S6 l
<li># A5 S1 P5 |, f$ [5 w0 K: D* m9 u
<p>填写站点配置:</p>
, d: I0 \: R% S; h+ Q+ h3 o' _# z2 j7 J) O<table># `# I; x: A; W: g1 {8 s" n
<thead>/ R! G0 _8 d! v2 N6 h$ O
<tr>
: c- A7 N% q6 ?! G8 t<th>配置项</th>: Q8 I- D6 h4 e( z& r
<th>填写内容</th>$ W3 B- @. ~& S7 i
</tr>
2 ~: D; J+ D1 X1 o* C" ]8 T2 `</thead>
8 w4 g2 \& |9 J: q* L<tbody>: B  }5 o  n6 j; T& S& ]! a
<tr>
" f$ m& m  J( ~/ r( b<td>域名</td>
; |: l+ d9 @0 t  D5 a4 A<td>你的域名(如 <code>pb.example.com</code>,若无需域名可填服务器 IP)</td>/ `% p! S, K6 O" e4 t7 k+ X4 I9 i
</tr>6 w& o5 W* D0 J: ~
<tr>0 t3 g( [5 p9 S3 r
<td>备注</td>
; h& |9 {( U; e; O<td>PocketBase 反向代理(自定义)</td>
, r: J7 R) u, F0 Y8 O2 S</tr>
8 o& g( r4 T, A- {- y<tr>8 }- J" M+ s$ b, U( y9 \
<td>根目录</td># L3 k& ~4 T; \% ^+ o% x
<td>任意(反向代理无需实际网站文件,如 <code>/www/wwwroot/pocketbase</code>)</td>
+ W0 M! U' N' @. H0 M* q5 n5 e</tr>  l! d: ^: t5 x& d0 ^+ I5 o9 N- z
<tr>8 g: Y0 U" o, @2 R1 p' J, C
<td>PHP 版本</td>
# [' ~" ~7 f0 l9 b7 `<td>纯静态(无需 PHP,选择此项)</td>
* f7 O3 l3 q4 o- s7 Q</tr>
( e6 |' v/ ?% E6 v<tr>
; j- w6 G' }8 U/ M  D! k2 a<td>数据库</td>: C9 E4 z) j- T/ Y
<td>不创建(无需)</td>) F3 X  i) z* Q- z
</tr>
* L, X/ h* P! w( J7 B7 H<tr>
5 C  e3 P4 M& e* ^<td>FTP</td>
9 H# F: p7 t$ I' u6 }8 ~3 h7 g<td>不创建(无需)</td>6 J2 l$ M% r* n( }8 Q8 x: p! a
</tr>
% |  \; m$ x$ Y' o4 u: B</tbody>
4 p5 n3 t. l" i" `& Q' _</table>
( \% ^1 {, _6 W7 d* _2 h6 Z</li># s6 J  C/ E6 _1 D4 d
<li>; h; X+ P: }- D0 m
<p>点击「提交」,完成站点创建。</p>
) H# c# W! N+ Z5 C</li>
" X; f  _  O3 e</ol>2 k+ Z0 n9 t5 D# |0 p' Z) u
<h3>步骤 2:配置反向代理(端口转发)</h3>
, I; H3 U7 x8 m4 X, r7 u; k8 s<ol>
5 q7 }. M$ N1 ^9 \4 s! D. B<li>
$ G9 E! p, w1 c' Q# n9 z<p>在「网站」列表中找到刚创建的站点,点击右侧的「设置」;</p>
6 I8 [7 A4 Z9 _) C</li>$ W# }0 z/ m8 }9 y" d; l
<li>6 |8 j! U. v  Z6 r
<p>点击左侧的「反向代理」→「添加反向代理」;</p>
7 S5 M* e$ ^* s1 Q# t+ v</li>: z3 y! w, X/ W; b, b6 O1 {
<li>4 Y; }( b, }( M7 O+ s! e) F
<p>填写反向代理配置:</p>
& V, A4 h& G9 Y<table>
. U* O- ?( ~* d1 {7 J% ?+ A6 J<thead>  v+ @1 x4 b; E* K
<tr>
" F: n" a. b$ @( w  {<th>配置项</th>
/ m9 l* k( D* ]0 k% c5 e0 s# W" `/ y<th>填写内容</th>; X. Q- m. l5 l. W- e( u
</tr>% ~0 }1 @& @' N3 b
</thead>
; U' J% a/ v5 e# H2 ~1 k$ \<tbody>* _2 K( z* ~$ T- B9 }9 u% v7 T
<tr>
) Q  @9 Q$ u& t$ z: Z8 ~; A6 Y<td>代理名称</td>6 H: e( E& Y& [' S0 [
<td>PocketBase(自定义)</td>
; I& L" T# R  J$ S, i</tr>8 \- G7 m& Y" a1 |# U7 i2 K8 t
<tr>" x. C5 U- Q" o' e# e+ K+ _
<td>代理目录</td>6 l: X7 t: N& q
<td>/(根目录,转发所有请求)</td>
6 {% ]- y. G' R/ A* E9 H- @</tr>
3 C; r: E* o/ s. I3 M; V, a1 R% M<tr>$ Q1 M7 @6 {' a! [7 k+ D5 S
<td>目标URL</td>9 ~9 a; e* P5 Z  j8 Y
<td><code>http://127.0.0.1:8090</code>(PocketBase 运行地址,和守护进程启动命令一致)</td>4 i8 H9 R* R8 ?1 p
</tr>
" y5 V, N1 N7 V' N5 c/ ^<tr>
: R) H3 O1 h4 b7 |<td>缓存</td>: O% j- x/ x+ t  |
<td>关闭(避免 API 数据缓存)</td>: Q1 I% M6 G4 ^3 Q) b/ |
</tr>
  X, P6 _5 D7 T; `& D<tr>
8 x( b# s9 c1 C; O& n<td>反向代理参数</td>
, t2 f3 N2 o/ u& d' y& S$ a8 F<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>' O( U% n5 c' m
</tr>
6 c: P* @; a4 ?4 m5 h</tbody>
7 c2 B7 p$ i6 O! R. C6 j</table>
# k& T! m, Z: b0 s( C</li>5 |4 M, g, _7 s8 d' F4 n: k1 m
<li>
9 p8 O" }6 A4 e# W. [- U  ?* {<p>点击「提交」,反向代理配置生效。</p>- F& X6 X3 a0 X* N% I/ ~# t! o# r
</li>4 W( V# z6 b# P
</ol>
; f$ {$ P! L  S% C8 p: H2 X<h3>步骤 3:配置 SSL 证书(可选,推荐)</h3>6 j' T6 ?, T/ G" @3 ?* @; Y
<p>为了安全访问,建议给域名配置 SSL 证书(堡塔面板支持一键申请 Let's Encrypt 免费证书):</p>: O# X; {; L  w1 s# B$ ~$ m
<ol>! [. r5 O' {6 a/ v
<li>在站点「设置」页面,点击左侧的「SSL」;</li>
, L: v4 I, w* P& \6 a! O<li>选择「Let's Encrypt」→ 勾选需要申请证书的域名 → 点击「申请」;</li>* x- b+ ~/ Y9 i. y1 p6 l/ y
<li>申请成功后,开启「强制 HTTPS」(自动将 HTTP 请求重定向到 HTTPS);</li>
# m, e; S3 J5 {4 o0 Y1 D  `4 ]; V<li>点击「保存」,SSL 配置生效。</li>
4 k* X( R, I* u5 N: ]</ol>) T1 i8 j1 `" w
<h3>步骤 4:验证端口转发</h3>
% _/ B; T4 M9 c  A/ ^, S/ v9 T<ol>8 V" y* O/ e( @+ z
<li>访问配置的域名/IP:  {4 Z$ }- D2 b9 X1 l- h  u
<ul>1 r7 F1 L6 c" s
<li>管理后台:<code>https://你的域名/_/</code>(替代 <code>http://服务器IP:8090/_/</code>);</li>$ U! z) t' f3 |' r7 {4 c  r
<li>API 接口:<code>https://你的域名/api/collections/users/records</code>(替代 8090 端口);</li>1 R5 T* ?7 Q5 n
</ul>' }9 c/ {  y* N, A* b6 U4 p! D
</li>
# L1 f- T8 v$ s' Y% ^, O) B) @. d5 {( P<li>若能正常访问 PocketBase 管理后台或 API,说明端口转发配置成功。</li>
* i) @5 v6 W- l' p3 ^$ b/ |</ol>  r: [3 L5 E( s) Z& X
<h2>五、常见问题排查</h2>
3 X9 t4 C( k, k2 @0 t7 G: E# v+ ]<ol>; ]. V8 ]4 A% |
<li><strong>守护进程启动失败</strong>:) g3 ~+ w4 S. p# ^( {2 [
<ul>$ ^+ G" {. F  W# V! d0 z+ J
<li>检查「运行目录」是否为 PocketBase 二进制文件所在目录;</li>
5 ], @4 c# K" z6 {' L<li>检查启动命令是否正确(如 <code>./pocketbase</code> 路径是否存在,可在堡塔面板「终端」执行 <code>ls /opt/pocketbase</code> 验证);</li>2 I% s  k$ g/ X& T. t- e* z! Q6 ^# [
<li>查看「错误日志」,若提示权限不足,执行 <code>chmod +x /opt/pocketbase/pocketbase</code> 赋予执行权限。</li>
3 ?' r" k8 s; ~/ u6 m, g4 U8 r</ul>0 y/ G" J3 j* ^0 g! J# a) m
</li>
7 r$ C' L( B: j5 S8 H<li><strong>反向代理访问 404/502</strong>:
4 C' e# ~6 P, A" a7 K( e% _! l<ul>( x, n# U! ]2 H$ k" Q
<li>502 错误:PocketBase 守护进程未运行,先确认进程状态为「运行中」;</li>- W( W0 g* r) P. N3 E
<li>404 错误:反向代理「目标URL」填写错误(需为 <code>127.0.0.1:8090</code>,而非服务器公网 IP);</li>; a9 b* Q0 }% Y
<li>跨域错误:检查反向代理「自定义参数」是否添加完整的 Header 配置。</li>. A: O/ o4 s) \% m: j; d1 D
</ul>
0 `3 s2 O1 n9 q* z, J</li>
' H0 a8 s* \9 k1 A5 P<li><strong>域名无法访问</strong>:& a% w( f. H" w) J
<ul>, |0 \% v5 G" u+ n$ s
<li>确认域名已解析到服务器公网 IP(可通过 <code>ping 你的域名</code> 验证);</li>
$ N/ q/ l8 F( u* ~/ G<li>确认服务器安全组/堡塔面板「安全」模块已开放 80/443 端口。</li>
; s8 Q4 C, @" `</ul>1 ?( t3 c0 f+ w7 P( ]' j9 v
</li>
+ Y$ Q+ \( e! U; Z* I</ol>* F/ w& l1 q* F! `6 C, Q* N9 L
匠心独运,千锤百炼,品质非凡。
回复

使用道具 举报

diggerLv.9 发表于 2026-1-4 12:57:08 | 查看全部 来自:Error
<h1>PocketBase 保留目录说明 &amp; 钩子(Hook)调用方式与示例</h1>( }# N& ]1 f4 l8 u  o7 {" J4 j
<h2>一、核心需求确认</h2>
$ [$ |( s9 r( ]$ {1 p<p>你希望了解 PocketBase 运行过程中自动生成/识别的<strong>保留目录</strong>的名称和具体作用,同时掌握 PocketBase 钩子(Hook)的调用方式,并通过实际示例理解钩子在业务场景中的应用(如数据校验、事件触发、自定义逻辑等)。</p>
6 ], F" l$ Y& e) w<h2>二、PocketBase 保留目录详解</h2>& L( a. q2 r% `. P8 [, [
<p>PocketBase 运行时会在其工作目录(如 <code>/opt/pocketbase</code>)自动生成/识别多个保留目录(文件名固定,PocketBase 会优先读取),所有核心数据、配置、自定义逻辑都集中在这些目录中。以下是所有保留目录的名称、作用及关键细节:</p>  f6 @: _: L' }& s
<table>
( ^( ?4 I0 c4 u0 \% p; S<thead>: j- \) V# ?/ Y1 h( w- F
<tr>
$ [1 o& w$ f: |5 c* g  [<th>目录名称</th>
9 e# i8 g! J# v( j3 N3 I2 l<th>核心作用</th>2 c9 m& o. @+ z" i4 P) |) m7 h
<th>关键文件/子目录</th>+ W/ m$ k% u; W; ?: ]* h/ L, u
<th>适用场景</th>- {& T) c& b0 e
</tr>
/ _3 @) L7 k; G: ?* X( D/ b</thead>
$ i/ z5 [# {/ V8 R+ Q<tbody>) Q0 M" ]$ k! j/ n  y
<tr>  C/ e& O/ k+ h) H# c* W
<td><code>pb_data/</code></td>3 [0 M$ V4 K( A, p& G" c  c$ {* R
<td><strong>最核心目录</strong>,存储所有持久化数据(数据库、配置、文件、日志等)</td>' P: u7 \3 L5 V
<td>- <code>pb.db</code>:SQLite 核心数据库(存储集合、记录、用户等)- <code>pb_config.json</code>:全局配置文件(应用名称、跨域、邮件等)- <code>storage/</code>:文件存储目录(上传的图片/文件)- <code>logs/</code>:运行日志(可选)- <code>pb_auth.json</code>:认证相关配置</td># f& s5 A' a5 d7 N7 V3 ~
<td>数据备份、配置修改、文件存储管理</td>! o% {/ w6 f* o
</tr>
. S2 [" f! S$ _5 ~/ K) p<tr>
! ?# @1 g: z* h) b<td><code>pb_hooks/</code></td>
! `: s" q9 y: p/ i+ ~$ }<td>存放 JS/TS 钩子脚本,PocketBase 启动时自动加载,用于扩展业务逻辑</td>
6 L2 T* f! f) n) o! }7 R' [+ p<td><code>*.js</code>/<code>*.ts</code>(如 <code>users.hooks.js</code>)</td>! C. U8 b$ o7 F6 C- J# o
<td>数据校验、事件触发、自定义认证、请求拦截</td>
! k5 K4 W) P# X% j1 z5 p% I& A( C</tr>+ }7 e# N* f9 O" X3 ^# s
<tr>0 \. H$ g; U/ L: K
<td><code>pb_migrations/</code></td>5 Y' [5 ^" o6 x1 q
<td>数据库迁移脚本目录,用于管理集合结构变更(版本升级/手动修改表结构)</td>+ D! \2 z" [' X3 b6 G% F1 Q; l
<td><code>*.js</code>/<code>*.ts</code>(如 <code>20240104120000_init.js</code>)</td>6 e# a, W: C( @6 n% \: z+ L9 g
<td>生产环境集合结构变更、版本迭代</td>
3 U5 S8 F" J3 ?( S, s</tr>
/ r3 @% I1 D6 _7 g<tr>: U# K1 [0 e* o' n3 \
<td><code>pb_public/</code></td>
3 T5 r% D  q# b<td>静态文件托管目录,可通过 URL 直接访问(无需认证)</td>
$ V7 h: W" u- b6 t; p1 a<td>任意静态文件(如 <code>index.html</code>、<code>logo.png</code>)</td>
, ~/ i3 f7 k' r<td>托管前端静态页面、公共资源(如图片、JS)</td>) b& E+ W# \- H* C! H4 M
</tr>" i. X! A$ T, ]5 y! l( T* U
</tbody>
- [4 _, f" k  o$ A5 m5 M</table>
. m  y1 w7 P9 o0 \0 |4 R7 q<h3>各目录详细说明</h3>
& R: n8 ^! D7 `) w" ^<h4>1. <code>pb_data/</code>(核心数据目录)</h4>
) p5 g$ Q4 K# B. d7 o' p/ p; _<ul>
$ w: O! F3 o  h$ L) Q* f<li><strong>不可删除</strong>:删除该目录会丢失所有数据(数据库、配置、上传文件);</li>" N8 s& }$ I( N7 N2 o$ b7 f
<li><strong>备份优先级</strong>:日常运维只需备份该目录即可完整恢复 PocketBase 所有数据;</li>
! d. j6 Q6 E) o: {9 }( ~  q<li><strong>关键文件说明</strong>:  S7 f# N8 n9 b6 Z
<ul>
9 D: u. k3 h  _; R5 k<li><code>pb.db</code>:SQLite 数据库文件,存储集合定义、记录数据、管理员/用户账号等核心数据;</li>
( _, `, d& `# G<li><code>pb_config.json</code>:自动生成的配置文件,可手动修改(如跨域允许的域名、邮件服务器配置),修改后需重启 PocketBase;</li># Y7 i. Z, h5 |
<li><code>storage/</code>:默认存储用户上传的文件(如集合中「File」类型字段的文件),路径对应 API 返回的 <code>fileUrl</code>;</li>
: f* z0 I( d/ K+ J% o<li>权限要求:运行 PocketBase 的用户需有该目录的读写权限(如 <code>chmod -R 755 pb_data/</code>)。</li>! C+ J- @$ I7 G: I( ~$ {
</ul>
: i8 N( m/ u6 q</li>
* H* T: s1 N3 I& Q% U  H, U</ul>  `' f$ @0 ]' _3 b' J( ?; \: Z6 e, o
<h4>2. <code>pb_hooks/</code>(钩子脚本目录)</h4>
; r! t  y% S8 X9 z. ?5 ]<ul>; f0 g7 R, l( I) @+ G
<li><strong>自动加载</strong>:PocketBase 启动时会扫描该目录下所有 <code>.js</code>/<code>.ts</code> 文件并执行,无需手动配置;</li>
6 q4 y% ~: O5 ^, e/ b, A* L<li><strong>运行环境</strong>:基于 Go 内置的 ESModule 运行时,支持大部分 ES6+ 语法,可直接使用 <code>console.log</code> 调试;</li>9 ?! l( x' F7 |3 H
<li><strong>无依赖</strong>:暂不支持 npm 包,需用原生 JS/TS 编写逻辑。</li>
$ d, a/ S3 E" x& V" J</ul>, n$ F3 h. Y+ l. c
<h4>3. <code>pb_migrations/</code>(数据库迁移目录)</h4>+ U, N; w  T, Q8 d% v
<ul>/ B! V5 h4 K$ a' `. A; r2 Y+ m8 h
<li><strong>自动生成</strong>:在管理后台修改集合结构(如添加字段)时,会自动生成迁移脚本;</li>8 X1 }7 C' ^! l
<li><strong>手动执行</strong>:可通过命令 <code>./pocketbase migrate up</code> 执行未应用的迁移脚本;</li>/ j# }+ C$ g  m) m
<li><strong>回滚</strong>:支持 <code>./pocketbase migrate down</code> 回滚最近一次迁移(需脚本支持)。</li>
' ~3 }: s- m" Q* d* A* P</ul>2 ?; u/ ^9 f; k7 {
<h4>4. <code>pb_public/</code>(静态文件目录)</h4>
0 |+ P9 V- u5 c. U9 \<ul>$ B. E- d9 z# m  ^
<li><strong>访问方式</strong>:文件路径对应 URL 路径,如 <code>pb_public/logo.png</code> 可通过 <code>http://域名/public/logo.png</code> 访问;</li>1 {3 v* P* C0 \
<li><strong>权限</strong>:所有文件无需认证即可访问,适合存放公共静态资源(不建议存放敏感文件)。</li>' W  f% s/ F/ S1 V( {' z$ r
</ul>; C% D( u) |( A. S! A8 k0 z7 t( w4 ?
<h2>三、PocketBase 钩子(Hook)调用方式与示例</h2>% a% e+ q2 {1 q( @
<h3>1. 钩子核心概念</h3>/ `( P& n! A! g4 K9 r9 x- x7 {
<p>PocketBase 钩子是<strong>服务端事件驱动脚本</strong>,可拦截/处理系统核心事件(如数据创建/更新、用户认证、服务启动等),实现自定义业务逻辑(如数据校验、自动填充字段、日志记录、权限控制)。</p>$ p3 n' N7 E2 W( h7 J2 ]/ F
<p>钩子分为两类:</p>
6 c0 o9 X' ]& |$ Y) ?! L1 A<ul>8 \! e1 x6 [4 Q3 w% ?3 U
<li><strong>集合钩子(Collection Hooks)</strong>:针对特定集合的操作(如 <code>users</code> 集合的创建/更新),最常用;</li>
( J' g' l) u+ h* @  J<li><strong>全局钩子(App Hooks)</strong>:针对全局事件(如服务启动、HTTP 请求拦截、用户登录)。</li>
1 {, j) s0 A# Y</ul>: a% ?1 e) ?8 E5 y% N, p$ L; X
<h3>2. 钩子基本使用步骤</h3>' l7 b. B) r# |+ Q; X; o* ^4 n
<ol>
% i" z# U2 u4 {  Z( Q, z<li>在 PocketBase 工作目录(如 <code>/opt/pocketbase</code>)创建 <code>pb_hooks</code> 目录:
- o& x# x6 j- c, x$ m<pre><code class="language-bash">mkdir -p /opt/pocketbase/pb_hooks
" z) _0 S! t! e/ I- }</code></pre>
& w/ t& Q7 A0 z* Z</li>- F6 ?* |' S1 p7 S
<li>在 <code>pb_hooks</code> 目录下创建 <code>.js</code> 文件(如 <code>users.hooks.js</code>);</li>
) M% L; ~. z6 |' o<li>编写钩子逻辑,保存后重启 PocketBase 守护进程(堡塔面板「进程守护」→ 重启);</li>  e  n! V% j5 k5 D0 _' j
<li>测试触发条件(如创建一条用户记录),验证钩子是否生效。</li>) n0 E& S- n3 a7 o: I6 q8 k, W. e2 c
</ol>
* ?9 x9 [: T: ?* N/ U# n<h3>3. 常用钩子示例</h3>
" f# h; O# K% D! Y# G: |: L  F<h4>示例 1:集合钩子 - 数据创建前校验(必填字段+格式校验)</h4>; F2 D  k# t3 t9 \6 X0 R
<p>场景:<code>users</code> 集合创建记录时,强制校验「email」字段格式,且「username」字段不能为空。</p>
: G$ m/ q. D! S% Z3 J<p>创建 <code>pb_hooks/users.hooks.js</code>:</p>8 R$ ]7 P, y2 Z& _' D
<pre><code class="language-javascript">// 监听 users 集合的 beforeCreate 事件(创建记录前触发)6 h0 u: A0 E/ N2 l7 M6 x
onRecordBeforeCreate((e) =&gt; {
+ B2 h2 I+ x( W1 n  // 仅针对 users 集合生效3 n) {8 [7 Z4 E1 i
  if (e.record.collectionName !== &quot;users&quot;) {
# P! o* ]  c2 P; h. _3 ^2 L    return;7 V# P( L8 y1 G
  }& J  w2 i0 B; J6 x5 q3 h
% q- ^" q4 D2 b1 Q" c
  // 1. 校验 username 不能为空
0 ], h. h/ I) P) K9 ~1 @, ?# V) \  const username = e.record.get(&quot;username&quot;);
+ F2 V3 ]: i  I2 n( ~  if (!username || username.trim() === &quot;&quot;) {6 @. ~. o' u1 g5 Y: [$ X
    throw new Error(&quot;用户名不能为空!&quot;); // 抛出错误会终止创建操作,前端会收到该错误信息
* I' N' o1 b1 ^! l  x+ h  }
7 W2 H3 G& {( G! b6 I5 e$ j, o+ \$ v, \; L# A
  // 2. 校验 email 格式
7 C; }1 k" i0 H8 a, d4 x  const email = e.record.get(&quot;email&quot;);
) _5 a3 `# b+ \8 E5 r$ B# t  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
" [/ k& f, W2 u7 h; \2 ?  if (!emailRegex.test(email)) {+ P& J6 U0 [% M1 [4 w2 |% K
    throw new Error(&quot;邮箱格式不正确!&quot;);: e' k: O: `9 V/ H% N/ N/ B+ U
  }
" y. W; u( V/ U
# q  g7 t" o/ V# q& s. q& j  // 3. 自动填充创建时间(无需前端传参)4 v/ j6 s! Z3 W0 B
  e.record.set(&quot;created_at&quot;, new Date().toISOString());
# U! @/ N2 a' }! D- z});
6 E9 r8 [6 S% n! O: U* Q</code></pre>3 Y1 o' Q% i7 ^0 f" S& e
<p><strong>触发方式</strong>:调用 <code>users</code> 集合的创建 API 时自动触发:</p>
* g) r- ]+ I# |3 P1 y2 a. L$ c<pre><code class="language-bash"># 测试:传入错误邮箱,会返回「邮箱格式不正确」% G6 l: k/ Q8 S
curl -X POST http://域名/api/collections/users/records \  r7 d6 i# g; @
  -H &quot;Content-Type: application/json&quot; \
. e  A4 j* z6 u8 M; B' D  -d '{&quot;username&quot;:&quot;test&quot;,&quot;email&quot;:&quot;invalid-email&quot;,&quot;age&quot;:25}'( P. ?" b. }7 x7 m& a" D$ A, ]
</code></pre>
/ N& V7 Z; w/ }. \- v/ R& G<h4>示例 2:集合钩子 - 数据更新后记录日志</h4>  z1 S; h/ C2 A1 c9 e5 C
<p>场景:<code>users</code> 集合记录更新后,自动将操作日志写入 <code>user_logs</code> 集合(需先创建该集合,包含 <code>user_id</code>、<code>operation</code>、<code>update_time</code> 字段)。</p>
# s4 ~7 a( `) d# ~* q<p>创建 <code>pb_hooks/users.hooks.js</code>:</p>
' ^0 c2 X3 z- i# C) }! y& }<pre><code class="language-javascript">// 监听 users 集合的 afterUpdate 事件(更新记录后触发)
: _* Z3 X: r) v8 Q3 k: [$ w/ ponRecordAfterUpdate(async (e) =&gt; {
  V% z7 O4 c: U# c1 u  if (e.record.collectionName !== &quot;users&quot;) {$ |) l8 w% y' h% C" e2 p
    return;9 u0 c5 [1 F' R7 U) u5 ^! _
  }2 V" P- b/ t: Q1 Q$ a7 S$ |

# @: N+ m7 d$ @5 a3 d% J$ q' d  // 获取更新的用户ID和操作时间
4 r, D1 U$ A# Q  T3 q  const userId = e.record.id;
  O$ ~/ ~/ N1 L7 \  const updateTime = new Date().toISOString();9 l# F) d2 g1 U( C" Y
5 o; o8 c* m3 f& {
  // 写入日志到 user_logs 集合' `+ `1 \% A0 v. `8 w- |% K1 z
  await $app.dao().createRecord(
( [/ R1 j% U  ^    $app.dao().findCollectionByNameOrId(&quot;user_logs&quot;),
3 d3 k; U4 S6 x    {
( ?- F% f, Y0 `8 K  ^# I4 L$ s      user_id: userId,$ G% _. D6 m) T& o& C
      operation: &quot;用户信息更新&quot;,
3 q" {' y( S0 ^( b' l- |      update_time: updateTime,
) @* Q( h. h8 S" w! }    }
+ {. \) C8 {. z+ A6 |) @  );/ C8 _0 Y" N# p9 D9 {
3 u: ]2 X* S. B6 R
  console.log(`用户 ${userId} 信息已更新,日志已记录`); // 日志会输出到 PocketBase 运行日志
8 f" a' k5 e% P& }; s, `});2 M$ m+ a* Y% w
</code></pre>
( a1 F: R. Y, l<h4>示例 3:全局钩子 - 服务启动时初始化</h4>6 B# s+ O, O9 a
<p>场景:PocketBase 启动时,自动检查 <code>settings</code> 集合是否存在默认配置,不存在则创建。</p>9 H& U; @0 U7 c% n; z, A
<p>创建 <code>pb_hooks/app.hooks.js</code>:</p>
( O. V9 v3 D! {1 s, D3 i4 M<pre><code class="language-javascript">// 监听服务启动后事件8 c6 e! C$ {$ _8 _  {+ U
onAppAfterServe((e) =&gt; {
# t" t+ @% p0 c; M7 j8 r! K0 e  console.log(&quot;PocketBase 服务已启动,开始初始化默认配置&quot;);! d- A7 u3 o/ j0 n" w5 @! B& C' _
; o; L2 S5 w" o2 W$ h
  // 获取 settings 集合
) ?6 J2 L# G6 G3 [  const settingsCollection = $app.dao().findCollectionByNameOrId(&quot;settings&quot;);
( e% ]( U7 N6 g4 W) S  if (!settingsCollection) {
0 w$ t$ n3 I) U' S" Y$ Z    console.log(&quot;settings 集合不存在,跳过初始化&quot;);
- s# G+ L$ Z+ O! m# U5 i1 i    return;
. v) O% C/ j4 |' h3 R$ `( ~. t  }
' w6 J1 L" l6 v/ i) H4 u
; t* F1 f- N6 S; y  m% w  // 检查是否已有默认配置
1 `3 B  h' I) ^: O9 x. ?  const defaultSettings = $app.dao().findFirstRecordByFilter(
5 K5 o# ]2 r/ v9 H8 s- S7 x    &quot;settings&quot;,
7 E# V1 s; `2 T0 j' M    &quot;key = 'site_name'&quot;,
7 D% i7 A+ ]/ j; v- m    &quot;&quot;& g3 |; w3 x: e* l* M. ?& w
  );
) @7 k- v9 e- B  `7 j2 U
; q1 f* }6 T+ p3 u4 \; T: `  // 无默认配置则创建* f  a/ ]$ O+ f
  if (!defaultSettings) {
  C  t0 u9 W0 q& U# [" A2 B. c& x3 [, {    const record = new Record(settingsCollection);- |8 L7 {4 r; ^* p
    record.set(&quot;key&quot;, &quot;site_name&quot;);
5 `) Z4 Q" f' M; W    record.set(&quot;value&quot;, &quot;我的 PocketBase 应用&quot;);
) E' n# Z; j. d! R4 R    $app.dao().saveRecord(record);* o9 K; D7 l: t  ?7 u
    console.log(&quot;默认站点名称已创建&quot;);7 g% K; M7 K0 e9 w3 E$ ]
  }
( L1 S  t( k+ B  T* u3 m});
# i% D3 F" s$ a2 |' B2 [</code></pre>/ }7 c; o& z2 `6 Y  d( c$ l
<h4>示例 4:全局钩子 - 拦截 HTTP 请求添加跨域头</h4>) |, P1 d, K6 ^' l' h
<p>场景:自定义跨域配置(替代 <code>pb_config.json</code> 中的跨域设置),允许指定域名的跨域请求。</p>
. ^% a8 s7 }4 z* Y<p>创建 <code>pb_hooks/app.hooks.js</code>:</p>
! z+ A: A9 v" Z9 y  \6 `# I<pre><code class="language-javascript">// 监听所有 HTTP 请求- v! p+ W8 t( O$ [  A3 p
onHttpRequest((e) =&gt; {
! K+ m' `. G7 e$ y; F0 T  [1 e, w  // 获取请求的 Origin 头
! L' {8 n! u2 B* z0 N) _2 L  const origin = e.request.headers.get(&quot;Origin&quot;);* l. t7 N5 B. \
  // 允许的跨域域名列表
) o1 U+ H5 |" D8 H3 Z4 H0 o  const allowedOrigins = [&quot;https://your-domain.com&quot;, &quot;http://localhost:3000&quot;];
' ?! p/ j% y& d) R* h  |# w- i8 B- B2 [& q
  // 若 Origin 在允许列表中,添加跨域头9 o. M( n  l; Z
  if (allowedOrigins.includes(origin)) {
( e, h* c  Y. ]    e.response.headers.set(&quot;Access-Control-Allow-Origin&quot;, origin);+ B8 K0 A4 J2 x7 u3 y' b0 S
    e.response.headers.set(&quot;Access-Control-Allow-Methods&quot;, &quot;GET, POST, PUT, DELETE, OPTIONS&quot;);0 b9 H8 A+ ^- ^3 [& I& L
    e.response.headers.set(&quot;Access-Control-Allow-Headers&quot;, &quot;Content-Type, Authorization&quot;);
5 Y/ ?* f# Y0 ~5 `' r6 `2 Y  }
$ K8 f& F* n$ G1 f- w: y$ y) ^5 `2 n$ D7 k7 C
  // 处理 OPTIONS 预检请求3 a0 T3 q) Q1 c  B9 N% T
  if (e.request.method === &quot;OPTIONS&quot;) {7 ^& p8 l; P! Z* E7 R' g/ M' q1 i
    e.response.status = 204;
/ B; e0 c0 ]& G# X    e.response.body = &quot;&quot;;
5 j. v; h. U* }% R  }
+ l7 G  q. h- m0 I; y( z2 v: ~) }});4 s! G3 ?; e- B' |& W% w5 s" |0 `
</code></pre>7 r( W5 e2 w3 D3 |3 V6 X( ~
<h4>示例 5:认证钩子 - 自定义用户登录逻辑</h4>
8 c  {2 p9 b  @3 N# }' F2 P<p>场景:用户登录时,额外校验「账号是否禁用」(<code>users</code> 集合需添加 <code>is_disabled</code> 布尔字段)。</p>
; }& Y  R! o. S6 J* m; u. \4 J<p>创建 <code>pb_hooks/auth.hooks.js</code>:</p>
7 H7 _, U: i- _( K- w<pre><code class="language-javascript">// 监听用户密码登录事件4 d$ o# x8 u: I: e4 U
onRecordAuthWithPassword((e) =&gt; {
- T- }( U/ e  F& H) A- |  // 仅针对 users 集合的登录
8 s7 K7 v. d/ R! v  if (e.record.collectionName !== &quot;users&quot;) {
( @' `/ P/ P. m8 {: p    return;7 _6 O2 R2 S# S# @  h# l" V6 A
  }
6 i8 S$ T9 `$ c- [* P4 Z" r" m+ X/ ^+ f" f+ B! }/ {; W
  // 检查用户是否被禁用
! D8 }; d/ w+ Y% s$ g% i! ?  const isDisabled = e.record.get(&quot;is_disabled&quot;);
3 j# B3 \) @1 R5 i! h2 f) o  if (isDisabled) {
, L$ e$ |% N) ?  ~1 ~% S% b    throw new Error(&quot;该账号已被禁用,请联系管理员!&quot;); // 终止登录5 V3 P( h2 A% c" |3 D
  }; D$ `9 Q* f8 _3 j

: R* S: O& S- c  // 登录成功后,记录最后登录时间5 V$ V3 o4 o7 _6 ^
  e.record.set(&quot;last_login_at&quot;, new Date().toISOString());
7 C( h* \. b8 E$ X& v% ]8 |" t  await $app.dao().saveRecord(e.record);
+ P' h# V4 U; m5 b/ Z1 B/ r3 n% h
; T/ H8 L; X) d" d3 C4 u. C7 d3 r  console.log(`用户 ${e.record.id} 登录成功,最后登录时间已更新`);) O! i+ a: Z3 i5 q
});. V7 I; R  {6 p8 [
</code></pre>* e& Z: J  k2 e- a; }3 F
<h3>4. 钩子调试技巧</h3>
5 g! j) `) {% h<ul>
$ G# C6 U- N" M4 Z: b- s# i3 M* [+ }<li><strong>日志输出</strong>:使用 <code>console.log(xxx)</code> 输出调试信息,日志会写入 PocketBase 运行日志(堡塔面板「进程守护」→「日志」可查看);</li>$ o1 |1 @0 B' u
<li><strong>错误排查</strong>:钩子脚本语法错误会导致 PocketBase 启动失败,可在终端手动运行 <code>./pocketbase serve</code> 查看具体错误信息;</li>  ^8 M! w. Z- T9 }7 k
<li><strong>参数打印</strong>:触发钩子时,打印事件对象 <code>e</code> 查看可用参数(如 <code>console.log(JSON.stringify(e.record))</code>)。</li>
* q" ^' k; T, b! o6 R( Y% x</ul>6 r+ w: F. _% K. G
<h2>四、总结</h2>8 F# \) @! n& Q- x6 ~. {: [
<ol>( R( T7 Y# v) u# X& J$ X1 L
<li><strong>保留目录核心要点</strong>:, r6 y$ {4 i& M! i! u. |9 o
<ul>; r( O- X8 }3 _1 p, H0 d& E1 X
<li><code>pb_data/</code> 是核心数据仓,备份该目录即可恢复所有数据;</li>8 S5 U4 q4 y2 A, V3 Q$ L2 u
<li><code>pb_hooks/</code> 存放自定义钩子脚本,启动时自动加载;</li>, y/ P& O7 w  ?
<li><code>pb_public/</code> 托管无需认证的静态文件,<code>pb_migrations/</code> 管理数据库结构变更。</li>- h' ]7 [, \3 W) _3 m" a& I
</ul># Q5 m( a- Q) c9 s) E4 F% \) h9 X
</li>% Z; l' ]: N% f- Q6 u
<li><strong>钩子使用核心要点</strong>:
' {) L; L0 E$ G<ul>
, q. K+ d( A- v8 D0 ?  @. K<li>钩子分「集合钩子」(针对数据操作)和「全局钩子」(针对系统事件),放在 <code>pb_hooks/</code> 目录自动加载;</li>6 G5 p( z& U' w' h7 a
<li>常用钩子:<code>onRecordBeforeCreate</code>(数据校验)、<code>onRecordAfterUpdate</code>(日志记录)、<code>onHttpRequest</code>(跨域配置);</li>; N" u8 O8 L8 l: j% Y% @/ t
<li>钩子中抛出错误会终止原操作,适合做数据校验;可通过 <code>$app.dao()</code> 操作数据库(如创建/更新记录)。</li>' R' @/ C* s1 B; c
</ul>" U2 |" T. W$ c7 I- E# w
</li>
" k% S3 P. r2 n<li><strong>实战建议</strong>:8 o, a* J) p; y& z# H. {- W! F
<ul>
$ E5 Q4 d; D+ {  k. [1 g, V' a7 z<li>钩子脚本优先实现核心业务逻辑(校验、自动填充),避免复杂计算;</li>
1 P  u" S* g, S% v( M<li>修改钩子后需重启 PocketBase 才能生效;</li>
+ m1 f" n$ u/ R' h( o9 U& K. f<li>生产环境需备份 <code>pb_hooks/</code> 目录,避免钩子脚本丢失。</li>+ D4 u  [; o. k# e( h3 f
</ul>% l) T0 U" A& [. q. O
</li>
$ q: P) d' F$ ^7 |+ s</ol>% m) i! t  d2 _
[!luckypost!]: digger 被钱袋砸中进医院,看病花了 1 匠币. !lucky_goodrank! / !lucky_badrank!
匠心独运,千锤百炼,品质非凡。
回复

使用道具 举报

打工日常 发表于 2026-1-4 13:00:20 | 查看全部 来自:Error
<h1>Debian 12 下 PocketBase 全维度配置指南</h1>
! S3 K/ f8 D& X3 e3 |<h2>一、核心需求确认</h2>1 _' t6 Z/ T  Z& E3 z
<p>你需要在 Debian 12 系统中完成 PocketBase 的<strong>全场景配置</strong>,包括基础网络(端口、绑定地址)、邮件(SMTP)、存储(本地/S3)、安全(跨域、认证)、应用基础(日志、时区)等核心配置,同时掌握配置的生效方式、备份与问题排查方法,适配生产环境的实际需求。</p>
8 l& H' [( F9 `  V( F9 Y$ b: f: R<h2>二、PocketBase 配置的核心入口(Debian 12 环境)</h2>$ X! n& c6 A1 V3 V. V. O5 n
<p>PocketBase 的配置主要通过 4 种方式实现(优先级:命令行参数 &gt; 管理后台 &gt; 配置文件 &gt; 钩子脚本),所有配置最终会落地到 <code>pb_data/pb_config.json</code>(运行后自动生成),以下是各入口的适用场景:</p>
( e4 K& p9 B+ b. u1 g<table>; T& e/ U0 S- I: H$ u
<thead>
. p- w1 \# }& _4 _<tr>
" p' u. `9 z, C<th>配置方式</th>. S6 s; [  ]' x7 M; H
<th>操作路径</th>
+ f8 [: }  Z/ f<th>适用场景</th>
' H7 S" \! y5 I$ G2 |$ d</tr>" Q) x6 B; N7 E* ^! B3 g
</thead>
" p* Q$ H9 I. s. C<tbody>
) V8 z+ W+ }% `9 ~) I& r/ G' ^<tr>
) F! f% ?. c& [& I: Z4 f<td>配置文件</td>. b( F8 y6 P5 ~% \0 n6 R  ~
<td><code>/opt/pocketbase/pb_data/pb_config.json</code>(手动编辑)</td>! Z( Q$ X& Z% q
<td>所有基础配置(网络、邮件、存储、安全)</td>
1 x1 {1 ]* D- ~" W4 {0 j( Q. S( e, p</tr>: X0 m/ ?. s9 n3 ]7 M' ~7 N. x
<tr>6 j1 \5 R  [0 H+ R4 G" o1 ^
<td>命令行启动参数</td># U; g% y5 Z; J3 j9 r" D
<td>启动时追加参数(如 <code>./pocketbase serve --http=0.0.0.0:8080</code>)</td>
9 V& b/ t+ s+ ~2 H# |; ]<td>临时覆盖配置(如测试端口、调试模式)</td>/ l# c) D, V; W2 S4 y- |) @
</tr>% V: ^. z" ~# C$ V, e, a7 p
<tr>
' ^, Y- ]0 Y6 M' R7 b<td>管理后台</td>1 A% w5 C+ ^( ~; |" v
<td><code>http://域名/_/</code> → 设置(Settings)</td>
. `2 n% l5 f5 O7 E. T; r1 `2 ^) x<td>可视化配置(邮件、跨域、认证策略)</td>
* G" p+ R" W0 u) I, t</tr>" V! `$ ]8 F9 ~3 S
<tr>
! d) Z  W% t3 o<td>钩子脚本</td>
. n5 Q+ C" ?% y* }9 [<td><code>pb_hooks/</code> 下的 JS 脚本</td>, B" R" A: l2 l* k8 s2 N  W6 Z
<td>自定义配置(如动态跨域、自定义认证规则)</td>/ V! O* c9 I3 D9 h$ i
</tr>2 A( k8 e; K9 Z$ u: ~4 {, i" s$ @  A
</tbody>/ G  n2 c( i' z8 Y
</table>
% u! `: ~% ~8 m! k<h3>前置操作(Debian 12)</h3>
# o& g/ F# U" D5 G& B# n<ol>
- K% V6 k* X# p3 ?<li>确认 PocketBase 工作目录(默认 <code>/opt/pocketbase</code>),若路径不同需替换下文所有路径;</li>' L3 h6 {4 W! f8 M) j9 D
<li>确保对 <code>pb_data/</code> 目录有读写权限:
6 N: s# E  Y) R( B( z<pre><code class="language-bash">sudo chmod -R 755 /opt/pocketbase/pb_data
: Y3 m/ e+ z0 Qsudo chown -R root:root /opt/pocketbase/pb_data  # 或你的运行用户
5 \. t, C4 p3 ^$ W</code></pre>1 T6 }3 l4 @6 s1 z8 l
</li>4 K- i+ f9 I2 F: ~3 ?
</ol>4 D# O  I1 R6 _* m  D4 B
<h2>三、核心配置模块(Debian 12 实操)</h2>
+ V: `, V+ C4 k) E2 u  _<h3>1. 基础网络配置(端口、绑定地址、HTTPS)</h3>
. f' `$ [+ U' a3 `8 j8 v9 K<h4>1.1 修改默认端口/绑定地址(3种方式)</h4>
+ r4 ~' ?3 @  L0 `2 T$ H5 L# \<p>PocketBase 默认监听 <code>0.0.0.0:8090</code>,以下是修改方式:</p>2 Y% S+ ^6 [0 ^" ?% I
<h5>方式1:命令行参数(临时生效,重启后失效)</h5>& n: e2 f3 R6 F$ @* B" Z& L
<pre><code class="language-bash"># 切换到 PocketBase 目录
9 n6 W- g1 s1 ~) f& N: o* f6 w  \cd /opt/pocketbase
1 J. e8 |2 e. R- x8 m- u/ W7 t1 s) M2 p$ y; r) {
# 监听 8080 端口,仅绑定本地回环地址(仅服务器内部访问)
1 q- b' s9 u, t7 u. `; x./pocketbase serve --http=127.0.0.1:8080
6 y, l& u! E* u& r# @& i& A% I. f: |" ^: b. B( t8 n
# 监听 80 端口(需 root 权限),绑定所有网卡; ?$ m2 D# t, ]8 g# w
sudo ./pocketbase serve --http=0.0.0.0:80
! _: T8 n0 c0 U5 O! \</code></pre>
9 L6 Y$ \% p4 M9 W: z<h5>方式2:配置文件(永久生效)</h5>! z6 c/ }# X! D
<ol>7 i* c. @  a+ T0 o( x+ j
<li>编辑配置文件:
; n% F1 }+ I/ ]8 k3 G% b' d  A<pre><code class="language-bash">nano /opt/pocketbase/pb_data/pb_config.json/ |. C: L5 Q0 q7 n" }! p/ X$ v
</code></pre>
& k5 b4 Z( I) D: ?- T: Z</li>$ P- a' ~2 {6 D
<li>添加/修改 <code>api</code> 节点(无则新增):
, s5 b, Q& g4 H# j4 r1 L<pre><code class="language-json">{3 _' z: k* ]6 K4 t) q
  &quot;api&quot;: {7 K: r7 M. g4 ]3 m/ l9 Z# u0 h3 ^
    &quot;httpAddr&quot;: &quot;0.0.0.0:8080&quot;,  // 绑定地址+端口8 o* F, B" b, Q( `8 _
    &quot;httpTimeout&quot;: 30           // 请求超时时间(秒)" |9 t. ^5 `4 T
  }) M2 |; x5 F! E7 g( m% H
}
. R! a! f" D! E! z+ {</code></pre>
- Q. W2 n+ V0 F3 C: p- u</li>
% h, _" k/ d* ]6 S  M0 L<li>保存后重启 PocketBase:
) I" y0 `8 S" o6 \% ^6 u<pre><code class="language-bash"># systemd 服务方式
! w/ a8 R# ~' Q! lsudo systemctl restart pocketbase1 l  l# `( c( h* C2 k4 W

1 |  w6 O! u2 L) u1 e! x# 堡塔面板方式:进程守护 → 重启 PocketBase) A! K$ z5 X) A' Y
</code></pre>/ J  D9 t. ]7 F9 S
</li>2 n  H1 G  `! W8 I: C2 F
</ol>
& Z" t5 Y, G  S6 p& X<h5>方式3:堡塔面板进程守护(永久生效)</h5>% v  `2 J% q, M$ [4 m6 d
<ol>
4 W  h# \/ l% I* x7 p. D8 v<li>登录堡塔面板 → 进程守护 → 找到 PocketBase 进程 → 编辑;</li>! r4 B# H0 E/ z4 V5 N4 a1 s! c
<li>修改「启动命令」为:
1 q1 K# K  n; w4 f% F2 L. X<pre><code class="language-bash">./pocketbase serve --http=0.0.0.0:80804 u- \4 _: Z& H+ e# G
</code></pre># b" H. [- B- z& ~8 R  P8 D
</li>& n+ B* [7 k. _0 F2 v( ?! r6 [
<li>保存并重启进程。</li># H' I- v$ ~# M4 Y( X" f
</ol>
0 v2 Z5 x% \! q8 b; I<h4>1.2 配置 HTTPS(Debian 12 推荐 Nginx 反向代理)</h4>, g$ p# V5 Y4 k4 ^$ `
<p>PocketBase 自身不直接支持 HTTPS,Debian 12 下推荐通过 Nginx 配置(替代 PocketBase 内置的 HTTPS 方式,更稳定):</p># o7 C1 U$ \4 }! \
<ol>- C, {5 g% }4 ]' M' @
<li>安装 Nginx(Debian 12):
* V3 u( W- H5 f) f<pre><code class="language-bash">sudo apt install nginx -y
' z7 n, [' |& h" H6 ~</code></pre>( a8 J+ T4 |" Y4 C1 t  _  G6 F! ^
</li>$ X. W* f+ W9 K6 G
<li>创建 Nginx 配置文件:
" U. G9 u8 g" }6 U% w* u<pre><code class="language-bash">sudo nano /etc/nginx/sites-available/pocketbase-https. ~8 N4 P! P" J  H0 y9 X% k
</code></pre>
% _" P( C6 L% T: m9 q9 C  P</li>4 q! v2 `1 t* Z
<li>粘贴以下配置(替换 <code>your-domain.com</code> 为你的域名):
6 ?* ?  X5 Y+ F, v<pre><code class="language-nginx">server {
' N! j+ F& u# a    listen 80;3 B2 s# D" z- t( q
    server_name your-domain.com;
- w5 }$ q$ I# S    # 重定向 HTTP 到 HTTPS7 _* S) r2 C* o2 \. y
    return 301 https://$host$request_uri;
; D" l" p) V. s& y( E8 I}9 z% w- s1 ~1 o# O: Z0 ~
/ y! O* L0 j4 l8 S' I# P) {( e
server {- E* r, R! v( H2 N  W
    listen 443 ssl http2;& r% y1 R8 E  X4 Z0 w& W
    server_name your-domain.com;( O- M# x7 t+ E1 G1 B
5 A, K3 {/ o5 ^4 U
    # SSL 证书(Let's Encrypt 免费证书)
# a, r1 _, m. L  T* `8 p4 |# t* @' X8 ^    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
4 s+ r. U% H  r6 O    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;0 k2 o3 H& ]' j. P, D
    ssl_protocols TLSv1.2 TLSv1.3;" X2 I0 l- I1 y7 o2 y
0 d* X9 P  c6 V' c! w
    # 反向代理到 PocketBase
# U" S- `1 I! K) s2 o    location / {. x* L$ ?3 V7 t2 w# j
        proxy_pass http://127.0.0.1:8090;2 f. X3 Z: w* @3 G0 R
        proxy_set_header Host $host;
/ Z/ i# G$ y* j; _        proxy_set_header X-Real-IP $remote_addr;
7 X( `7 K1 }# Z. c+ C) U7 G        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
: w4 l8 B: }+ ]# i' z. D        proxy_set_header X-Forwarded-Proto $scheme;/ P+ V6 W6 E9 |' I
    }8 `1 z# R5 X0 B. }2 n7 v
}
" w4 i4 n( Q6 @</code></pre>+ b# l% T  j- d  B9 `1 w3 I# x8 n, I
</li># P$ b' ?% j8 C
<li>启用配置并重启 Nginx:
/ R; M# M' ?( @) a9 K+ G<pre><code class="language-bash">sudo ln -s /etc/nginx/sites-available/pocketbase-https /etc/nginx/sites-enabled/
3 l) h! c6 S3 R% Z1 K8 y/ gsudo nginx -t  # 校验配置语法
4 f7 ~. o( Y; n; F5 V9 e: U1 L, asudo systemctl restart nginx
* n% r+ r5 t2 t</code></pre>
2 X1 Z/ d2 C1 T3 {0 y</li>: G6 Z/ e2 N! }; l( h
<li>申请 Let's Encrypt 证书(Debian 12):+ G0 d0 C* I8 k& w8 d
<pre><code class="language-bash">sudo apt install certbot python3-certbot-nginx -y
) f/ m8 `& I6 N: z8 m  esudo certbot --nginx -d your-domain.com! q6 o9 C4 I# ^% L: h  c
</code></pre>
/ I# h9 ]8 p, X: Y</li>
0 K! H& ^- \+ @( U, W& ]</ol>1 |" }# f0 e- ~' k; e
<h3>2. 邮件配置(SMTP,用于密码重置/验证)</h3>) A' y6 {8 Z; [! N* h/ {
<p>PocketBase 需配置 SMTP 才能发送邮件(如用户注册验证、密码重置),以下是 Debian 12 下的配置步骤:</p>6 a/ |/ f' {1 A! \0 Q) c: j
<h4>方式1:管理后台可视化配置(推荐)</h4>- s- `+ ~( q" j) G+ b7 b) f( T
<ol># B/ p' n0 p! V) L" D* V
<li>+ |5 U) L8 X1 Q$ W/ c- M2 U
<p>访问 <code>http://域名/_/</code> → 左侧「Settings」→「Mailer」;</p>! E) P. B6 T2 T; u$ P  o. c( s
</li>/ I* Z( ~4 V+ ^/ m1 d  [
<li>" S& n( q& k$ I
<p>填写 SMTP 信息(以腾讯企业邮/QQ 邮箱为例):</p>
. b3 n# _% s  ^1 x/ X<table>
2 n- @. C) w7 m* Y& S& r<thead># M5 k( s$ w6 |0 {6 K( Z3 \
<tr>
" d/ l4 V, t" N& i5 Z& Q5 H<th>配置项</th>& L- k+ F6 {, L" R) l; D
<th>填写内容(QQ 邮箱)</th>- t. V$ r+ K: z9 \; I6 Q
</tr>5 }: ?0 ~  @6 I. Y! k$ L& c
</thead>& m( f. N: c3 `. c
<tbody>4 [. s. Y* ]. V' \6 V: k! A
<tr>
# @' V* B4 {. ~9 h/ @) |8 C& X<td>From address</td>: n9 C! V- q9 e2 n) [
<td>你的邮箱(如 <code>xxx@qq.com</code>)</td>7 S3 ?  W& E9 k/ k+ n. _
</tr>& @7 n/ h$ j4 f% t$ [
<tr>" A7 {6 y3 Z  t: ~2 d# C# a- `
<td>From name</td>8 Q' d$ |+ [; ~5 t0 H
<td>PocketBase 应用(自定义)</td>
1 M7 }# D) _3 ?0 a( y$ C' r/ u</tr>' \1 Z, p# l4 A; ~5 A" E3 A
<tr>/ q3 w$ g  ^3 Z3 W) i  y
<td>SMTP host</td>) ?! Q8 r' r/ p: q6 H% O
<td>smtp.qq.com</td>
3 Y( Z; X" N4 i* z</tr>
; i/ d0 ~7 C& Y' g4 D<tr>
2 _2 w- |* A- x! G. m! v; }<td>SMTP port</td>
  z( |" \: _2 i& x<td>465(SSL)/587(TLS)</td>
" }4 E2 O5 R  n# ~: F' i' _# M</tr>4 j! O4 Z, ~* N2 B+ ]' G
<tr>. c; v) v* Z, U' O/ b* s7 U. _
<td>SMTP username</td>( o* B6 m  f* W9 T9 R0 F- \- y
<td>你的邮箱(如 <code>xxx@qq.com</code>)</td>; N( w) r6 }6 g+ C0 I' f
</tr>1 \/ y8 L1 Y  e, O& h) i; p* S
<tr>
* b: \  K# f1 \0 O7 W  K<td>SMTP password</td>* U- l- [/ h5 o" ?7 V
<td>邮箱授权码(非登录密码)</td>- J! b9 Q1 r! ]* |9 Z. C
</tr>" [; \! W2 z$ y' B( f+ b8 o: q
<tr>
5 t) R7 U7 o2 J6 A& x( T<td>SMTP secure</td>
- D3 M6 V. z2 a% X, w<td>SSL(对应 465 端口)/TLS(对应 587 端口)</td>* R; Q. A% D; |- K, L  b' |, O7 j
</tr>: o, @1 j- i9 |0 d
</tbody>9 g6 E- ^8 T; u  c/ I+ |: j
</table>- V: F0 m1 E/ [6 u2 N/ [
</li>
4 `9 Q+ m2 l0 U. ]7 }) G<li>
" l0 l0 s5 }( F' L' E1 C<p>点击「Test」测试邮件发送,成功后点击「Save」保存。</p>( G5 }. n. V4 [) k
</li>+ c* n8 j6 k0 I
</ol>1 j2 i- C5 P; ^& T6 f( e3 }
<h4>方式2:手动编辑配置文件(永久生效)</h4>1 e. x8 i8 `2 T$ f8 I  n+ G
<ol>
0 n" N* v: ?& b- n<li>编辑 <code>pb_config.json</code>:
# @# |! j; `: |<pre><code class="language-bash">nano /opt/pocketbase/pb_data/pb_config.json- ^: D2 n* C9 f1 f/ J- z0 ]  b6 f1 _
</code></pre># P. R% L, L& Z6 L: N0 T
</li>
6 T( s+ |( S6 i" r6 u4 e6 k% k8 T<li>添加/修改 <code>mailer</code> 节点:7 I/ T' S4 v/ b& Y% ?
<pre><code class="language-json">{
5 w- F9 `8 W0 J) W& X! U* }  &quot;mailer&quot;: {- Q9 l* f- g/ D% p
    &quot;fromAddress&quot;: &quot;xxx@qq.com&quot;,/ g0 i; Z* c2 o/ \) |& E
    &quot;fromName&quot;: &quot;PocketBase 应用&quot;,: k  ~) _: l) R" P1 q! p) k8 W
    &quot;smtp&quot;: {
( m* W6 Y: ?9 O6 J8 M/ J% T0 e7 J      &quot;host&quot;: &quot;smtp.qq.com&quot;,* r1 g: a( X$ u! D
      &quot;port&quot;: 465,
6 M9 h, w3 N( |5 V* K& q      &quot;username&quot;: &quot;xxx@qq.com&quot;,1 E2 m3 S& R4 E& G
      &quot;password&quot;: &quot;你的邮箱授权码&quot;,  A; y. A& q7 s2 I
      &quot;secure&quot;: true  // true=SSL,false=TLS# p0 R, e# o" `4 r& b2 d5 ~
    }
& t: w. G" b( k: c9 C# ?$ [  }" R3 J2 y; Z- f2 B5 b5 s  C# R
}
& b$ h1 ]; b$ P</code></pre>
* U  ]" y4 q4 a</li>) @4 m8 A( U+ S3 @3 O
<li>重启 PocketBase 生效。</li>
. G& n8 _0 b8 }</ol>
! q- d) o. R' R4 u<h3>3. 存储配置(本地/S3 兼容存储)</h3>
; H- j# z# F7 v9 O! G& E. Y1 w<p>PocketBase 默认将上传文件存储在 <code>pb_data/storage/</code>,可配置为 S3 兼容存储(如阿里云 OSS、腾讯云 COS)。</p>6 ^) r* S( K5 P6 J) w. Q
<h4>3.1 本地存储配置(默认,调整路径)</h4>+ R! b9 h/ Y9 m. f6 l
<ol>
4 D3 }/ D) }! w<li>编辑 <code>pb_config.json</code>:
! e: f. K2 g! B& P( v* m& }3 v4 w<pre><code class="language-bash">nano /opt/pocketbase/pb_data/pb_config.json9 P# t! z! l! c  x1 E# d; `
</code></pre>
# T1 X% [  @6 a5 ?' }</li>
2 M  l' u5 O0 E5 {! S! v1 q4 e/ n<li>修改 <code>storage</code> 节点(自定义本地存储路径):
% s0 D+ o5 J# a" [<pre><code class="language-json">{
* d! o/ B+ H. V& E! Y9 s  &quot;storage&quot;: {
7 L5 l, N+ k' @8 Q' G5 k" ^    &quot;local&quot;: {
# f/ t) w) Y- r4 V8 T+ e      &quot;path&quot;: &quot;/data/pocketbase/storage&quot;  // 自定义存储路径(Debian 12 需提前创建)1 W/ |2 n* E+ g' U( w
    },
: x) N  h4 l; j' C2 b3 `    &quot;active&quot;: &quot;local&quot;  // 启用本地存储
) t) @4 J: R! f  }, g& a# Q& W# H" L( r5 c1 z
}
* M& v4 K- F  I, @8 }( t# J. c) s</code></pre>
0 H. Q8 l7 P" ~, ]</li>* y9 }3 R8 J2 S, s& v  s4 X
<li>创建自定义路径并授权:% S) [5 F% a% ]" R3 {# s' k. ^
<pre><code class="language-bash">sudo mkdir -p /data/pocketbase/storage
1 X7 [% o3 g1 Xsudo chmod -R 755 /data/pocketbase/storage
* O* `( [' A! P) b; h. d* {sudo chown -R root:root /data/pocketbase/storage
# s% T( r0 G0 S$ L/ A+ z% |</code></pre>" ^& a6 Q8 m  o8 `# R
</li>" T' Y% y) O4 `0 O& E& ]) V
<li>重启 PocketBase 生效。</li>$ c) z- S. L! |' T
</ol>
* L6 J) J! c1 Z  p9 J9 l# ^<h4>3.2 S3 兼容存储配置(阿里云 OSS 示例)</h4>
* F  B9 N9 t& O* q# x. Q" j<ol>
& ~& `. k- D# P3 ~# v8 c+ G<li>编辑 <code>pb_config.json</code>:1 [% k" z6 ~5 G+ ]% ?% C: |
<pre><code class="language-json">{
$ e) `: G9 R$ x+ C  &quot;storage&quot;: {
/ ^3 m& D0 T1 ~4 ?  |  z    &quot;s3&quot;: {9 b3 d% m8 f! `/ K9 x
      &quot;accessKeyID&quot;: &quot;你的阿里云 AccessKey ID&quot;,1 v/ h  q. m/ e& _: A3 Q
      &quot;secretAccessKey&quot;: &quot;你的阿里云 AccessKey Secret&quot;,
% @% D; |( A- {. [7 ~, C4 x      &quot;region&quot;: &quot;oss-cn-beijing&quot;,  // 阿里云 OSS 地域" x' m/ U1 M% H/ o2 ?- D: k
      &quot;bucket&quot;: &quot;your-bucket-name&quot;,  // OSS 桶名称( s& \9 s7 I$ H" T0 h/ E7 m
      &quot;endpoint&quot;: &quot;oss-cn-beijing.aliyuncs.com&quot;,  // OSS 端点1 R- W" a4 I1 j( k# U' N, s8 x5 i
      &quot;disableSSL&quot;: false,% \* B- `7 S2 \
      &quot;forcePathStyle&quot;: false5 C. q/ R" h& f
    },
; J$ w7 R) {4 I) \# b6 @# a    &quot;active&quot;: &quot;s3&quot;  // 启用 S3 存储
! c0 M  k$ ]; X% ]& I; }' H  v3 C8 |' o  }
: V0 C) G) d! \4 M( w8 c5 B}% O' i3 [1 I7 n# l
</code></pre>
3 n% c  X+ a6 S</li>
2 Q6 p, L4 G  N7 M- R0 k: Q<li>重启 PocketBase 生效,上传文件会自动存储到 OSS 桶。</li>1 Y3 i. x% g0 q$ o
</ol># J. d6 I5 u; w4 G' J% I
<h3>4. 安全配置(跨域、认证、密码策略)</h3>" Z+ R3 D2 t3 L% F
<h4>4.1 跨域配置(CORS)</h4>
4 |8 R" W' ^0 z) O8 A- n/ R<h5>方式1:管理后台配置</h5>
# ^: W; t/ T# x: X) \<ol>
1 z9 T- y" u% f* d4 G9 A% C<li>访问 <code>http://域名/_/</code> →「Settings」→「API」;</li>
' o! j2 c, x- D6 @$ I3 y" E& s; ^& H<li>在「Allowed origins」中填写允许的跨域域名(如 <code>https://your-domain.com,http://localhost:3000</code>),多个域名用逗号分隔;</li>  H& U* [$ `: {5 w) }5 g- N% v0 s
<li>可选:开启「Allow credentials」(允许携带 Cookie/Token);</li>; o$ p; y+ Q8 n' F' z6 J
<li>保存后立即生效(无需重启)。</li>+ ~. l  W# z* Q+ K( N0 v/ K3 D
</ol>/ w  x" d! N# p( E7 N$ E. a! s
<h5>方式2:配置文件配置</h5>6 N# ]$ ~. Y4 C% q% s
<ol>5 m: X: d0 _7 Y$ {# Q
<li>编辑 <code>pb_config.json</code>:
; g7 ^7 m- T4 h<pre><code class="language-json">{
. H& d  b. C+ i% {$ W  &quot;api&quot;: {+ P2 l& A7 Q2 n& T
    &quot;allowedOrigins&quot;: [&quot;https://your-domain.com&quot;, &quot;http://localhost:3000&quot;],, @  z8 r$ z* m) L( K. j6 Y
    &quot;allowCredentials&quot;: true7 w; S4 C& R3 |- F" U! ]# `
  }" Y; j1 ?* V+ W6 [8 u# ?# C
}
3 U- B0 _. T+ |# E, G</code></pre>8 [4 Y- S2 E1 |4 B3 x
</li>
" R% I6 o! R; m8 {8 ?* Z<li>重启 PocketBase 生效。</li>0 l  K+ W. z% u; S
</ol>1 ~  J% ?6 D6 M  E* E6 o+ m. |
<h4>4.2 认证安全配置(Token 超时、密码策略)</h4>
* V# V) }! R: O) k+ N<ol>
! R+ e# c9 [+ t4 E8 \7 ]<li>2 z; I. Z+ Y' N% _- z
<p>管理后台配置路径:<code>Settings</code> →「Auth」;</p>
1 F( ~- S5 u5 I3 E7 _- r</li>
: t/ M7 T! M/ n) |; b& k5 ?<li>
8 b( Z* h, L5 ?: Q<p>核心配置项:</p>
/ M4 Q3 o+ c: j<table>
5 c. V" B- [0 e- O3 N, s8 F& d<thead>6 G; F" n! i. R6 M, e( \& W
<tr>
( x" }$ D; n6 S% N  f- f! _+ w' H<th>配置项</th>
0 c, l. H* F) H) u: C+ E1 B<th>作用</th>% ]/ N% X1 l- {' T( ?
</tr>( r# E# D9 r' z6 ]- W5 [
</thead>
. ?6 a4 R* o+ ~8 c! }& q<tbody>3 h& x) }6 V0 I" q) ~$ t) }( I
<tr>0 X3 X1 i' p- q# L9 d2 v
<td>Token duration</td>
5 M! n% i3 \; l- n<td>用户 Token 有效期(如 7d=7 天,1h=1 小时)</td>
6 A$ [' i9 L& v6 p</tr>
/ b+ G# s6 J& ]( t- m& {8 o+ {  {, t9 X<tr>1 p, a6 F. i& ]( r
<td>Password min length</td>
9 f9 n5 L: O1 _9 J% l) }<td>用户密码最小长度(推荐 ≥8)</td>7 d$ {- G) |5 ^) @( d, ~& Z; D
</tr>, F+ m0 V1 \: K6 i
<tr>
- d! @: ^9 f; x- W! j% f8 Z<td>Password require chars</td>- m* \% A5 V+ @! [
<td>密码复杂度(是否要求大小写、数字、特殊字符)</td>
" n3 w9 e( Y, V0 l- T3 P</tr>  C# u" |  ?' u$ G7 T; ^
<tr>& y" q: l, i/ \7 P& |, a5 K
<td>Max failed attempts</td>
* A4 j9 T0 t8 w: i8 s<td>登录失败最大次数(超过后锁定账号)</td>
2 w7 g! G. j9 Y( r' V. Y, m( `. O</tr>1 C2 T" j& W/ q) J
</tbody>. v3 g8 n: L* b) G
</table>
+ }3 Z9 A% B' g9 a& o* P( N8 x</li>) |& Y5 Z2 A% w4 R( e; V
<li>
# p) g& g# g) Q; u* Q) S6 [<p>保存后立即生效。</p>3 Q! l' \# A4 h5 X
</li>
; o# J! Y* G; u$ @8 p- W</ol>% K% y( d( x' ^$ j+ @, H
<h4>4.3 管理后台安全配置</h4>
, u7 h* J% }# Q# d' f6 ?<ol>
  s8 r: ?$ U6 e5 C! l" l<li>限制管理后台访问 IP(Debian 12 防火墙):& a8 ^* I& R" H: T1 X4 x
<pre><code class="language-bash"># 仅允许 192.168.1.100 访问 8090 端口(管理后台)
# N0 ~( Q# d$ a( D: C, Csudo ufw allow from 192.168.1.100 to any port 80903 C1 G  E1 r8 k7 u
sudo ufw reload
( Z' J/ ]8 f- B' I- y</code></pre>
9 t8 V1 C% j' q</li>
/ _8 r/ t* t, N# U<li>或通过钩子拦截(推荐,见前文请求拦截示例)。</li>
5 \$ l3 R# r& k. h6 @</ol>
3 Y' X* |. ~7 H$ O<h3>5. 应用基础配置(名称、日志、时区)</h3>" W. K! X! \2 P* V" t; k* |" K+ C
<h4>5.1 应用名称/描述配置</h4>" W9 p* v$ m- C  G' X* \
<ol>8 I! D3 `. l8 U5 M
<li>编辑 <code>pb_config.json</code>:
; i  e' F: t1 G8 t5 r( h<pre><code class="language-json">{& L) B8 \% v" E
  &quot;app&quot;: {8 c: N8 R: K1 s2 b# \. I, Y, @) ?& o
    &quot;name&quot;: &quot;我的 PocketBase 应用&quot;,
& R  K% ~2 {: x    &quot;url&quot;: &quot;https://your-domain.com&quot;,' `7 y+ m! G2 ~, ]% c( S$ Z# d3 Z, `
    &quot;description&quot;: &quot;基于 PocketBase 的后端服务&quot;2 w2 C- [0 R/ S7 x; `* |# q' u
  }( `: r5 v3 J2 j7 d1 ]
}/ f( o0 I/ {' I& _0 M
</code></pre>8 r* s0 f* {. \* e
</li>
$ `3 D8 ~  P- }6 j' w<li>重启生效。</li>
) g9 W, I5 z2 o2 J: R</ol>
! r" ~! j5 Y; [3 c<h4>5.2 日志配置(Debian 12 持久化日志)</h4>; {' q' T5 k3 \) _3 k- S. }6 a: Z8 V/ T0 d
<ol>' [4 q; ]. S0 y
<li>编辑 <code>pb_config.json</code>:  L5 H, Z& Y; ~% f9 w1 Y; b
<pre><code class="language-json">{  y  s4 X& X" f4 T; n. H
  &quot;logs&quot;: {
3 j) m( K# x5 A5 j# C0 ?0 \    &quot;level&quot;: &quot;info&quot;,  // 日志级别:debug/info/warn/error8 U& s& T! Y& [6 e) D
    &quot;file&quot;: &quot;/var/log/pocketbase/pb.log&quot;  // 日志文件路径(Debian 12); C( P$ q4 u9 a: h
  }
  E5 ?/ {+ l4 \: T4 L; C}
% `! v7 h2 ]- D4 @7 W7 }</code></pre>
; G: r$ r2 Q$ d  H</li>- e3 h2 r5 k- }) N# i: x
<li>创建日志目录并授权:& }' `* a" q- ]& G5 @6 B2 y
<pre><code class="language-bash">sudo mkdir -p /var/log/pocketbase3 I; |8 ~- d* ^/ Q0 M) p' l
sudo chmod -R 755 /var/log/pocketbase
: R0 _3 ^" z  \# xsudo chown -R root:root /var/log/pocketbase
  ~: ]+ d+ B# G; j4 d  g</code></pre>1 l: T0 R9 j: C% V! H, k, W- }
</li>! Q2 p: H2 I$ c- l
<li>重启 PocketBase 生效,日志会自动写入 <code>/var/log/pocketbase/pb.log</code>。</li>7 y. Z2 P& F2 |: M/ j" _
</ol>6 U' B' ~2 |9 j- i
<h4>5.3 时区配置(Debian 12 系统时区同步)</h4>- ^6 k; T+ p4 E% ]( W9 J
<ol>0 O: I5 n: X6 q+ A% K
<li>先设置 Debian 12 系统时区:8 [6 Y& V+ R2 @5 V% m( y
<pre><code class="language-bash">sudo timedatectl set-timezone Asia/Shanghai$ \: }8 Z* U+ P4 J: H
</code></pre>
( Z1 V. P. p1 R- R6 W</li>1 P3 D- A) K1 }% E! X6 U$ [
<li>PocketBase 会自动同步系统时区,无需额外配置;若需手动指定,可通过启动参数:, W/ ~* \/ X7 x
<pre><code class="language-bash">./pocketbase serve --timezone=Asia/Shanghai, p, q( `' L5 d5 `1 f  k
</code></pre>+ G) b( W' E, [" R, \$ b3 l
</li>
2 O, j8 Q0 n/ {</ol>& k! ^; \" ?  M( \- @. i. o
<h3>6. 自定义配置(钩子脚本补充)</h3>( z$ Q) w  W2 v( X
<p>对于配置文件无法实现的自定义需求,通过 <code>pb_hooks/</code> 脚本补充:</p>
& C9 S2 s+ |# r4 S6 t<h4>示例:动态跨域配置(根据请求域名放行)</h4>5 _# [& {  S* O4 U4 Q& E
<pre><code class="language-javascript">// pb_hooks/cors.hooks.js
2 E/ C" i+ a/ i' F& UonHttpRequest((e) =&gt; {  D. C& e# O% {+ X$ c! W
  // 动态允许所有子域名跨域
3 ]+ B) A( u! E+ f% d  const origin = e.request.headers.get(&quot;Origin&quot;);
; G0 x1 J2 x+ X. l% s8 U  if (origin &amp;&amp; origin.endsWith(&quot;.your-domain.com&quot;)) {7 e+ V* f/ \$ h$ e$ y' K# _* p
    e.response.headers.set(&quot;Access-Control-Allow-Origin&quot;, origin);
6 D5 s! _1 A- h$ D  S    e.response.headers.set(&quot;Access-Control-Allow-Credentials&quot;, &quot;true&quot;);
$ q/ i, [/ m+ z* ?  }
# ?9 l* L. O8 O* ^7 N$ x7 N0 L  e.next();
* A+ F8 w3 J0 A) }/ O7 v2 J) F});1 n; e( W9 e# J
</code></pre>! c1 H, p) `" q9 p5 ]" |
<h2>四、配置的备份、恢复与生效方式</h2>+ ~2 l. f1 u, o- G0 V9 E2 c* D% C
<h3>1. 配置生效方式</h3>
$ I9 M8 F( u% v7 ]/ {9 F! ~<table>
3 j  ?+ R- {5 `& f<thead>
9 I  a" O% d" @$ I<tr>. H9 _* U4 ^3 }8 [# r7 G
<th>配置类型</th>6 L  n# N: x0 `4 g: ?, j
<th>生效方式</th>
( d: F: q  t+ {! }- B, g</tr>- Y# ]7 U! v" m6 k
</thead>
# d0 x1 D6 H9 z4 y2 {6 g) |" c<tbody>
! x4 D$ m6 h3 z% d& l" C<tr>
1 x8 t' l8 t: V% R4 r<td>命令行参数</td>
  n' ]; K0 Q& u8 K5 d4 e5 |<td>启动时立即生效(临时)</td>
- V0 Y  {: m8 l2 f- H, ]</tr>
. [0 L* f/ _0 ~) K) R4 K' {<tr>
" j4 U. u0 N$ {' E<td>管理后台配置</td>- Y1 `$ u5 n9 S7 `& T
<td>保存后立即生效(部分需重启,如邮件)</td>
, C' g1 d4 }" ]+ d</tr>( k8 V2 `0 a; Y: R& M* {4 ?
<tr>
4 T, G# g' d  ]0 n9 T/ p<td>配置文件修改</td>
  F- b" e% ^' f" R<td>重启 PocketBase 生效</td>% N, X* j+ v  Y' Z0 \$ v' W1 K
</tr>7 Q  J  \/ B2 ]" k! H) c2 L, o
<tr>$ J" c' g9 g- E% y6 Z8 [
<td>钩子脚本</td>
9 g+ Q3 R5 L$ l, W) b: J9 q+ s' y7 j<td>重启 PocketBase 生效</td>
8 s% N9 M% L6 V' l' K2 ?</tr>: L9 ], k, j4 H" R! [9 j, k
</tbody>- j: C; ~3 _5 E" B) P
</table>
5 C* V" |$ j1 z: k0 a  h<h3>2. 配置备份(Debian 12)</h3>
" q9 J# a! n& `) I! G2 }3 j& r, U5 S<pre><code class="language-bash"># 备份 pb_config.json(核心配置文件)5 i5 A5 M. ?( K8 n0 N$ y8 Q4 @
cp /opt/pocketbase/pb_data/pb_config.json /opt/pocketbase/pb_config.backup.json! D% T; P" `+ }

2 H6 m" A4 S! u, `' Y  g# 完整备份所有配置+数据(推荐)7 X* O0 f1 V4 q- h
zip -r /opt/pocketbase_backup_$(date +%Y%m%d).zip /opt/pocketbase/pb_data/  Y: a0 R5 O& D) P. s# |# D* m0 s
</code></pre>
/ n: m1 l8 o" K+ ^! B# ^$ v5 v, F<h3>3. 配置恢复</h3>* J- H5 M$ x' d* k( b
<pre><code class="language-bash"># 恢复配置文件
9 a) D- G6 Y) O* D- ccp /opt/pocketbase/pb_config.backup.json /opt/pocketbase/pb_data/pb_config.json; R* I6 \6 ~. l$ `4 {& W
  Q4 H6 V$ M2 ^
# 重启 PocketBase
/ O, n0 ]  [# E) w4 P' Lsudo systemctl restart pocketbase% E( N& w; t+ V2 c5 C: S3 u
</code></pre>( m: j2 e5 r7 |& w  e, f
<h3>4. 常见配置问题排查</h3>6 C& v: v( d  a2 d! n; |! }) ?' i
<h4>问题1:配置修改后不生效</h4>
5 h: T% x/ n5 |<ul>% n& s5 y% Z! s# g" S7 d
<li>检查是否重启 PocketBase;</li>
3 A' a! x3 ~" D( `8 |" E<li>检查配置文件语法(JSON 格式是否正确,可通过 <code>https://jsonlint.com/</code> 校验);</li>* @0 k7 t: M8 u3 }6 B
<li>检查配置文件权限(是否可读写)。</li>
( J5 W1 |* S' ^0 L# J( e</ul>. l" t! @5 B! c
<h4>问题2:邮件发送失败</h4>" c5 D4 [% L! K1 m
<ul>3 |1 C' \1 p3 s- L- l& G
<li>检查 SMTP 端口是否开放(Debian 12 防火墙/云服务器安全组);</li>
- r) `* L* k" b. _; d4 i5 O  Y% C<li>验证 SMTP 账号/授权码是否正确;</li>7 Z3 A, t; g) V1 J' e
<li>查看 PocketBase 日志:<code>sudo journalctl -u pocketbase -f</code>。</li>
8 H8 n6 ^# Y/ |5 z6 i7 k( e: [</ul>
) p) }( V+ M7 ~, @<h4>问题3:端口无法访问</h4>! m7 r! H2 H9 ~, h$ H) ?
<ul>
- @3 ^& G$ t' L# r$ u4 O/ c: Z<li>检查 Debian 12 防火墙:<code>sudo ufw status</code>;</li>
9 R7 L: k  f9 [5 Q5 ^8 y/ ^3 _% M<li>检查云服务器安全组是否开放端口;</li>2 k& p; b' \" P6 O
<li>检查 PocketBase 绑定地址(是否为 <code>0.0.0.0</code>,而非 <code>127.0.0.1</code>)。</li>
- ?# k) K6 v$ O8 k4 P3 I% v: \</ul>6 s6 g$ V& v( ^( ~+ D" L, r3 |
<h2>五、总结</h2>+ ?, p0 `1 u9 J
<ol>
0 z6 p! l7 P1 q" ]  F<li><strong>配置核心入口</strong>:. [( C/ n* A+ e) @
<ul>) @5 q& j, m5 [
<li>基础配置(网络、邮件、存储)优先通过 <code>pb_config.json</code> 或管理后台配置(永久生效);</li>
$ `0 G: O2 ]. U/ u- \) K; ^5 V: t" Z<li>临时测试用命令行参数(重启失效);</li>
) U" T) d9 C4 h, S$ q<li>自定义逻辑用钩子脚本补充。</li>. V: }, U' ?: T! c8 j
</ul># @( Z: h; o9 R* P/ q
</li>
3 ]/ s/ \* J9 q$ I8 r- w* U<li><strong>Debian 12 关键操作</strong>:
' X$ ?9 f4 u; u9 `<ul>
: `; k$ ^! c5 P3 f2 h7 @* j<li>修改配置文件后需重启 PocketBase(systemctl/堡塔面板);</li>' U. l  {+ H$ c- b: M. _! W$ M/ E$ H3 F9 I
<li>自定义路径(存储/日志)需提前创建并授权;</li>  x: X8 P8 z$ h1 Q7 W
<li>HTTPS 推荐用 Nginx 反向代理,而非 PocketBase 内置方式。</li>
0 q. ~, b! [/ V' Z</ul>2 Z3 F! t8 U' N
</li>
$ t& A5 {# r, L( ?" l<li><strong>生产环境必配</strong>:4 l. ]+ p! T7 V: e+ \8 S% F+ P- ~
<ul>
2 w. w: E( o1 J' T/ |0 s* n<li>邮件配置(密码重置)、HTTPS(安全访问)、跨域配置(前端访问)、日志持久化(排查问题);</li>: Y, d! I" f+ _9 Q4 F, H: l  Y: e
<li>配置文件定期备份,避免丢失。</li>
6 X) a' Q2 ?! ~</ul>7 T" B; j& `' G: h
</li>
; g0 l, z  ~7 j' l8 {</ol>
$ j7 K- g5 V; F% u<p>通过以上配置,可完全适配 Debian 12 系统下 PocketBase 的生产环境需求,兼顾安全性、稳定性和自定义性。</p>
* s8 }9 e& S3 W1 z0 t8 E. p
匠心独运,千锤百炼,品质非凡。
回复

使用道具 举报

回复

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

本版积分规则

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