Repository navigation
Upgrade and Backup
中文 · English
这个项目的运维面很小:数据就一个 SQLite 文件加几把密钥,没有外部数据库、没有 Alembic 迁移脚本,升级就是 git pull + 重建前端 + 重启服务。代价是:密钥和 instance/ 目录必须自己备份,丢了没有后路。
| # | 备份什么 | 位置(默认) | 丢了会怎样 |
|---|---|---|---|
| ① | 整个实例目录 |
$BASTION_INSTANCE_DIR(默认 bastion-backend/instance/) |
全部业务数据丢失 |
| ② |
.env 里显式写过的密钥 |
BASTION_SECRET_KEY / BASTION_JWT_SECRET / BASTION_FERNET_KEY
|
与 ① 里的密钥文件不匹配时,登录或解密失败 |
| ③ | 当前版本号 |
git rev-parse HEAD、git describe --tags
|
回滚时不知道回哪个版本 |
实例目录里有什么、各自的作用:
-
bastion.db—— SQLite 单文件:用户、角色、主机与协议端点、账号、授权、策略、会话与命令审计、AI 对话、哈希链,全在这里。 -
fernet.key—— 资产(被管主机)口令的加密密钥。丢了,库里已存的口令就无法解密,只能重新录入。 -
secret.key—— JWT 签名密钥。丢了,所有人的登录态立即失效(重新登录即可,数据不受影响)。 -
gateway_host_rsa.key—— SSH 网关的主机密钥。丢了会重新生成,客户端下次连接会看到 host key 变化。 - 录像文件 —— 远程桌面录像(边录边传,落在这里)。
建议权限 600、属主是服务运行用户;备份文件本身也要当机密数据对待(里面有数据库和三把密钥)。
SQLite 在写入过程中直接 cp 可能拿到不一致的快照,用官方的 .backup 更稳:
sudo systemctl stop autoops # 或者挑低峰期
cd /opt/autoops/app/bastion-backend
sqlite3 instance/bastion.db ".backup '/var/backups/autoops/bastion-$(date +%F).db'"
tar -czf /var/backups/autoops/instance-$(date +%F).tar.gz instance/
cp /opt/autoops/app/bastion-backend/.env /var/backups/autoops/env-$(date +%F).bak # 含密钥,注意权限
sudo systemctl start autoops只想快速备份、且能忍受短暂停机,直接 tar -czf 整个 instance/ 目录就够;录像多的话它会是备份里最大的一块。
- 停服务:
sudo systemctl stop autoops。 - 把备份的
instance/放回去(覆盖前先留一份现场),确认属主与权限(chmod 600 instance/*.key)。 -
.env一起还原(否则密钥对不上,登录或资产口令解密会失败)。 - 起服务、验证:
curl -fsS http://127.0.0.1:5000/api/health,登录后台,随便开一台主机的终端点一下「测试连接」。
只恢复数据库、不恢复密钥 = 数据库能开但资产口令解不开,这是最常见的恢复事故。跨机器迁移请把 .env 和 instance/ 当一对整体搬。
cd /opt/autoops/app
git pull # ① 拉代码
cd bastion-backend && .venv/bin/python -m pip install -r requirements.txt # ② 后端依赖
cd ../ant-design-pro && npm ci && npm run build # ③ 前端依赖 + 构建产物
sudo systemctl restart autoops # ④ 重启服务升级后确认四件事:/api/health 返回 success:true;能正常登录;随便开一个网页终端能连上;「审计中心」的命令记录还在(哈希链没断)。
项目没有 Alembic:app/schema_sync.py:ensure_schema() 在 create_app() 里 db.create_all() 之后做一轮只加字段的 ALTER TABLE … ADD COLUMN,所以老库升级不会丢数据,也不会自动删字段或改类型。跟着跑的 backfill_host_protocols() 会给「还没有协议端点行」的主机补一条端点(已经有端点的跳过,管理员手工配过多协议的不被覆盖)。
内置策略是版本化的:BUILTIN_POLICY_REV、BUILTIN_FILE_POLICY_REV 变了,升级后会自动把内置命令/文件策略刷新到新版本;管理员自建的策略不受影响。
升级后如果发现角色权限没更新,先回想这条历史缺陷:
seed_data()曾经把「本次是否需要提交」只在新建角色时置为真,老库里角色都在,于是角色权限的更新永远不会commit。现在的代码已经修了,但如果你是从很老的版本升上来的,值得在「角色管理」里点开看一眼权限是不是符合预期。
-
代码回滚:
git checkout <tag>(历史基线 tag 形如green-oss、green-multiproto、green-winrm、green-rdp-legacy、green-rec-chunk、green-upload-progress、green-no-footer、green-ai-channel等),重装依赖、重建前端、重启服务。 -
数据回滚:从备份恢复
instance/。注意数据库不会因为代码回滚而自动回退字段(ensure_schema()只加不减),所以先回滚代码再决定要不要回滚数据,顺序反了容易白忙。 -
只回滚前端:把旧
dist/放回去再重启后端即可,后端代码与数据都不用动。
- 先备份(见上),并记下
git rev-parse HEAD。 - 检查
instance/是不是完整四个文件都在(bastion.db、fernet.key、secret.key、gateway_host_rsa.key)——少一个都别急着升级,先找备份。 - 按四步升级。
- 「审计中心」里跑一遍哈希链校验(
python tools/verify_audit_chain.py):链起步之前的空哈希行是历史遗留,正常;链起步之后还出现空哈希行才需要排查。 - 老库如果只有一台主机一个协议,升级后按需在主机编辑里补第二个协议端点(或者干脆用「合并」把同地址的历史记录并起来)。
The operational surface of this project is small: the data is one SQLite file plus a few key files, with no external database and no Alembic migrations. Upgrading means git pull, rebuild the frontend, restart the service. The price of that simplicity is this: the keys and the instance/ directory are yours to back up — lose them and there is no way back.
| # | What to back up | Where (default) | If you lose it |
|---|---|---|---|
| ① | The whole instance directory |
$BASTION_INSTANCE_DIR (default bastion-backend/instance/) |
all business data is gone |
| ② | Keys written explicitly into .env
|
BASTION_SECRET_KEY / BASTION_JWT_SECRET / BASTION_FERNET_KEY
|
mismatched with the key files in ①, sign-in or decryption fails |
| ③ | The current version |
git rev-parse HEAD, git describe --tags
|
you will not know what to roll back to |
What lives in the instance directory, and what each piece does:
-
bastion.db— the single SQLite file: users, roles, hosts and protocol endpoints, accounts, grants, policies, session and command audits, AI conversations, and the hash chain. Everything. -
fernet.key— the encryption key for managed-host credentials. Lose it and the stored passwords can no longer be decrypted — they have to be re-entered. -
secret.key— the JWT signing key. Lose it and every sign-in is invalidated at once (people simply sign in again; no data is lost). -
gateway_host_rsa.key— the SSH gateway's host key. If it disappears it is regenerated, and clients will see the host key change. - Recording files — remote-desktop recordings (streamed to disk while recording).
Set permissions to 600 with the service user as owner, and treat the backup itself as confidential material: it contains the database and all three keys.
Copying a live SQLite file with cp can capture a torn snapshot; the official .backup command is safer:
sudo systemctl stop autoops # or pick a quiet window
cd /opt/autoops/app/bastion-backend
sqlite3 instance/bastion.db ".backup '/var/backups/autoops/bastion-$(date +%F).db'"
tar -czf /var/backups/autoops/instance-$(date +%F).tar.gz instance/
cp /opt/autoops/app/bastion-backend/.env /var/backups/autoops/env-$(date +%F).bak # contains keys: mind the permissions
sudo systemctl start autoopsIf you only need a quick copy and can tolerate a short stop, archiving the whole instance/ directory with tar -czf is enough. Recordings will be the largest part of it.
- Stop the service:
sudo systemctl stop autoops. - Put the backed-up
instance/back (keep a copy of the current state first), then fix ownership and permissions (chmod 600 instance/*.key). - Restore
.envas well, otherwise the keys do not match and sign-in or credential decryption will fail. - Start the service and verify:
curl -fsS http://127.0.0.1:5000/api/health, sign in, and use "Test connection" on any host.
Restoring the database without the keys means the database opens but the stored credentials stay encrypted forever — that is the most common restore accident. When moving to another machine, move .env and instance/ as one unit.
cd /opt/autoops/app
git pull # 1. pull the code
cd bastion-backend && .venv/bin/python -m pip install -r requirements.txt # 2. backend deps
cd ../ant-design-pro && npm ci && npm run build # 3. frontend deps + build
sudo systemctl restart autoops # 4. restart the serviceAfterwards confirm four things: /api/health returns success:true; you can sign in; a web terminal connects to some host; and "Audit Center → Command records" still lists the old entries (the hash chain is intact).
There is no Alembic: app/schema_sync.py:ensure_schema() runs a round of additive-only ALTER TABLE … ADD COLUMN after db.create_all() inside create_app(). Upgrading an old database therefore loses no data, and it will not drop columns or change types for you. The backfill_host_protocols() call that follows gives every host that has no protocol endpoint row one endpoint row (hosts that already have endpoints are skipped, so manually configured multi-protocol hosts are never overwritten).
Built-in policies are versioned: when BUILTIN_POLICY_REV or BUILTIN_FILE_POLICY_REV changes, an upgrade refreshes the built-in command and file policies; administrator-created policies are untouched.
If role permissions look stale after an upgrade, remember this historical defect:
seed_data()once set its "needs commit" flag only when it created a role — with every role already present in an old database, permission updates were never committed. The code is fixed now, but if you are coming from a very old version it is worth opening "Roles" and eyeballing the permissions.
-
Code:
git checkout <tag>(historical baseline tags look likegreen-oss,green-multiproto,green-winrm,green-rdp-legacy,green-rec-chunk,green-upload-progress,green-no-footer,green-ai-channel), reinstall dependencies, rebuild the frontend, restart the service. -
Data: restore
instance/from a backup. Note that the database does not follow the code backwards (ensure_schema()only adds), so roll back the code first and then decide about the data — doing it in the other order usually wastes the effort. -
Frontend only: put the previous
dist/back and restart the backend; neither backend code nor data has to move.
- Back up first (see above) and record
git rev-parse HEAD. - Check that
instance/really holds all four files (bastion.db,fernet.key,secret.key,gateway_host_rsa.key). If one is missing, do not upgrade yet — find a backup first. - Upgrade with the four steps.
- Run the hash-chain verifier from the Audit Center (
python tools/verify_audit_chain.py): empty hash rows before the chain starts are historical and fine; only empty hash rows after it starts need investigating. - If an old database had one protocol per host, add the second protocol endpoint in the host editor, or simply use "Merge" to combine the historical records for the same address.
相关页面 / Related pages: Install-and-Deploy · FAQ · Security-and-Maintenance · Home
很高兴认识你,陌生人! 我是一名初二学生,在中国新疆读初中。英语和写的代码都还在慢慢练,这份手册也还在补,请大家多多谅解,也欢迎直接指正。
Nice to meet you, stranger! I'm an eighth-grade student in Xinjiang, China. My English and my code are still a work in progress, and so is this manual — please bear with me (and tell me if you can).
AutoOps 堡垒机 · 使用手册
起步
资产与权限
干活
查账与维护
AutoOps Bastion · Manual
Getting started
Assets and permissions
Work
Audit and upkeep