Linux服务器运维踩坑记录:Nginx、SSL与禅道迁移实战

Linux服务器运维踩坑记录:Nginx、SSL与禅道迁移实战

搞了几年服务器运维,从Nginx部署到SSL证书配置,再到禅道迁移,记录一下踩过的坑和解决方案。

Nginx部署

Amazon Linux 2安装

Amazon Linux 2有内置的amazon-linux-extras,装Nginx很方便:

1
2
sudo amazon-linux-extras install -y nginx1
nginx -v

配置文件目录:

1
2
3
4
/etc/nginx/
├── nginx.conf # 主配置
├── conf.d/ # 站点配置
└── default.d/ # 默认配置

基础配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# /etc/nginx/nginx.conf

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

events {
worker_connections 1024;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;

include /etc/nginx/conf.d/*.conf;
}

虚拟主机配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# /etc/nginx/conf.d/example.com.conf

server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.html index.htm;

access_log /var/log/nginx/example.com.access.log main;
error_log /var/log/nginx/example.com.error.log;

gzip on;
gzip_types text/plain text/css application/json application/javascript;

location / {
try_files $uri $uri/ =404;
}

# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}

Let’s Encrypt SSL证书

安装Certbot

用Snap安装(推荐):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 安装snapd
sudo yum install -y snapd
sudo systemctl enable --now snapd.socket
sudo ln -s /var/lib/snapd/snap /snap

# 更新snap
eval $(echo 'export PATH=$PATH:/var/lib/snapd/snap/bin' | sudo tee /etc/profile.d/snap.sh)
sudo snap install core
sudo snap refresh core

# 删除旧版certbot
sudo yum remove certbot

# 安装certbot
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

注意:装完需要重新登录或重启服务器。

获取证书

自动配置Nginx(推荐):

1
sudo certbot --nginx -d example.com -d www.example.com

按提示输入邮箱、同意条款、选择是否重定向HTTP到HTTPS。

仅获取证书(手动配置):

1
sudo certbot certonly --nginx -d example.com -d www.example.com

证书位置:

1
2
3
4
5
/etc/letsencrypt/live/example.com/
├── cert.pem # 服务器证书
├── chain.pem # 中间证书
├── fullchain.pem # 完整证书链
└── privkey.pem # 私钥

手动配置SSL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
server {
listen 443 ssl http2;
server_name example.com;
root /var/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;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;

location / {
try_files $uri $uri/ =404;
}
}

# HTTP重定向到HTTPS
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}

自动续期

测试续期流程:

1
sudo certbot renew --dry-run

Certbot会自动创建定时任务:

1
2
3
4
5
6
7
# 查看定时任务
systemctl list-timers | grep certbot
# 或
cat /etc/cron.d/certbot

# 手动触发续期
sudo certbot renew

续期后自动重载Nginx:

1
2
3
4
5
6
sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx << 'EOF'
#!/bin/bash
systemctl reload nginx
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx

Nginx访问日志分析

日志格式解析

标准Nginx日志:

1
192.168.1.100 - - [15/Dec/2024:14:30:25 +0800] "GET /index.html HTTP/1.1" 200 1234 "https://www.example.com/" "Mozilla/5.0"

字段说明:

字段 说明 示例
$remote_addr 客户端IP 192.168.1.100
$time_local 访问时间 15/Dec/2024:14:30:25
$request 请求行 GET /index.html HTTP/1.1
$status HTTP状态码 200
$body_bytes_sent 发送字节数 1234
$http_referer 来源页面 https://www.example.com/
$http_user_agent 用户代理 Mozilla/5.0

常用分析命令

统计IP访问量:

1
2
3
4
5
# 独立IP数量
awk '{print $1}' /var/log/nginx/access.log | sort | uniq | wc -l

# 访问最多的前10个IP
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10

统计特定URL:

1
2
3
4
5
# 首页访问次数
grep "GET / HTTP/1.1" /var/log/nginx/access.log | wc -l

# 静态资源访问量
grep "GET /js/main.js" /var/log/nginx/access.log | wc -l

按时间段统计:

1
2
3
4
5
6
7
8
# 某天访问量
grep "15/Dec/2024" /var/log/nginx/access.log | wc -l

# 特定小时访问量
grep "15/Dec/2024:14:" /var/log/nginx/access.log | wc -l

# 特定时间段独立IP
awk '/15\/Dec\/2024:14:/{print $1}' /var/log/nginx/access.log | sort | uniq | wc -l

高级统计:

1
2
3
4
5
6
7
8
# 按状态码统计
cat /var/log/nginx/access.log | awk '{print $9}' | sort | uniq -c | sort -rn

# 统计404错误
cat /var/log/nginx/access.log | grep ' 404 ' | awk '{print $7}' | sort | uniq -c | sort -rn | head -10

# 统计带宽使用
awk '{sum+=$10} END {print "Total bytes:", sum, "MB:", sum/1024/1024}' /var/log/nginx/access.log

可视化分析工具GoAccess

1
2
3
4
5
6
7
8
9
10
11
12
# 安装
sudo amazon-linux-extras install -y epel
sudo yum install -y goaccess

# 实时分析
goaccess /var/log/nginx/access.log -c

# 生成HTML报告
goaccess /var/log/nginx/access.log -o /var/www/html/report.html --log-format=COMBINED

# 实时WebSocket模式
goaccess /var/log/nginx/access.log -o /var/www/html/report.html --real-time-html --daemon

禅道项目管理运维

数据存储优化

禅道默认每天自动备份一次,保留21天,约占用31GB空间。

清理备份数据:

1
2
3
4
5
# 登录禅道后台
# 数据 → 备份 → 备份历史 → 删除不要的历史数据

# 禁用自动备份
# 系统 → 备份数据和附件 → 禁用

迁移数据目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. 备份原数据
cd /opt/zbox/app/zentao/www/data
sudo cp -r upload/ upload_bk
sudo rm -rf upload

# 2. 创建新存储目录
cd /data
sudo mkdir -p zentao_resource
sudo chmod -R 777 zentao_resource

# 3. 创建软链接
cd /opt/zbox/app/zentao/www/data
sudo ln -s /data/zentao_resource upload

数据库迁移

1
2
3
4
5
6
7
8
9
10
11
12
# 1. 停止禅道服务
/opt/zbox/zbox stop

# 2. 备份数据库
/opt/zbox/run/mysql/mysqldump -u root -p zentao > zentao_backup.sql

# 3. 迁移数据目录
sudo mv /opt/zbox/data/mysql /data/mysql_new
sudo ln -s /data/mysql_new /opt/zbox/data/mysql

# 4. 启动服务
/opt/zbox/zbox start

Git配置与故障处理

GitHub密码认证迁移

GitHub已经移除密码认证,会报错:

1
2
fatal: unable to access 'https://github.com/.../':
The requested URL returned error: 403

使用Personal Access Token:

1
2
3
4
5
6
7
8
9
10
11
# 1. GitHub Settings → Developer settings → Personal access tokens → Generate new token

# 2. 克隆时使用Token
git clone https://oauth2:<token>@github.com/username/repo.git

# 3. 更新已有仓库
git remote set-url origin https://oauth2:<token>@github.com/username/repo.git

# 4. 缓存凭证
git config --global credential.helper cache
git config --global credential.helper 'cache --timeout=3600'

Git常用配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 用户名和邮箱
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"

# 默认编辑器
git config --global core.editor vim

# 别名
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status

# 忽略文件权限变化
git config --global core.filemode false

# 长文件名支持(Windows)
git config --global core.longpaths true

服务器监控与维护

磁盘空间监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 查看磁盘使用情况
df -h

# 查看目录大小
du -sh /var/log/*
du -sh /opt/zbox/*

# 查找大文件
find / -type f -size +100M -exec ls -lh {} \;

# 清空日志
sudo truncate -s 0 /var/log/nginx/access.log

# 或使用logrotate
sudo logrotate -f /etc/logrotate.conf

系统性能监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 内存使用
free -h

# CPU使用
top
htop

# 查看进程
ps aux --sort=-%mem | head -10

# 网络连接
netstat -tulnp
ss -tulnp

# IO使用
iostat -x 1

# 系统负载
uptime
cat /proc/loadavg

定时任务配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 编辑定时任务
crontab -e

# 每天凌晨2点备份
0 2 * * * /opt/backup.sh

# 每小时清理临时文件
0 * * * * /opt/cleanup.sh

# 每周一发送报告
0 9 * * 1 /opt/report.sh

# 查看定时任务日志
tail -f /var/log/cron

安全防护配置

Nginx安全加固

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 隐藏Nginx版本号
server_tokens off;

# 限制请求方法
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 444;
}

# 基础SQL注入防护
if ($query_string ~* "union.*select.*\(") {
return 403;
}

# 限制连接数
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn addr 10;

# 速率限制
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
limit_req zone=one burst=20 nodelay;

SSL安全评分优化

SSL Labs测试配置。

1
2
3
4
5
# 生成DH参数
sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048

# 配置中添加
ssl_dhparam /etc/nginx/dhparam.pem;

防火墙配置

1
2
3
4
5
6
7
8
9
# firewalld
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

# iptables
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
sudo service iptables save

故障排查

Nginx无法启动

1
2
3
4
5
6
7
8
9
10
11
12
13
# 检查配置语法
sudo nginx -t

# 查看错误日志
sudo tail -f /var/log/nginx/error.log

# 检查端口占用
sudo netstat -tulnp | grep :80
sudo netstat -tulnp | grep :443

# 检查文件权限
sudo ls -la /etc/nginx/
sudo ls -la /var/www/

SSL证书问题

1
2
3
4
5
6
7
8
# 检查证书有效期
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -noout -dates

# 检查证书链
openssl s_client -connect example.com:443 -servername example.com

# 验证证书
certbot certificates

性能问题排查

1
2
3
4
5
6
7
8
9
10
# 查看慢请求
sudo tail -f /var/log/nginx/access.log | awk '$11 > 5'

# 检查系统资源
vmstat 1
iostat -x 1

# 分析连接数
netstat -an | grep :80 | wc -l
netstat -an | grep :443 | wc -l

服务器运维是个持续的过程,证书过期、磁盘满了、服务挂了这些问题都是家常便饭。建议:

  1. 证书续期要测试,别等过期了才发现
  2. 磁盘监控要到位,禅道这种日志大户要特别注意
  3. Nginx配置要备份,改错了能快速回滚
  4. 定时任务要检查,确保备份真的在跑

有问题的欢迎留言讨论。