Ubuntu 22.04 安装 Beaver Habit Tracker v0.10.0 指南

Ubuntu 22.04 源码安装 BeaverHabits v0.10.0 实战:uv 与 pip 双方案 0→1 安装、systemd 托管、配置、升级回滚与 7 类故障排障,全部命令实测。

Beaver Habit TrackerBeaver Habit Tracker习惯追踪Ubuntu 22.04Python2026/10/23

Ubuntu 22.04 安装 Beaver Habit Tracker v0.10.0 指南

目标:在 Ubuntu 22.04 服务器上从零安装 Beaver Habit Tracker(BeaverHabits)v0.10.0,并以 systemd 托管为常驻生产服务。全文提供两种安装方案:方案 A 使用官方推荐的 uv 工具链(锁版本、可复现),方案 B 使用系统 Python + pip(不引入额外工具链),两种方案均给出完整命令与实测回显。已在 Ubuntu 22.04(x86_64)环境逐条实测通过,安装根目录 /opt/beaverhabits,数据目录 /opt/beaverhabits/.user/,服务端口 8080,示例管理账号 admin@example.com / q1w2e3r4。

一、环境信息

本文所有命令与回显均在以下环境实测(2026-10-22):

  • 操作系统:Ubuntu 22.04 LTS(x86_64,内核 5.15+ 均适用)
  • 应用版本:Beaver Habit Tracker v0.10.0(源码标签 v0.10.0,对应提交 4b3bc6d)
  • Python:3.12.15(deadsnakes PPA 安装,系统级 /usr/bin/python3.12)
  • 包管理工具:uv 0.13.5(方案 A)/ pip 25.0.1(方案 B)
  • 应用服务器:gunicorn 26.x + uvicorn-worker(单 worker,监听 0.0.0.0:8080)
  • 安装目录:/opt/beaverhabits;数据目录:/opt/beaverhabits/.user/
  • 运行账号:系统服务账号 beaver(无登录 shell)
  • 服务管理:systemd(单元文件 /etc/systemd/system/beaverhabits.service)

二、前置条件

开始安装前,请确认以下条件已满足。每条都给出检查命令与期望结果,避免装到一半才发现环境缺项。

  1. 一台 Ubuntu 22.04 服务器,拥有 root 权限(本文命令均以 root 执行;如用普通用户,请在每条命令前加 sudo);
  2. 服务器可访问外网(需访问 GitHub 拉取源码、PyPI 下载依赖包、launchpad.net 添加 PPA);内网隔离环境请直接采用方案 B 的离线思路(见 5.1 方案说明);
  3. 端口 8080 未被占用(或你计划使用的其他端口),检查命令:
ss -ltn | grep 8080 || echo "8080 端口空闲"

实测回显(空闲时):

8080 端口空闲

若回显为空但 echo 也未输出,说明命令拼写有误;若 grep 命中了监听行(如 LISTEN 0 511 *:8080),说明端口已被占用,需先释放或在后续配置中改用其他端口。

  1. 基础工具 git 与 curl(步骤 4.2 一并安装);
  2. 磁盘空间不少于 1GB(源码约 10MB,依赖虚拟环境约 300-400MB,SQLite 数据随使用增长)。

三、版本选型说明

BeaverHabits 遵循语义化版本,源码标签带 v 前缀(如 v0.10.0),而 Docker Hub 镜像标签不带 v(如 0.10.0)——这是同一版本的两种命名,源码安装一律使用带 v 的标签。近六个稳定版本如下(GitHub releases 实查,查询日期 2026-10-22):

版本发布日期关键变化
v0.10.02026-07-30原生客户端实时同步(WebSocket /api/v1/sync/ws)、无损快照导出、iOS TestFlight
v0.9.12026-05-20完成状态总览页、TIME_ZONE 环境变量、自定义 CSS XSS 修复
v0.9.02026-02-20OpenClaw AI 集成、长期 API Token
v0.8.22026-02-03管理员编程创建用户端点
v0.8.12026-01-04streak 图标自定义、skip/failed 状态、全局视图页
v0.8.02025-12-02备注标签驱动 streak 定制

