第 1 讲服务器安全加固
这一讲我做了什么:把一台刚开通、还在"裸奔"的阿里云 ECS(Rocky Linux 9.8)加固成只认密钥、防火墙最小化放行、能自动封禁爆破的机器。
我记下的要点
- 公网上的服务器时刻被扫描,用
journalctl一查就能看到大量登录失败的爆破记录,绝大多数在试 root。 - 登录服务器有两条通道:SSH(含 Workbench,走安全组 22 端口和 sshd)和 VNC(走带外管理,不经过安全组和 sshd)。真正能救命的后路是 VNC,动手前我先登录走通了一次。
- 密钥认证:私钥留自己电脑、公钥放服务器
~/.ssh/authorized_keys。权限必须是.ssh为 700、authorized_keys为 600,权限过松 SSH 会静默拒绝。 - 铁律:先验证密钥能登录,再禁用密码登录——顺序反了会把自己锁在门外。
- 给老师配巡检账号的正确思路是装"老师的公钥",而不是把自己的私钥发出去。私钥永不外传。
- 云服务器有两层门:安全组(平台层)+ firewalld(主机层),都要按最小化原则配置。
- 安全组里 ICMP 规则端口显示 "-1/任何" 是因为 ICMP 协议本身没有端口的概念,不代表全端口开放,保留它可以方便 ping 诊断。
关键命令
# 查看 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 账号用不了 sudo | teacher 没有密码,而 wheel 组 sudo 必须输本人密码,单独写了免密规则 /etc/sudoers.d/teacher,并用 visudo -c 验证语法。 |
| firewalld 改了不生效 | 忘了加 --permanent 或忘了 --reload。 |
| 担心把自己锁在门外 | 走控制台 VNC(不走 sshd、不受安全组影响)改回配置,先 sshd -t 再 reload。 |
这一讲养成的三个习惯:私钥永不外传、改配置先留后路(VNC)、先验证再收口。
第 2 讲网站上线:域名解析与 Nginx 个人主页
这一讲我做了什么:为已备案的域名添加 A 记录解析到服务器,开放 80 端口,安装 Nginx 并发布一个带备案号的个人主页。
我记下的要点
- DNS 是互联网的"通讯录":浏览器先查域名对应的 IP,再去连接服务器。让网站上线要打通三环节:DNS 解析 → 开门放行 80 → Nginx 发布页面。
- 解析记录用 A 记录(指向 IPv4 地址),主机记录
@代表域名本身、www代表 www 子域名;解析需要时间生效,所以第一步就先做解析,等待期间做后面的事。 - "最小化"不是什么都不开,而是服务上线时才开对应的门:本章只开 80,443 留到下一讲。
- Nginx 靠请求头里的
Host字段和各站点的server_name匹配来区分同一台机器上的多个网站——所以用 IP 访问看到的是默认页。 - 排查 403 的套路:先看错误日志,再用
ls -l核对权限;网页文件至少 644、目录至少 755。 - 首页底部必须显示 ICP 备案号并链接到工信部备案查询网站,这是合规硬性要求。
关键命令
# 验证解析是否生效:看 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 全程明文,中间任何网络设备都能看到访问的页面和提交的内容。HTTPS = HTTP + TLS,解决两件事:加密和身份认证(靠 CA 签发的数字证书)。
- Let's Encrypt 用 HTTP-01 验证确认域名归属:要求把一个随机验证文件放到
/.well-known/acme-challenge/,它从公网能读到就签发。所以申请前提是:解析正确、80 端口开放、Nginx 配置正确。 - 证书只有 90 天有效期且不再发提醒邮件,自动续期是必做项而不是可选项。
- 80 端口不能关:一是要把 http 请求跳转到 https,二是证书续期仍要走 80 验证。
privkey.pem(证书私钥)和 SSH 私钥是同一个道理:谁拿到谁就能冒充我的网站,绝不外泄。- HTTPS 抓包仍能看到域名:建立加密连接前要明文告知访问哪个网站(SNI)。所以 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)再正式,靠自动化(定时器+钩子)而不是靠人记续期。