ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

个人Linux服务器开荒指南:从初始化到SSH安全加固与备份

个人Linux服务器开荒指南:从初始化到SSH安全加固与备份

前阵子帮朋友搞了一台新入手的Linux服务器,从裸机状态一路配到能跑服务,整个过程让我重新体会了一把“个人向Linux服务器开荒”这件事。其实现在云服务商给的“镜像”越来越完善,很多机器拿到手就不是纯裸机,但真正需要你自己动手的,恰恰是系统镜像之外的那一层:用户、密钥、防火墙、软件源、时区、日志、备份规则……这些看似零碎的活儿,决定了这台机器以后是好用还是闹心。

我自己踩过的坑太多,所以这篇想把整套“开荒”流程整理下来,讲清楚每一步为什么要这么做,参数怎么选,遇到问题怎么救。不搞什么大而全的服务器运维手册,就聚焦到“个人向”这三个字:一台机器、一个管理员、需求明确、预算有限、没有专业运维团队兜底。适合刚买了第一台云服务器的同学,也适合给家里NAS或自己常用的VPS重装后做一次彻底整理的朋友。内容可以照着抄,逻辑也可以换成你的场景。

1. 开荒前先想清楚:这台服务器到底要干什么

1.1 个人向服务器的定位

先说“个人向”和“企业生产环境”的区别。生产服务器要求的是稳定性、高可用、有监控告警、有角色权限分离、有变更审批流程。而个人服务器通常就一个人用,跑几个自用Web服务、挂一个博客、跑点定时脚本,偶尔开个开发环境。这种情况下,方案选型的核心不再是“全”,而是“简单可靠不折腾”。

所以我会把整个开荒主线定为四步:系统初始化、远程访问加固、运行环境准备、日常运维兜底。这四步做完,一台服务器才算“能放心用”。在动手之前,最好拿一张纸写下来:这台机器未来最多跑什么服务?内存多大?磁盘够不够?需要公网访问吗?不需要的就别开端口,不开端口就少一半麻烦。

1.2 先定用途再选发行版

个人向服务器最常选的发行版就四个:Debian、Ubuntu Server、Rocky Linux/AlmaLinux、Alpine Linux。它们的区别不在“好坏”,而在“习惯”和“生态”。

发行版适合人群特点注意点
Debian追求稳定、不喜欢频繁升级保守、包稳、占用低软件版本偏老
Ubuntu Server习惯Debian系、想省心生态好、文档多、新软件上手快版本升级有周期压力
Rocky/AlmaLinux习惯Red Hat系、要兼容企业玩法和商业发行版高度兼容,SELinux默认开启对新手有额外配置门槛
Alpine Linux极度精简、容器场景体积小、内存少、musl libc部分闭源软件兼容有坑

我的建议很简单:如果你不常折腾软件包,Debian首选;如果希望常见教程拿过来就能跑,Ubuntu Server 22.04/24.04 LTS最省心;如果以后想接触企业运维场景,选Rocky,但要做好和SELinux做朋友的心理准备。

看完这些,可能有人会纠结“是不是应该从最精简的Arch入手显得比较酷”,说句实在话:个人服务器要的是稳定,不是“时刻走在最前沿”,所以别在发行版上追求炫技。

1.3 内存、磁盘与Swap的规划

个人服务器最常见的配置是1核2G或2核4G。内存2G的话,装完系统基础占用大概在400-600M,再跑一两个轻量服务还够,但编译东西或者跑容器就有点悬。我的做法是:内存小于等于2G时,一定要开Swap,大小给到物理内存的1到1.5倍;4G以上可以不开,或者只开2G作为兜底。

这里提醒一点,很多云厂商的默认镜像未必开了Swap。到手后先跑free -h看一眼,如果Swap为0,建议手动创建。用swapfile方案比独立Swap分区更灵活,不用动磁盘分区表:

# 创建2G的swap文件(block大小1M,共2048块) 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 # 调整swappiness,避免过分使用Swap sudo sysctl vm.swappiness=10 echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf

写完之后free -h再确认一次,如果有显示Swap那说明已经生效。我个人习惯把vm.swappiness调成10,内存还够的时候就别急着把数据往磁盘上倒,反正磁盘IO比内存慢得多。

2. 系统初始化的第一小时:装完系统后的固定动作

2.1 先更新再折腾

拿到一台机器,第一件事永远是系统更新,我建议把它当成“开荒启动仪式”。不要指望镜像自带的包版本够新,更不要带着旧系统直接配服务。个人服务器没有专门的变更窗口,现在不更新,等跑起来之后发现问题再更新,风险才是最大的。

Debian/Ubuntu系执行:

sudo apt update && sudo apt full-upgrade -y

注意不要只跑apt upgrade,full-upgrade会处理依赖变化需要移除老包的情况。跑完以后顺手清理一下缓存:

sudo apt autoremove -y && sudo apt autoclean

我这个习惯是大版本升级初期形成的:刚装完系统时最干净,装完软件再清理依赖会麻烦一点。基础更新做完,后面所有操作都是在“最新的系统”之上叠加,排查问题的时候至少少一类干扰。

2.2 时区、主机名与DNS

时区设不对,日志时间永远是UTC,和浏览器控制台的报错对不上,排查时麻烦得像对暗号。设置方法一句话:

sudo timedatectl set-timezone Asia/Shanghai

主机名也要顺手改掉,不然满屏都是ip-xxx-xx-xx或者默认的localhost。我用习惯的命令:

sudo hostnamectl set-hostname mybox

改完后把127.0.1.1 mybox追加到/etc/hosts里,避免某些程序解析主机名时绕了一圈访问不到本机。

DNS这一项容易被忽略。很多云厂商默认配置的DNS没问题,但也见过镜像写死内网DNS的情况,换网络环境或迁移主机后就解析失败。建议直接写成公共DNS作为兜底:

sudo tee /etc/resolv.conf > /dev/null <<EOF nameserver 223.5.5.5 nameserver 1.1.1.1 EOF

223.5.5.5是国内常用公共DNS,1.1.1.1是国外公共DNS,两个一起放能兼顾国内外解析。设完用dig或nslookup验证一下能解析任意域名就行。

2.3 创建管理员账号,别用root裸奔

很多云厂商创建机器时会让你直接设置为root登录。这时候别贪省事,迟早会后悔。我的习惯是第一时间新建一个普通用户,然后加入sudo组:

sudo adduser dev sudo usermod -aG sudo dev

注意Debian系的sudo组就叫sudo,Red Hat系叫wheel,别搞混。创建完以后,后续所有操作都切到这个用户来执行,root只用来做系统级变更。这样做的好处主要体现在后期维护:一旦误操作删了文件,普通用户和root之间至少还有一道缓冲;如果这台机器将来换了维护者,交接时交出去的是一个普通用户,而不是直接暴露root。

2.4 配置软件源加速

个人服务器如果放在本地或海外机房,下载速度往往一言难尽。Debian/Ubuntu系的主源切换成国内镜像,效果立竿见影。以Ubuntu 22.04为例,编辑/etc/apt/sources.list,把archive.ubuntu.com和security.ubuntu.com换成对应镜像域名。Debian 12类似,需要换的是deb.debian.org。

这里有一点要说清楚:不同云厂商或机房的网络环境不一样,并不存在“哪个源一定最快”,而是要根据实测来选。你可以先跑一条命令测延迟:

curl -s -o /dev/null -w '%{speed_download}\n' http://某镜像域名/ubuntu/dists/jammy/InRelease

文件小、响应快、下载速度高,就选哪个。换完之后记得sudo apt update一次确认索引能正常拉下来。这是很多新手忽略的“开荒前一分钟”操作,但实际带来的体验提升比后装任何工具都直观。

3. SSH远程安全加固:这是开荒的关键一步

3.1 默认SSH配置为什么必须改

默认情况下,SSH服务监听22端口,允许root登录,允许密码认证。这三个“默认”放在个人服务器上就是三个风险点。22端口是全网扫描器的重点照顾对象,root账号如果密码不够坚固,暴力破解大多是时间问题。即使密码密码强度还行,每天看着被扫描的日志也会心烦意乱。