选型建议:新装一律选最新稳定版 v0.10.0(本文实测版本);已运行的旧版本升级方法见第八章。BeaverHabits 版本迭代以功能增强为主、破坏性变更少,紧跟最新稳定版的风险很低;但升级前仍建议按第九章 FAQ 的方式备份 .user/ 目录。

四、方案 A:uv 工具链源码安装(在线,官方推荐)

4.1 方案说明

BeaverHabits 官方开发与构建均使用 uv 工具链(README 明确写有 "BeaverHabits favors uv as package management tool"),仓库自带 uv.lock 锁定文件。本方案用 uv 按 uv.lock 精确复现官方构建的依赖版本组合,可复现性最好,是与官方 Docker 镜像内部构建完全一致的安装路径。

方案主线:装基础依赖 → 装 uv → 装系统级 Python 3.12 → 拉源码 → uv 依赖安装 → 建运行账号 → systemd 托管 → 验证。

4.2 安装基础依赖

更新软件源索引并安装 git、curl(后续拉源码与下载工具用):

apt-get update

实测回显(输出较长,节选首尾):

Get:1 http://security.ubuntu.com/ubuntu jammy-security InRelease [129 kB]
...
Get:18 http://archive.ubuntu.com/ubuntu jammy-backports/main amd64 Packages [82.9 kB]
Fetched 49.0 MB in 14s (3549 kB/s)
Reading package lists...
DEBIAN_FRONTEND=noninteractive apt-get install -y git curl ca-certificates

实测回显(节选尾部):

Setting up git (1:2.34.1-1ubuntu1.15) ...
Processing triggers for man-db (2.10.2-1) ...
Running hooks in /etc/ca-certificates/update.d...
done.

⚠️ 注意:若 apt-get update 报 Temporary failure resolving 类错误,说明服务器无法解析域名,请先修复 DNS(检查 /etc/resolv.conf)再继续。

4.3 安装 uv

用官方安装脚本安装 uv(安装到当前用户 ~/.local/bin/,本文将其软链到系统路径便于后续使用):

curl -LsSf https://astral.sh/uv/install.sh | sh
ln -sf /root/.local/bin/uv /usr/local/bin/uv
uv --version

实测回显:

uv 0.13.5 (x86_64-unknown-linux-gnu)

💡 说明:uv 是 Rust 编写的 Python 包与项目管理器,替代 pip/venv/virtualenv 的组合,核心优势是全局缓存与 uv.lock 锁定文件的确定性安装。若你所在团队已统一使用 pip 工作流,可跳过本节直接采用第五章方案 B。

4.4 安装系统级 Python 3.12

BeaverHabits v0.10.0 要求 Python >=3.12(pyproject.toml 声明 requires-python = ">=3.12,<4.0"),而 Ubuntu 22.04 自带的是 Python 3.10,需要通过社区维护的 deadsnakes PPA 安装 3.12。这里特意选择系统级安装而非让 uv 自动下载 Python:uv 默认把受管 Python 装到执行账号的家目录(root 时为 /root/.local/share/uv/python/),后续 systemd 以 beaver 账号运行服务时会因无权访问该目录而启动失败(实测排障见 4.9 的 ⚠️ 与第九章 FAQ 2)。

DEBIAN_FRONTEND=noninteractive apt-get install -y software-properties-common
add-apt-repository -y ppa:deadsnakes/ppa
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y python3.12
/usr/bin/python3.12 --version

实测回显(add-apt-repository 节选 + 版本验证):

Adding key to /etc/apt/trusted.gpg.d/deadsnakes-ubuntu-ppa.gpg with fingerprint F23C5A6CF475977595C89F51BA6932366A755776
...
Python 3.12.15

4.5 获取源码

克隆 v0.10.0 标签到 /opt/beaverhabits:

git clone --depth 1 --branch v0.10.0 https://github.com/daya0576/beaverhabits.git /opt/beaverhabits

实测回显(节选尾部;--branch 指向标签时 git 会提示 detached HEAD,属正常现象):

Note: switching to '4b3bc6d64548feb3c0a431d70f307be1117a820c'.
...
Turn off this advice by setting config variable advice.detachedHead to false

确认源码完整:

ls /opt/beaverhabits

实测回显:

beaverhabits  docker      healthcheck.py  openclaw  pytest.ini  start.sh  tests
uv.lock       README.md   fly.toml        LICENSE   pyproject.toml  statics

⚠️ 注意:--depth 1 浅克隆只取 v0.10.0 一个提交,节省时间与磁盘;若后续需要 git pull 方式升级(第八章),建议改用完整克隆 git clone --branch v0.10.0 https://github.com/daya0576/beaverhabits.git /opt/beaverhabits。

4.6 安装依赖(uv sync)

按 uv.lock 锁定版本安装生产依赖。参数与官方 Dockerfile 构建命令保持一致:--frozen 严格按锁定文件不重新解析、--no-dev 跳过开发依赖、--no-install-project 不把应用本身装成包(应用以源码目录直接运行)、--python 显式指定刚装好的系统级 Python:

cd /opt/beaverhabits
uv sync --frozen --no-dev --no-install-project --python /usr/bin/python3.12

实测回显(输出较长,节选尾部):

 + pydantic-settings==2.14.2
 + pygments==2.20.0
 + pyjwt==2.13.0
 + python-dateutil==2.9.0.post0
 + python-dotenv==1.2.2
 + python-engineio==4.13.3
 + python-multipart==0.0.32
 + python-socketio==5.16.3
 + pytz==2024.2
 + pyyaml==6.0.3
 + redis==8.0.0
 + requests==2.34.2
 + sqlalchemy==2.0.51
 + uvicorn==0.49.0
 + uvicorn-worker==0.4.0
 + uvloop==0.22.1
 + websockets==16.0
 + yarl==1.24.2

验证虚拟环境与应用服务器就位:

ls /opt/beaverhabits/.venv/bin/ | grep -E '^(python|gunicorn|uvicorn)$'

实测回显:

gunicorn
python
python3
python3.12
uvicorn

4.7 创建运行账号

创建无登录 shell 的系统服务账号 beaver,并把安装目录属主交给它(数据目录 .user/ 需要写权限):

useradd -r -s /usr/sbin/nologin beaver
mkdir -p /home/beaver
chown -R beaver:beaver /opt/beaverhabits /home/beaver
id beaver

实测回显:

uid=999(beaver) gid=999(beaver) groups=999(beaver)

⚠️ 注意:/home/beaver 目录必须有且属主为 beaver——gunicorn 运行时会在用户家目录下创建控制套接字目录 .gunicorn/,家目录缺失或不属主时日志会出现 Control server error: [Errno 13] Permission denied 告警(不影响服务,但建议消除,见第九章 FAQ 3)。

4.8 配置生产启动

BeaverHabits 的生产入口是仓库自带的 start.sh prd,其实际执行的核心命令为(start.sh 实查):

gunicorn beaverhabits.main:app --bind 0.0.0.0:8080 -w 1 -k uvicorn_worker.UvicornWorker --max-requests 10000 --log-level info

三个关键点(配置解读):

  • -w 1:固定单 worker。BeaverHabits 的 Web 交互基于 socket.io 长连接,多 worker 会导致连接漂移到不同进程而出错,不要改大;
  • -k uvicorn_worker.UvicornWorker:让 gunicorn 承载 uvicorn 的 ASGI 异步运行时;
  • --max-requests 10000:每个 worker 处理 1 万请求后自动重启进程,规避潜在内存缓涨。

环境变量 ENV=production 会启用生产模式(同时默认把 NiceGUI 的浏览器端存储路径设为 .user/.nicegui)。这些将在 systemd 单元中显式声明。

4.9 systemd 托管

创建单元文件 /etc/systemd/system/beaverhabits.service:

cat > /etc/systemd/system/beaverhabits.service <<'EOF'
[Unit]
Description=Beaver Habit Tracker (BeaverHabits)
After=network.target

[Service]
Type=simple
User=beaver
Group=beaver
WorkingDirectory=/opt/beaverhabits
Environment=ENV=production
Environment=NICEGUI_STORAGE_PATH=/opt/beaverhabits/.user/.nicegui
ExecStart=/opt/beaverhabits/.venv/bin/gunicorn beaverhabits.main:app --bind 0.0.0.0:8080 -w 1 -k uvicorn_worker.UvicornWorker --max-requests 10000 --log-level info
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

