跳转至主要内容

PocketBase + Caddy 安装和快速添加项目的一键脚本

ghostart

PocketBase 非常适合个人小项目,AI 编程场景下的后端用户注册登录、数据和文件存储必备。

PocketBase 视频教程推荐

这个脚本可以快速安装 PocketBase 和 Caddy,并实现快速添加多个 PocketBase 和绑定域名,自动申请 SSL 证书,以便用于不同的项目。提前解析域名之后,运行脚本即可开始使用。

创建脚本

vim pocketbase.sh
#!/bin/bash

# ==============================================================================
# 脚本名称: install_pocketbase.sh
# 描述:     在 Ubuntu VPS 上安装 PocketBase 和 Caddy,并管理多个项目实例。
# 作者:     ghostart.blog
# ==============================================================================

# 颜色定义
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color

# 确保脚本以 root 权限运行 (Caddy 和 systemd 操作需要)
# if [[ $EUID -ne 0 ]]; then
#   echo -e "${RED}错误: 此脚本必须以 root 权限运行。${NC}"
#   echo -e "请尝试使用: ${YELLOW}sudo ./install_pocketbase.sh${NC}"
#   exit 1
# fi
# 注意:直接以 root 运行脚本不是最佳实践,但 Caddy 和 systemd 的操作确实需要 sudo。
# 脚本中已为需要 root 权限的命令添加了 'sudo',因此请以普通用户运行,
# 它会在需要时提示您输入 sudo 密码。

# ------------------------------------------------------------------------------
# 函数: 首次安装 PocketBase 和 Caddy
# ------------------------------------------------------------------------------
initial_setup() {
    echo -e "${GREEN}--- 1. 开始系统更新与清理 ---${NC}"
    sudo apt update && sudo apt upgrade -y && sudo apt autoremove -y
    echo -e "${GREEN}系统更新完成。${NC}"

    echo -e "\n${GREEN}--- 2. 安装 unzip ---${NC}"
    sudo apt install unzip -y
    echo -e "${GREEN}unzip 安装完成。${NC}"

    echo -e "\n${GREEN}--- 3. 下载 PocketBase ---${NC}"
    read -p "请输入 PocketBase 版本号 (回车则默认使用 0.31.0): " PB_VERSION
    # 如果输入为空,则使用默认值
    PB_VERSION=${PB_VERSION:-"0.31.0"}
    
    PB_ZIP_FILE="pocketbase_${PB_VERSION}_linux_amd64.zip"
    PB_DOWNLOAD_URL="https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/${PB_ZIP_FILE}"
    PB_ZIP_PATH="$HOME/${PB_ZIP_FILE}"

    echo -e "${YELLOW}正在从 ${PB_DOWNLOAD_URL} 下载...${NC}"
    wget -O "$PB_ZIP_PATH" "$PB_DOWNLOAD_URL"

    if [ $? -ne 0 ]; then
        echo -e "${RED}下载失败! 请检查版本号或网络连接。${NC}"
        return 1
    fi
    echo -e "${GREEN}PocketBase v${PB_VERSION} 下载完成,已保存至 ${PB_ZIP_PATH}${NC}"

    echo -e "\n${GREEN}--- 4. 安装 Caddy ---${NC}"
    sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list > /dev/null
    sudo apt update
    sudo apt install caddy
    echo -e "${GREEN}Caddy 安装完成。${NC}"

    echo -e "\n${GREEN}--- 5. 配置 Caddy ---${NC}"
    read -p "请输入用于 Caddy 自动申请 SSL 证书的邮箱: " CADDY_EMAIL
    if [ -z "$CADDY_EMAIL" ]; then
        echo -e "${RED}邮箱不能为空!${NC}"
        return 1
    fi

    echo -e "${YELLOW}正在写入 /etc/caddy/Caddyfile...${NC}"
    # 使用 sudo tee 写入 Caddyfile
    sudo tee /etc/caddy/Caddyfile > /dev/null <<EOF
{
  email $CADDY_EMAIL
}
EOF
    echo -e "${GREEN}Caddyfile 配置完成。${NC}"

    echo -e "\n${GREEN}--- 6. 启动并设置 Caddy 开机自启 ---${NC}"
    sudo systemctl enable caddy
    sudo systemctl start caddy
    sudo systemctl status caddy --no-pager
    echo -e "${GREEN}Caddy 已启动并设置开机自启${NC}"

    echo -e "\n${GREEN}--- 7. 配置防火墙 (ufw) ---${NC}"
    echo -e "${YELLOW}为 Caddy 开放 HTTP (80) 和 HTTPS (443) 端口...${NC}"
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    echo -e "${GREEN}防火墙规则已添加${NC}"

    echo -e "\n${GREEN}🎉 首次安装全部完成!${NC}"
    echo -e "${YELLOW}再次执行脚本可以开始添加 PocketBase 项目${NC}"
}