我的理念是:改掉默认端口不是“安全”,但它能显著减少日志里的垃圾扫描记录,属于“减少暴露面”。真正的安全核心是——禁用密码登录,只保留密钥认证。密码可以爆破,密钥文件爆破难度是指数级上升的。所以开荒的关键动作就是这两根支柱:密钥强制、密码关闭。

3.2 生成密钥对与配置免密登录

先在本地机器上生成密钥对。Windows用户可以在PowerShell或WSL里执行,macOS和Linux直接在终端执行:

ssh-keygen -t ed25519 -a 64 -C "my-server-key"

解释一下这几个参数的意义:ed25519是目前最推荐的公钥算法,安全性高、密钥短、性能好;-a 64指定KDF轮数,增加暴力破解密钥的成本;-C是注释,方便以后知道这把钥匙是干嘛的。生成完以后,默认会在~/.ssh/下出现id_ed25519(私钥)和id_ed25519.pub(公钥)。

接下来把公钥上传到服务器。如果有ssh-copy-id,直接一条命令搞定:

ssh-copy-id -i ~/.ssh/id_ed25519.pub 用户名@服务器IP -p 原端口

没有这个命令就手动复制,把id_ed25519.pub的内容追加到服务器上/home/用户名/.ssh/authorized_keys里,目录和文件的权限也要注意:.ssh目录是700,authorized_keys文件是600。权限不对,很多人会卡在密钥认证失效的坑里:

mkdir -p ~/.ssh chmod 700 ~/.ssh touch ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys

上传完先别急着关密码登录,先在本地重开一个SSH会话,用密钥连一次,确认能进去,再进行下一步。

3.3 关闭密码登录与禁止root远程登录

确认密钥登录正常后,修改/etc/ssh/sshd_config。我建议优先使用/etc/ssh/sshd_config.d/目录下的独立配置文件,比直接改主配置更易回滚。比如建立/etc/ssh/sshd_config.d/99-hardening.conf,写入:

Port 2222 PermitRootLogin no PubkeyAuthentication yes PasswordAuthentication no PermitEmptyPasswords no KbdInteractiveAuthentication no UsePAM yes

这里最要小心的坑就是端口。如果你把SSH端口从22改成了2222,一定要先确认防火墙规则已经放开2222。改完以后:

sudo sshd -t # 检查语法 sudo systemctl reload sshd

语法检查通过后再重载服务。reload会保留现有连接,不会把你正在用的SSH挤掉。这是我反复强调的操作顺序:先检查、后重载、再测试。另一个坑是有些云厂商的安全组规则是独立于操作系统防火墙的,外部云安全策略没放行时,即使服务器内部开了端口也进不来。

整个过程别着急一口气操作完,每改一条配置就重开一个会话验证一次,避免把自己锁在外面。真要是全改完才发现当前连接已经断了,那就只能通过云控制台或带外管理界面恢复了,那边通常能连到VNC。

3.4 用ufw和fail2ban做基础防护

防火墙个人向服务器选ufw就足够了,不需要直接上手iptables。ufw是iptables的前端封装,配置简单,规则清晰。启用方法:

sudo ufw allow 2222/tcp sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw enable

顺序很关键:必须先把SSH端口放行,再执行enable。默认规则是拒绝所有入站流量、放行所有出站流量,所以一旦启用后忘放行SSH端口,当前连接马上就会断掉。启用后跑sudo ufw status numbered查看规则列表,确认无误再接新会话。

fail2ban的作用是检测反复登录失败的行为并临时封禁IP,配合SSH使用非常经典。安装:

sudo apt install fail2ban -y sudo systemctl enable --now fail2ban

需要最小化配置的话,在/etc/fail2ban/jail.local里加上:

[sshd] enabled = true port = 2222 maxretry = 5 bantime = 3600

含义是SSH尝试登录失败5次就封禁1小时,这个策略对个人服务器来说足够严格。我曾经在默认配置下忘记指定端口,导致fail2ban还盯着22端口看,而我已经改成了2222,结果完全没起到防护作用。后来学会了,改SSH端口之后第一件事情就是同步更新fail2ban的配置。