配置逐项说明:

  • User/Group=beaver:以低权限服务账号运行,不使用 root;
  • WorkingDirectory=/opt/beaverhabits:应用要求在该目录下启动,beaverhabits 包与 .user/ 数据目录都按相对路径解析;
  • Environment=ENV=production:生产模式开关(对应 configs.py 的 ENV 字段);
  • Environment=NICEGUI_STORAGE_PATH=...:显式指定 NiceGUI 浏览器端存储目录,避免权限歧义;
  • ExecStart:直接指向虚拟环境内的 gunicorn 绝对路径(等价于 start.sh prd,但 systemd 下无需再套一层 shell);
  • Restart=on-failure + RestartSec=5:异常退出 5 秒后自动拉起。

⚠️ 注意(实测排障沉淀):如果 4.4 步没有安装系统级 Python 3.12,而是让 uv 自动下载了受管 Python,本步启动会失败——systemd 日志报 Failed to execute /opt/beaverhabits/.venv/bin/gunicorn: Permission denied、状态码 203/EXEC。根因是 uv 把 Python 解释器装在 /root/.local/share/uv/python/ 下,beaver 账号无法访问 venv 中指向该路径的 python。解决办法就是按 4.4 用系统级 Python 重建虚拟环境(rm -rf .venv 后重跑 uv sync ... --python /usr/bin/python3.12),详见第九章 FAQ 2。

加载并启用服务(每条命令仅针对一个单元):

systemctl daemon-reload
systemctl enable beaverhabits

实测回显:

Created symlink /etc/systemd/system/multi-user.target.wants/beaverhabits.service → /etc/systemd/system/beaverhabits.service.
systemctl start beaverhabits

4.10 验证

依次确认服务状态、HTTP 服务与监听端口:

systemctl is-enabled beaverhabits

实测回显:

enabled
systemctl is-active beaverhabits

实测回显:

active
systemctl status beaverhabits --no-pager | head -12

实测回显:

● beaverhabits.service - Beaver Habit Tracker (BeaverHabits)
     Loaded: loaded (/etc/systemd/system/beaverhabits.service; enabled; vendor preset: enabled)
     Active: active (running) since Thu 2026-10-22 16:36:39 UTC; 14s ago
   Main PID: 2236 (gunicorn)
      Tasks: 4 (limit: 94371)
     Memory: 145.0M
        CPU: 2.133s
     CGroup: /system.slice/beaverhabits.service
             ├─2236 /opt/beaverhabits/.venv/bin/python /opt/beaverhabits/.venv/bin/gunicorn beaverhabits.main:app --bind 0.0.0.0:8080 -w 1 -k uvicorn_worker.UvicornWorker --max-requests 10000 --log-level info
             └─2238 /opt/beaverhabits/.venv/bin/python /opt/beaverhabits/.venv/bin/gunicorn beaverhabits.main:app --bind 0.0.0.0:8080 -w 1 -k uvicorn_worker.UvicornWorker --max-requests 10000 --log-level info

应用启动日志(journalctl 节选):

journalctl -u beaverhabits --no-pager -n 5

实测回显:

Oct 22 16:37:06 beaver-server gunicorn[2268]: 2026-10-22 16:37:06.506 | INFO     | beaverhabits.main:<module>:16 - Starting BeaverHabits...
Oct 22 16:37:06 beaver-server gunicorn[2268]: [2026-10-22 16:37:06 +0000] [2268] [INFO] Started server process [2268]
Oct 22 16:37:06 beaver-server gunicorn[2268]: [2026-10-22 16:37:06 +0000] [2268] [INFO] Waiting for application startup.
Oct 22 16:37:06 beaver-server gunicorn[2268]: [2026-10-22 16:37:06 +0000] [2268] [INFO] Application startup complete.

HTTP 验证(登录页应返回 200;根路径 / 会 307 跳转到 /login,同样正常):

curl -si --max-time 10 http://127.0.0.1:8080/login | head -3

实测回显:

HTTP/1.1 200 OK
date: Thu, 22 Oct 2026 16:36:53 GMT
server: uvicorn
curl -si --max-time 10 http://127.0.0.1:8080/ | head -4

实测回显:

