编程闭关教程 · 系列 08–20 · 编制日期 2026-10-14

部署运维专题:1GB 低配服务器的生产化落点

这是全系列最后一个模块:把 11 模块在本地跑通的 Go 工作台,搬到一台约 1GB 内存的低配 Linux 云服务器上,做成开机自启、HTTPS 可访问、可回滚、可备份、挂了能自动拉起的生产服务。全程不装 Docker、不堆中间件:单 Go 二进制 + systemd + Nginx/Caddy + 一套 cron 备份脚本,就这么多。承接 08 总纲 M1 与阶段二、阶段三的部署环节,与 11/16/17/18/19 模块互为引用。
本模块承诺一台 1GB 内存的 Debian 13.7 服务器,安全承载工作台(单 Go 二进制)+ 一个数据库实例 + HTTPS 站点;出问题可回滚到上一版本、可从备份恢复、重启后自动拉起。所有命令、配置文件、脚本本页给全,照做即可,不需要跳出教程。
Debian 13.7
trixie stable,低配服务器首选系统
systemd
服务托管,随发行版,不用 supervisor/docker
Nginx 1.30.5
/ Caddy v2.11.4
反向代理与 HTTPS 二选一
1 套
cron 备份脚本(SQLite/MySQL/PG/Redis)
12+
条常见报错对照表,卡住先查表
部署心智五原则(08 §3):单二进制交付 / 不装 Docker / 数据库按需 / swap 兜底 / 服务越少越好。1GB 服务器不装 Docker(Ubuntu Server 官方要求 1.5GB 内存起,1GB 跑不动)。版本唯一事实来源:09 模块与本系列 versions.md。
08 总纲 09 环境·版本 10 Go 内核 11 工作台 12 Vue3 13 Flutter 14 Python 15 C/C++ 16 MySQL 17 PostgreSQL 18 Redis 19 SQLite3 20 部署
本页目录
  1. 服务器安全地基(承接 09 §2 并深化)
  2. Go 应用部署:交叉编译 → systemd 托管
  3. 反向代理与 HTTPS:Nginx 与 Caddy 两套方案
  4. 数据库在 1GB 服务器上的部署要点
  5. 备份策略:完整可执行脚本 + 恢复演练
  6. 轻量监控:符合 1GB 约束
  7. 常见报错对照表(14 条)
  8. 验收清单(对应 08 总纲 M1 与阶段二)
  9. 本模块版本速览与来源
01

服务器安全地基(承接 09 §2 并深化)

刚拿到一台干净的 Debian 13.7 云服务器,第一件事不是部署应用,而是把"门"关好。09 §2 已讲过基础 SSH 登录,本节给出生产化最小配置全集:一套做完,这台机器才配跑业务。

前置假设:你已在本地 Windows 用 ssh-keygen 生成密钥对(09 §2 已给命令),公钥内容形如 ssh-ed25519 AAAA...。下面所有命令默认以刚创建的普通用户(如 deploy)+ sudo 执行,不再用 root 直接登录。

1.1 SSH 密钥登录、禁用密码与 root 直登

先确认本地公钥已写入服务器 ~/.ssh/authorized_keys 且能免密登录,再改配置——否则会把自己锁在门外。

# 1) 本地(Windows PowerShell)测试免密登录,成功后再继续
ssh deploy@服务器IP

# 2) 服务器上编辑 SSH 配置
sudo nano /etc/ssh/sshd_config

# 确保以下三行(取消注释、改值):
PubkeyAuthentication yes
PasswordAuthentication no
PermitRootLogin no

# 3) 校验语法并重载(不是重启,避免踢掉当前连接)
sudo sshd -t
sudo systemctl reload ssh

# 4) 另开一个新终端测试免密登录成功后,再关掉旧终端

铁律:改 sshd_config 后永远不要关掉当前已登录的终端,新开一个终端验证能登录,再退旧的。这是运维第一课,能救你无数次被锁门外。

1.2 防火墙 ufw:只开必要端口

sudo apt update && sudo apt install -y ufw

# 默认:拒绝入站、放行出站
sudo ufw default deny incoming
sudo ufw default allow outgoing

# 只放行:SSH(22)、HTTP(80)、HTTPS(443)
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

sudo ufw enable        # 会提示 y/n,输入 y
sudo ufw status verbose

数据库端口(3306/5432/6379)一律不对公网开放——它们只监听 127.0.0.1,应用本机直连(见 §4)。

