我的运维笔记

《服务器运维》课程 · Rocky Linux 9 · 阿里云 ECS 实践记录

第 1 讲服务器安全加固

这一讲我做了什么:把一台刚开通、还在"裸奔"的阿里云 ECS(Rocky Linux 9.8)加固成只认密钥、防火墙最小化放行、能自动封禁爆破的机器。

我记下的要点

关键命令

# 查看 SSH 登录失败记录(-i 忽略大小写,tail -30 只看最后 30 条)
sudo journalctl -u sshd | grep -i "failed" | tail -30

# 新建普通用户并加入 wheel 组(wheel 组成员才能用 sudo)
sudo adduser study
sudo passwd study
sudo usermod -aG wheel study

# 在自己电脑上生成 ed25519 密钥对
ssh-keygen -t ed25519 -C "我的名字-服务器加固"

# 安装公钥(权限一步都不能省,否则 SSH 静默拒绝)
mkdir -p ~/.ssh && chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

# 收口:加固 sshd(先 sshd -t 验证语法,再 reload 生效)
sudo vi /etc/ssh/sshd_config   # PasswordAuthentication no / PermitRootLogin no / AllowUsers study teacher
sudo sshd -t
sudo systemctl reload sshd

# 主机防火墙:--permanent 必须加,否则重启后失效
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

# 查看服务器实际监听的端口,与安全组对照
sudo ss -tlnp

# fail2ban 自动封禁爆破:10 分钟内失败 3 次封 1 小时
sudo dnf install -y epel-release fail2ban
sudo vi /etc/fail2ban/jail.d/sshd.local   # backend = systemd 是 Rocky 9 的关键写法
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd          # 看 Banned IP list

遇到的问题和解决办法

问题原因与解决
配好公钥后登录仍要密码99% 是权限问题:检查 .ssh 是否 700、authorized_keys 是否 600、属主是否本人而不是 root。
teacher 账号用不了 sudoteacher 没有密码,而 wheel 组 sudo 必须输本人密码,单独写了免密规则 /etc/sudoers.d/teacher,并用 visudo -c 验证语法。
firewalld 改了不生效忘了加 --permanent 或忘了 --reload。
担心把自己锁在门外走控制台 VNC(不走 sshd、不受安全组影响)改回配置,先 sshd -t 再 reload。
这一讲养成的三个习惯:私钥永不外传、改配置先留后路(VNC)、先验证再收口。

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

这一讲我做了什么:为已备案的域名添加 A 记录解析到服务器,开放 80 端口,安装 Nginx 并发布一个带备案号的个人主页。

我记下的要点

关键命令

# 验证解析是否生效:看 Address 是否为自己的服务器公网 IP
nslookup 我的域名

# 两层门都放行 HTTP(80 端口)
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload
sudo firewall-cmd --list-services   # 应包含 ssh 和 http

# 安装并启动 Nginx
sudo dnf install -y nginx
sudo systemctl enable --now nginx

# 准备网站目录(交给 study 用户,755 让 Nginx 能进入)
sudo mkdir -p /var/www/mysite
sudo chown -R study:study /var/www/mysite
sudo chmod 755 /var/www/mysite

# 站点配置:server_name 写对域名,reload 前先 nginx -t
sudo vi /etc/nginx/conf.d/mysite.conf
sudo nginx -t
sudo systemctl reload nginx

# 用 scp 上传主页(走 SSH 密钥,不用密码)
scp index.html study@服务器公网IP:/var/www/mysite/

# 验证 server_name 机制:手动指定 Host 访问本机
curl -H "Host: 我的域名" http://127.0.0.1

# 观察访问日志:同学每刷新一次就多一行记录
sudo tail -f /var/log/nginx/mysite_access.log

排障实验:亲手制造并修复一次 403

chmod 600 /var/www/mysite/test.html                      # 故意把权限改成 600
curl -I -H "Host: 我的域名" http://127.0.0.1/test.html   # 结果 403 Forbidden
ps -o user= -C nginx | sort -u                          # 发现工作进程是以 nginx 用户运行的
sudo tail -3 /var/log/nginx/mysite_error.log            # 日志:Permission denied
chmod 644 /var/www/mysite/test.html                      # 放宽权限后恢复 200 OK

原因:读网页的不是 study,而是以 nginx 用户身份运行的工作进程;600 权限不允许"其他人"读取,所以 403。

遇到的问题和解决办法

现象排查方法
域名打不开,IP 能打开解析未生效或记录填错,nslookup 查看、等 TTL 过后再试。
连接超时80 端口没开,检查安全组入方向规则和 firewall-cmd --list-services。
403 Forbidden文件或目录权限不足,文件 644、目录 755。
404 Not Found文件名必须叫 index.html,核对 root 路径。
用域名访问仍是默认页server_name 写错或漏写,改好后 nginx -t 再 reload。

第 3 讲HTTPS 与证书自动续期

这一讲我做了什么:先抓包亲眼看到 HTTP 明文传输的风险,然后用 certbot 为域名申请 Let's Encrypt 免费证书,改写 Nginx 配置启用 HTTPS,并配置到期自动续期。

我记下的要点

关键命令

# 抓包对比:HTTP 80 端口能看到 GET 请求、Host、User-Agent、网页标题
sudo tcpdump -i any -A -nn 'tcp port 80' | grep -a -E "GET |Host:|User-Agent|<title>"

# 开门:两层都放行 HTTPS(443),80 保留
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

# 安装 certbot,先用 --dry-run 演练(不占正式申请的失败次数)
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 --dry-run
sudo certbot certonly --webroot -w /var/www/mysite \   # 演练成功后去掉 --dry-run 正式申请
  -d example.com -d www.example.com \
  -m 我的邮箱 --agree-tos --no-eff-email

# 查看证书信息(到期时间、包含的域名)
sudo certbot certificates
sudo openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -issuer -dates -ext subjectAltName

# 改写 Nginx:80 只做验证文件 + 301 跳转,443 用证书提供内容(改前先备份 .bak,注意备份名不能以 .conf 结尾)
sudo cp /etc/nginx/conf.d/mysite.conf /etc/nginx/conf.d/mysite.conf.bak
sudo nginx -t && sudo systemctl reload nginx

# 验证:http 应返回 301,https 应返回 200(Windows PowerShell 里要写 curl.exe)
curl.exe -I http://example.com
curl.exe -I https://example.com

# 自动续期:启用定时器 + 续期成功后自动重载 Nginx 的 deploy 钩子
sudo systemctl enable --now certbot-renew.timer
systemctl list-timers 'certbot*'
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   # 演练一次续期,确认流程是通的

遇到的问题和解决办法

现象排查方法
certbot 报 DNS problem: NXDOMAIN域名或 www 子域名缺解析记录,先 nslookup 检查、补 A 记录。
certbot 报 unauthorized / 404验证文件没被访问到:核对 -w 是否与 Nginx 的 root 一致、server_name 是否包含该域名、80 是否开放。
too many failed authorizations一小时内失败次数过多被限流,等待一小时,先 --dry-run 演练成功再正式申请。
nginx -t 报 cannot load certificate证书路径里域名写错,对照 certbot certificates 的目录名修改。
浏览器锁图标带警告页面里引用了 http:// 开头的资源,改成 https:// 或相对路径。
到这里作品一完成:一个有域名、有备案号、带 HTTPS 安全锁的个人主页。关键心法:先演练(--dry-run)再正式,靠自动化(定时器+钩子)而不是靠人记续期。