Nginx实战部署与踩坑总结 附带详细配置教程

目录

Nginx

[一. 充当web服务器](#一. 充当web服务器)

动静分离

[二. 反向代理](#二. 反向代理)

[1. proxy_pass](#1. proxy_pass)

[2. 为什么必须处理请求头](#2. 为什么必须处理请求头)

[3. 协议升级](#3. 协议升级)

[HTTPS 安全加固:SSL 卸载](#HTTPS 安全加固:SSL 卸载)

[WebSocket 升级:实时通信的关键](#WebSocket 升级:实时通信的关键)

[三. 负载均衡](#三. 负载均衡)

[1. 基础配置](#1. 基础配置)

[2. Nginx不同的分配策略:](#2. Nginx不同的分配策略:)

[3. ip_hash](#3. ip_hash)


聊起高性能 Web 服务器,Nginx 几乎是绕不开的骨干。最近我们帮学院部署开发项目学习到了Nginx的使用, 既然要实战部署,那咱们就以最经典的 Vue 3 + Golang (Gin) 架构为例。这种架构下,Nginx 不再单单只是一个工具,而是连接前后端的核心管家。

Nginx的主要作用有三个: 1. 充当web服务器 2. 反向代理 3. 负载均衡

一. 充当web服务器

动静分离

当用户访问你的网站时,请求的本质流程是这样的:

浏览器 → Nginx

├── 返回前端静态资源(HTML / JS / CSS)

└── 转发 API 请求 → Gin 后端

而浏览器从头到尾只知道 Nginx,不知道你的后端服务。当Vue项目build打包后,本质上就是一堆静态文件:

index.html

app.js

chunk-vendors.js

style.css

当浏览器请求这些资源时:

GET /index.html

GET /assets/app.js

Nginx 直接:

  1. 根据 URL 匹配 location

  2. 找到磁盘文件路径利用Sendfile机制从磁盘推送到网卡

  3. 把文件返回给浏览器

这些步骤完全不经过后端, 但是如果让 Gin 来做这件事,会多一层:

浏览器 → Nginx → Gin → 文件 → 返回

而现在直接:

浏览器 → Nginx → 文件 → 返回

即使是少一次网络跳转,性能差距在高并发下会被无限放大。

前端项目部署注意点:

Vue 使用 history 路由时:

假如访问 /user/profile → 404

原因:

浏览器请求 /user/profile

→ Nginx 当成文件路径

→ 文件不存在

→ 返回 404

解决方式:

location / {

try_files $uri /index.html;

}

这段配置意思就是把前端路由交给前端管理

二. 反向代理

1. proxy_pass

既然静态资源可以直接有Nginx管理, 那么动态请求怎么被管理呢?

也就是说请求是怎么被转发给后端的?

当浏览器发起 API 请求:

GET /api/user/info

Nginx 不再返回文件,而是把请求转发给后端服务:

比如:

location /api/ {

proxy_pass http://127.0.0.1:8080;

}

这样就是变成:

浏览器 → Nginx → Gin(8080) → 返回数据 → Nginx → 浏览器

当然很多人第一次部署就踩这里, 比如我:

location /api/ {

proxy_pass http://127.0.0.1:8080/;

}

请求:

/api/user

实际转发:

/user

但如果写成:

location /api/ {

proxy_pass http://127.0.0.1:8080;

}

请求:

/api/user

转发变成:

/api/user

选择哪种配置方式,完全取决于后端服务期望接收的路径格式

  • 使用不带 / 的配置 :如果后端接口本身就设计为包含/api前缀,

    (例如http://127.0.0.1:8080/api/...),那么我们应该使用这种配置,将完整的路径透传给后端

  • 使用带 / 的配置 :如果后端服务直接监听在根路径,

    (例如http://127.0.0.1:8080/user/...),而我希望通过 Nginx 对外暴露 /api 前缀来区分或组织接口,那么应该使用这种配置来剥离前缀

Nginx这种反向代理也是同时解决了http的跨域问题

2. 为什么必须处理请求头

默认情况下,后端拿到的信息是有误的:

客户端 IP:127.0.0.1(本机状态下)

Host:127.0.0.1:8080(本机状态下)

需要手动补齐:

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;

正确状态:

IP = 用户真实IP(比如 8.x.x.x)

Host = www.yoursite.com

这样后端就能看到用户真实的代理请求

一个基础的静态服务配置:

XML 复制代码
server {
    listen 80;
    server_name yourdomain.com;

    # 1. 前端静态资源
    location / {
        root   /var/www/dist; # Vue build后的目录
        index  index.html;
        try_files $uri $uri/ /index.html; # 解决 Vue Router 的 history 模式 404 问题
    }

    # 2. 后端 API 代理
    location /api/ {
        
        proxy_pass http://127.0.0.1:8080; 
        
        # 代理头设置
        # 1. 传递域名
        proxy_set_header Host $host;
    
        # 2. 传递真实 IP (单跳)
        proxy_set_header X-Real-IP $remote_addr;
    
        # 3. 传递代理链 IP (多跳)
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
        # 4. 传递原始协议 (http/https)
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

3. 协议升级

HTTPS 安全加固:SSL 卸载

在 2026 年,没有 HTTPS 的网站基本没法看了。通过 Nginx 处理 SSL,你的 Golang 代码只需要关注 HTTP 逻辑,不需要处理证书加载。

值得注意的细节:

  • 强制跳转:把所有的 80 端口(HTTP)请求重定向到 443(HTTPS)。

  • HSTS:告诉浏览器,以后直接用 HTTPS 访问我。

XML 复制代码
# 1. HTTP Server 块:负责重定向到 HTTPS
server {
    listen 80;
    server_name yourdomain.com;
    
    # 强制跳转
    return 301 https://$server_name$request_uri; 
}

# 2. HTTPS Server 块:负责处理业务逻辑(Vue + Gin)
server {
    listen 443 ssl;
    server_name yourdomain.com;

    # SSL 证书路径
    ssl_certificate     /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;

    # 推荐的安全配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # --- 1. 前端静态资源 ---
    location / {
        root   /var/www/dist; # Vue build后的目录
        index  index.html;
        # 解决 Vue Router 的 history 模式 404 问题
        try_files $uri $uri/ /index.html; 
    }

    # --- 2. 后端 API 代理 ---
    location /api/ {

        proxy_pass http://127.0.0.1:8080; 

        # 代理头设置
        # 1. 传递域名
        proxy_set_header Host $host;
    
        # 2. 传递真实 IP (单跳)
        proxy_set_header X-Real-IP $remote_addr;
    
        # 3. 传递代理链 IP (多跳)
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
        # 4. 传递原始协议 (http/https)
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket 升级配置
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    # 其他可选配置:开启 Gzip 提高 Vue 静态资源加载速度
    gzip on;
    gzip_types text/plain text/css application/javascript application/json;
}

WebSocket 升级:实时通信的关键

如果你的项目里有即时通讯(比如聊天、监控大屏),Golang 通常会起一个 WebSocket 服务。Nginx 默认不支持长连接转发,必须显式修改 Header。

XML 复制代码
# 1. HTTP Server 块:负责重定向到 HTTPS
server {
    listen 80;
    server_name yourdomain.com;
    
    # 强制跳转
    return 301 https://$server_name$request_uri; 
}

# 2. HTTPS Server 块:负责处理业务逻辑(Vue + Gin)
server {
    listen 443 ssl;
    server_name yourdomain.com;

    # SSL 证书路径
    ssl_certificate     /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;

    # 推荐的安全配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # --- 1. 前端静态资源 ---
    location / {
        root   /var/www/dist; # Vue build后的目录
        index  index.html;
        # 解决 Vue Router 的 history 模式 404 问题
        try_files $uri $uri/ /index.html; 
    }

    # --- 2. 后端 API 代理 (包含基础 WebSocket 支持) ---
    location /api {
        proxy_pass http://127.0.0.1:8080; 

        # 代理头设置
        # 1. 传递域名
        proxy_set_header Host $host;
    
        # 2. 传递真实 IP (单跳)
        proxy_set_header X-Real-IP $remote_addr;
    
        # 3. 传递代理链 IP (多跳)
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
        # 4. 传递原始协议 (http/https)
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket 升级配置 (让普通的 /api 也能支持升级握手)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    # --- 3. 专门的 WebSocket 路径优化 ---
    # 如果你的 WS 地址是 /api/ws,则该块会优先匹配,并增加超时保护
    location /api/ws/ {
        proxy_pass http://127.0.0.1:8080;
        
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        # 传递真实 IP 
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # 调大超时时间,防止 WebSocket 莫名其妙断开
        # 默认 60s 没数据就会断开,这里改为 1 小时
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }

    # 其他可选配置:开启 Gzip 提高 Vue 静态资源加载速度
    gzip on;
    gzip_types text/plain text/css application/javascript application/json;
}

三. 负载均衡

1. 基础配置

负载均衡的核心逻辑是:Nginx 站在最前面,收到请求后,根据预设的"策略",把请求转发给后端最合适的服务器。

当后端服务(或者服务器)不止一个时:

8080

8081

8082

Nginx 可以这样配置(分配权重):

XML 复制代码
# 定义后端集群
upstream backend {
    # 策略 1:轮询 (默认) - 每个请求按时间顺序逐一分配
    # 策略 2:权重 (weight) - 性能好的机器多扛点
    server 127.0.0.1:8080 weight=3; 
    server 127.0.0.1:8081 weight=1;
    server 127.0.0.1:8082 backup; # 备用机,平时休息,其他都挂了它再上
}

server {
    listen 443 ssl;
    server_name yourdomain.com;

    # ... 其他 SSL 和静态资源配置保持不变 ...

    location /api {
        proxy_pass http://backend; 
        
        # 代理头设置
        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;

        # WebSocket 
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

然后:

location /api/ {

proxy_pass http://backend;

}

效果:

请求1 → 8080

请求2 → 8081

从而避免服务器单点崩溃, 分摊并发压力

2. Nginx不同的分配策略:

A. 轮询 (Round Robin) ------ 最公平

  • 做法:每个请求按顺序轮流发给后端

  • 场景:后端服务器硬件配置完全一样,且业务没啥特殊要求

B. 权重 (Weight) ------ 能者多劳

  • 做法:在server后面加weight=x

  • 场景:比如 8080 是你的主力服务器(16核),8081 是你的旧笔记本(2核),那就给 8080 分更高的权重

C. IP Hash ------ 解决认人问题

  • 做法:在upstream块里写上ip_hash

  • 场景:如果后端涉及到 Session(比如用户登录状态存存在服务器内存里,而不是 Redis 中),必须开启这个。它能保证同一个用户的请求始终发往同一台服务器,防止用户刷一下页面就掉线了

3. ip_hash

使用ip_hash就无法与backup连用: 正如代码注释里提到的,一旦开启了ip_hash,你就不能在这一组服务器里设置backup (备用机)了。因为ip_hash算法要求所有的服务器都在线参与计算。如果你非要搞一台备用机,可能得考虑其他的负载均衡方式或者使用更高级的第三方模块。

例如:

XML 复制代码
# 定义后端集群
upstream backend {
    # 关键指令:开启 IP Hash 策略
    ip_hash; 
    
    server 127.0.0.1:8080 weight=3; 
    server 127.0.0.1:8081 weight=1;
    
    # 注意:在使用 ip_hash 时,不能直接使用 backup 标志,
    # 因为 ip_hash 的算法需要确定的服务器列表。
}

server {
    listen 443 ssl;
    server_name yourdomain.com;

    # ... 其他 SSL 和静态资源配置保持不变 ...

    location /api {
        proxy_pass http://backend; 
        
        # 代理头设置
        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;

        # WebSocket
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }     
}

为什么负载均衡很重要?

  1. 高可用性: 如果你只跑一个 Gin 实例,它万一崩了,全校同学就都打不开网页了。有了负载均衡,Nginx 会自动检测后端健康状况,如果 8080 挂了,它会立刻把流量转给 8081

  2. 无缝升级: 当需要更新后端代码时,可以先停掉 8080 升级,此时 8081 顶上;等 8080 升好了,再换 8081。整个过程用户完全感知不到

  3. 横向扩展: 明天校赛突然有几万人访问,我们只需要多开几个 Gin 端口,在 Nginx 配置里加一行server,并发能力能提高很多

总结: Nginx 是一个异步框架的Web 服务器,也可以用作反向代理 ,负载均衡和HTTPS缓存等核心功能。

下面是一个完整参考的nginx.conf配置文件:

XML 复制代码
# 运行 nginx 的用户(通常不用改)
user nginx;

# 根据你的 CPU 核心数调整,一般设为 auto
worker_processes auto;

# 错误日志路径和级别
error_log /var/log/nginx/error.log warn;

# 进程 ID 文件
pid /var/run/nginx.pid;

# 事件模块配置
events {
    worker_connections 1024;  # 单个进程最大连接数
    use epoll;                # Linux 下高性能网络 IO 模型
    multi_accept on;          # 尽可能多地接受新连接
}

# HTTP 核心模块
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;            # 禁用 Nagle 算法
    keepalive_timeout 65;      # 保持连接超时时间
    client_max_body_size 50M;  # 允许上传的最大文件大小

    # Gzip 压缩(提升前端加载速度)
    gzip on;
    gzip_vary on;
    gzip_min_length 1k;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml text/javascript 
               application/json application/javascript application/xml+rss 
               application/x-javascript image/svg+xml;
    gzip_disable "MSIE [1-6]\.";

    # ---------- 以下是你需要修改的核心 Server 块 ----------
    
    # 1. HTTP 服务(监听 80 端口,负责跳转到 HTTPS)
    server {
        listen 80;
        listen [::]:80;  # 支持 IPv6
        server_name your-domain.com www.your-domain.com;  # 【改成你的域名】

        # 将所有 HTTP 请求永久重定向到 HTTPS
        return 301 https://$server_name$request_uri;
    }

    # 2. HTTPS 服务(监听 443 端口,真正的业务入口)
    server {
        listen 443 ssl http2;  # 启用 HTTP/2 提升性能
        listen [::]:443 ssl http2;
        server_name your-domain.com www.your-domain.com;  # 【改成你的域名】

        # ---------- SSL 证书配置(请修改为你的实际路径)----------
        ssl_certificate /etc/nginx/ssl/your-domain.com.pem;      # 证书文件
        ssl_certificate_key /etc/nginx/ssl/your-domain.com.key;  # 私钥文件

        # SSL 安全增强配置(推荐)
        ssl_protocols TLSv1.2 TLSv1.3;                # 只启用安全的 TLS 版本
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;

        # ---------- 前端静态文件代理(以 Vue 打包后的 dist 为例)----------
        root /var/www/dist;
        index index.html;

        # 处理前端路由(History 模式)
        location / {
            try_files $uri $uri/ /index.html;
        }

        # 缓存静态资源(CSS/JS/图片等)
        location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
            expires 30d;
            add_header Cache-Control "public, immutable";
        }

        # ---------- 后端 API & WebSocket 统一代理 ----------
        # 整合了普通接口和 WebSocket 协议升级,统一指向 8080 端口
        location /api/ {
            proxy_pass http://127.0.0.1:8080;  # 【改成你的后端地址】
            
            # 基础代理头设置
            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; 

            # WebSocket 核心配置:允许协议升级
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";

            # 超时设置:同时兼顾普通 API 和 WebSocket 长连接
            proxy_connect_timeout 60s;
            # 调大发送和读取超时,防止 WebSocket 莫名其妙断开(设为 1 小时)
            proxy_send_timeout 3600s;
            proxy_read_timeout 3600s;
        }

        # 可选:健康检查路径(不记录日志)
        location /health {
            access_log off;
            return 200 "healthy\n";
            add_header Content-Type text/plain;
        }
    }
}
相关推荐
va学弟1 小时前
Agent入门开发(2):个性化功能添加
java·服务器·ai
IP老炮不瞎唠2 小时前
什么是Grok?以及如何解决卡顿、风控问题
服务器·网络
Live&&learn2 小时前
Vue项目打包后内联字符串不显示的原因
前端·javascript·vue.js
神奇小汤圆2 小时前
JAVA 面经汇总2026最新版,1100+ 大厂面试题附答案详解
后端
淼淼爱喝水2 小时前
eNSP 防火墙 NAT 策略配置(Easy IP/No-PAT/NAPT/ 黑洞路由)
服务器·网络·tcp/ip·ensp·防火墙·nat
爱上好庆祝2 小时前
学习js的第三天
前端·css·人工智能·学习·计算机外设·js
aq55356002 小时前
Chrome如何重塑Web标准的未来格局
前端·chrome
宁雨桥2 小时前
深入剖析Vue2与Vue3响应式原理:从Object.defineProperty到Proxy的演进
前端·vue.js
程序员老邢2 小时前
【技术底稿 23】Ollama + Docker + Ubuntu 部署踩坑实录:网络通了,参数还在调
java·经验分享·后端·ubuntu·docker·容器·milvus