Ubuntu 22.04 安装 IHateMoney 7.2.1 指南
Ubuntu 22.04 从零安装 IHateMoney 7.2.1:Python 3.11 环境准备(PyPI 7.x 要求 >=3.11 实测)、PyPI/离线 wheel/源码三方案、Gunicorn+systemd+Nginx 托管、端到端验证与四大排障实录。
Ubuntu 22.04 安装 IHateMoney 7.2.1 指南
目标:在一台 Ubuntu 22.04 服务器上从零安装 IHateMoney 7.2.1(多人共享记账 Web 应用),覆盖 Python 3.11 环境准备、三种安装方案(PyPI 在线 / 离线 wheel / 源码)、Gunicorn + systemd 生产托管、Nginx 反向代理、端到端验证与常见故障排查。已在 Ubuntu 22.04.5 LTS(系统 Python 3.10.12 + deadsnakes Python 3.11.17)、ihatemoney 7.2.1、gunicorn 26.2.0、nginx 1.18.0、SQLite 后端环境实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- 系统自带 Python:3.10.12(Ubuntu 22.04 默认)
- 新装 Python:3.11.17(deadsnakes PPA,IHateMoney 7.x 实际要求的最低版本,见第三章)
- IHateMoney 版本:7.2.1(官方最新稳定版,GitHub Releases 查询日期 2026-10-23)
- Gunicorn:26.2.0(WSGI 服务,官方部署栈组件)
- Nginx:1.18.0(Ubuntu 22.04 官方仓库版本,反向代理)
- 数据库:SQLite(文件
/var/lib/ihatemoney/ihatemoney.sqlite;PostgreSQL/MariaDB 的接法见第八章说明) - 安装布局:专用系统用户
ihatemoney;虚拟环境/home/ihatemoney/ihatemoney;配置目录/etc/ihatemoney;数据目录/var/lib/ihatemoney - 服务端口:Gunicorn 监听
127.0.0.1:8000,Nginx 监听80对外
二、前置条件
本章准备工作是三条安装方案共同的地基:更新系统包索引、安装基础工具、创建运行用户与目录。
# 更新包索引并安装基础工具(curl/nginx 在方案 A 主线用到,git 仅方案 C 需要)
apt-get update
apt-get install -y curl nginx
实测回显(输出节选):
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
0 upgraded, 0 newly installed, 0 to remove and 11 not upgraded.
# 创建专用运行用户(系统服务以该用户身份运行,不带登录 shell 密码)
useradd -m -s /bin/bash ihatemoney
# 创建配置目录与数据目录(官方文档规定的标准位置)
mkdir -p /etc/ihatemoney /var/lib/ihatemoney
# 数据目录归属运行用户(SQLite 需要对目录有写权限才能建库文件)
chown ihatemoney /var/lib/ihatemoney
⚠️ 注意:
/var/lib/ihatemoney必须在首次初始化数据库之前把属主交给ihatemoney用户,否则后续任何ihatemoney命令加载应用时都会报sqlite3.OperationalError: unable to open database file(排障实录见第十章)。
验证前置就绪:
id ihatemoney && ls -ld /etc/ihatemoney /var/lib/ihatemoney
实测回显:
uid=1001(ihatemoney) gid=1001(ihatemoney) groups=1001(ihatemoney)
drwxr-xr-x 2 root root 4096 Oct 23 11:00 /etc/ihatemoney
drwxr-xr-x 2 ihatemoney root 4096 Oct 23 11:10 /var/lib/ihatemoney
三、版本选型说明
IHateMoney 的版本选择有一个容易踩坑的隐藏约束:Python 版本决定你能装到哪个 ihatemoney 版本。官方最新稳定版为 7.2.1(GitHub Releases 实查于 2026-10-23,发布于 2026-08-07,属安全修复版),但 PyPI 上 7.x 系列的包元数据声明了 requires-python >= 3.11。Ubuntu 22.04 系统自带 Python 3.10,直接 pip install ihatemoney 会静默降级安装到 6.1.5(6.x 是支持 Python 3.10 的最后系列)——本机实测:
# 在系统 Python 3.10 建立的虚拟环境里安装(模拟不升级 Python 直接装的结果)
python3 -m venv venv-py310 && source venv-py310/bin/activate
pip install ihatemoney
实测回显(输出节选):
Successfully installed Babel-2.18.0 Flask-2.2.5 ... SQLAlchemy-1.4.54 ... ihatemoney-6.1.5 ...
pip index versions ihatemoney
实测回显(Python 3.10 环境下,pip 视 6.1.5 为最新可用版本):
ihatemoney (6.1.5)
Available versions: 6.1.5, 6.1.4, 6.1.3, 6.1.2, 6.1.1, 6.1.0, 6.0.1, 6.0.0, 5.2.0, 5.1.1, 5.0.1, 5.0.0, 4.1.5, 4.1.4, 4.1.3, 4.1.2, 4.1, 4.0, 3.0, 2.1, 2.0, 1.0
INSTALLED: 6.1.5
LATEST: 6.1.5
版本约束核实(PyPI JSON API 实查于 2026-10-23):
| 版本 | PyPI 包元数据 requires_python | 说明 |
|---|---|---|
| 6.1.5 | 无限制 | 6.x 系列最后一版,Python 3.10 可用 |
| 7.2.1 | >=3.11 | 当前最新稳定版,wheel 为 py3-none-any 通用包 |
⚠️ 注意:官方文档站(readthedocs latest 页)写的支持范围是「Python 3.8 至 3.12」,该描述落后于 PyPI 包元数据;以 PyPI 的
requires-python >= 3.11为准(实查于 2026-10-23)。
因此 Ubuntu 22.04 上要装 7.2.1,必须先补 Python 3.11/3.12。Ubuntu 22.04 官方仓库内的 python3.11 是候选版 3.11.0~rc1(RC 版,不推荐生产使用),推荐用社区维护的 deadsnakes PPA 安装正式版:
# 安装 PPA 管理工具
apt-get install -y software-properties-common gpg-agent
# 添加 deadsnakes PPA(Ubuntu 官方社区认可的 Python 补充源)
add-apt-repository -y ppa:deadsnakes/ppa
# 安装 Python 3.11 及 venv/dev 组件
apt-get install -y python3.11 python3.11-venv python3.11-dev
实测回显(输出节选):
Setting up python3.11-dev (3.11.17-1+jammy1) ...
Processing triggers for libc-bin (2.35-0ubuntu3.15) ...
python3.11 -V
实测回显:
Python 3.11.17
选型结论:目标版本取 7.2.1(最新稳定且修复了会话安全问题),Python 取 3.11.17(满足 >=3.11 且在官方文档描述的 3.8–3.12 区间内);SQLite 作为数据库开箱即用,中小规模(家庭/小团队,几十人以下项目)完全够用,需多人运维或已有数据库设施时再切 PostgreSQL/MariaDB(第八章)。
四、方案 A:PyPI 在线安装(官方推荐主线)
本方案是官方文档的推荐路径:专用用户 + 虚拟环境 + pip 安装 + Gunicorn + systemd 托管 + Nginx 反代。以下步骤在 22.04 服务器上从零走完整条生产线。
4.1 建立虚拟环境并安装
# 用 Python 3.11 在运行用户家目录下建虚拟环境(官方推荐隔离安装)
runuser -u ihatemoney -- python3.11 -m venv /home/ihatemoney/ihatemoney
# 激活并安装(服务器可直连 PyPI;网络受限时给 pip 加代理参数)
runuser -u ihatemoney -- bash -c 'source /home/ihatemoney/ihatemoney/bin/activate && pip install --upgrade pip && pip install ihatemoney gunicorn'
实测回显(输出节选,依赖安装清单较长):
Successfully installed pip-26.2.2
Successfully installed Babel-2.18.0 Flask-2.2.5 Flask-Babel-3.1.0 Flask-Cors-3.0.10 Flask-Limiter-2.9.2 Flask-Mail-0.10.0 Flask-Migrate-4.1.0 Flask-RESTful-0.3.10 Flask-SQLAlchemy-2.5.1 Flask-Talisman-1.1.0 Flask-WTF-1.3.0 Jinja2-3.1.6 ... SQLAlchemy-1.4.54 ... gunicorn-26.2.0 ihatemoney-7.2.1 ...
runuser -u ihatemoney -- bash -c 'source /home/ihatemoney/ihatemoney/bin/activate && pip show ihatemoney gunicorn | grep -E "^(Name|Version|Location)"'
实测回显:
Name: ihatemoney
Version: 7.2.1
Location: /home/ihatemoney/ihatemoney/lib/python3.11/site-packages
Name: gunicorn
Version: 26.2.0
关键差异解读:同一个 pip install ihatemoney 命令,在 Python 3.11 环境拿到的是 7.2.1,在 3.10 环境拿到 6.1.5——虚拟环境解释器版本即版本开关,这就是第三章强调先装 Python 3.11 的原因。
4.2 生成生产配置并初始化数据库
IHateMoney 默认从 /etc/ihatemoney/ihatemoney.cfg 读取配置(可用环境变量 IHATEMONEY_SETTINGS_FILE_PATH 改路径,须为绝对路径)。用官方 CLI 生成带随机 SECRET_KEY 的配置模板:
runuser -u ihatemoney -- bash -c 'source /home/ihatemoney/ihatemoney/bin/activate && ihatemoney generate-config ihatemoney.cfg' > /etc/ihatemoney/ihatemoney.cfg
chmod 740 /etc/ihatemoney/ihatemoney.cfg
chgrp ihatemoney /etc/ihatemoney/ihatemoney.cfg
生成后核对关键项(模板默认已含随机密钥与 /var/lib 库路径):
grep -E "^(DEBUG|SQLALCHEMY_DATABASE_URI|SECRET_KEY|SESSION_COOKIE_SECURE)" /etc/ihatemoney/ihatemoney.cfg
实测回显(SECRET_KEY 每次生成不同,截断显示):
DEBUG = False
SQLALCHEMY_DATABASE_URI = 'sqlite:////var/lib/ihatemoney/ihatemoney.sqlite'
SECRET_KEY = "$snpc2l2+o9bjju$6qdx3#_=g%o46-49s62qj9&+f=e7gn#cwu"
SESSION_COOKIE_SECURE = True
逐项说明:
DEBUG = False:生产必须关闭,模板默认已关;SQLALCHEMY_DATABASE_URI:SQLite 用四条斜杠格式sqlite:////绝对路径,模板默认已指向/var/lib/ihatemoney/ihatemoney.sqlite,无需改动;换 PostgreSQL/MariaDB 时改这一行(第八章);SECRET_KEY:generate-config已自动生成 64 位随机串,绝不能用可预测值(官方警告:密钥泄露可伪造会话冒充任意项目登录);SESSION_COOKIE_SECURE:模板默认True,仅 HTTPS 部署保留;本文 Nginx 暂为纯 HTTP(80 端口),须改为False,否则浏览器会拒绝回传会话 Cookie、表现为「登录后一刷新又回到登录页」。第八章配置详解含此项。
# 本文为纯 HTTP 环境,关闭安全 Cookie;生产上 HTTPS 部署请保持 True
sed -i 's|^SESSION_COOKIE_SECURE = True|SESSION_COOKIE_SECURE = False|' /etc/ihatemoney/ihatemoney.cfg
初始化数据库(Alembic 迁移到最新结构):
runuser -u ihatemoney -- bash -c 'source /home/ihatemoney/ihatemoney/bin/activate && ihatemoney db upgrade head'
实测回显(输出节选,共 14 个迁移):
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> b9a10d5d63ce, Initial migration
INFO [alembic.runtime.migration] Running upgrade b9a10d5d63ce -> 26d6a218c329, Add Person.weight column
...
INFO [alembic.runtime.migration] Running upgrade 06884b17c50f -> c941aaca38c2, remove ip recording
ls -lh /var/lib/ihatemoney/
实测回显:
total 144K
-rw-r--r-- 1 ihatemoney ihatemoney 143360 Oct 23 11:10 ihatemoney.sqlite
💡 说明:IHateMoney 的每个 CLI 命令(甚至
--help)执行前都会加载 Flask 应用并检查数据库结构,所以任何一次 CLI 调用都可能触发自动建库/迁移。若配置里库路径所在目录不可写,命令会直接报错——这是 6.1.5/7.x 系列共有的行为,也是第十章unable to open database file排障的根源。
4.3 Gunicorn 配置
# 生成 Gunicorn 配置模板
runuser -u ihatemoney -- bash -c 'source /home/ihatemoney/ihatemoney/bin/activate && ihatemoney generate-config gunicorn.conf.py' > /etc/ihatemoney/gunicorn.conf.py
chmod 640 /etc/ihatemoney/gunicorn.conf.py && chgrp ihatemoney /etc/ihatemoney/gunicorn.conf.py
模板默认绑 unix socket 且 debug = True,生产改为 TCP 监听并关闭 debug:
cat > /etc/ihatemoney/gunicorn.conf.py <<'EOF'
backlog = 2048
daemon = False
debug = False
workers = 3
# log to stdout, visible in journalctl
logfile = "-"
loglevel = "info"
bind = "127.0.0.1:8000"
EOF
逐项说明:workers = 3(默认值,CPU 核数×2+1 经验公式的轻量取值,共享记账负载低,2–4 足够);bind = "127.0.0.1:8000"(只监听本机回环,外部流量一律经 Nginx);daemon = False(systemd Type=simple 前台运行,日志进 journald)。
4.4 systemd 服务托管
官方文档提供 systemd 单元模板,SQLite 部署按官方说明去掉数据库服务依赖项:
cat > /etc/systemd/system/ihatemoney.service <<'EOF'
[Unit]
Description=I hate money
Requires=network.target
After=network.target
[Service]
Type=simple
User=ihatemoney
ExecStart=/home/ihatemoney/ihatemoney/bin/gunicorn -c /etc/ihatemoney/gunicorn.conf.py ihatemoney.wsgi:application
SyslogIdentifier=ihatemoney
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now ihatemoney.service
实测回显:
Created symlink /etc/systemd/system/multi-user.target.wants/ihatemoney.service → /etc/systemd/system/ihatemoney.service.
验证服务状态:
systemctl status ihatemoney.service --no-pager | head -8
实测回显:
● ihatemoney.service - I hate money
Loaded: loaded (/etc/systemd/system/ihatemoney.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2026-10-23 11:10:27 UTC; 3s ago
Main PID: 5899 (gunicorn)
Tasks: 5 (limit: 94371)
Memory: 203.7M
CPU: 1.580s
⚠️ 注意:
ExecStart路径要与你的实际虚拟环境路径一致;官方模板中的%h/ihatemoney/bin/gunicorn会被 systemd 展开为User=用户家目录,两种写法等价。若数据库用 PostgreSQL/MariaDB,按官方说明在Requires/After中把postgresql.service/mariadb.service加回。
4.5 Nginx 反向代理
# 生成 Nginx 配置模板(官方推荐栈:Nginx + Gunicorn + systemd)
runuser -u ihatemoney -- bash -c 'source /home/ihatemoney/ihatemoney/bin/activate && ihatemoney generate-config nginx.conf'
模板输出(官方原样,server_name 与 upstream 需按实际环境定制):
server {
server_name ihatemoney.example.com; # CUSTOMIZE
keepalive_timeout 5;
location /static/ {
alias /home/ihatemoney/ihatemoney/lib/python3.11/site-packages/ihatemoney/static/;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_connect_timeout 90;
proxy_send_timeout 180;
proxy_read_timeout 180;
proxy_buffer_size 16k;
proxy_buffers 8 16k;
proxy_busy_buffers_size 32k;
proxy_intercept_errors on;
if (!-f $request_filename) {
proxy_pass http://ihatemoney_backend;
break;
}
}
}
upstream ihatemoney_backend {
server unix:/tmp/ihatemoney.gunicorn.sock;
}
按本文环境定制后落位启用(upstream 由模板的 unix socket 改为 127.0.0.1:8000,与 4.3 的 Gunicorn bind 对应;server_name _ 表示接受任意域名/IP 访问):
cat > /etc/nginx/sites-available/ihatemoney <<'EOF'
server {
listen 80;
server_name _;
keepalive_timeout 5;
location /static/ {
alias /home/ihatemoney/ihatemoney/lib/python3.11/site-packages/ihatemoney/static/;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_connect_timeout 90;
proxy_send_timeout 180;
proxy_read_timeout 180;
proxy_buffer_size 16k;
proxy_buffers 8 16k;
proxy_busy_buffers_size 32k;
proxy_intercept_errors on;
if (!-f $request_filename) {
proxy_pass http://ihatemoney_backend;
break;
}
}
}
upstream ihatemoney_backend {
server 127.0.0.1:8000;
}
EOF
rm -f /etc/nginx/sites-enabled/default
ln -sf /etc/nginx/sites-available/ihatemoney /etc/nginx/sites-enabled/ihatemoney
nginx -t && systemctl restart nginx
实测回显:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
4.6 端到端验证
# 1. 经 Nginx 访问首页
curl -s -o /dev/null -w "via-nginx HTTP %{http_code}\n" http://127.0.0.1/
curl -s http://127.0.0.1/ | grep -oE "<title>[^<]+" | head -1
实测回显:
via-nginx HTTP 200
<title>I Hate Money — Account manager
# 2. 直连 Gunicorn 验证后端
curl -s -o /dev/null -w "direct-8000 HTTP %{http_code}\n" http://127.0.0.1:8000/
# 3. 经 API 创建测试项目(HTTP 201 即成功,响应为项目标识)
curl -s -X POST http://127.0.0.1:8000/api/projects -d "name=测试家庭&id=testhome&password=q1w2e3r4&contact_email=admin@example.com"
实测回显:
direct-8000 HTTP 200
api HTTP 201
# 4. 重启持久性:重启服务后数据与登录态接口仍正常
systemctl restart ihatemoney.service
sleep 2
systemctl is-active ihatemoney.service
curl -s -o /dev/null -w "after-restart HTTP %{http_code}\n" http://127.0.0.1:8000/
实测回显:
active
after-restart HTTP 200
用服务器 IP 或域名在浏览器打开 http://<服务器IP>/,应看到 IHateMoney 首页;用 testhome / q1w2e3r4 可登录前面创建的测试项目。
五、方案 B:离线 wheel 包安装(断网服务器)
内网/断网服务器无法直连 PyPI。思路:在一台能联网的同架构机器(同为 x86_64、Python 版本一致 3.11)上把 ihatemoney 及全部依赖下载成 wheel 包,拷贝到目标服务器后用 --no-index 纯离线安装。
5.1 联网机:下载离线包
source /home/ihatemoney/ihatemoney/bin/activate
pip download ihatemoney==7.2.1 -d /home/ihatemoney/wheels
实测回显(输出节选):
Saved ./home/ihatemoney/wheels/tzdata-2026.5-py2.py3-none-any.whl
Successfully downloaded ihatemoney cachetools debts email-validator flask flask-babel flask-cors flask-limiter flask-mail flask-migrate flask-restful flask-sqlalchemy flask-talisman flask-wtf itsdangerous jinja2 ordered-set qrcode requests charset_normalizer idna sqlalchemy sqlalchemy-continuum urllib3 werkzeug wtforms alembic aniso8601 Babel blinker certifi click dnspython greenlet limits deprecated wrapt markupsafe packaging pytz six typing-extensions Mako python-dateutil tzdata
ls /home/ihatemoney/wheels | wc -l
实测回显:
45
# 打包拷贝到目标服务器(示例路径,按实际网络环境调整)
tar -C /home/ihatemoney -czf ihm-wheels.tar.gz wheels
scp ihm-wheels.tar.gz user@内网服务器:/home/ihatemoney/
5.2 目标机:纯离线安装与排障实录
cd /home/ihatemoney && tar -xzf ihm-wheels.tar.gz
python3.11 -m venv ihm-offline-venv
source ihm-offline-venv/bin/activate
pip install --no-index --find-links=/home/ihatemoney/wheels ihatemoney
排障实录(第一次执行报错)——错误现象:
Processing /home/ihatemoney/wheels/debts-0.5.tar.gz (from ihatemoney)
Installing build dependencies: started
Installing build dependencies: finished with status 'error'
error: subprocess-exited-with-error
ERROR: Could not find a version that satisfies the requirement setuptools>=40.8.0 (from versions: none)
ERROR: No matching distribution found for setuptools>=40.8.0
定位:依赖包 debts 在 PyPI 上只发布源码包(sdist,.tar.gz),离线安装时需要在目标机现场构建,构建依赖 setuptools 不在 wheels 目录里(Python 3.11 的新建 venv 也不再自带 setuptools)。解决方案:在联网机补下 setuptools 进同一个目录再打包一次。
# 联网机补包
pip download setuptools -d /home/ihatemoney/wheels
实测回显:
Successfully downloaded setuptools
# 目标机重试离线安装
pip install --no-index --find-links=/home/ihatemoney/wheels ihatemoney
实测回显(输出节选):
Successfully installed Babel-2.18.0 Mako-1.4.3 alembic-1.20.1 ... flask-3.1.3 ... ihatemoney-7.2.1 ... sqlalchemy-2.0.55 ... setuptools-80.9.0 ...
pip show ihatemoney | grep Version
实测回显:
Version: 7.2.1
💡 说明:离线安装时 pip 会重新解析依赖版本,可能拿到比 4.1 节在线安装更新的次级依赖(如实测中 Flask 解析到 3.1.3、SQLAlchemy 2.0.55),均在 ihatemoney 声明的依赖范围内,不影响使用。若要锁定与在线环境完全一致的版本组合,可在联网机用
pip freeze > requirements.txt后在目标机pip install --no-index --find-links=/home/ihatemoney/wheels -r requirements.txt。
后续配置、systemd 托管与 Nginx 反代与方案 A 完全一致(见 4.2–4.6 节)。
六、方案 C:源码安装(指定版本/跟踪开发分支)
PyPI 拿不到的特定版本(如历史版本回退、修复尚未发版的 commit)可以直接从源码安装。IHateMoney 的 Git tag 与 Release 版本号一一对应。
# 安装 git(目标机无外网时先离线准备 git 包)
apt-get install -y git
# 浅克隆 7.2.1 标签(--depth 1 只取该提交,减小体积)
runuser -u ihatemoney -- bash -c 'cd /home/ihatemoney && git clone --depth 1 --branch 7.2.1 https://github.com/spiral-project/ihatemoney.git ihatemoney-src'
实测回显(输出节选):
Cloning into 'ihatemoney-src'...
Note: switching to '7.2.1'.
You are in 'detached HEAD' state.
# 独立虚拟环境中从本地源码构建安装
runuser -u ihatemoney -- bash -c 'python3.11 -m venv /home/ihatemoney/ihm-src-venv && source /home/ihatemoney/ihm-src-venv/bin/activate && cd /home/ihatemoney/ihatemoney-src && pip install . && pip show ihatemoney | grep Version'
实测回显:
Version: 7.2.1
💡 说明:源码安装适合两类场景——锁版本(tag 即版本)、测试未发版的修复(换分支名)。日常生产用方案 A/B 即可;源码目录没有 wheel 缓存,升级时需重新
git fetch+pip install .。
七、方案对比与选择建议
| 维度 | 方案 A:PyPI 在线 | 方案 B:离线 wheel | 方案 C:源码安装 |
|---|---|---|---|
| 适用场景 | 可联网的标准服务器 | 内网/断网生产环境 | 锁定特定 tag/测试未发版修复 |
| 版本控制 | pip install ihatemoney==7.2.1 | 下载时锁定 ==7.2.1 | git tag 锁定 7.2.1 |
| 依赖解析 | 安装时在线解析 | 下载时解析后固化 | 安装时解析(需构建工具) |
| 操作复杂度 | 低 | 中(含 setuptools 补包坑) | 中(需 git + 构建) |
| 升级便利性 | pip install -U 一条命令 | 重新打包传输 | 重新 clone + install |
| 本文档实测结果 | 7.2.1 ✅ | 7.2.1 ✅(补 setuptools 后) | 7.2.1 ✅ |
选择建议:能联网选方案 A;生产内网选方案 B(记得补 setuptools);要钉死 tag 或跟修复选方案 C。三方案产出的运行形态完全一致(venv + Gunicorn + systemd),可与第八章配置和 4.4/4.5 节托管随意组合。
八、生产配置详解
配置文件为 /etc/ihatemoney/ihatemoney.cfg(Python 语法,键 = 值)。改配置后 systemctl restart ihatemoney.service 生效。以下为生产环境建议关注的全部参数(含模板默认值与本文实测改动值):
| 参数 | 模板默认 | 本文实测值 | 说明 |
|---|---|---|---|
DEBUG | False | False | 调试开关,生产必须 False |
SQLALCHEMY_DATABASE_URI | sqlite:////var/lib/ihatemoney/ihatemoney.sqlite | 同默认 | 数据库连接串;SQLite 四斜杠 + 绝对路径 |
SQLALCHEMY_TRACK_MODIFICATIONS | False | False | Flask-SQLAlchemy 事件通知,保持默认 |
SECRET_KEY | generate-config 自动随机 | 随机值 | 会话加密密钥,泄露可冒充登录,禁止可预测值 |
MAIL_DEFAULT_SENDER | Budget manager <admin@example.com> | 同默认 | 发件人展示;要真发邮件需配 MAIL_* 系列 |
SHOW_ADMIN_EMAIL | True | True | 错误页是否展示管理员邮箱 |
ACTIVATE_DEMO_PROJECT | True | False | 公共演示项目开关,私有实例应关 |
ADMIN_PASSWORD | "" | scrypt 哈希 | 管理操作口令哈希(见下),空串=管理功能禁用 |
ALLOW_PUBLIC_PROJECT_CREATION | True | True | 是否允许匿名建项目;收口后需输入管理口令 |
ACTIVATE_ADMIN_DASHBOARD | False | True | 管理员仪表盘,需配合非空 ADMIN_PASSWORD |
SESSION_COOKIE_SECURE | True | False(纯 HTTP) | HTTPS 部署必须 True;HTTP 部署必须 False |
APPLICATION_ROOT | / | / | 子路径部署时改(如 /ihm) |
BABEL_DEFAULT_TIMEZONE | 未设置(随系统) | 未设置 | 显示时区,如 "Asia/Shanghai" |
ENABLE_CAPTCHA | False | False | 建项目验证码,公网实例建议 True |
LEGAL_LINK | "" | "" | 法律/隐私页 URL |
管理口令哈希生成(交互式,输入明文回车输出哈希;演示口令为 q1w2e3r4):
echo q1w2e3r4 | runuser -u ihatemoney -- bash -c 'source /home/ihatemoney/ihatemoney/bin/activate && ihatemoney generate_password_hash'
实测回显:
Password:
scrypt:32768:8:1$iwQ9yFAKP2U9PlLC$2c2b6f627d0e66bd858e35b5f660de8f2c688e38fc52ef72c0ecd63468ee14b83d67612265fe1e57e63ebd57efe5c2294349b9539c22fe465d37b49ba69bce86
💡 技术拓展:
ADMIN_PASSWORD存的是哈希而非明文,默认算法为 werkzeug 的 scrypt(回显前缀scrypt:32768:8:1$即「算法:内存参数:并行度:盐」结构)。同口令每次生成哈希不同(盐随机)属正常现象。可在配置中用PASSWORD_HASH_METHOD、PASSWORD_HASH_SALT_LENGTH自定义算法与盐长。
本文实测改动后的生效验证:
systemctl restart ihatemoney.service && sleep 2
systemctl is-active ihatemoney.service
curl -s -o /dev/null -w "home %{http_code}; " http://127.0.0.1:8000/
curl -s -o /dev/null -w "admin %{http_code}\n" http://127.0.0.1:8000/admin
实测回显:
active
home 200; admin 200
/admin 返回 200 即管理仪表盘入口已启用(浏览器访问输入管理口令 q1w2e3r4 进入)。
接入外部数据库(可选):
- PostgreSQL:虚拟环境内
pip install psycopg2,SQLALCHEMY_DATABASE_URI = 'postgresql://myuser:mypass@localhost/mydb?client_encoding=utf8'(官方文档特别提醒 PostgreSQL 客户端编码须 utf8,否则要显式加client_encoding参数); - MariaDB:虚拟环境内
pip install 'PyMySQL>=0.9,<1.1',SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://user:pass@localhost/mydb',要求 MariaDB ≥ 10.3.2。
九、升级与多版本管理
升级到新版本的标准流程(以从 7.2.0 升 7.2.1 为例,命令同样适用于未来版本,版本号以 PyPI 实查为准):
# 1. 升级包(在虚拟环境中)
runuser -u ihatemoney -- bash -c 'source /home/ihatemoney/ihatemoney/bin/activate && pip install --upgrade ihatemoney'
# 2. 升级数据库结构(新版本常带新迁移)
runuser -u ihatemoney -- bash -c 'source /home/ihatemoney/ihatemoney/bin/activate && ihatemoney db upgrade head'
# 3. 重启服务
systemctl restart ihatemoney.service
实测回显(数据库已在最新结构时重复执行的输出):
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
多版本并存:虚拟环境天然隔离,为不同版本各建一个 venv(如 /home/ihatemoney/ihatemoney 跑 7.2.1、/home/ihatemoney/ihatemoney-615 跑 6.1.5)并配两套 systemd 单元(不同端口)即可并行验证后切换。回退降级用 pip install ihatemoney==6.1.5 指定旧版,随后执行 db upgrade head 前先确认旧版迁移兼容(跨大版本降级请先备份 ihatemoney.sqlite)。
十、常见问题(FAQ)
Q1:pip install ihatemoney 装出来是 6.1.5 而不是 7.2.1?
原因:Python 3.10 及以下环境 pip 会自动跳过 requires-python >= 3.11 的 7.x 包,静默装到 6.1.5(实测回显见第三章)。解决:按第三章安装 Python 3.11(deadsnakes PPA),用 python3.11 -m venv 重建虚拟环境重装,pip show ihatemoney 确认 Version: 7.2.1。
Q2:执行任何 ihatemoney 命令报 sqlite3.OperationalError: unable to open database file?
实测现象:配置指向 sqlite:////var/lib/ihatemoney/ihatemoney.sqlite,但该目录属主还是 root。定位:SQLite 建库需要对目录的写权限,ihatemoney 用户无权在 /var/lib/ihatemoney 下创建文件。解决:chown ihatemoney /var/lib/ihatemoney 后重试;若库文件已存在,还需 chown ihatemoney /var/lib/ihatemoney/ihatemoney.sqlite。
Q3:浏览器登录项目后一刷新就回到登录页?
原因:配置 SESSION_COOKIE_SECURE = True 但服务跑在纯 HTTP 上,浏览器拒绝回传「secure」标记的会话 Cookie。解决:HTTP 环境改为 False(本文 4.2 节实测改动);生产建议反过来——上 HTTPS 并保持 True。
Q4:apt 安装时报 Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?
实测现象与定位:ps aux | grep -E "apt|dpkg" 可看到 Ubuntu 的无人值守更新(unattended-upgrades)或上一个 apt 进程仍在配置包(本文实测时是一个卡在 tzdata 交互确认的 apt 进程)。解决:等待其自然结束;确认无输出后重试。若是交互卡死可终止该进程后 dpkg --configure -a 修复。
Q5:管理仪表盘 /admin 打不开(404)?
原因:ACTIVATE_ADMIN_DASHBOARD 未开或 ADMIN_PASSWORD 为空(两者任一为默认值时管理面禁用)。解决:按第八章设置非空 ADMIN_PASSWORD 哈希、ACTIVATE_ADMIN_DASHBOARD = True 并重启服务。
十一、卸载与清理
# 1. 停止并禁用服务
systemctl disable --now ihatemoney.service
systemctl stop nginx # 若 nginx 仅用于本服务,可同样 disable
# 2. 删除 systemd 单元并重载
rm -f /etc/systemd/system/ihatemoney.service
systemctl daemon-reload
# 3. 删除 Nginx 站点
rm -f /etc/nginx/sites-enabled/ihatemoney /etc/nginx/sites-available/ihatemoney
systemctl reload nginx
# 4. 删除应用目录(虚拟环境/配置/数据/源码/离线包,按实际存在的删)
rm -rf /home/ihatemoney /etc/ihatemoney /var/lib/ihatemoney
# 5. 删除运行用户
userdel ihatemoney
清理验证:
id ihatemoney 2>&1; ls /etc/ihatemoney 2>&1; systemctl status ihatemoney.service 2>&1 | head -2
实测回显(卸载后):
id: 'ihatemoney': no such user
ls: cannot access '/etc/ihatemoney': No such file or directory
Unit ihatemoney.service could not be found.
十二、参考链接
- 官方安装文档(本篇流程的主要依据):https://ihatemoney.readthedocs.io/en/latest/installation.html
- 官方配置文档:https://ihatemoney.readthedocs.io/en/latest/configuration.html
- GitHub Releases(版本实查):https://github.com/spiral-project/ihatemoney/releases
- PyPI 包页(requires-python 元数据实查):https://pypi.org/project/ihatemoney/
- deadsnakes PPA:https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa
- 本专栏其他篇目:《IHateMoney 7.2.1 介绍与选型指南》《IHateMoney 7.2.1 配置参数详解》《IHateMoney 7.2.1 API/CLI 使用详解》