上个月我把开发环境整体搬到了 Linux。不是虚拟机,不是 WSL,是一台真实的云服务器。整个过程比预想的顺利,但踩的坑也确实不少。

为什么要迁

因为我写的服务端代码最终要跑在 Linux 上。在 Windows 上编译通过、跑起来正常,部署上去出问题,这种来回折腾的成本太高了。

与其在两个环境之间反复横跳,不如直接把开发环境搬过去。

坑一:源文件编码

这是最浪费时间的一个。代码在 Windows 上编译得好好的,换到 Linux 用 g++ 编,报了一堆语法错误,位置全在中文注释附近。

原因是源文件带了 BOM。Windows 上的编辑器习惯性加了这个东西,MSVC 能容忍,g++ 不行。

# 找出所有带 BOM 的文件
grep -rlI $'xEFxBBxBF' .

解决办法是统一转成 UTF-8 无 BOM。另外要注意,Windows 上的中文注释在 GBK 编码下存盘的话,转到 Linux 会全是乱码,而且不会有任何报错——只是注释变得不可读。

坑二:换行符

CRLF 和 LF 的问题老生常谈,但真正麻烦的不是代码,是脚本。一个带 CRLF 的 shell 脚本执行时会报 /bin/bash^M: bad interpreter,报错信息里那个 ^M 就是回车符。

根治办法是在 git 里配好:

git config --global core.autocrlf input

坑三:文件名大小写

Windows 的文件系统不区分大小写,Linux 区分。Images/Logo.png 和 images/logo.png 在 Windows 上是同一个文件,在 Linux 上是两个。

这个问题最阴险的地方在于:本地测试全过,部署上去图片全裂。因为 HTML 里写的是 Images/logo.png,而实际文件叫 images/logo.png。

我现在养成习惯:所有资源路径一律小写,文件名里不用空格。

坑四:动态库版本

本地编译链接的库版本和服务器上的不一致,表现是启动时报 error while loading shared libraries。

用 ldd 可以看清楚一个可执行文件到底依赖了哪些库:

ldd ./BlogServer

如果某个库显示 not found,就是缺了。最好的做法是在目标机器上编译,而不是本地编好再传上去。跨发行版传二进制文件,迟早出事。

坑五:权限

用 root 跑服务是能跑,但不该这么干。一旦服务被攻破,攻击者直接拿到 root。

正确做法是建一个普通用户,只给它访问必要目录的权限,然后用 systemd 指定运行用户:

[Service]
User=www-data
Group=www-data
WorkingDirectory=/opt/blog

迁移之后

现在我的工作流是:本地写代码,同步到服务器,在服务器上编译和运行。听起来绕,但实际体验比想象中好——因为两边环境完全一致,本地能跑就等于线上能跑。

唯一的不便是没有图形界面。不过写服务端代码本来也用不上。


记录技术、生活与思考。