Skip to content

Upgrade and Backup

AutoOps edited this page Oct 12, 2026 · 1 revision

中文 · 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/ 目录就够;录像多的话它会是备份里最大的一块。

恢复

  1. 停服务:sudo systemctl stop autoops。
  2. 把备份的 instance/ 放回去(覆盖前先留一份现场),确认属主与权限(chmod 600 instance/*.key)。
  3. .env 一起还原(否则密钥对不上,登录或资产口令解密会失败)。
  4. 起服务、验证: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/ 放回去再重启后端即可,后端代码与数据都不用动。

从很老的版本升上来

  1. 先备份(见上),并记下 git rev-parse HEAD。
  2. 检查 instance/ 是不是完整四个文件都在(bastion.db、fernet.key、secret.key、gateway_host_rsa.key)——少一个都别急着升级,先找备份。
  3. 按四步升级。
  4. 「审计中心」里跑一遍哈希链校验(python tools/verify_audit_chain.py):链起步之前的空哈希行是历史遗留,正常;链起步之后还出现空哈希行才需要排查。
  5. 老库如果只有一台主机一个协议,升级后按需在主机编辑里补第二个协议端点(或者干脆用「合并」把同地址的历史记录并起来)。

Upgrade and Backup

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.

Backup: three things are enough

# 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.

Example backup

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 autoops

If 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.

Restore

  1. Stop the service: sudo systemctl stop autoops.
  2. Put the backed-up instance/ back (keep a copy of the current state first), then fix ownership and permissions (chmod 600 instance/*.key).
  3. Restore .env as well, otherwise the keys do not match and sign-in or credential decryption will fail.
  4. 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.

Upgrade (four steps)

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 service

Afterwards 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).

How the schema evolves

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.

Rollback

  • Code: git checkout <tag> (historical baseline tags look like green-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.

Upgrading from a very old version

  1. Back up first (see above) and record git rev-parse HEAD.
  2. 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.
  3. Upgrade with the four steps.
  4. 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.
  5. 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

Clone this wiki locally