1.3 fail2ban:自动封爆破 IP(最小配置)

sudo apt install -y fail2ban

# 写本地覆盖配置(不动官方 jail.conf)
sudo tee /etc/fail2ban/jail.d/sshd.local >/dev/null <<'EOF'
[sshd]
enabled = true
port    = 22
maxretry = 5
bantime  = 1h
findtime = 10m
EOF

sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd   # 查看已封的 IP

1.4 自动安全更新(一句话)

sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades   # 选"是",安全补丁自动装

这一行做完,安全类 apt 补丁会在后台自动安装并按需重启服务,不用你手动追 CVE。

1.5 2G swap:1GB 机器的兜底垫

1GB 内存的机器,一次 apt 编译或数据库突发就可能 OOM。加 2G swap 当"最后一道缓冲",不是替代内存。

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# 开机自动挂载
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

# 降低 swap 倾向(默认 60 太激进,1GB 机器设 10)
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

free -h    # 确认 Swap 行出现 2.0Gi

做完 §1 的验收

① 用密码 + root 登录被拒绝;② ufw status 只放行 22/80/443;③ fail2ban 在运行;④ free -h 看到 2G swap;⑤ 自动更新服务已启用。这台机器才算"可投产"。

不要做的事

不要在 1GB 机器上装 Docker(09 §3 部署心智);不要把数据库端口暴露公网;不要为了"方便"把 ufw 整个关掉。服务越少越好——每多一个常驻进程,都是内存和攻击面。
02

Go 应用部署:交叉编译 → systemd 托管

工作台在 11 模块是一个 Go 后端(Gin v1.12 + GORM v1.31)。部署到 Linux 的关键:在 Windows 本地交叉编译出一个纯静态 Linux 二进制,scp 上传,用 systemd 托管。服务器上不需要装 Go、不需要 gcc——这就是 CGO_ENABLED=0 + 纯 Go 驱动的红利。

2.1 交叉编译命令(对应 11 工作台)

工作台 SQLite 用的是 glebarez/sqlite(底层 modernc.org/sqlite,纯 Go 实现),所以整个二进制零 CGO 依赖,可完美交叉编译。MySQL/PG 同理用 go-sql-driver/mysql、pgx(均为纯 Go)。

# 本地 Windows PowerShell,进入工作台项目根目录(含 go.mod)
cd D:\your\workbench

# 交叉编译:目标 linux/amd64,禁用 CGO,strip 掉调试信息减小体积
$env:CGO_ENABLED=0
$env:GOOS="linux"
$env:GOARCH="amd64"
go build -ldflags "-s -w" -o workbench ./cmd/server

# 产物是单个文件 workbench(约 8–15MB),无任何动态库依赖
dir workbench
关于架构:绝大多数云服务器是 x86_64(amd64)。若你买的是 ARM 小规格机(如鲲鹏/ Ampere),把 GOARCH 改成 arm64 即可,其余步骤完全一样。判断方法:服务器上跑 uname -m,输出 x86_64 用 amd64,输出 aarch64 用 arm64。

2.2 上传与目录约定

# 本地 PowerShell:上传二进制到服务器临时目录
scp .\workbench deploy@服务器IP:/tmp/workbench

# 服务器上建立生产目录约定
sudo mkdir -p /opt/workbench          # 程序本体
sudo mkdir -p /var/log/workbench      # 日志(本方案日志走 journald,此目录留给文件型日志可选)
sudo mkdir -p /etc/workbench          # 配置文件(.env)
sudo mkdir -p /var/lib/workbench      # 数据文件(SQLite db、上传文件)

# 移动并赋权:程序归 root,运行用户用专用系统用户 app
sudo useradd -r -s /usr/sbin/nologin app || true
sudo mv /tmp/workbench /opt/workbench/workbench
sudo chmod +x /opt/workbench/workbench
sudo chown -R app:app /opt/workbench /var/log/workbench /var/lib/workbench

目录约定总表(照此建,不要乱放)

路径放什么说明
/opt/workbench/二进制本体程序文件。新版本上传为 workbench.v2,再原子替换,便于回滚(见 §2.5)
/etc/workbench/.env配置(密钥/DB DSN)权限 600、属 app。绝不进 git、不打进二进制
/var/lib/workbench/SQLite 数据库文件、上传附件数据与程序分离,备份只盯这个目录
/etc/systemd/system/workbench.servicesystemd unit服务定义文件,见下
journald运行日志journalctl -u workbench,无需自建 logrotate(见 §2.6)