3.5 常见坑:锁死自己、端口冲突与SELinux

这一节讲的经验都是真金白银换的。锁死自己的场景是最常见的:改了端口忘记放行防火墙,运气好当前连接没断,还能抢救;运气不好连接断了,只能去云控制台用VNC把配置改回来。所以我的铁律是:任何时候修改SSH、防火墙相关配置,先开一个新的SSH会话,确认新连接能进来,再关闭旧会话。

端口冲突不太起眼,但有几次装其他软件时发现服务启动失败,最后查下来是某个程序占用了2222端口。改SSH端口前可以先看看:

sudo ss -tlnp | grep -E ':(22|2222)\b'

还有Rocky/AlmaLinux这类系统如果启用SELinux,光在firewalld放行端口还不够,还得让SELinux放行对应端口上下文:

sudo semanage port -a -t ssh_port_t -p tcp 2222

这一点很容易让人怀疑人生,因为防火墙“看着”已经放行了,但SSH就是连不上,用ausearch查审计日志才能发现是SELinux拦截。

4. 常用工具与容器环境准备

4.1 个人向必备工具清单

基础环境配置完之后,就该装一些每天都用得上的工具了。我列一个不带多余依赖的清单:

  • vim或nano:文本编辑器,至少会一种
  • curl、wget:网络请求与下载工具
  • htop:交互式进程查看,比top直观
  • ncdu:磁盘占用分析,看哪个目录吃掉了空间
  • tree:目录结构展示
  • git:版本管理,几乎所有部署场景都会用到
  • rsync:文件同步与备份
  • traceroute和mtr:网络链路排查

这些用发行版自带包管理器一键装即可,别贪多,装得越多占用越高,个人服务器保持简洁最重要。我个人习惯连screen或tmux一起装上,用于长时间跑任务时防止SSH断线导致任务中断。

顺便说一句,经常看到有人装了zsh、oh-my-zsh、各种插件,把.load整得花里胡哨。个人服务器上我更推荐先掌握bash本身,减少依赖不等于降低效率,反而会让排查问题更快。

4.2 Docker与Docker Compose安装

个人服务器跑服务,现在最高性价比的方案就是Docker。它不是“最佳实践”,但确实让部署省心太多:扔一个docker-compose.yml,一条命令起服务,迁移机器也能一键复制。

Debian/Ubuntu系的安装我建议走官方脚本或官方源,不要用发行版内置的老版本:

curl -fsSL https://get.docker.com | sh sudo usermod -aG docker dev sudo systemctl enable --now docker

这里有个细节:直接执行管道脚本前要先看清楚这个域名是不是官方来源,谨慎一点可以先把脚本下载下来,打开看一眼再跑:

curl -fsSL https://get.docker.com -o get-docker.sh less get-docker.sh sudo sh get-docker.sh

把普通用户加进docker组之后,需要重新登录一次SSH才能生效。Docker Compose现在通常作为插件安装,验证一下docker compose version能正常输出版本就行。个人服务器上,我建议所有自建服务都用compose文件来声明,而不是一条条docker run,事后看可读性至少差一个数量级。

装好以后谨慎起见再配置一下日志上限,避免某个容器刷日志把磁盘写满:

{ "log-driver": "json-file", "log-opts": { "max-size": "20m", "max-file": "3" } }

写入/etc/docker/daemon.json后重启Docker。个人服务器上没有日志采集系统,本地日志文件也尽量限制体积。

4.3 用systemd管理自己的服务

不是所有服务都适合塞进Docker。比如一些需要直接访问宿主机设备的脚本、系统级任务,用systemd管理才是正道。写一个service单元文件也很简单,以我常跑的备份任务为例:

[Unit] Description=Daily Backup Service After=network-online.target [Service] Type=oneshot User=dev ExecStart=/home/dev/bin/backup.sh [Install] WantedBy=multi-user.target

