记一次个人服务器迁移
个人使用了三年的腾讯云轻量应用服务器最近快到期了,所以来了一次数据迁移。
问题背景
用了三年的腾讯云轻量应用服务器,最近快到期了。续费要500多一年,新购一台相同配置的99元一年。这个定价很有技术含量😭。续不续费让人有些犹豫。续吧,感觉太坑,我好歹也是搞技术的;不续吧,因为是个人拿来瞎折腾用的服务器,所以上面各种数据和服务有点乱,迁到新的服务器要花些时间。但转念一想,反正都是个人的东西,再怎么折腾也不会有任何风险。好处倒有一些:一是梳理一下自己常用的后端软件,二是来个数据大扫除方便下次迁移,三是小小地挑战一下自己解决问题的能力。
梳理常用软件
迁移前先我梳理了一下旧服务器上装过的那些软件,剔除掉不怎么使用的,剩下的就是我个人的必备工具了。
- 服务器
- Nginx
- PostgREST
- 数据库
- PostgreSQL
- Redis
- 容器
- Docker
- Docker Compose
- 开发工具
- nvm + Node.js
- Pyenv + Python
- Git
- 管理工具
- Screen
- Rsync
- Certbot
- 其他工具
- Gogs
- Cloudreve
以上都是一些常见软件。有几个相对没那么知名的,这里简要介绍一下:
- PostgREST - 将 PostgreSQL 数据库直接映射成 RESTful API 的 Web 服务器。作为一个多年的移动端开发,借助这个 PostgREST 也我能轻松搞定后端服务了
- nvm - nvm 用于多版本的 Node.js 管理。(nvm is a version manager for Node.js)
- Gogs - Gogs 用于搭建私有的轻量 Git 服务。 A painless self-hosted Git service.
- Cloudreve - Cloudreve 用于搭建私有网盘。我老婆需要一个可以多端同步的笔记工具,还想自己永久保留数据。我们试用了一圈发现 Joplin 还不错,所以我搭了一个 Cloudreve 云盘作为 WebDAV 来存 Joplin 数据。
安装常用软件
CentOS 上安装软件很方便,大部分时候只是无脑执行 yum install
即可。安装过程中经常要我们确认 ,所以用这样输入命令会方便很多:
1 | yes | yum install <name> |
有部分软件是用 curl
加脚本方式安装的。有些参数我们可能不熟,不过有 AI + 搜索引擎,所以这些参数通常不是什么问题。这里有一份 curl 常用参数总结 | aimuke,供遇到问题时查询。
curl -o
--o
用于指定文件名。有时我们会看到-o-
这种写法,它表示自动生成一个临时文件名<curl 命令> | bash
-| bash
表示将前一个命令的输出作为 bash 的输入curl -fsSL
-f
- (HTTP)连接失败时(400以上错误)不返回默认错误页面,而是返回一个curl错误码“22”;-s
- Silent mode-S
- 输出错误信息-L
- 支持重定向
少量软件安装步骤稍繁琐,比如 Docker。
1 | yum install -y yum-utils //扩展yum功能 |
注意:移除上图 version 前导的 “3:” 得到的字符串才是 yum 命令中的 [VERSION]
yum -y install docker-ce-[VERSION]
有些软件如 Docker 或 Redis 安装完成后记得要用 systemctl
或 service
命令启动:
1 | systemctl restart nginx.service |
梳理待迁移数据
接下来是梳理待迁移的数据以及配置。
- 服务器
- Nginx 配置
- PostgREST 配置
Certbot
- 数据库
- PostgreSQL 数据
Redis
- 容器
Docker- Docker Compose 配置
开发工具Node.jsnvmPyenvPythonGit
管理工具screenrsync
- 其他工具
- Gogs 数据和配置
- Cloudreve 配置
- 个人项目
- 博客
- 博客评论系统
- 博客内容数据
- Anki Server
- 其他静态网站数据
- 博客
以上待迁移内容可以分个类:
- 无需迁移:像 Certbot, Redis, Docker 等应用或工具本身的二进制内容,我会在新机器上重新安装,所以无需迁移
- 需要迁移
- 迁移成本极低。静态网站数据,只需要将数据同步到新机器指定位置即可
- 迁移成本低。PostgreSQL 和 Gogs 部署在 Docker 中,所以我简单拷贝它们各自的 “Docker Compose 配置”、
./data
和./conf
目录到新机器,重新执行docker-compose up -d
,几分钟就恢复了服务。(当然,这里没有算上解决镜像无法下载、镜像版本不对、恢复 Nginx 反向代理配置耗费的时间) - 迁移成本高。剩下的这些,迁移成本相对高一些。要么是它们本身不支持 Docker 部署,要么是我以前偷懒没有走 Docker 部署。毕竟,如果部署环境永远不会变、数据和服务不会发生迁移的话,直接部署有时也很简单。
梳理及迁移过程中发现有几个明显问题或风险:
- Docker 相关问题
- 无法下载 Docker 镜像
- 之前未指定 Docker 镜像版本
- Nginx 配置问题。
- 第一个问题是我用 Nginx 反向代理了接近10个不同服务或静态站点,但全部配置都直接放在
/etc/nginx/nginx.conf
里面 - 第二个问题是没有使用 Docker 部署 Nginx,无法快速地迁移反向代理配置以及静态站点数据
- 第一个问题是我用 Nginx 反向代理了接近10个不同服务或静态站点,但全部配置都直接放在
- 开发工具版本一致性问题
- Anki Server 是 Python 编写的,要求 Python 3.10 以上。而新的服务器上默认安装的 Python 3.8,版本过低
- 博客评论系统 waline 是 Node.js 编写的,在 Node.js 18 上运行良好。新的服务器上已有的 Node.js 版本过高,运行 waline 可能有问题
开始迁移数据
Docker 问题处理
无法下载 Docker 镜像
无法下载 Docker 镜像是个常见问题。这个问题的错误信息类似于:
1 | Error Get "https://registry-1.docker.io/v2/" |
解决办法是使用国内镜像:
1 | # 创建目录 |
具体的操作步骤以及可用的镜像源,目前国内可用Docker镜像源汇总(截至2025年2月) - CoderJia一文中总结得很清晰,这里不赘述。
未指定 Docker 镜像版本号
Docker Compose 的配置文件中应当指定 Docker 镜像具体版本号,我们很容易忽略这一点。
不指定版本时,默认使用的是 latest 版本。容易理解,当前的 latest 版本肯定跟两年前的 latest 版本不同。一般来说,用当前的 latest 是没什么问题的。但是我保留着两年前的数据呢。
我在新的服务器上装好 PostgreSQL 数据库之后,不能正常访问。使用 docker-compose ps
查看发现 PostgreSQL 没有正常启动,一直在重启。
docker-compose logs
看错误日志发现以下提示:
1 | The data directory was initialized by PostgreSQL version 14, which is not compatible with this version 17.4 (Debian 17.4-1.pgdg120+2). |
这条日志简直能救命。先在配置文件中加上版本号,
1 | version: "3.1" |
再重新启动容器,可以正常访问了。搞定!
使用 Docker 启动 Gogs 时也有类似问题,但我并没有找到明确的错误日志。不过好在先遇到 PostgreSQL 版本不兼容问题,所以我马上想到 Gogs 的 Docker Compose 配置文件中也要指定版本号,否则很可能我要花费不少时间排查错误。
提示:使用 docker image inspect <IMAGE ID>
可以找到 latest 版本的具体信息。
Nginx 反向代理配置拆分
直接修改 /etc/nginx/nginx.conf
这个默认配置文件不是一个好的实践。如下的方式更可取。
先在 /etc/nginx/nginx.conf
中引入 sites-enabled
目录下的所有配置文件。
1 | ... |
再在 /etc/nginx/sites-available
目录中编辑具体的配置文件,每个配置文件对应一个站点或服务。
然后根据需要建立从 sites-enabled 目录到 sites-available 的软链接。
1 | ln -s /etc/nginx/sites-available/a.site.conf /etc/nginx/sites-enabled/ |
最后,运行 service nginx reload
重新加载配置。
将配置拆分到不同的文件有很多好处,
- 删除 sites-enabled 目录中某个软链接就能很方便地下线该站点或服务,不影响其他配置
- 使用 Certbot 开启 HTTPS 访问时,Certbot 只自动修改对应的配置文件,而不是
/etc/nginx/nginx.conf
- 备份配置和恢复配置很方便
Pyenv 安装和管理 Python
我有一些使用 Pyenv 管理和使用多版本 Python 的经验,见之前的浅谈编程环境管理 | 皮皮小黑屋
1 | flowchart LR |
Anki Server 依赖 Python 3.10,所以需要用 Pyenv 安装 Python 3.10。一顿轻车熟路地操作下来,我傻眼了,Python 报错并提示 No module named '_sqlite3'
。
原来我忘记 Pyenv 编译安装 Python 前,要确保已安装必要的依赖项。
1 | flowchart LR |
yum install sqlite-devel
后重新在 pyenv 中安装 Python 3.10,问题解决。
一些小技巧
第一个是关于 tar 和 scp 的小技巧。
1 | # 打包成一个文件来传输 |
- 使用 tar 命令将目录打包成一个文件来传输
- 一定要走内网IP,否则文件传输速度太慢
第二个是关于 ssh 的小技巧。迁移数据过程中经常要 ssh 远程登录两台不同的机器,所以可以编辑 ~/.ssh/config
给远程机器取个简单的名字,
1 | ~/.ssh/config |
配置好之后可以使用 ssh user@s1
和 ssh user@s2
来登录远程机器,方便很多。
数据备份与恢复
Docker
一开始我没太注意到 Docker Compose 的配置和数据这样存放会有什么好处。
1 | . |
经过这次迁移,我发现如果把所有容器的配置和数据放在同一个目录下,备份和迁移起来是最方便的。
如果一开始我也使用 Docker Compose 来管理 Nginx,那么对应的配置和数据迁移起来会快很多。
备份点、快照与自定义镜像
数据迁移不是我一个人会遇到的问题。事实上,腾讯云也提供一些工具来支持数据迁移。我了解到的有三个功能:
- 备份点。备份点可以为云硬盘保留某一时刻的历史数据。当前仅支持为数据盘创建备份点
- 快照。快照可用于服务器系统盘数据备份。可以回滚到当前服务器的某个快照。不支持跨机器回滚
- 自定义镜像。自定义镜像相当于自己的安装盘。
1 | mindmap |
看起来使用自定义镜像最符合我的应用场景。明年很可能还会再迁移一次数据,到时候或许会试试。
总结
经过好几个小时的工作,数据终于迁移完成。我的博客又能访问和评论了,不过其实已经换了一台机器。
简单回顾一下:
- 梳理了自己常用的后端软件
- 处理了几个使用 Docker 过程遇到的问题
- 一是镜像无法下载
- 二是未指定镜像版本号
- 拆分 Nginx 配置方便管理和迁移
- 一些小技巧,例如使用内网IP传输数据