2.3 systemd unit 完整模板(直接照抄)

sudo tee /etc/systemd/system/workbench.service >/dev/null <<'EOF'
[Unit]
Description=Workbench Go Service (11 module)
After=network.target

[Service]
Type=simple
User=app
Group=app
WorkingDirectory=/opt/workbench

# 通过 EnvironmentFile 注入配置(.env 里写 DB_DSN、JWT_SECRET、PORT 等)
EnvironmentFile=/etc/workbench/.env
ExecStart=/opt/workbench/workbench

# 崩溃自动拉起
Restart=on-failure
RestartSec=3

# 优雅停机:给 Go 的 context 取消最多 10 秒收尾时间
TimeoutStopSec=10
KillSignal=SIGTERM

# 日志直接进 journald
StandardOutput=journal
StandardError=journal
SyslogIdentifier=workbench

# 资源与文件描述符兜底
LimitNOFILE=65535

# ---- 安全加固(可选但推荐,逐行取消注释即可)----
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
# ReadWritePaths=/var/lib/workbench   # 若开了 ProtectSystem=strict 才需要显式放行数据目录

[Install]
WantedBy=multi-user.target
EOF

配置文件 /etc/workbench/.env 示例

sudo tee /etc/workbench/.env >/dev/null <<'EOF'
PORT=8080
GIN_MODE=release
DB_DSN=/var/lib/workbench/workbench.db
JWT_SECRET=换成一串足够长的随机字符串
EOF
sudo chmod 600 /etc/workbench/.env
sudo chown app:app /etc/workbench/.env

2.4 systemctl 常用命令(背下来)

sudo systemctl daemon-reload                 # 改了 unit 文件后必须执行
sudo systemctl enable --now workbench        # 启动 + 开机自启(关键!对应验收"重启自启")
sudo systemctl status workbench              # 看运行状态、最近日志
sudo systemctl restart workbench             # 改了配置/换了二进制后重启
sudo systemctl stop workbench                # 停止
journalctl -u workbench -f                   # 实时跟踪日志(最重要的排查入口)
journalctl -u workbench --since "10 min ago" # 看最近 10 分钟

2.5 优雅停机验证与回滚

11 模块的工作台已实现 signal.NotifyContext(ctx, SIGINT, SIGTERM)(见 10 模块并发章与 11 模块优雅停机小节)。验证:

# 1) 启动服务,确认监听
sudo systemctl restart workbench
curl http://127.0.0.1:8080/healthz     # 应返回 ok

# 2) 触发停止,观察日志里是否打印"正在关闭..."、连接排空后才退出
sudo systemctl stop workbench
journalctl -u workbench --since "1 min ago"

# 3) 回滚:新版本先传为 v2,验证失败就切回旧版(原子替换)
sudo systemctl stop workbench
sudo cp /opt/workbench/workbench /opt/workbench/workbench.v1.bak
# (上传新二进制到 /tmp/workbench.v2 后)
sudo cp /tmp/workbench.v2 /opt/workbench/workbench
sudo chmod +x /opt/workbench/workbench
sudo chown app:app /opt/workbench/workbench
sudo systemctl start workbench
curl http://127.0.0.1:8080/healthz
# 失败则:sudo cp /opt/workbench/workbench.v1.bak /opt/workbench/workbench && sudo systemctl start workbench

2.6 日志查看与轮转

本方案用 journald(systemd 自带),不需要额外配置 logrotate——journald 默认按大小/时间自动轮转并压缩。一行调整即可:

# 限制 journal 总上限(1GB 机器别让日志吃光磁盘)
sudo journalctl --vacuum-size=200M
# 永久生效:编辑 /etc/systemd/journald.conf,设 SystemMaxUse=200M,再 sudo systemctl restart systemd-journald

结论:程序日志 = journald(journalctl -u workbench -f);访问日志也由 Gin 输出到 stdout 进 journald。1GB 机器不要再叠一套文件日志 + logrotate,那是重复造轮子。

03

反向代理与 HTTPS:Nginx 与 Caddy 两套方案

Go 服务只监听 127.0.0.1:8080(不对公网),前面挂一个反向代理对外开 80/443,负责:静态文件分发、HTTPS 终止、把 /api 转发给后端。下面给 Nginx stable 1.30.5 与 Caddy v2.11.4 两套完整配置,二选一。

3.1 方案 A:Nginx stable 1.30.5

