Linux服务器部署踩坑记录:TencentOS、Nginx、Node.js实战经验

Linux服务器部署踩坑记录

用TencentOS 3.1(基于RHEL 8/CentOS 8.x兼容)部署Node.js服务时踩了不少坑,记录一下完整的配置流程。

系统初始配置

登录与基础检查

1
2
3
4
5
6
7
8
9
# 登录后先改root密码
passwd root

# 查看系统基本信息
top # 系统负载
df -h # 磁盘使用
free -h # 内存使用
uname -a # 内核版本
cat /etc/os-release # 操作系统版本

系统更新

1
2
3
4
5
# 升级系统软件包
yum update -y

# 安装常用工具
yum install -y vim wget curl net-tools

安全配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 配置防火墙
systemctl start firewalld
systemctl enable firewalld

# 开放必要端口
firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --permanent --add-port=443/tcp
firewall-cmd --permanent --add-port=22/tcp
firewall-cmd --permanent --add-port=3000/tcp
firewall-cmd --reload

# 创建普通用户
useradd -m deploy
passwd deploy
usermod -aG wheel deploy # 添加到sudo组

MongoDB安装与配置

添加YUM源

1
2
# 创建MongoDB的yum源文件
vim /etc/yum.repos.d/mongodb-org-4.4.repo

添加内容:

1
2
3
4
5
6
[mongodb-org-4.4]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/8Server/mongodb-org/4.4/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.4.asc

安装MongoDB

1
2
3
4
5
6
7
8
9
10
11
# 安装
yum install -y mongodb-org

# 启动服务
systemctl start mongod

# 设置开机自启
systemctl enable mongod

# 查看状态
systemctl status mongod

基础配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 进入MongoDB shell
mongo

# 创建管理员用户
use admin
db.createUser({
user: "admin",
pwd: "your_password",
roles: [{ role: "root", db: "admin" }]
})

# 退出
exit

# 修改配置文件启用认证
vim /etc/mongod.conf

# 添加以下配置
security:
authorization: enabled

# 重启生效
systemctl restart mongod

Node.js环境部署

安装Node.js

1
2
3
4
5
6
7
8
9
# 添加NodeSource仓库
curl --silent --location https://rpm.nodesource.com/setup_16.x | sudo bash -

# 安装
yum install -y nodejs

# 验证安装
node -v
npm -v

配置npm

1
2
3
4
5
6
7
8
9
10
11
# 安装cnpm(国内镜像)
npm install -g cnpm --registry=https://registry.npmmirror.com

# 或设置npm淘宝镜像
npm config set registry https://registry.npmmirror.com

# 安装PM2进程管理器
npm install -g pm2

# 安装常用构建工具
yum install -y pcre-devel zlib-devel openssl openssl-devel unzip

PM2配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 配置PM2开机自启
pm2 startup

# 启动应用示例
pm2 start app.js --name "myapp"
pm2 start app.js --name "myapp" --max-memory-restart 300M

# 保存PM2配置
pm2 save

# 常用PM2命令
pm2 list # 查看所有进程
pm2 logs # 查看日志
pm2 logs myapp # 查看指定应用日志
pm2 monit # 监控面板
pm2 restart myapp # 重启应用
pm2 stop myapp # 停止应用
pm2 delete myapp # 删除应用