HTTP/1.1 307 Temporary Redirect
date: Thu, 22 Oct 2026 16:28:56 GMT
server: uvicorn
location: /login
vary: Cookie

最后确认数据文件已自动创建(首次启动即初始化 SQLite 库):

ls -la /opt/beaverhabits/.user/

实测回显:

total 104
drwxr-xr-x 2 beaver beaver     4096 Oct 22 16:36 .
drwxr-xr-x 13 beaver beaver     4096 Oct 22 16:36 ..
-rw-r--r--  1 beaver beaver    94208 Oct 22 16:36 habits.db

浏览器访问 http://<服务器IP>:8080,看到登录/注册页即安装成功。首次使用先注册账号(示例:admin@example.com / q1w2e3r4,仅本文演示用,生产请更换强口令),再登录创建习惯开始打卡。API 调用与更多验证手段见本专栏《Beaver Habit Tracker v0.10.0 API 使用详解》。

五、方案 B:pip + venv 安装(备用)

5.1 方案说明

不引入 uv 工具链,直接用 Ubuntu 系统级 Python 3.12 创建 venv 并以 pip 安装依赖。适用场景:受管控的服务器不允许安装额外二进制工具、或团队标准就是 pip 工作流。与方案 A 的差异在于依赖解析:方案 A 按 uv.lock 锁定精确版本(如 nicegui==3.13.0),方案 B 按 pyproject.toml 的版本范围解析,实际会装到更新的兼容版本(实测 nicegui==3.18.0、gunicorn==26.2.0),启动与功能验证一致。

方案主线:装 Python 3.12 与 venv 支持 → 拉源码 → 建 venv → pip 装依赖 → 启动验证 → systemd 托管。本方案在 4.4 已装 deadsnakes Python 的基础上只需补装 python3.12-venv;如果服务器还没装 Python 3.12,先按 4.2/4.4 完成基础依赖与 deadsnakes 步骤。

5.2 获取源码与创建虚拟环境

apt-get install -y python3.12-venv
git clone --depth 1 --branch v0.10.0 https://github.com/daya0576/beaverhabits.git /opt/beaverhabits
python3.12 -m venv /opt/beaverhabits/.venv

实测回显(无输出的命令静默成功,验证 venv 就位):

/opt/beaverhabits/.venv/bin/python --version

实测回显:

Python 3.12.15

5.3 安装依赖

按 pyproject.toml 声明的依赖范围用 pip 安装(与 v0.10.0 的 pyproject.toml dependencies 列表一致):

/opt/beaverhabits/.venv/bin/pip install \
  'nicegui[redis]>=3.13.0' \
  'pydantic-settings<3.0.0,>=2.2.1' \
  'fastapi-users[sqlalchemy]>=15.0.0,<16.0.0' \
  'uvicorn[standard]>=0.28.0,<1.0.0' \
  'sqlalchemy[asyncio]<3.0.0,>=2.0.29' \
  'asyncpg<1.0.0,>=0.29.0' \
  'aiosqlite>=0.20.0,<1.0.0' \
  'pytz<2025.0,>=2024.1' \
  'python-dateutil<3.0.0.0,>=2.9.0.post0' \
  'loguru>=0.7.3' \
  'cachetools>=5.5.1' \
  'jinja2>=3.1.6' \
  'dataclasses-json>=0.6.7' \
  'psutil>=7.0.0' \
  'uvicorn-worker>=0.3.0' \
  'python-multipart>=0.0.20' \
  'requests>=2.32.4' \
  'httpx[socks]>=0.28.1'

实测回显(安装输出较长,用 pip list 验证关键包版本):

/opt/beaverhabits/.venv/bin/pip list | grep -iE 'nicegui|gunicorn|sqlalchemy|uvicorn '

实测回显:

fastapi-users-db-sqlalchemy 7.0.0
gunicorn                    26.2.0
nicegui                     3.18.0
SQLAlchemy                  2.0.55
uvicorn                     0.54.0

💡 说明:uvicorn-worker 会自动带入 gunicorn(它是 gunicorn 的 worker 实现),所以无需单独安装 gunicorn;asyncpg 是 PostgreSQL 驱动,默认 SQLite 存储用不到但 pyproject.toml 声明了它,保持与官方一致以免后续切换存储时缺依赖。