sudo apt install -y nginx
# Debian 13.7 apt 源里的 nginx 为 stable 线;版本核对:nginx -v

站点配置 /etc/nginx/sites-available/workbench(完整示例)

server {
    listen 80;
    server_name your-domain.com;          # 换成你的域名(需先解析到本机 IP)

    root /var/www/workbench;              # Vue3 前端打包产物(12 模块 pnpm build 输出 dist)
    index index.html;

    # gzip 压缩
    gzip on;
    gzip_types text/css application/javascript application/json image/svg+xml;
    gzip_min_length 1k;

    # 后端 API 反代
    location /api/ {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # 健康检查直接打后端
    location /healthz {
        proxy_pass http://127.0.0.1:8080;
    }

    # 静态资源缓存(Vue 打包带 hash 的 js/css)
    location ~* \.(?:js|css|png|jpg|svg|woff2?)$ {
        expires 7d;
        add_header Cache-Control "public";
    }

    # 前端单页应用回退到 index.html
    location / {
        try_files $uri $uri/ /index.html;
    }
}
# 启用站点 + 放前端产物 + 校验重载
sudo ln -s /etc/nginx/sites-available/workbench /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo mkdir -p /var/www/workbench
# 本地把 12 模块 pnpm build 的 dist/* 用 scp 传到 /var/www/workbench
sudo nginx -t && sudo systemctl reload nginx

certbot 自动 HTTPS 命令序列

sudo apt install -y certbot python3-certbot-nginx
# 自动改 nginx 配置、申请并部署 Let's Encrypt 证书、配自动续期
sudo certbot --nginx -d your-domain.com
sudo systemctl status certbot.timer     # 确认自动续期定时器在跑
sudo certbot renew --dry-run            # 测试续期是否正常

3.2 方案 B:Caddy v2.11.4(配置极简,自动 HTTPS)

# 官方安装脚本(Debian 13.7)
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
sudo apt update && sudo apt install -y caddy
caddy version       # 核对 v2.11.4

Caddyfile(/etc/caddy/Caddyfile,完整示例)

your-domain.com {
    # 一句自动 HTTPS:Caddy 自动申请、自动续期 Let's Encrypt 证书

    # 前端静态文件
    root * /var/www/workbench
    encode gzip
    file_server

    # API 反代到 Go 后端
    handle /api/* {
        reverse_proxy 127.0.0.1:8080
    }

    # 健康检查
    handle /healthz {
        reverse_proxy 127.0.0.1:8080
    }

    # SPA 回退
    try_files {path} /index.html
}
sudo systemctl reload caddy    # 改完 Caddyfile 后重载;证书全自动

3.3 选型表:Nginx 还是 Caddy

维度Nginx stable 1.30.5Caddy v2.11.4
配置复杂度较长,location/proxy_pass/gzip/cache 逐条写极短,核心反代一行 reverse_proxy
HTTPS需 certbot 配合,多一步内置自动申请 + 自动续期,零配置
生态/文档最广,全网资料、招聘、运维惯例都是它较新,资料少但官方文档清晰
内存占用轻量(常驻约 5–15MB)轻量(Go 单二进制,约 10–20MB)
1GB 机器都够用,任选其一,不要同时装两个抢 80/443同左
建议要走职场、要跟主流运维接轨 → 选它只想最少配置跑起来、域名已解析 → 选它

选择建议:学习/求职主线选 Nginx(生态全、面试常问);纯个人小站想省心选 Caddy(一句 auto HTTPS)。二选一,别两个都装——它们都抢 80/443 端口,必出 §7 的 "Port 80 in use"。

04

数据库在 1GB 服务器上的部署要点

四数据库的完整安装、SQL、Go 集成、低配调优分别在 16(MySQL)/ 17(PostgreSQL)/ 18(Redis)/ 19(SQLite3)模块各自的"低配调优"小节。本节不重复长篇,只给 1GB 服务器部署时的统一原则 + 每条关键配置 + systemd 下的注意点。

统一原则(先记住):① 数据库只监听 127.0.0.1,不对公网开端口(ufw 也不放行);② 一个业务一个库实例,不要在一个 MySQL 里塞十几个互不相关的库;③ 1GB 机器上 SQLite 是默认首选,只有并发写/多连接需求上来才上 MySQL/PG;④ Redis 只做缓存/队列,宕机可重建,不持久化重要数据。

4.1 三种原生数据库的关键低配配置(各 1 条,详见对应模块)

数据库版本1GB 机器关键配置(1 条)完整内容见
MySQL8.4.12 LTSinnodb_buffer_pool_size = 128M(默认 128M 即可,1GB 机器不要再调大;max_connections=50)见本系列 16 MySQL 专题的"低配部署/调优"小节
PostgreSQL18.6shared_buffers = 128MB、work_mem = 4MB(1GB 机器按物理内存 1/8 估 shared_buffers)见本系列 17 PostgreSQL 专题的"低配部署/调优"小节
Redis8.10.2maxmemory = 128mb + maxmemory-policy = allkeys-lru(防缓存吃光内存被 OOM)见本系列 18 Redis 专题的"持久化/低配"小节

三者均通过发行版 apt 原生安装(sudo apt install mysql-server / postgresql / redis-server),自动注册为 systemd 服务并开机自启,不需要 Docker。安装后的初始账号、建库、建用户、Go DSN 写法,分别见 16/17/18 模块,本页不再展开。

4.2 SQLite 方案(1GB 机器默认首选)在 systemd 下的注意点

工作台 11 模块默认就是 SQLite(glebarez/sqlite 纯 Go 驱动,见 19 模块)。它没有独立服务,就是一个 .db 文件,跟着 Go 进程走。systemd 下只有两个注意点:

# 1) db 文件放在数据目录,属主是运行用户 app(不是 root)
sudo chown -R app:app /var/lib/workbench
# .env 里 DB_DSN=/var/lib/workbench/workbench.db

# 2) 务必开启 WAL 模式(19 模块详述),提升并发读、减少锁等待
#    在应用首次连接后执行一次(或迁移里开启):
#    PRAGMA journal_mode=WAL;

SQLite 在 1GB 机器的优势

零守护进程、零内存常驻、单文件好备份(直接拷文件或 VACUUM INTO)。个人工作台、低并发工具,它就是最优解——别为了"听起来专业"硬上 MySQL。

systemd 下最常踩的坑

db 文件目录权限:unit 里 User=app,但你用 root 手动跑过一次程序,db 文件变成 root 属主,systemd 启动后 app 用户 permission denied 打不开库。解决:sudo chown -R app:app /var/lib/workbench。
05

备份策略:完整可执行脚本 + 恢复演练

"没演练过恢复的备份等于没有备份"。本节给一套完整可复制的备份脚本:覆盖 SQLite(VACUUM INTO)、MySQL(mysqldump)、PostgreSQL(pg_dump)、Redis(RDB 拷贝),自动保留最近 N 份、写日志,挂到 cron 每天跑一次。

5.1 备份目录结构

/var/backups/workbench/
├── sqlite/         # SQLite 备份(按日期 .db)
├── mysql/          # MySQL dump(.sql.gz)
├── pgsql/          # PostgreSQL dump(.dump.gz)
├── redis/          # Redis RDB 拷贝
└── backup.log      # 每次备份的日志
sudo mkdir -p /var/backups/workbench/{sqlite,mysql,pgsql,redis}
sudo chown -R app:app /var/backups/workbench   # 让备份脚本能写

5.2 完整备份脚本 /usr/local/bin/workbench-backup.sh

sudo tee /usr/local/bin/workbench-backup.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
# 工作台备份脚本:覆盖 SQLite/MySQL/PG/Redis,保留最近 7 份
set -euo pipefail

DEST=/var/backups/workbench
DATE=$(date +%Y%m%d-%H%M%S)
KEEP=7                                   # 每类保留最近 7 份
LOG=$DEST/backup.log

log(){ echo "[$(date '+%F %T')] $*" >> "$LOG"; }

log "==== 备份开始 ===="

# ---- 1) SQLite:用 VACUUM INTO 得到一致性快照(不锁库)----
if [ -f /var/lib/workbench/workbench.db ]; then
  sqlite3 /var/lib/workbench/workbench.db "VACUUM INTO '$DEST/sqlite/workbench-$DATE.db'"
  log "SQLite ok -> sqlite/workbench-$DATE.db"
fi

# ---- 2) MySQL:mysqldump(按需取消注释,填库名/账号)----
# if command -v mysqldump >/dev/null; then
#   mysqldump -u root --single-transaction workbench \
#     | gzip > "$DEST/mysql/workbench-$DATE.sql.gz"
#   log "MySQL ok -> mysql/workbench-$DATE.sql.gz"
# fi

# ---- 3) PostgreSQL:pg_dump(按需取消注释)----
# if command -v pg_dump >/dev/null; then
#   sudo -u postgres pg_dump workbench | gzip > "$DEST/pgsql/workbench-$DATE.dump.gz"
#   log "PostgreSQL ok -> pgsql/workbench-$DATE.dump.gz"
# fi

# ---- 4) Redis:拷贝 RDB 文件(缓存可重建,这里仅留个快照)----
if [ -f /var/lib/redis/dump.rdb ]; then
  cp /var/lib/redis/dump.rdb "$DEST/redis/dump-$DATE.rdb"
  log "Redis ok -> redis/dump-$DATE.rdb"
fi

# ---- 5) 每类只保留最近 KEEP 份,删除更老的 ----
for dir in sqlite mysql pgsql redis; do
  ls -1t "$DEST/$dir"/* 2>/dev/null | tail -n +$((KEEP+1)) | xargs -r rm -f
done

log "==== 备份完成,磁盘占用:$(du -sh $DEST | cut -f1) ===="
EOF

sudo chmod +x /usr/local/bin/workbench-backup.sh
# SQLite 备份需要 sqlite3 客户端:sudo apt install -y sqlite3

5.3 挂到 cron(每天凌晨 3:17 跑一次)

sudo crontab -e
# 加入这一行:每天 03:17 执行(避开整点高峰)
17 3 * * * /usr/local/bin/workbench-backup.sh

# 手动跑一次验证(这是必做动作,不要等 cron)
sudo /usr/local/bin/workbench-backup.sh
cat /var/backups/workbench/backup.log
ls -lh /var/backups/workbench/sqlite/

5.4 异地备份(一句话)

本机备份只能防"误删/程序坏",防不了"整台机器被服务商回收/磁盘损坏"。加一步异地:用 rclone 或 rsync 把 /var/backups/workbench/ 每天同步一份到对象存储(如 S3 兼容存储)或另一台机器。在备份脚本末尾加一行 rclone copy /var/backups/workbench/ remote:workbench-backup 即可,rclone 的配置见其官方入门(本系列不展开,一句带过)。

5.5 恢复演练步骤(每季度做一次)

  1. 选一份最近的备份:ls -t /var/backups/workbench/sqlite/ | head -1。
  2. 停服务:sudo systemctl stop workbench。
  3. 恢复 SQLite:把备份 .db 拷回数据目录并赋权——sudo cp /var/backups/workbench/sqlite/workbench-XXXX.db /var/lib/workbench/workbench.db && sudo chown app:app /var/lib/workbench/workbench.db。
  4. (MySQL/PG):gunzip -c workbench-XXXX.sql.gz | mysql workbench / gunzip -c workbench-XXXX.dump.gz | sudo -u postgres psql workbench。
  5. 启服务 + 验证:sudo systemctl start workbench,curl http://127.0.0.1:8080/healthz,登录工作台看数据是否是备份时点的状态。
  6. 记录:把"恢复耗时、是否成功"写进 backup.log——这就是演练报告。

验收硬指标:你能在 15 分钟内从一份 SQLite 备份把数据完整恢复回来。做不到这一条,§8 的"恢复演练成功"就不通过。

06

轻量监控:符合 1GB 约束

1GB 机器不装 Prometheus + Grafana 全家桶(光这俩常驻就吃两三百 MB)。本节给"系统自带 + 一个 cron 脚本"的轻量方案,足够个人工作台用。

6.1 四层轻量监控

层做法命令/配置
① 进程存活systemd 自动拉起(Restart=on-failure 已配)systemctl status workbench
② 健康检查cron 每分钟 curl /healthz,失败记日志见下脚本
③ 日志排查出问题先 journalctljournalctl -u workbench -f
④ 内存告警cron 定时 free 阈值判断,超阈值写告警日志见下一句话

/healthz 轮询脚本 /usr/local/bin/workbench-healthcheck.sh

sudo tee /usr/local/bin/workbench-healthcheck.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
# 每分钟探活 /healthz;失败则记录并尝试重启服务
URL="http://127.0.0.1:8080/healthz"
LOG="/var/log/workbench/health.log"

if ! curl -sf --max-time 5 "$URL" >/dev/null; then
  echo "[$(date '+%F %T')] HEALTH CHECK FAILED, restarting..." >> "$LOG"
  systemctl restart workbench
fi
EOF
sudo chmod +x /usr/local/bin/workbench-healthcheck.sh

# 挂 cron:每分钟跑一次
sudo crontab -e
# * * * * * /usr/local/bin/workbench-healthcheck.sh

内存告警(一句话版,挂到每小时 cron)

# 可用内存低于 100MB 就写一行告警日志(1GB 机器红线约 100MB)
# crontab 里加:
0 * * * * [ "$(free -m | awk '/Mem:/{print $7}')" -lt 100 ] && echo "[$(date)] LOW MEM $(free -m | grep Mem)" >> /var/log/workbench/memwarn.log

6.2 重方案的边界(何时才上 Prometheus/Grafana)

阶段三扩展,本模块不做:当你进入阶段三(企业级模式,08 §2 第 3–6 月)、服务从"个人工作台"变成"多用户、要 SLA、要历史曲线图"时,才上 Prometheus + Grafana + node_exporter。在那之前,1GB 机器上用上面这套 cron + journald 足够——上重监控本身就会把这台小机器压垮。这是一条明确的阶段边界,不要提前。
07

常见报错对照表(14 条)

卡住了先查这张表。左列是你会在屏幕上看到的原文,中列是原因,右列是照做的解法。

报错原文 / 现象原因解决
permission denied(启动二进制 / 打开 db)二进制没 +x,或数据目录/db 文件属主是 root 而非 appsudo chmod +x /opt/workbench/workbench;sudo chown -R app:app /var/lib/workbench /opt/workbench
bind: address already in use / Port 80 in use80/443/8080 被别的进程占了(Nginx 与 Caddy 同时装、旧进程没退)sudo ss -ltnp | grep ':80' 找到占用进程;二选一保留,sudo systemctl stop/disable 另一个
certbot 验证失败 Challenge failed域名没解析到本机 IP;或 ufw 没放行 80;或 80 被别的服务占了先 dig your-domain.com 确认 A 记录指向本机 IP;sudo ufw allow 80;确保 80 端口是 nginx/caddy 在听
Failed to start workbench.service: Unit not found.unit 文件放错目录,或没 daemon-reload确认文件在 /etc/systemd/system/workbench.service;执行 sudo systemctl daemon-reload
ExecStart: permission denied(二进制不可执行)上传的二进制丢了执行权限,或文件系统挂了 noexecsudo chmod +x;确认 /opt 没挂 noexec(mount | grep opt)
main.go: out of memory / dmesg 里 Out of memory: Killed process1GB 内存被吃光,内核 OOM Killer 杀进程确认 §1.5 的 2G swap 已加;按 §4 压低 MySQL/PG/Redis 内存上限;用 journalctl -k | grep -i oom 定位被杀的是谁
journalctl -u workbench 日志为空程序日志没输出到 stdout/stderr,或 unit 里没配 StandardOutput确认 unit 有 StandardOutput=journal;确认 Go 程序日志打到 stdout(不要只写文件);sudo systemctl restart workbench 后再看
502 Bad Gateway(Nginx/Caddy)反代后端 127.0.0.1:8080 没在跑或崩了systemctl status workbench 看后端是否 active;curl 127.0.0.1:8080/healthz 直连测试;看 journalctl 后端日志
404 / API 全 404(proxy_pass 路径错误)Nginx proxy_pass http://127.0.0.1:8080; 带不带尾部斜杠,导致 /api/ 被错误改写路径后端路由若就是 /api/xxx,用 proxy_pass http://127.0.0.1:8080;(不带 URI 部分、路径原样转发);改完 nginx -t && reload
too many open files(文件描述符用尽)systemd 默认 LimitNOFILE 偏小,高并发打满unit 里加 LimitNOFILE=65535,daemon-reload 后重启服务
日志/时间差 8 小时,日志时间戳不对服务器时区是 UTC,没设成 Asia/Shanghaisudo timedatectl set-timezone Asia/Shanghai,重启服务
备份脚本 cron 里不执行,但手动跑正常cron 环境变量极简(PATH 不含自定义路径)、或脚本里用了相对路径/交互式命令脚本内一律用绝对路径;set -euo pipefail;先 sudo bash -x /usr/local/bin/workbench-backup.sh 看哪行挂;检查 backup.log 有无报错
改完配置不生效(systemctl restart 后行为依旧)改了 .env 但没重启进程,或改了 unit 没 daemon-reload改 .env → systemctl restart;改 unit 文件 → 必须先 daemon-reload 再 restart
SSH 突然连不上(改 sshd 后被锁门外)sshd_config 改错了(如 PubkeyAuthentication no)这就是 §1.1 强调"别关旧终端"的原因;用云服务商控制台的 VNC/网页终端登录回滚配置,sudo sshd -t 校验后再 reload
08

验收清单(对应 08 总纲 M1 与阶段二)

这是本模块的结业标准,也是 08 总纲 M1"工作台跑通"与阶段二"服务器生产化部署"在部署侧的最终落地。逐项打勾,全部通过才算完成。

#验收项(怎么测)对应章节
1服务器重启后工作台自启:sudo reboot,重连后 systemctl is-active workbench 返回 active,且 curl 127.0.0.1:8080/healthz 返回 ok§2.4(enable --now)
2HTTPS 可访问:浏览器打开 https://your-domain.com,证书有效(小绿锁),登录 + 增删改查正常,/api 反代通§3(Nginx 或 Caddy)
3手动触发一次备份与恢复演练成功:跑 workbench-backup.sh 生成备份;按 §5.5 停服务→恢复→启动,数据回到备份时点§5.3 / §5.5
4/healthz 监控脚本有输出:/var/log/workbench/health.log 存在;故意停掉后端,一分钟内脚本记录 FAILED 并自动重启§6.1
5安全地基到位:密码登录与 root 直登被拒;ufw 只放行 22/80/443;fail2ban 运行;2G swap 生效§1
6回滚可用:换一版二进制,验证失败能在一分钟内切回旧版正常运行§2.5
7内存健康:free -h 下,工作台 + 数据库 + 代理常驻后,可用内存仍有富余,无 OOM 记录§1.5 / §4

全系列到此闭环:08 给路线 → 09 给环境与版本 → 10/11 把工作台写出来 → 12–19 把前端与四个数据库补齐 → 20 把这一切搬上一台 1GB 真实服务器、做成生产形态。7 项验收全过,你就走完了 08 总纲里"M1 + 阶段二"的全部部署环节,可以向阶段三的企业级模式进发。

09

本模块版本速览与来源

完整版本总表见 09 环境搭建与版本清单。本模块涉及的服务器侧组件版本如下,均来自全系列 versions.md(2026-10-14 核验)。

组件锁定版本来源
Debian(服务器首选)13.7 "trixie" stablehttps://www.debian.org/releases/
Ubuntu(备选)26.04.1 LTS(官方要求 1.5GB 内存起,1GB 不推荐)https://ubuntu.com/download/server
Nginx(生产锁 stable)stable 1.30.5https://nginx.org/en/download.html
Caddyv2.11.4https://github.com/caddyserver/caddy/releases
systemd随发行版—(不用 supervisor/docker)
Go(交叉编译工具链)1.27.2(1.27.x 线)https://go.dev/dl/
MySQL / PostgreSQL / Redis8.4.12 LTS / 18.6 / 8.10.2见 16/17/18 模块来源表
SQLite(纯 Go 驱动 modernc.org/sqlite)3.53.4 / modernc v1.60.1见 19 模块来源表
Docker不用于 1GB 服务器(仅本机开发)09 §3 部署心智

来源表

本模块与全系列的路线/部署心智五原则/里程碑口径来源:08 闭关总纲、07 编程主线决策报告file:///D:/02-Docs/金融知识/08-闭关总纲.html · 07-编程主线决策报告.html
工作台单 Go 二进制、CGO_ENABLED=0 交叉编译、纯 Go SQLite 驱动(glebarez/modernc)见本系列 11 工作台实战 · https://pkg.go.dev/github.com/glebarez/sqlite
Debian 13.7 trixie stable(2026-09-12 更新)https://www.debian.org/releases/
Nginx stable 1.30.5(2026-09-15)https://nginx.org/en/download.html
Caddy v2.11.4(2026-06-03)与自动 HTTPS 机制https://github.com/caddyserver/caddy/releases
systemd unit 字段(Restart/EnvironmentFile/StandardOutput/ProtectSystem 等)https://www.freedesktop.org/software/systemd/man/systemd.service.html
Let's Encrypt / certbot 自动证书与续期https://certbot.eff.org/
MySQL 8.4 / PG 18 / Redis 8 / SQLite 3.53 低配调优具体参数见本系列 16/17/18/19 模块对应小节

(编者整理:本页的目录约定、备份脚本、监控脚本、报错对照表、验收清单为基于上述官方文档与 08/11 模块契约的运维实践设计,无外部独立来源。)