服务器运维 · 课程笔记

我的运维笔记

基于《服务器安全加固》《网站上线》《HTTPS 与证书自动续期》三讲整理,记录关键命令、操作顺序与排障思路。

第 1 讲

服务器安全加固

把一台“裸奔”的服务器加固成只认密钥、守得住、还会自动反击的服务器。

一、看见威胁:服务器一直在被扫描

服务器接入公网的那一刻起,自动化扫描程序就会昼夜遍历 IP。发现 22 端口(SSH 默认端口)后,会用大量常见用户名和密码反复尝试,这就是暴力破解。

sudo journalctl -u sshd | grep -i "failed" | tail -30

多半会看到大量陌生 IP 的失败记录,且绝大多数在尝试 root。加固思路就是沿着“攻击者会从哪里进来”,一处处把门堵死。

二、两条登录通道:SSH 与 VNC

真正能救命的后路是 VNC。 后路只有亲自走通一次才靠得住。任何有风险的修改之前,先用 VNC 登录验证一遍。

whoami
tty

VNC 使用提示:粘贴支持较差,长命令手动输入或使用控制台“复制命令输入”;忘记系统密码可在控制台重置实例密码,重启生效;禁用 SSH 密码登录和 root 远程登录只作用于 SSH,不影响 VNC 用系统密码登录。

三、用密钥代替密码登录

密码可能被猜中、也可能泄露。密钥认证使用一对相互配对的钥匙:

登录时服务器用公钥出一道只有对应私钥才能解开的“数学难题”。持有私钥的人能解开并登录;攻击者即使拿到公钥也无从下手。

1. 在自己电脑上生成密钥对

ssh-keygen -t ed25519 -C "你的名字-服务器加固"

查看公钥。Windows(PowerShell):

type $env:USERPROFILE\.ssh\id_ed25519.pub

Mac / Linux:

cat ~/.ssh/id_ed25519.pub

复制以 ssh-ed25519 AAAA... 开头的一整行,中间不能有换行。不带 .pub 的是私钥,切勿外传。

2. 把公钥安装到服务器

sudo su - study
mkdir -p ~/.ssh
chmod 700 ~/.ssh
vi ~/.ssh/authorized_keys

在 vi 中按 i 粘贴公钥(一整行),按 Esc,输入 :wq 回车保存。随后设置权限并核对:

chmod 600 ~/.ssh/authorized_keys
ls -l ~/.ssh

权限陷阱:.ssh 目录必须是 700,authorized_keys 必须是 600,属主必须是本人。权限过松时 SSH 会直接拒绝使用它登录,而且不给出任何报错。

3. 铁律:先验证密钥能登录,再禁用密码

ssh study@服务器公网IP

能直接登入且不要求输入密码,说明密钥配置成功。失败则回控制台检查公钥、权限、用户名。验证成功之前,绝对不要进行下一步。

4. 为老师配置巡检账号 teacher

绝对不要把私钥发给老师。 正确做法是:老师持有自己的密钥对,你只把老师的公钥安装到服务器上。

sudo adduser teacher
sudo mkdir -p /home/teacher/.ssh
sudo vi /home/teacher/.ssh/authorized_keys

贴入老师的公钥(一整行),保存退出,然后:

sudo chmod 700 /home/teacher/.ssh
sudo chmod 600 /home/teacher/.ssh/authorized_keys
sudo chown -R teacher:teacher /home/teacher/.ssh
echo "teacher ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/teacher
sudo chmod 440 /etc/sudoers.d/teacher
sudo visudo -c
sudo -u teacher sudo -n true && echo "teacher 免密 sudo 可用"

teacher 没有密码,而 Rocky 规定 wheel 组成员使用 sudo 必须输入本人密码,所以单独写免密规则。visudo -c 必须执行:sudo 配置写错,所有账号的 sudo 都会失效,包括 study。万一如此,用 VNC 以 root 登录修复。

四、加固 sshd 配置

sudo vi /etc/ssh/sshd_config
PubkeyAuthentication yes
PasswordAuthentication no
PermitRootLogin no
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers study teacher
sudo sshd -t
sudo systemctl reload sshd

sshd -t 没有输出就代表语法正确;reload 不会断开当前连接,比 restart 安全。

五、两道门:安全组与主机防火墙

两层相互独立、都需要配置,原则都是最小化:只开必须的门。

sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

Rocky 上最容易被忽略的细节:修改规则时必须加 --permanent,再执行 --reload,否则规则在重启后会失效。

安全组入方向规则:必须保留 SSH(TCP 22),删掉它本机 SSH 和 Workbench 会同时中断,只剩 VNC 能进;删除或收紧用不到的端口;ICMP-IPv4 可以保留,用于 ping 和连通性诊断。

安全组按“协议 + 端口”两个维度控制。TCP / UDP 才有端口概念;ICMP 是网络层诊断协议,本身不使用端口,控制台端口栏只能填 -1/-1 或显示“任何”,这只是占位符,不代表所有端口都被打开。放行 ICMP 只是让别人能 ping 通你的机器,既无法登录,也无法传输数据。

查看实际监听的端口,与安全组规则对照:

sudo ss -tlnp

六、fail2ban:让服务器自动反击