5.4 启动验证

先手工启动一次确认能跑通(激活 venv 后走官方 start.sh prd):

cd /opt/beaverhabits
export PATH=/opt/beaverhabits/.venv/bin:$PATH
ENV=production nohup ./start.sh prd > /tmp/beaver.log 2>&1 &
sleep 12
head -5 /tmp/beaver.log

实测回显:

Starting Uvicorn server in production mode...
[2026-10-22 16:49:29 +0000] [5302] [INFO] Starting gunicorn 26.2.0
[2026-10-22 16:49:29 +0000] [5302] [INFO] Listening at: http://0.0.0.0:8080 (5302)
[2026-10-22 16:49:29 +0000] [5302] [INFO] Using worker: uvicorn_worker.UvicornWorker
[2026-10-22 16:49:29 +0000] [5302] [INFO] Booting worker with pid: 5303

⚠️ 注意:./start.sh prd 必须在 venv 已激活(或 PATH 已包含 .venv/bin)的前提下执行,否则脚本里的 gunicorn 找不到命令直接退出(line 17: gunicorn: command not found,实测复现;官方 Dockerfile 同样通过 PATH 注入 venv 解决)。

HTTP 验证(该测试环境无 curl 时可用 python 内置库验证,效果等价):

/opt/beaverhabits/.venv/bin/python -c "import urllib.request; print('HTTP', urllib.request.urlopen('http://127.0.0.1:8080/login', timeout=10).status)"

实测回显:

HTTP 200
ls -la /opt/beaverhabits/.user/

实测回显:

total 104
drwxr-xr-x  2 root root  4096 Oct 22 16:49 .
drwxr-xr-x 13 root root  4096 Oct 22 16:49 ..
-rw-r--r--  1 root root 94208 Oct 22 16:49 habits.db

5.5 systemd 托管

停掉手工进程,改用 systemd 托管(单元内容与方案 A 完全一致,直接复用):

pkill -x gunicorn
cat > /etc/systemd/system/beaverhabits.service <<'EOF'
[Unit]
Description=Beaver Habit Tracker (BeaverHabits)
After=network.target

[Service]
Type=simple
User=beaver
Group=beaver
WorkingDirectory=/opt/beaverhabits
Environment=ENV=production
Environment=NICEGUI_STORAGE_PATH=/opt/beaverhabits/.user/.nicegui
ExecStart=/opt/beaverhabits/.venv/bin/gunicorn beaverhabits.main:app --bind 0.0.0.0:8080 -w 1 -k uvicorn_worker.UvicornWorker --max-requests 10000 --log-level info
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
useradd -r -s /usr/sbin/nologin beaver 2>/dev/null || true
mkdir -p /home/beaver
chown -R beaver:beaver /opt/beaverhabits /home/beaver
systemctl daemon-reload
systemctl enable beaverhabits
systemctl start beaverhabits

5.6 验证

systemctl is-active beaverhabits

实测回显:

active
curl -si --max-time 10 http://127.0.0.1:8080/login | head -3

实测回显:

HTTP/1.1 200 OK
date: Thu, 22 Oct 2026 16:49:55 GMT
server: uvicorn

六、方案对比与选择建议

维度方案 A:uv 工具链方案 B:pip + venv
官方推荐度官方 README 与 Dockerfile 同款构建路径备选,仅依赖 pyproject 声明
依赖版本按 uv.lock 锁定(nicegui==3.13.0 等,与官方镜像一致)按范围解析到最新兼容版(实测 nicegui==3.18.0)
可复现性高:锁定文件精确复现中:随 PyPI 新版本漂移
额外工具需安装 uv 二进制仅系统 Python + venv,无额外工具
依赖获取uv 全局缓存,重复安装快每台机器独立下载
适用场景常规联网服务器,追求与官方构建一致受管控环境不便装 uv、或已标准化 pip 工作流
systemd/服务形态完全相同(同一单元文件)完全相同

选择建议:能联网且允许装 uv,选方案 A——锁定版本带来的可复现性对升级与回滚都更友好(重装即复现);对工具链有约束的服务器选方案 B,功能完全等价。两方案的升级操作见第八章。

七、配置说明