# ------------------------------------------------------------------------------
# 函数: 添加新的 PocketBase 项目实例
# ------------------------------------------------------------------------------
add_project() {
    echo -e "${GREEN}--- 1. 准备项目环境 ---${NC}"
    read -p "请输入新项目的文件夹名称 (例如: project1): " PROJECT_NAME
    if [ -z "$PROJECT_NAME" ]; then
        echo -e "${RED}项目名称不能为空!${NC}"
        return 1
    fi
    if [ -d "$PROJECT_NAME" ]; then
        echo -e "${RED}错误: 目录 ${PROJECT_NAME} 已存在!${NC}"
        return 1
    fi

    # 询问 PB 版本,并检查 zip 文件是否存在
    read -p "请输入您已下载的 PocketBase 版本号 (默认 0.31.0): " PB_VERSION
    PB_VERSION=${PB_VERSION:-"0.31.0"}
    PB_ZIP_FILE="pocketbase_${PB_VERSION}_linux_amd64.zip"
    PB_ZIP_PATH="$HOME/${PB_ZIP_FILE}"

    if [ ! -f "$PB_ZIP_PATH" ]; then
        echo -e "${RED}错误: 未在 ${PB_ZIP_PATH} 找到 PocketBase 压缩包。${NC}"
        echo -e "${YELLOW}请确保该文件存在,或者先运行“首次安装”来下载它。${NC}"
        return 1
    fi

    echo -e "${YELLOW}正在创建目录 ${PROJECT_NAME} 并解压 PocketBase...${NC}"
    mkdir "$PROJECT_NAME"
    cp "$PB_ZIP_PATH" "$PROJECT_NAME/"
    cd "$PROJECT_NAME"
    unzip "$PB_ZIP_FILE"
    chmod +x pocketbase
    echo -e "${GREEN}项目目录 (${PROJECT_NAME}) 中的文件:${NC}"
    ls -l
    WORKING_DIR=$(pwd) # 获取完整的绝对路径
    cd .. # 返回上一级目录
    echo -e "${GREEN}项目准备完成,工作目录: ${WORKING_DIR}${NC}"

    echo -e "\n${GREEN}--- 2. 创建 systemd 服务与配置防火墙 ---${NC}"
    read -p "请输入此项目实例的端口号 (留空则默认 8090): " PB_PORT
    PB_PORT=${PB_PORT:-"8090"}

    echo -e "${YELLOW}正在为端口 ${PB_PORT} 添加防火墙规则 (ufw allow ${PB_PORT}/tcp)...${NC}"
    sudo ufw allow ${PB_PORT}/tcp
    echo -e "${GREEN}防火墙规则已添加。${NC}"

    SERVICE_NAME="pocketbase-$PROJECT_NAME"
    SERVICE_FILE_PATH="/etc/systemd/system/${SERVICE_NAME}.service"

    echo -e "${YELLOW}正在创建服务文件: ${SERVICE_FILE_PATH}${NC}"
    # 使用 sudo tee 写入 service 文件
    sudo tee "$SERVICE_FILE_PATH" > /dev/null <<EOF
[Unit]
Description=PocketBase ${PROJECT_NAME} service
After=network.target

[Service]
User=root
Group=root
Type=simple
WorkingDirectory=${WORKING_DIR}
ExecStart=${WORKING_DIR}/pocketbase serve --http="127.0.0.1:${PB_PORT}"
Restart=always
RestartSec=3
LimitNOFILE=4096

[Install]
WantedBy=multi-user.target
EOF
    echo -e "${GREEN}服务文件创建成功。${NC}"

    echo -e "\n${GREEN}--- 3. 配置 Caddy 反向代理 ---${NC}"
    read -p "请输入您要绑定的域名 (例如: ${PROJECT_NAME}.example.com): " DOMAIN_NAME
    if [ -z "$DOMAIN_NAME" ]; then
        echo -e "${RED}域名不能为空!${NC}"
        return 1
    fi

    echo -e "${YELLOW}正在将域名配置追加到 /etc/caddy/Caddyfile...${NC}"
    # 使用 sudo tee -a 追加配置
    echo "" | sudo tee -a /etc/caddy/Caddyfile > /dev/null
    sudo tee -a /etc/caddy/Caddyfile > /dev/null <<EOF
${DOMAIN_NAME} {
  reverse_proxy localhost:${PB_PORT}
}
EOF
    echo -e "${GREEN}Caddyfile 配置追加成功。${NC}"

    echo -e "\n${GREEN}--- 4. 重载 Caddy 配置 ---${NC}"
    sudo systemctl reload caddy
    echo -e "${GREEN}Caddy 配置已重载。${NC}"

    echo -e "\n${GREEN}--- 5. 启动服务并创建 PocketBase 管理员 ---${NC}"
    read -p "请输入新 PocketBase 实例的管理员邮箱: " ADMIN_EMAIL
    read -s -p "请输入新 PocketBase 实例的管理员密码: " ADMIN_PASS
    echo # 换行
    if [ -z "$ADMIN_EMAIL" ] || [ -z "$ADMIN_PASS" ]; then
        echo -e "${RED}管理员邮箱和密码均不能为空!${NC}"
        return 1
    fi

    sudo systemctl daemon-reload # 重新加载 systemd 配置,因为创建了新服务
    sudo systemctl enable "$SERVICE_NAME"
    sudo systemctl start "$SERVICE_NAME"

    echo -e "${YELLOW}已启动服务,等待 3 秒让 PocketBase 初始化数据库...${NC}"
    sleep 3

    # 停止服务以安全地创建管理员 (防止 "database is locked")
    sudo systemctl stop "$SERVICE_NAME"
    echo -e "${YELLOW}服务已临时停止,正在创建超级管理员...${NC}"

    # 进入工作目录执行 upsert 命令
    cd "$WORKING_DIR"
    ./pocketbase superuser upsert "$ADMIN_EMAIL" "$ADMIN_PASS"
    cd ..

    echo -e "${YELLOW}管理员创建成功,正在重启服务...${NC}"
    sudo systemctl start "$SERVICE_NAME"
    
    echo -e "\n${GREEN}服务状态:${NC}"
    sudo systemctl status "$SERVICE_NAME" --no-pager

    echo -e "\n${GREEN}--- 🎉 新项目添加完成! ---${NC}"
    echo -e "项目名称: ${YELLOW}${PROJECT_NAME}${NC}"
    echo -e "后台地址: ${YELLOW}https://${DOMAIN_NAME}/_${NC}"
    echo -e "管理员邮箱: ${YELLOW}${ADMIN_EMAIL}${NC}"
}

# ------------------------------------------------------------------------------
# 主菜单
# ------------------------------------------------------------------------------
main_menu() {
    echo -e "\n${GREEN}=====================================${NC}"
    echo -e "${GREEN}  PocketBase & Caddy 多项目管理脚本  ${NC}"
    echo -e "${GREEN}=====================================${NC}"
    echo -e "请选择一个操作:"
    echo -e "  ${YELLOW}1)${NC} 首次安装 PocketBase 和 Caddy"
    echo -e "  ${YELLOW}2)${NC} 添加一个新的 PocketBase 项目实例"
    echo -e "  ${YELLOW}3)${NC} 退出脚本"
    read -p "请输入选项 [1-3]: " choice

    case $choice in
        1)
            initial_setup
            ;;
        2)
            add_project
            ;;
        3)
            echo -e "${GREEN}再见!${NC}"
            exit 0
            ;;
        *)
            echo -e "${RED}无效选项,请输入 1, 2 或 3。${NC}"
            main_menu
            ;;
    esac
}

# 运行主菜单
main_menu
# 后续步骤:
# 授予执行权限:chmod +x pocketbase.sh
# 运行脚本:./pocketbase.sh

授予执行权限

chmod +x pocketbase.sh

运行脚本

./pocketbase.sh