文件名放在/etc/systemd/system/backup.service,然后启用。配合一个对应的定时器,或者直接用cron调到夜里执行都可以。重点在于:systemd能统一管理日志(journalctl -u backup),可以设置重启策略,比裸写脚本扔后台可靠太多。

如果是长驻进程,Type要改成simple,并保证ExecStart的程序前台运行,不要自己fork到后台。

4.4 定时任务与日志清理

个人服务器的日志一定要管,不然半年以后你会看到磁盘莫名其妙满了。两件事:日志转储和系统更新。

logrotate一般系统自带,服务和软件也自带配置,但值得确认一下默认配置是否合理,尤其是Docker容器日志,上文已经通过Docker配置控制了。

定时任务方面,cron依旧是个人服务器最经典的方案。写任务前先确认cron服务在跑:

sudo systemctl enable --now cron

日常维护类任务我一般分成三类:每天执行的备份、每周执行的全量状态报告、每月执行的系统更新检查。在/etc/crontab里记录清楚,方便以后排查。个人服务器用cron,追求的是简单,不想额外引入一套任务编排系统。

5. 监控、备份与日常维护

5.1 看懂系统指标,提前发现问题

个人服务器没有专业监控平台,但完全可以靠几条命令快速判断状态。我建议掌握这几个指标以及它们代表的含义:

  • uptime:负载均值,三个数分别是1分钟、5分钟、15分钟平均值。别只看数字,要和CPU核数做对比。
  • free -h:内存使用、Swap使用。如果Swap持续增长,说明内存压力很大。
  • df -h:磁盘使用率,超过80%就要警惕。
  • journalctl -p err -b:当前启动以来的错误日志,是排查问题的第一入口。

举个例子:uptime显示load average: 4.00, 4.10, 4.05,如果你这台机器只有2核,说明负载已经超过CPU能力的上限,需要关注是不是有进程在死循环或者流量异常。

还有一个很有用的排查姿势,当系统变卡时先看哪个进程占资源:

sudo htop

按CPU或内存排序,通常能一眼看到异常进程。如果发现一个叫不出名字的进程在狂转,结合systemctl status和ss -tlnp查它开着哪些端口,基本就能判断出是否被入侵。

5.2 journalctl日志排查思路

遇到问题先查日志,这是运维铁律。journalctl的用法可深可浅,我个人最常用的就三条:

sudo journalctl -u 服务名 -n 100 # 查看某个服务的最新100行日志 sudo journalctl -u 服务名 --since "1 hour ago" # 查看最近一小时 sudo journalctl -p err -b # 查看本次启动以来的错误信息

说到日志有一个血的教训:我早年遇到过MySQL起不来,看服务状态发现只有一句“failed”,完全不知道原因。后来学会journalctl -u mysql -n 50去翻完整日志,才发现是磁盘空间不足导致初始化失败。日志不会骗人,先看日志再动手改配置,能让排查效率翻倍。

5.3 个人服务器的轻量备份方案

个人服务器最怕丢的不是系统,是数据。配置丢了可以重来,数据库丢了就麻烦了。我的备份方案核心是两个词:分离和自动化。

分离指的是备份文件不能只放在本机磁盘上。最简做法是rsync加异地存储,比如上传到另一个对象存储服务,或者推送到家里的NAS。自动化交给cron,每天凌晨执行。

写一个示例备份脚本,思路可以照搬:

#!/bin/bash BACKUP_DIR="/home/dev/backups" TARGET_DIR="/mnt/backup_drive" DATE=$(date +%F) mkdir -p "$BACKUP_DIR/$DATE" # 备份关键配置目录 rsync -a /etc/nginx/ "$BACKUP_DIR/$DATE/nginx/" rsync -a /home/dev/docker-data/ "$BACKUP_DIR/$DATE/docker-data/" # 打包数据库导出文件(容器内的mysqldump示例) docker exec mysql-db mysqldump -u backup --all-databases > "$BACKUP_DIR/$DATE/db.sql" # 压缩后同步到异地 tar -czf "$BACKUP_DIR/$DATE.tar.gz" -C "$BACKUP_DIR" "$DATE" rsync -av "$BACKUP_DIR/$DATE.tar.gz" user@remote-backup-host:/backup/