两种方案的配置方式完全一致:BeaverHabits 使用 pydantic-settings 管理配置,支持「环境变量 + 仓库根目录 .env 文件」两种来源(configs.py 通过 dotenv.load_dotenv() 自动读取 .env)。

  1. 最小生产配置:在 /opt/beaverhabits/.env 写入(文件属主设为 beaver):
cat > /opt/beaverhabits/.env <<'EOF'
ENV=production
TIME_ZONE=Asia/Shanghai
JWT_SECRET=q1w2e3r4
EOF
chown beaver:beaver /opt/beaverhabits/.env
chmod 600 /opt/beaverhabits/.env

配置项解读:

  • ENV=production:与 systemd 的 Environment= 等效(环境变量优先级高于 .env,二者留一处即可);
  • TIME_ZONE=Asia/Shanghai:为所有用户固定打卡日期的判定时区(默认跟随浏览器时区,服务器场景建议固定,无效值会启动失败,实测见本专栏《配置参数详解》);
  • JWT_SECRET=q1w2e3r4:登录令牌签名密钥,默认值是公开的 SECRET,必须更换(示例值仅演示格式,生产请用随机长串,如 openssl rand -hex 32 生成)。
  1. 数据存储位置:全部数据在 /opt/beaverhabits/.user/(SQLite 库 habits.db 与浏览器端存储 .nicegui/),备份与迁移只需处理该目录;存储后端可用 HABITS_STORAGE 切换(默认 DATABASE),完整参数说明见本专栏《Beaver Habit Tracker v0.10.0 配置参数详解》。

  2. 修改监听端口:改 systemd 单元中 --bind 0.0.0.0:8080 为目标端口后 systemctl daemon-reload && systemctl restart beaverhabits。

  3. 防火墙放行(如启用 ufw):

ufw allow 8080/tcp

实测回显:

Rules updated
Rules updated (v6)

八、升级与多版本管理

升级到新版本(以未来发布 v0.11.0 为例,操作形态与实测过的标签切换一致):

cd /opt/beaverhabits
systemctl stop beaverhabits
git fetch --tags
git checkout v0.11.0
uv sync --frozen --no-dev --no-install-project --python /usr/bin/python3.12
systemctl start beaverhabits

(方案 B 环境把 uv sync 一行替换为 5.3 的 pip install 命令即可。)升级前建议备份:cp -a /opt/beaverhabits/.user /opt/beaverhabits/.user.bak-$(date +%F)。

验证升级结果:

git -C /opt/beaverhabits log --oneline -1

实测回显(v0.10.0 时点):

