我的运维笔记

第1讲:服务器安全加固

1. 看见威胁

服务器接入公网就会面临暴力破解。用以下命令查看 SSH 登录失败记录:

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

大量来自陌生 IP 的失败尝试,多数在尝试 root 用户。

2. 两条登录通道

铁律:私钥永不外传、改配置先留后路(VNC)、先验证再收口。

3. 密钥登录配置

本地生成密钥对:

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

查看公钥:

# Windows:
type $env:USERPROFILE\.ssh\id_ed25519.pub
# Mac/Linux:
cat ~/.ssh/id_ed25519.pub

在服务器上安装公钥(study 用户):

sudo su - study
mkdir -p ~/.ssh
chmod 700 ~/.ssh
vi ~/.ssh/authorized_keys   # 粘贴公钥(一整行),保存退出
chmod 600 ~/.ssh/authorized_keys
ls -l ~/.ssh                # 核对权限

验证密钥登录(在本地电脑上):

ssh study@服务器公网IP

无需输入密码即成功,方可继续。

4. 为老师配置巡检账号

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 可用"

5. 加固 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

6. 防火墙与安全组

主机防火墙(firewalld):

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

安全组要点:保留 SSH (TCP 22);删除无用端口;ICMP 规则可保留(端口显示“任何”是协议特性,不代表开放所有端口)。

查看监听端口:

sudo ss -tlnp

7. fail2ban 自动封禁

sudo dnf install -y epel-release
sudo dnf install -y fail2ban
sudo vi /etc/fail2ban/jail.d/sshd.local

写入:

[sshd]
enabled = true
backend = systemd
maxretry = 3
findtime = 600
bantime = 3600

启动并查看:

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

8. 验证清单

第2讲:网站上线

1. 域名解析

在阿里云云解析 DNS 添加两条 A 记录:

验证解析:

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

2. 开放 80 端口

安全组:入方向添加 TCP 80,授权对象 0.0.0.0/0。

主机防火墙:

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

3. 安装 Nginx

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

浏览器访问 http://服务器公网IP 应看到默认测试页。

4. 准备网站目录

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

5. 编写站点配置

sudo vi /etc/nginx/conf.d/mysite.conf

填入(将 example.com 换成你的域名):

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

6. 发布个人主页

首页底部必须显示 ICP 备案号并链接到工信部备案查询网站。

上传主页(本地 → 服务器):

scp index.html study@你的服务器公网IP:/var/www/mysite/

或在服务器上直接编辑:

vi /var/www/mysite/index.html

7. 理解 IP 访问与域名访问的差异

用 IP 访问看到默认页,用域名访问看到自己的主页——因为 Nginx 根据请求头中的 Host 字段匹配 server_name。

curl -H "Host: 你的域名" http://127.0.0.1
curl http://127.0.0.1 | head -5

8. 403 排障实验

echo "<h1>test</h1>" > /var/www/mysite/test.html
chmod 600 /var/www/mysite/test.html
curl -I -H "Host: 你的域名" http://127.0.0.1/test.html   # 返回 403
ps -o user= -C nginx | sort -u
ls -l /var/www/mysite/
sudo tail -3 /var/log/nginx/mysite_error.log             # 显示 Permission denied

修复:放宽为 644,Nginx 工作进程以 nginx 用户身份读取文件。

chmod 644 /var/www/mysite/test.html
curl -I -H "Host: 你的域名" http://127.0.0.1/test.html   # 返回 200 OK
rm /var/www/mysite/test.html

9. 查看访问日志

sudo tail -f /var/log/nginx/mysite_access.log

第3讲:HTTPS 与证书自动续期

1. HTTP 明文抓包实验

sudo dnf install -y tcpdump
sudo tcpdump -i any -A -nn 'tcp port 80' | grep -a -E "GET |Host: |User-Agent|title"

用手机访问 http://你的域名,可看到请求路径、域名、浏览器信息甚至网页标题。HTTP 明文传输,毫无隐私。

2. HTTPS 原理

3. 开放 443 端口

安全组:入方向添加 TCP 443。

主机防火墙:

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

注意:80 端口不能关(跳转和证书续期验证都需要)。

4. 安装 certbot 并申请证书

sudo dnf install -y certbot
certbot --version

先演练(--dry-run):

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

看到 The dry run was successful. 后,去掉 --dry-run 正式申请:

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

查看证书:

sudo certbot certificates
sudo ls -l /etc/letsencrypt/live/example.com/

关键文件:fullchain.pem(证书链)、privkey.pem(私钥,绝不泄露)。

5. 配置 Nginx 启用 HTTPS

先备份:

sudo cp /etc/nginx/conf.d/mysite.conf /etc/nginx/conf.d/mysite.conf.bak

改写配置:

sudo vi /etc/nginx/conf.d/mysite.conf

80 端口只做两件事:提供续期验证文件、其余请求跳转 HTTPS。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

6. 验证 HTTPS

# Windows PowerShell 用 curl.exe
curl.exe -I http://example.com          # 应返回 301
curl.exe -I https://example.com         # 应返回 200
curl.exe -I https://www.example.com     # 应返回 200

7. 配置自动续期

启用定时器:

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

创建续期后重载 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 /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
systemctl is-active nginx

演练续期:

sudo certbot renew --dry-run

看到 Congratulations, all simulated renewals succeeded 即成功。

8. HTTPS 抓包对比

sudo tcpdump -i any -A -nn -c 48 'tcp port 443'

与 HTTP 抓包对比:内容变为乱码,但域名仍然可见(TLS 握手阶段 SNI 明文)。HTTPS 隐藏了“看了什么”,但没有隐藏“访问了哪个网站”。

9. 验证清单