PM2配置文件(ecosystem.config.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
module.exports = {
apps: [{
name: 'myapp',
script: './app.js',
instances: 'max',
exec_mode: 'cluster',
max_memory_restart: '300M',
env: {
NODE_ENV: 'production',
PORT: 3000
},
env_development: {
NODE_ENV: 'development',
PORT: 3000
},
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
error_file: './logs/err.log',
out_file: './logs/out.log',
log_file: './logs/combined.log',
time: true
}]
};

Redis安装与配置

安装Redis

1
2
3
4
5
6
7
8
9
10
11
12
# 安装
yum install -y redis

# 启动服务
systemctl start redis

# 设置开机自启
systemctl enable redis

# 测试连接
redis-cli ping
# 返回PONG表示正常

基础配置

1
2
3
4
5
6
7
8
9
10
11
12
13
# 编辑配置文件
vim /etc/redis.conf

# 关键配置项
bind 127.0.0.1 # 绑定地址,生产环境建议只绑定本地
port 6379 # 端口
requirepass your_password # 设置密码
databases 16 # 数据库数量
maxmemory 256mb # 最大内存
maxmemory-policy allkeys-lru # 内存淘汰策略

# 重启生效
systemctl restart redis

Nginx安装与配置

使用官方源安装

1
2
# 创建Nginx yum源
vim /etc/yum.repos.d/nginx.repo

添加内容:

1
2
3
4
5
6
7
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

安装Nginx

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
# 安装依赖
yum install -y gcc gcc-c++ autoconf pcre pcre-devel make automake httpd-tools yum-utils

# 清除yum缓存
yum clean all

# 重新缓存yum源
yum makecache

# 查看可用版本
yum list nginx --showduplicates

# 安装Nginx
yum install -y nginx

# 查看版本
nginx -V

# 启动并设置开机自启
systemctl enable --now nginx

# 查看状态
systemctl status nginx

# 查看进程和端口
netstat -ltnp | grep nginx
# 或
ss -nltp | grep nginx

基础配置

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
32
33
34
35
36
37
# /etc/nginx/nginx.conf

user nginx;
worker_processes auto;

error_log /var/log/nginx/error.log warn;
pid /var/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;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;

# Gzip压缩
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;

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

Node.js反向代理配置

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
32
33
34
35
36
37
# /etc/nginx/conf.d/nodejs-app.conf

upstream nodejs_backend {
server 127.0.0.1:3000 weight=5;
server 127.0.0.1:3001 weight=5;
keepalive 64;
}

server {
listen 80;
server_name yourdomain.com;

# 静态文件直接由Nginx处理
location ~ ^/(images|javascript|js|css|flash|media|static)/ {
root /var/www/static;
expires 30d;
}

# 反向代理到Node.js
location / {
proxy_pass http://nodejs_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}

# 错误页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

HTTPS配置

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
server {
listen 443 ssl http2;
server_name yourdomain.com;

# SSL证书
ssl_certificate /etc/nginx/ssl/yourdomain.crt;
ssl_certificate_key /etc/nginx/ssl/yourdomain.key;

# SSL优化
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 10m;

location / {
proxy_pass http://nodejs_backend;
}
}

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

解决403 Forbidden错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 查看Nginx错误日志
tail -f /var/log/nginx/error.log

# 常见原因1:权限问题
chmod -R 755 /var/www
chown -R nginx:nginx /var/www

# 常见原因2:SELinux限制
# 临时关闭SELinux
setenforce 0

# 永久关闭(需要重启)
vim /etc/selinux/config
# 修改:SELINUX=disabled

# 或配置SELinux允许Nginx访问
setsebool -P httpd_can_network_connect 1

系统参数优化

文件描述符限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 查看当前限制
ulimit -n

# 查看系统最大支持值
sysctl -n -e fs.file-max

# 重要:不能超过系统支持的最大值!

# 备份配置文件
cp /etc/security/limits.conf /etc/security/limits.conf.backup

# 修改配置
vim /etc/security/limits.conf

# 添加以下内容
* soft nofile 65535
* hard nofile 65535
root soft nofile 65535
root hard nofile 65535

内核参数优化

1
2
3
4
5
6
7
8
9
10
11
12
13
# 编辑sysctl配置
vim /etc/sysctl.conf

# 添加网络优化参数
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_max_tw_buckets = 5000

# 应用配置
sysctl -p

监控与告警

使用mailx配置邮件告警

安装mailx

1
2
3
4
5
6
7
8
# 关闭其他邮件服务
chkconfig postfix off
service postfix stop
chkconfig sendmail off
service sendmail stop

# 安装mailx
yum -y install mailx

配置邮件

1
2
3
4
5
6
7
8
9
10
11
# 编辑mail.rc
vim /etc/mail.rc

# 添加QQ邮箱配置
set from=your_qq@qq.com
set smtp=smtps://smtp.qq.com:465
set smtp-auth-user=your_qq@qq.com
set smtp-auth-password=your_auth_code # QQ邮箱授权码,不是登录密码
set smtp-auth=login
set ssl-verify=strict
set nss-config-dir=/etc/pki/nssdb

获取SSL证书

1
2
3
4
5
6
# 获取邮件服务器证书
echo -n " " | openssl s_client -connect smtp.qq.com:465 | \
sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > /etc/pki/nssdb/qq.crt

# 添加证书到信任列表
certutil -A -n 'qq' -t "P,P,P" -d /etc/pki/nssdb -i /etc/pki/nssdb/qq.crt

测试邮件发送

1
2
3
4
5
6
7
8
# 发送测试邮件
echo "邮件正文内容" | mail -s "邮件主题" recipient@example.com

# 发送带附件的邮件
echo "邮件正文" | mail -s "主题" -A attachment.txt recipient@example.com

# 从文件发送
cat report.txt | mail -s "每日报告" recipient@example.com

API监控脚本

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
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/bin/bash
# api_monitor.sh

# 配置
API_URL="http://your-api.com/api/health"
CHECK_INTERVAL=60
MAIL_LIST=("admin@example.com" "ops@example.com")

# 发送邮件函数
send_alert() {
local subject="$1"
local body="$2"
local now=$(date "+%Y-%m-%d %H:%M:%S")

for email in "${MAIL_LIST[@]}"; do
echo -e "$body\n\n时间: $now" | mail -s "$subject" "$email"
done
}

# 检查API
check_api() {
local result=$(curl -k -s --max-time 10 "$API_URL")
local http_code=$(curl -k -s -o /dev/null -w "%{http_code}" --max-time 10 "$API_URL")

if [ "$http_code" != "200" ]; then
send_alert "API告警:HTTP $http_code" \
"API服务器返回异常状态码:$http_code\nURL: $API_URL"
return 1
fi

if [[ "$result" != *"success"* ]]; then
send_alert "API告警:业务异常" \
"API返回结果异常\n返回结果: $result"
return 1
fi

return 0
}

# 主循环
while true; do
check_api
sleep $CHECK_INTERVAL
done

系统资源监控脚本

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
32
33
34
35
36
#!/bin/bash
# system_monitor.sh

# 阈值配置
CPU_THRESHOLD=80
MEM_THRESHOLD=80
DISK_THRESHOLD=90

# 检查CPU使用率
check_cpu() {
local cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
if (( $(echo "$cpu_usage > $CPU_THRESHOLD" | bc -l) )); then
echo "CPU使用率告警: ${cpu_usage}%" | mail -s "服务器CPU告警" admin@example.com
fi
}

# 检查内存使用率
check_memory() {
local mem_usage=$(free | awk 'NR==2{printf "%.2f", $3*100/$2}')
if (( $(echo "$mem_usage > $MEM_THRESHOLD" | bc -l) )); then
echo "内存使用率告警: ${mem_usage}%" | mail -s "服务器内存告警" admin@example.com
fi
}

# 检查磁盘使用率
check_disk() {
local disk_usage=$(df -h / | awk 'NR==2 {print $5}' | cut -d'%' -f1)
if [ "$disk_usage" -gt "$DISK_THRESHOLD" ]; then
echo "磁盘使用率告警: ${disk_usage}%" | mail -s "服务器磁盘告警" admin@example.com
fi
}

# 执行检查
check_cpu
check_memory
check_disk

服务自动启动配置

1
2
3
4
5
6
7
8
9
10
11
12
13
# 配置所有服务开机自启
systemctl enable nginx.service
systemctl enable redis.service
systemctl enable mongod.service

# 重启验证
reboot

# 重启后检查服务状态
systemctl status nginx
systemctl status redis
systemctl status mongod
pm2 list

安全加固

SSH安全配置

1
2
3
4
5
6
7
8
9
10
11
12
13
# 编辑SSH配置
vim /etc/ssh/sshd_config

# 修改以下配置
Port 2222 # 修改默认端口
PermitRootLogin no # 禁止root登录
PasswordAuthentication no # 使用密钥认证(配置好后)
MaxAuthTries 3 # 最大尝试次数
ClientAliveInterval 300 # 心跳检测
ClientAliveCountMax 2

# 重启SSH
systemctl restart sshd

防火墙配置

1
2
3
4
5
6
# 只开放必要端口
firewall-cmd --permanent --remove-service=ssh
firewall-cmd --permanent --add-port=2222/tcp
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload

Fail2ban安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 安装fail2ban
yum install -y fail2ban

# 配置
vim /etc/fail2ban/jail.local

[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/secure
maxretry = 3
bantime = 3600

# 启动
systemctl enable fail2ban
systemctl start fail2ban

这些都是实际部署时用过的配置,从系统初始化到服务部署、监控告警、安全加固都有。重点注意Nginx反向代理配置和SELinux可能导致的403问题。

参考