前端开发必会的Nginx知识及结合Docker的项目部署实战
起因

事情的起因来自一封邮件,年前上线了一个项目官网,在过年期间,突然收到了一封来自安全部门邮件,说上线的官网存在以上安全风险,让尽快处理。现在看来解决这个问题很容易,只需要在 Nginx 上的 server 块中配置 server_name 为备案域名,再设置一个默认的 server 模块,匹配所有未明确指定 server_name 的请求并返回 403 就 OK,但是当时对 Nginx 并不熟悉,导致走了些弯路。所以这篇文章主要是前端在项目部署中,针对常见的 Nginx 功能的介绍。基于目前前端项目部署方式大多采用 Docker 的 CI/CD 工作流来进行,所以也会涉及到 Docker 以及常见项目部署配置的相关知识。
Nginx 介绍
Nginx 是由伊戈尔·赛索耶夫在 2002 年创建的,最初是为了解决 C10K 问题,也就是同时处理上万个并发连接的问题。Apache 服务器当时在处理大量并发时效率不高,所以 Nginx 采用了事件驱动的异步架构,性能更好,资源消耗更低。后来在 2004 年公开发布,凭借其轻量级、事件驱动、异步非阻塞的架构,迅速成为高性能 Web 服务器和反向代理的热门选择。
前端常用的 Nginx 功能
我们将从以下方面介绍前端开发与项目部署中常见的 Nginx 相关功能,主要涉及:基于 Docker 的 Nginx 安装、配置文件、静态资源托管、反向代理、负载均衡、HTTPS 配置(SSL 证书)等
基于 Docker 的 Nginx 安装
基于 Mac 电脑,假设你已经安装好看 Docker,通过下面的一行命令就可以安装基于 Docker 容器的 Nginx
docker run -d -p 80:80 --name my-nginx nginx
这段命令用于运行一个 Nginx Docker 容器,并将其端口映射到主机的端口。
docker run:这是 Docker 命令,用于创建并运行一个新的容器。-d:这是一个选项,表示以分离模式(detached mode)运行容器。容器将在后台运行,而不会占用当前终端。-p 80:80:这是一个端口映射选项,格式为 主机端口:容器端口, 80:80 表示将主机的端口 80 映射到容器的端口 80。这样,访问主机的端口 80 时,实际上是在访问容器的端口 80。--name my-nginx:这是一个选项,用于为容器指定一个名称。在这里,容器的名称被指定为 my-nginx。 这样你可以通过这个名称来管理和引用这个容器,而不需要使用容器的 ID。nginx:这是要运行的镜像名称。在这里,使用的是官方的 Nginx 镜像。 Docker 会从 Docker Hub 拉取这个镜像(如果本地没有的话),并基于这个镜像创建并运行一个新的容器。
当我们在浏览器访问: http://localhost,若看到欢迎页即安装成功。