4b3bc6d Fix bare except: patterns in Python files (#217)
systemctl is-active beaverhabits
curl -si --max-time 10 http://127.0.0.1:8080/login | head -1

实测回显:

active
HTTP/1.1 200 OK

降级:与升级同构——git checkout v0.9.1 后重跑依赖安装并重启服务;数据目录向后兼容(v0.x 系列内无破坏性 schema 变更记录,跨大版本降级前务必先备份 .user/ 并核对官方 Release Notes)。

多版本并存:源码安装天然支持多实例——将不同标签克隆到独立目录(如 /opt/beaverhabits-0.9.1、/opt/beaverhabits-0.10.0),各自执行依赖安装,复制 systemd 单元文件并修改 Description、WorkingDirectory、ExecStart 与 --bind 端口(如 8081),daemon-reload 后即可并行运行、灰度切换。

九、常见问题(FAQ)

Q1:手工执行 ./start.sh prd 报 gunicorn: command not found? 现象(实测):

./start.sh: line 17: gunicorn: command not found

原因:start.sh 直接调用 gunicorn,未激活 venv 时 PATH 中没有该命令。解决:先 source /opt/beaverhabits/.venv/bin/activate 或 export PATH=/opt/beaverhabits/.venv/bin:$PATH 再执行;systemd 方式则无此问题(ExecStart 用绝对路径)。

Q2:systemd 启动失败,状态码 203/EXEC,日志 Permission denied? 现象(实测 journalctl 节选):

beaverhabits.service: Failed to execute /opt/beaverhabits/.venv/bin/gunicorn: Permission denied
beaverhabits.service: Failed at step EXEC spawning /opt/beaverhabits/.venv/bin/gunicorn: Permission denied
beaverhabits.service: Main process exited, code=exited, status=203/EXEC

定位:以 beaver 账号手工执行 /opt/beaverhabits/.venv/bin/gunicorn --version,报 bad interpreter: /opt/beaverhabits/.venv/bin/python: Permission denied——问题不在 gunicorn 本身,而在 venv 的 python 解释器。根因:uv 默认把受管 Python 安装到执行账号家目录(root 时为 /root/.local/share/uv/python/),目录权限 0700,服务账号 beaver 无法访问。解决:按 4.4 安装系统级 Python 3.12,删除旧 venv 并用 --python /usr/bin/python3.12 重建:

rm -rf /opt/beaverhabits/.venv
cd /opt/beaverhabits
uv sync --frozen --no-dev --no-install-project --python /usr/bin/python3.12
chown -R beaver:beaver /opt/beaverhabits
systemctl restart beaverhabits

实测重启后 systemctl is-active 返回 active,问题消失。

Q3:日志出现 Control server error: [Errno 13] Permission denied: '/home/beaver'? 现象(实测):服务正常 active、HTTP 正常,但 journalctl 有该 ERROR 行。原因:gunicorn 会在用户家目录创建控制套接字目录 .gunicorn/,useradd -r 创建的系统账号默认没有家目录。解决:

mkdir -p /home/beaver
chown beaver:beaver /home/beaver
systemctl restart beaverhabits

实测重启后日志中该告警消失,仅剩正常启动行。属良性告警(不影响服务),但建议消除以免排查其他问题时被干扰。

Q4:设置了 TIME_ZONE 后服务起不来? 现象(实测,TIME_ZONE=Bad/Zone 时 gunicorn worker 退出):

Value error, Invalid TIME_ZONE 'Bad/Zone'. Must be a valid IANA timezone name (e.g. 'America/New_York', 'Europe/London', 'Asia/Tokyo'). [type=value_error, input_value='Bad/Zone', input_type=str]
[ERROR] Worker (pid:2416) exited with code 3.
[ERROR] Reason: Worker failed to boot.

解决:换成合法 IANA 时区名(如 Asia/Shanghai、UTC),systemctl restart beaverhabits。BeaverHabits 启动时用 pydantic 严格校验该值,拼错即拒绝启动——这是特性而非缺陷,能第一时间暴露配置笔误。

Q5:端口被占用导致启动失败? 排查:ss -ltnp | grep 8080 找到占用进程;若是其他服务,改 systemd 单元中 --bind 端口并 daemon-reload + restart;浏览器访问记得同步改端口。

Q6:注册/登录页打不开或浏览器访问超时? 依次检查:systemctl is-active beaverhabits(服务状态)→ curl -si http://127.0.0.1:8080/login(本机连通性,区分服务问题与网络问题)→ 服务器安全组/防火墙是否放行 8080 → 云服务商控制台安全规则。本机 curl 通而外网不通,基本可定位在防火墙/安全组层。

Q7:如何备份数据? 整目录拷贝即可:cp -a /opt/beaverhabits/.user /backup/beaver-$(date +%F)。应用还内置每日自动备份调度(ENABLE_DAILY_BACKUP=true,间隔 DAILY_BACKUP_INTERVAL 默认 86400 秒),开启后由应用自行在 .user/ 内生成备份,细节见本专栏 《Beaver Habit Tracker v0.10.0 配置参数详解》。

十、卸载与清理

完整卸载(按安装路径逆序执行):

systemctl stop beaverhabits
systemctl disable beaverhabits

实测回显(disable):

Removed "/etc/systemd/system/multi-user.target.wants/beaverhabits.service".
rm -f /etc/systemd/system/beaverhabits.service
systemctl daemon-reload
rm -rf /opt/beaverhabits /home/beaver
userdel beaver

如不再需要 uv 与 Python 3.12,可一并清理:rm -f /usr/local/bin/uv && rm -rf /root/.local/bin/uv /root/.local/share/uv;apt-get purge -y python3.12 && add-apt-repository -y --remove ppa:deadsnakes/ppa。卸载前如需保留数据,先备份 /opt/beaverhabits/.user/。

十一、参考链接