前面的加固是“被动”防守。fail2ban 持续盯着登录日志,发现某个 IP 反复失败尝试登录,就自动把它封禁一段时间。

sudo dnf install -y epel-release
sudo dnf install -y fail2ban

规范做法是在 jail.d/ 下新建 .local 文件,而不是直接修改主配置文件 jail.conf,这样软件升级时配置不会被覆盖。

sudo vi /etc/fail2ban/jail.d/sshd.local
[sshd]
enabled = true
backend = systemd
maxretry = 3
findtime = 600
bantime = 3600

连起来读就是一句话:10 分钟内失败 3 次,就把这个 IP 封禁一小时。

backend = systemd 是 Rocky 9 的关键:新系统日志由 systemd 统一管理,网上许多旧教程仍在读取 /var/log/secure,那种写法在这里不生效。

sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

重点看 Banned IP list,列出的就是被服务器自动封禁的攻击者 IP。名单暂时为空不代表操作有误,只是还没被扫描器盯上;规则已生效,挂一段时间自然会出现记录。

七、验证与提交

提交方式:只需要交给老师主机的公网 IP。老师会用自己的私钥,通过你安装好的 teacher 公钥登录检查。任何时候都不要把自己的私钥发给任何人。

八、遇到问题怎么办

第 2 讲

网站上线:域名解析与 Nginx 个人主页

为已备案域名配置解析,安装 Nginx,发布带备案号的个人主页。

一、从 IP 到域名:三个环节

DNS(域名系统)负责把域名翻译成 IP 地址。要让别人通过域名看到你的主页,需要打通三个环节:

  1. DNS:让域名指向你的服务器 IP。
  2. 开门:让安全组和防火墙放行网页访问(80 端口)。
  3. Nginx:在服务器上运行一个程序,接收请求并把主页发出去。

添加解析记录时会遇到三个字段:记录类型(A 记录,指向 IPv4 地址)、主机记录(@ 代表域名本身,www 代表 www.域名)、TTL(缓存时长)。

nslookup 你的域名
nslookup www.你的域名

二、为网站开门

服务器要对外提供网页,需要开放 HTTP 使用的 80 端口。两层门都要开。

阿里云安全组:添加规则,协议 TCP,端口 80,授权对象 0.0.0.0/0。

主机防火墙:

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload
sudo firewall-cmd --list-services

三、安装 Nginx 并配置站点

sudo dnf install -y nginx
sudo systemctl enable --now nginx

为自己的站点单独建目录:

sudo mkdir -p /var/www/mysite
sudo chown -R study:study /var/www/mysite
sudo chmod 755 /var/www/mysite

编写站点配置 /etc/nginx/conf.d/mysite.conf:

server {
    listen 80;
    server_name example.com www.example.com;
    root /var/www/mysite;
    index index.html;
    access_log /var/log/nginx/mysite_access.log;
    error_log  /var/log/nginx/mysite_error.log;

    location / {
        try_files $uri $uri/ =404;
    }
}
sudo nginx -t
sudo systemctl reload nginx

四、排障实验:403 Forbidden 与权限

如果 Nginx 工作进程无法读取文件,会返回 403。排查思路:先看错误日志找原因,再用 ls -l 核对权限。

sudo tail -3 /var/log/nginx/mysite_error.log

网页文件至少需要 644,目录至少需要 755,Nginx 才能正常读取。

chmod 644 /var/www/mysite/index.html
第 3 讲

给网站加上安全锁:HTTPS 与证书自动续期

申请免费 HTTPS 证书,让网站从“不安全”变为带安全锁的加密网站,并配置自动续期。

一、HTTPS 与证书的原理

HTTPS 解决两个问题:加密(传输内容变成密文)和身份认证(证明服务器真实身份)。认证依靠数字证书。

本章使用 Let's Encrypt,通过 HTTP-01 验证。三个前提:域名正确解析、80 端口对外开放、Nginx 能把验证文件发出去。

二、开放 443 端口

按照最小化原则,开放 HTTPS 使用的 443 端口。注意:80 端口不能关,跳转和续期都要用到。

sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

三、申请证书

安装 certbot 并使用 webroot 方式申请证书:

sudo dnf install -y certbot
sudo certbot certonly --webroot -w /var/www/mysite \
  -d example.com -d www.example.com \
  -m 你的邮箱 --agree-tos --no-eff-email

四、配置 Nginx 启用 HTTPS

将站点配置分为 80 端口(做跳转和 ACME 验证)和 443 端口(提供内容):

server {
    listen 80;
    server_name example.com www.example.com;

    location /.well-known/acme-challenge/ {
        root /var/www/mysite;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name example.com www.example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;

    root /var/www/mysite;
    index index.html;
    access_log /var/log/nginx/mysite_access.log;
    error_log  /var/log/nginx/mysite_error.log;

    location / {
        try_files $uri $uri/ =404;
    }
}
sudo nginx -t
sudo systemctl reload nginx

五、配置自动续期

sudo systemctl enable --now certbot-renew.timer
systemctl list-timers 'certbot*'

配置 deploy 钩子,让续期后自动重载 Nginx:

sudo vi /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

写入:

#!/bin/bash
systemctl reload nginx
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
sudo certbot renew --dry-run