配置文件
当我们在主机上运行 my-nginx 容器后,可以通过命令:
docker exec -it my-nginx /bin/sh
来进入到容器中,查看和修改 nginx 的相关配置,nginx 的主配置文件为: /etc/nginx/nginx.conf,执行cat nginx.conf查看文件为:
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
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;
keepalive_timeout 65;
#gzip on;
# 引入站点配置
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
这是 Nginx 的核心配置文件,定义了全局配置(如 Worker 进程数、日志格式、事件模型等)。通常不直接在这里配置具体的站点,而是通过 include 指令引入其他配置文件。我们一般不会修改这里的主配置文件,而是通过下面的/etc/nginx/conf.d/ 或 /etc/nginx/sites-available/来进行站点配置文件的配置。
站点配置目录: /etc/nginx/conf.d/ 或 /etc/nginx/sites-available/为什么有两个目录?
- /etc/nginx/conf.d/:这是一个简单的配置目录,通常用于存放单个站点的配置文件。每个文件通常对应一个站点或服务,文件名以 .conf 结尾。适合小型项目或简单场景。也是我们前端开发最常用的目录。
- /etc/nginx/sites-available/ 和 /etc/nginx/sites-enabled/:这是一个更灵活的配置管理方式,适合复杂的多站点场景。
/sites-available/: 存放所有站点的配置文件(相当于“配置仓库”),/sites-enabled/: 存放当前启用的站点配置,这种方式可以方便地启用或禁用站点,而无需删除配置文件。
执行cat /etc/nginx/conf.d/default.conf 查看默认的配置文件:
server {
listen 80;
listen [::]:80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
#access_log /var/log/nginx/host.access.log main;
location / {
try_files $uri $uri/ /index.html;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
我们部署前端项目,通过 Nginx 实现的相关功能,都是在这个文件中进行相关字段的配置而实现的。
- server : 用于定义一个虚拟主机(Virtual Host),它决定了 Nginx 如何处理来自不同域名或 IP 的请求。
- listen 80:监听 80 端口(HTTP 默认端口)。
- server_name localhost:指定匹配的域名,用于虚拟主机识别,当请求的 Host 头匹配 localhost 时,该服务器块会处理请求。
- root /usr/share/nginx/html;:指定服务器的根目录,用于查找静态文件。
- index index.html:设置默认的首页文件: 用于指定默认的索引文件,当请求的路径是目录时,Nginx 会尝试返回 index.html 或 index.htm
- location 块: 根据请求的 URL 路径定义不同的处理规则。
- error_page:定义错误页面的处理规则。当服务器返回 500、502、503 或 504 错误时,返回 /50x.html
- location = /50x.html : 精确匹配 /50x.html 路径,并指定其根目录, 也就是/50x.html 文件会从 /usr/share/nginx/html 目录中查找
根据这些字段的配置就可以解决上面邮件中提到的问题了。只需要在 Nginx 上的 server 块中配置 server_name 为备案域名,再设置一个默认的 server 快,匹配所有未明确指定 server_name 的请求并返回 403 就可以了。
server {
listen 80;
listen [::]:80;
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/dist;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
# 默认 server 块,拒绝非法请求
server {
listen 80 default_server;
server_name _;
return 403;
}
上面我们定义了两个 server 块,只有当来自 host 为 localhost 的请求才会匹配第一个 server 块,第二个是默认的 server,匹配任意的 host,我们直接返回 403 状态码。
注意:server_name 是必须的吗?不是必须的,但强烈建议配置。如果 server_name 未指定,Nginx 可能会匹配默认服务器,导致:
- 潜在的安全问题:恶意用户可以通过 IP 直接访问 你的 Nginx 服务器,可能会暴露本应受限的服务。
- 错误的路由: 多个站点可能会被错误地解析到默认的 server 块,导致访问到错误的网站或泄露敏感信息。
静态资源托管
Nginx 采用事件驱动架构,能够高效处理大量并发请求,适合托管静态资源(如 HTML、CSS、JavaScript、图片等),最长见的方式是托管一个单页应用(SPA)。我们将前端打包好的dist文件直接拷贝到 Nginx 的静态资源目录,并进行 Nginx 的相关配置就可以实现 SPA 应用的部署。
- 在启动的
my-nginxdocker 容器中执行:docker cp ./Desktop/dist my-nginx:/usr/share/nginx/
将本地的 dist 文件拷贝到容器的/usr/share/nginx/目录下,你可以通过docker exec -it my-nginx /bin/bash 进入容器,查看是否拷贝成功。
- 在本地修改
default.conf配置文件,然后将其拷贝到 Nginx 主配置文件下进行覆盖server { listen 80; listen [::]:80; server_name localhost; #access_log /var/log/nginx/host.access.log main; # 这个静态资源目录进行了修改 root /usr/share/nginx/dist; index index.html index.htm; location / { try_files $uri $uri/ /index.html; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } # 设置缓存时间 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 1y; add_header Cache-Control "public"; } } # 默认 server 块,拒绝非法请求 server { listen 80 default_server; server_name _; return 403; }注意将原来的静态资源目录修改为
root /usr/share/nginx/dist;这个是刚才我们拷贝的打包资源的目录。 - 执行覆盖命令
docker cp ./Desktop/default.conf my-nginx:/etc/nginx/conf.d/default.conf
执行完成后,重新启动 Docker 容器:
docker restart my-nginx, 浏览器访问http://localhost/就可以看到项目部署成功了。 try_files指令的设置为:**try_files $uri $uri/ /index.html;** 当访问指定路径时,$uri:尝试查找请求的文件,$uri/:尝试查找请求的目录,/index.html:如果未找到文件或目录,则返回index.html。SPA 只有一个 index.html,前端路由由 JavaScript 处理,所有它最终都返回 index.html,由前端来解析路径。这适用于Vue Router、React Router、Angular Router的 history 模式,避免 404 的问题。
反向代理与负载均衡
为什么前端要了解 Nginx 的反向代理?
- 解决跨域问题:对于前后端分离的项目比如:如前端部署在
http://frontend.com,后端在http://api.example.com),通过 Nginx 将前后端请求统一到同一域名下(如前端http://example.com,APIhttp://example.com/api),浏览器认为这是同源请求,避免跨域限制。 - 隐藏后端服务:另一方面可以避免直接暴露后端服务的 IP 或端口存在安全风险,通过反向代理方案,后端服务仅对 Nginx 可见,外部请求通过 Nginx 转发,隐藏真实后端地址。
- 高并发场景下的负载均衡:高并发场景下,单台后端服务器可能无法处理所有请求。通过反向代理,Nginx 将流量分发到多个后端实例,提升系统吞吐量和容错能力。
如何实现反向代理:
还是基于上面的例子,假如我们有个后端的服务地址为:http://example.com/api, 而前端是本地的 localhost,可以通过如下配置实现反向代理:
server {
listen 80;
server_name localhost;
# 前端静态资源
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html; # 支持 SPA 路由
}
# 反向代理到后端 API
location /api/ {
proxy_pass http://example.com; # 后端服务地址
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_pass:将匹配的请求转发到后端服务。这里需要注意 location 后面的路径与 proxy_pass 的匹配规则,当前的设置会匹配以
/api/开头的请求(例如/api/user、/api/data),**proxy_pass**末尾不带/,则会将客户端请求的 URI 完整追加到目标地址后,实际的代理路径为:http://example.com/api/user 与 http://example.com/api/data, 若proxy_pass包含路径且以/结尾,Nginx 会替换location匹配部分,实际路径为:http://example.com/user,http://example.com/data - proxy_set_header:传递客户端真实 IP 和域名信息到服务端。方便后端记录和分析。后端可以通过 X-Real-IP 读取用户 IP,用于日志记录、IP 限制、用户追踪等操作。
负载均衡
要配置 Nginx 实现负载均衡,你需要在 Nginx 配置文件中定义一个 upstream 块,并在服务器块中使用 proxy_pass 指令将请求转发到定义的上游服务器组。以下是一个示例配置,展示了如何配置 Nginx 实现负载均衡:
upstream backend {
server backend1.example.com weight=3;
server backend2.example.com;
server backend3.example.com;
}
server {
listen 80;
server_name example.com;
# 反向代理到上游服务器组
location / {
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;
}
}
- 上游服务器组:使用 upstream 指令定义一个上游服务器组,包含多个后端服务器。
- 负载均衡策略:默认情况下,Nginx 使用轮询(round-robin)策略进行负载均衡。你可以通过设置权重(weight)来调整服务器的负载分配,权重用于控制请求的分配比例:
- 权重越高:分配到的请求越多。
- 默认权重:如果未指定权重,默认为 1。
- 反向代理:在服务器块中使用 proxy_pass 指令将请求转发到上游服务器组。
HTTPS 配置(SSL 证书)
通过 Nginx 配置网站的 HTTPS 协议访问是一个常见且重要的任务,首先我们准备好SSL/TLS 证书,一般是从权威证书颁发机构(CA)来获取,证书通常包括以下两个文件:
- 证书文件(如
example.com.crt) - 私钥文件(如
example.com.key)
将证书文件拷贝到 Nginx 服务的目录下一般放在:/etc/nginx/ssl/目录下
进行 Nginx 的配置:
server {
listen 443 ssl;
server_name example.com;
# SSL 证书和私钥路径
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
# SSL 配置
ssl_protocols TLSv1.2 TLSv1.3; # 推荐使用 TLS 1.2 和 1.3
ssl_ciphers HIGH:!aNULL:!MD5; # 推荐使用安全的加密套件
ssl_prefer_server_ciphers on;
root /usr/share/nginx/html;
index index.html index.htm;
# 处理请求
location / {
try_files $uri $uri/ =404;
}
}
监听 443 端口,并且通过certificate与ssl_certificate_key设置对应的证书与 key 的路径
为了确保所有访问都通过 HTTPS,可以配置 HTTP 请求自动重定向到 HTTPS:
server {
listen 80;
server_name example.com;
# 重定向所有 HTTP 请求到 HTTPS
return 301 https://$host$request_uri;
}
以上就是前端常见的 Nginx 的配置方式,下面我们结合 docker 来实际部署我们项目。
部署 SPA 项目
假设你已经打包好了你的项目,并且生成了 dist 文件,下面是文件目录结构:
my-nginx-spa/ ├─ dist/ │ ├─ index.html │ └─ styles.css ├─ default.conf └─ Dockerfile
default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/dist;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
# 默认 server 块,拒绝非法请求
server {
listen 80 default_server;
server_name _;
return 403;
}
Dockerfile
# 使用官方 Nginx 镜像作为基础镜像 FROM nginx:1.25-alpine # 将本地的 default.conf 复制到容器中 COPY default.conf /etc/nginx/conf.d/ #将本地的 dist 目录复制到容器中的 Nginx 默认静态文件目录 COPY dist /usr/share/nginx/dist # 暴露 80 端口 EXPOSE 80 # 启动 Nginx CMD ["nginx", "-g", "daemon off;"]
执行 docker 构建命令打包镜像:
docker build -t nginx-spa-image .
基于镜像运行 docker 容器:
docker run --name nginx-spa-container -d -p 80:80 nginx-spa-image
运行后浏览器访问: http://localhost 就可以看到我们部署的项目了。
部署 nuxtjs 的 SSR 项目
相比 SPA 项目,SSR 项目的部署要麻烦一点,因为不仅需要一个 Nginx 服务来托管我们的静态资源,还需要一个 Node 服务来进行服务端的渲染逻辑。
这里介绍两种部署方案:由于需要两个容器来分别进行 node 服务与 Nginx 服务的启动,我们需要使用 docker-compose 来进行容器的管理与编排,这就是方案 1 的思路,当然也可以不使用 docker-compose,而是将 node 与 Nginx 服务放在一个容器中来简化部署,这就是方案 2 的部署思路。
方案 1:
my-nginx-ssr/ ├─ .output/ │ ├─ public/ │ └─ server/ ├─ node/ │ └─ Dockerfile ├─ nginx/ │ └─ nginx.conf ├─ docker-compose.yml └─ package.json
nginx.conf
server {
listen 80;
server_name localhost;
# 静态资源处理(由 Nginx 直接提供)
location /_nuxt/ {
alias /usr/share/nginx/html/_nuxt/; # 静态资源目录(需与 Docker 挂载路径一致)
expires 1d;
add_header Cache-Control "public";
try_files $uri $uri/ =404;
}
# 反向代理到 Node 服务(处理 SSR 请求)
location / {
proxy_pass http://node-service:3000; # 使用 Docker 服务名通信
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;
}
}
# 默认 server 块,拒绝非法请求
server {
listen 80 default_server;
server_name _;
return 403;
}
Dockerfile
FROM node:18-alpine # 设置工作目录 WORKDIR /app # 1. 复制依赖清单文件(利用 Docker 层缓存加速构建) COPY package*.json ./ # 2. 安装生产依赖 RUN npm install # 3. 复制构建产物(.output 目录) COPY .output/ ./.output/ # 4. 暴露服务端口(与 Nuxt 配置的端口一致,默认 3000) EXPOSE3000 # 5. 启动命令(直接运行 Node 服务) CMD ["node", ".output/server/index.mjs"]
docker-compose.yml
version: '3.8' services: # Node.js 服务 node-service: build: context:. # 上下文路径为项目根目录 dockerfile:node/Dockerfile# 指定 Dockerfile 路径 container_name:nuxt-node environment: -NODE_ENV=production networks: -nuxt-network # Nginx 服务 nginx: image:nginx:alpine # 使用官方 Nginx Alpine 镜像 container_name:nuxt-nginx ports: -"80:80" # 映射宿主机 80 端口到容器 80 端口 volumes: # 挂载 Nginx 配置文件(覆盖默认配置) -./nginx/nginx.conf:/etc/nginx/conf.d/default.conf # 挂载静态资源目录(Nginx 直接提供 _nuxt 内容) -./.output/public/_nuxt:/usr/share/nginx/html/_nuxt depends_on: -node-service # 确保 Node 服务先启动 networks: -nuxt-network # 定义共享网络(容器间通过服务名通信) networks: nuxt-network: driver:bridge
为了减轻 node 服务的压力,实现静态资源的高效访问,这里利用了 Nginx 的静态资源托管的能力,将 Nuxt 的静态资源通过 docker-compose 的 volumes 来挂载到 Nginx 对应的目录上,静态资源处理由 Nginx 直接提供。
需要运行docker-compose命令来进行镜像的打包与容器的启动
#构建镜像并启动容器(后台运行) docker-compose up -d --build
方案 2:
my-nginx-node-ssr/ ├─ .output/ │ ├─ public/ │ └─ server/ ├─ node/ │ └─ Dockerfile ├─ nginx/ │ └─ nginx.conf └─ package.json
不使用 docker-compose,而是将 node 与 Nginx 服务放在一个容器中来简化部署的方案:
nginx.conf
server {
listen 80;
server_name localhost;
location /_nuxt/ {
alias /usr/share/nginx/html/_nuxt/;
expires 1d;
add_header Cache-Control "public";
try_files $uri $uri/ =404;
}
location / {
proxy_pass http://localhost:3000;
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;
}
}
server {
listen 80 default_server;
server_name _;
return 403;
}
Dockerfile
# 使用 Node.js 官方镜像(Alpine 版本体积更小)
FROM node:18-alpine
# 设置工作目录
WORKDIR /app
# 1. 复制依赖清单文件(利用 Docker 层缓存加速构建)
COPY package*.json ./
# 2. 安装生产依赖
RUN npm install
# 3. 复制构建产物(.output 目录)
COPY .output/ ./.output/
# 4. 安装 Nginx
RUN apk add --no-cache nginx
# 5. 复制 Nginx 配置文件
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
# 6. 确保 Nginx 主配置文件包含必要的基本结构
RUN echo "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; \
keepalive_timeout 65; \
include /etc/nginx/conf.d/*.conf; \
}" > /etc/nginx/nginx.conf
# 7. 检查 Nginx 配置语法
RUN nginx -t
# 8. 复制静态资源到 Nginx 目录
COPY .output/public/_nuxt /usr/share/nginx/html/_nuxt
# 9. 暴露端口
EXPOSE80
# 10. 启动命令
CMD sh -c "npm run start & nginx -g 'daemon off;'"
同样的先运行 docker 镜像构建命令然后运行 docker 命令:
# 构建镜像 docker build -t nginx-node-image -f node/Dockerfile . # 基于镜像启动容器 docker run -d -p 80:80 --name nginx-node-container nginx-node-image
总结
通过掌握上述 Nginx 核心功能及 Docker 化部署技巧,前端开发者可独立完成从本地开发到生产上线的全链路工作,构建高效、安全、易维护的 Web 应用。
文章来源:奇舞精选,作者:天明
以上关于前端开发必会的Nginx知识及结合Docker的项目部署实战的文章就介绍到这了,更多相关内容请搜索码云笔记以前的文章或继续浏览下面的相关文章,希望大家以后多多支持码云笔记。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 admin@mybj123.com 进行投诉反馈,一经查实,立即处理!
重要:如软件存在付费、会员、充值等,均属软件开发者或所属公司行为,与本站无关,网友需自行判断
码云笔记 » 前端开发必会的Nginx知识及结合Docker的项目部署实战

微信
支付宝