这个脚本关键点在于每个备份都以日期命名,并保留最近N天。个人数据量不大,留最近7天足够;关键业务数据最好异地多留一份。备份不是“配好了就行”,每月手动模拟一次恢复才叫真的备份。我至今吃过亏的都是因为还原流程从没测过,真正需要时才发现路径都不对。

5.4 日常维护清单

开荒完成不代表以后就能彻底不管,养成固定频率的巡检习惯很重要。我给自己定的频率是:

每周一次:登录服务器,跑一遍df -h、free -h、uptime,看一下journalctl里有没有新增错误,顺便更新一下安全补丁。

每月一次:检查Docker镜像版本是否落后、备份文件是否成功生成、是否有异常进程、磁盘是否有在增长。

这些都没什么门槛,但能让服务器“无感运行”的时间大大延长。

6. 开荒过程中最容易踩的坑与排查技巧

6.1 刚配好服务器就连不上,怎么救

这是典型的“开荒综合症”。可能性排序通常是:防火墙没放行SSH端口、ssh_config写错、云安全组没放行、本地SSH客户端还保留旧known_hosts缓存。

排查时不要慌,先确认机器本身还活着,可以通过云控制台的VNC或带外管理界面登录。如果带外能进去,立刻查:

sudo ufw status sudo ss -tlnp | grep sshd sudo sshd -t

绝大多数救急场景都能定位在这几步里。另外如果本地报的是“REMOTE HOST IDENTIFICATION HAS CHANGED”,说明服务器的SSH主机密钥变了,很可能重装过系统,把本地known_hosts里旧记录删除即可:

ssh-keygen -R 服务器IP

我每次“开荒新机”前都会顺手清一遍known_hosts,避免关键时刻被这个常见问题卡住。

6.2 磁盘写满导致服务异常的恢复流程

个人服务器因为日志、容器镜像、备份文件堆积导致磁盘满的情况太常见了。先找哪个目录占用大:

sudo ncdu /

如果系统已经处于异常状态,按顺序做这几件事:先ls -lh查看明显大文件;用du -sh *一级一级排查;检查/var/log是否有超大日志;检查Docker占用docker system df。清理完之后确认Docker日志是否被限制,参考前文配置。

如果是Docker日志把所有空间吃满,这种经典灾难只要加上了日志上限配置就不会再出现。临时救急时可以用:

sudo truncate -s 0 /var/lib/docker/containers/容器ID/容器ID-json.log

truncate清空日志文件,不要直接rm删除,因为容器还持有文件描述符,删掉后空间不会释放。

6.3 SSH端口修改后导致PAM或AppArmor/SELinux报错

改SSH端口遇到服务起不来的情况,通常不是SSH本身的问题,而是用了非默认端口条件触发SELinux或者AppArmor的限制。Rocky/AlmaLinux处理SELinux的命令前面写过了。Debian/Ubuntu的AppArmor一般默认只约束特定程序,影响不大,但如果改到一个奇怪的端口,还是值得留意审计日志:

sudo journalctl -u sshd -n 50 sudo ausearch -m avc -ts recent

如果确认和SELinux相关,那句话很重要:不要图省事把SELinux设置成permissive,更不要disabled。个人服务器没那么容易碰到复杂策略,真正需要放行一个端口时,把对应的布尔值和端口上下文放行即可。

6.4 一些个人经验总结

开荒这件事做多了以后,我最大的体会是:每一步操作都要有“可撤销”的备案。改配置前先备份原文件,跑命令前先想清楚会导致什么结果,关旧连接前一定开新连接验证。一次顺畅的开荒,未必是技术多炫,而是没有把自己锁在门外面,没有把数据清理到找不到的地方。

另外再说一个小技巧:把整个开荒过程做成一个记录文件,不用写多华丽,把每一步配置、每一条改动、每一个坑记下来。几个月后就算这台机器已经不是“裸机”了,你依然能知道当初为什么这样设置。这种记事习惯,比任何运维平台都可靠。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进