ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Nginx静态网站部署实战:从安装配置到性能优化

Nginx静态网站部署实战:从安装配置到性能优化 1. 部署前的准备与安装选型1.1 静态站点部署的核心思路先说说静态HTML到底是什么。简单讲就是浏览器拿到什么就渲染什么不需要后端程序动态生成页面内容典型的就是个人博客、产品介绍页、前端打包后的dist目录、或者一个纯展示型的官网。这类站点的最大特点是文件就是一切服务器要做的只是把磁盘上的html、css、js、图片原样发给浏览器。那为什么选Nginx而不是Apache也不是直接用Python的http.server或者Node的serve我个人的看法是Nginx在高并发下表现极其稳定内存占用低配置语法清晰而且静态文件处理能力几乎是目前主流Web服务器里最强的那一档。Apache当然也能做但配置语法偏老派性能上在同配置下也不占优。Node的serve这类工具更适合本地开发调试放到生产环境里无论是稳定性还是安全性都不够看。所以生产环境静态站点Nginx基本是默认答案也是绝大多数云厂商镜像里自带的标配。另外要提的是很多人以为静态站点部署就是“把文件丢进服务器就能访问”其实中间还隔着三个环节文件放到哪个目录、Nginx怎么知道去这个目录找文件、访问者的请求怎么到达Nginx。这三个环节对应到Nginx配置里就是root指令、server块监听端口、以及系统防火墙/安全组放行规则。这篇文章的核心目标就是把这条链路彻底打通。1.2 Nginx安装的几种方式对比Nginx的安装方式主要有三种我按个人推荐程度排序说明。第一种是包管理器安装。Ubuntu/Debian系执行apt install nginxCentOS/RHEL系执行yum install nginx新版用dnf。这种方式的优势是快、省心安装完系统自动注册好systemd服务开机自启一条命令搞定后续卸载也干净。缺点是版本往往偏旧拿Ubuntu 20.04来说自带的Nginx版本是1.18虽然稳定但一些新特性用不上。如果你对版本没有执念就选这个。第二种是源码编译安装。去nginx.org下载源码包自己configure、make、make install。这种方式的好处是版本最新、可以自定义编译模块比如需要某些第三方模块时只能走编译路线安装路径也完全可控。坏处是需要装一堆编译依赖gcc、pcre-devel、zlib-devel、openssl-devel等编译过程要花几分钟后续卸载全靠手动。除非你明确需要特定模块或最新版本否则我没必要让小白一上来就走这条路。第三种是用Docker跑容器。docker run一个nginx镜像通过-v挂载静态目录和配置文件。这种方式和宿主机环境完全隔离环境干净、迁移方便适合本身已经容器化的业务。缺点是排障链路多一层文件权限映射偶尔也会踩坑。如果你是纯静态站点、服务器上也没跑别的容器直接用宿主机安装反倒更简单直接。我接下来以Debian/Ubuntu系系统的apt安装为主线讲因为这是最通用、最少坑的路径源码编译部分会单独开一节说明编译参数。1.3 验证安装与基础目录结构安装完成后先别急着改配置花两分钟摸清Nginx的文件布局。不同安装方式的目录略有差异apt安装的默认结构大概是这样的/etc/nginx/主配置目录nginx.conf在这里/etc/nginx/sites-available/站点可用配置目录/etc/nginx/sites-enabled/站点启用配置目录/etc/nginx/conf.d/额外的配置文件目录/var/www/html/Ubuntu下默认的网站根目录/var/log/nginx/access.log和error.log都在这里执行nginx -v可以看版本号执行systemctl status nginx看服务状态。如果一切正常直接访问服务器IP就能看到Nginx默认的欢迎页。这一步很关键它证明了Web服务本身已经跑起来了后面配置出问题你可以确定问题出在配置或文件路径上而不是进程没起来。注意如果你是刚买的云服务器访问IP没看到欢迎页先检查云控制台的安全组是否放行了80端口再检查服务器内部防火墙顺序不要反。很多新手在这上面卡了一晚上其实和安全组规则有关。2. Nginx静态站点核心配置详解2.1 配置文件整体结构与加载顺序Nginx的配置看起来很长但只要抓住一条主线就能看懂Nginx启动时读主配置文件nginx.conf里面通过http块包含server块每个server块处理一类请求。apt安装的nginx.conf末尾通常有include /etc/nginx/sites-enabled/*意思就是把sites-enabled目录下所有文件的内容“粘贴”进来。所以你在sites-enabled里放多少个server块Nginx就能处理多少个站点。这个设计的精髓在于分离。nginx.conf管全局公共配置运行用户、进程数、日志路径而每个具体站点的配置独立成一个文件互不干扰。新增一个站点只需要在sites-available里新建配置文件然后做一个软链接到sites-enabled这个操作习惯很多人不理解为什么不能直接放sites-enabled原因很简单sites-available相当于“仓库”不参与加载sites-enabled才是“上架”的配置。临时下线一个站点删掉软链接就行原文件还在仓库里随时可以恢复。验证配置语法用nginx -t它会提示配置文件是否有语法错误。这个命令每次改完配置都必须执行我见过太多人改完直接reload结果语法错误导致Nginx拒绝重启线上站点全线挂掉。2.2 server块三个核心指令listen、root、index一个最基本、只服务单个静态站点的server块长这样server { listen 80; server_name example.com www.example.com; root /var/www/example; index index.html; location / { try_files $uri $uri/ 404; } }逐个拆解。listen指定监听端口80是HTTP默认端口如果你有多个server块Nginx会根据请求的Host头也就是域名来匹配对应server块匹配不到就找默认server块。server_name就是域名匹配的规则支持精确匹配、通配符和正则静态站点场景下填你的域名或IP即可。root是整个站点文件的根目录Nginx收到请求后会把URL路径拼在root后面去磁盘上找文件。举个例子root是/var/www/example请求/它找/var/www/example/请求/about.html它找/var/www/example/about.html。index指定的是当请求路径指向目录时默认返回哪个文件比如请求/目录它就尝试返回index.html或index.htm。location /这个块是核心中的核心。location后面跟的是URL路径前缀这里的/表示匹配所有请求。里面那行try_files $uri $uri/ 404意思是先尝试请求的完整路径是否有对应文件没有就尝试把它当目录找默认文件再找不到就返回404。这行配置防止了访问不存在文件时出现意外的目录索引或500错误。2.3 location匹配规则与alias的差异location在静态站点里主要干三件事精确匹配某个路径、做目录别名、控制缓存和静态文件处理。它支持几种匹配优先级从高到低是精确匹配、^~前缀匹配、正则匹配~和~*、普通前缀匹配。很多人在配置时有个误区以为location /和location /static/可以同时生效并叠加。实际上Nginx只选一个location来处理请求规则是按优先级匹配不是拼接。比如你配置了location /static/的root和location /的root请求/static/a.js只会匹配到/static/那个location不会先匹配/再去匹配/static/。再说alias。root和alias都能改文件查找路径但行为完全不同。root是“拼接”alias是“替换”。比如location /static/ { alias /data/files/; }请求/static/logo.pngNginx会去找/data/files/logo.png注意是直接替换掉/static/这个前缀。如果这里误写成root /data/files/它就会去找/data/files/static/logo.png路径直接就错了。这是静态站点配置里非常经典的一个坑值得单独拉出来强调。2.4 多站点部署场景下的配置组织部署多个web项目是Nginx的拿手好戏而且方式不只一种。如果多个站点共用同一个IP域名不同那就每个域名一个server块server_name区分这是最标准的做法。我举个例子A站点是blog.example.comB站点是shop.example.com两个server块监听同一个80端口Nginx通过Host头分发。如果只有一个域名但想通过路径区分项目比如example.com/和example.com/app/指向两个不同目录那就用location前缀加alias实现。前面已经说了root和alias的区别这里正好用上。如果端口充足也可以用不同端口区分项目比如8010、8020各挂一个项目但这样URL里会带端口体验上不太好看而且如果涉及HTTPS证书端口的方案会让证书配置复杂很多。多站点下最需要留意的坑是默认server块。Nginx允许一个IP上配置多个server块但请求的Host头不匹配任何server_name时它会走“默认server块”——要么是配置文件里的default_server要么是第一个加载的server块。这意味着你新加的站点配置没生效时很可能是因为请求被旧的默认站点接管了。稳妥的做法是在监听80端口时单独指定一个default_server。3. 完整实操从html文件到线上访问3.1 准备站点文件与目录结构我拿一个实际场景来走全程现在有个前端项目构建产物是一个dist目录里面是index.html、assets文件夹等静态资源。要把它部署到一台全新的Ubuntu服务器上。第一步把文件传到服务器。我习惯用scp或者rsyncrsync在大量文件时优势明显支持断点续传和增量同步。命令大概是rsync -avz dist/ rootyour-server:/var/www/mysite/。如果没有本地文件只想测试也可以直接在服务器上建一个测试页mkdir -p /var/www/mysite echo h1Hello Nginx/h1 /var/www/mysite/index.html这里有个目录设计的建议/var/www/下按项目名建子目录每个项目一个文件夹别把所有文件堆在/var/www/html里。一是目录清晰多个项目好区分二是每个站点的配置里root指向明确不会互相污染。3.2 编写站点配置并测试在sites-available下新建配置文件名字我用域名或项目名命名方便识别vim /etc/nginx/sites-available/mysite写入配置server { listen 80; server_name your-domain.com; root /var/www/mysite; index index.html; location / { try_files $uri $uri/ 404; } }保存后执行nginx -t检查语法。看到syntax is ok和test is successful两行提示就说明配置没问题。接着创建软链接到sites-enabledln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/然后重载Nginxsystemctl reload nginx注意我用的是reload不是restart。reload是平滑重载Nginx会重新读取配置文件但不会中断当前连接对线上服务友好得多restart是强杀重启会造成瞬间断连。日常配置变更一律用reload。3.3 设置开机自启如果你用的是apt安装Nginx服务已经注册了systemd直接执行systemctl enable nginx systemctl start nginx第一条命令是设置开机自启第二条是立即启动。如果没有systemd比如某些精简容器环境老派做法是把nginx命令写进/etc/rc.local或者写一个init脚本但现在主流的Linux发行版基本都支持systemd这一步通常是最省心的。验证自启是否生效可以执行systemctl is-enabled nginx返回enabled就代表当前已在开机启动列表里。3.4 部署多个web项目的实战配置在同一个IP上部署两个静态站点域名分别是site-a.com和site-b.com配置文件可以这样组织server { listen 80; server_name site-a.com; root /var/www/site-a; index index.html; } server { listen 80; server_name site-b.com; root /var/www/site-b; index index.html; }两个server块放在同一个文件或者两个文件都行。我的习惯是一个站点一个文件文件名和域名对应这样改配置时不需要翻找。再补充一个前端单页应用SPA常遇到的情况路由用的history模式刷新子路径时出现404。原因很简单浏览器请求/site-a/aboutNginx去/var/www/site-a/找about文件找不到返回404。解法是把try_files改成兜底到index.htmllocation / { try_files $uri $uri/ /index.html; }这样所有找不到文件的请求都会回退到index.html前端路由自己去解析路径。这个坑在部署Vue和React项目时几乎必踩记住了能省不少排查时间。4. 常见问题排查与避坑指南4.1 403 Forbidden的三种常见原因403是静态站点最常见的错误我遇到过的情况基本可以归为三类。第一类是文件权限不足。Nginx的worker进程运行在www-data用户下apt安装默认如果你的站点目录权限是700所有者是root那www-data用户就完全没有读取权限。解决方式是设置合适的目录权限我常用的策略是目录755、文件644所有者可以是root因为www-data只要能读取就行。执行chown -R root:root /var/www/mysite chmod -R 755 /var/www/mysite第二类是index.html缺失。root指向的目录里没有配置里指定的index文件Nginx会拒绝列出目录内容出于安全考虑默认关闭autoindex于是返回403。检查一下目录里到底有没有index.html或者把index指令改成实际存在的文件名。第三类是SELinux拦截。这个在CentOS/RHEL系上概率很大Ubuntu默认不开SELinux所以没这问题。如果是CentOS检查一下SELinux状态临时关闭可以执行setenforce 0但正确做法是给网站目录打上正确的上下文标签chcon -R -t httpd_sys_content_t /var/www/mysite4.2 404 Not Found的排查路径404说明请求已经到达Nginx但文件没找到。先确认URL路径和文件实际路径的对应关系这里最容易犯的错就是root和alias的误用前面已经着重讲过。其次确认文件是否真的存在最简单的方式是直接curl访问和本地cat验证排查时我最常执行的命令组合是curl -I http://your-domain.com/path ls -l /var/www/mysite/path一个在真实项目中遇到过的case前端打包后资源文件的路径是/xxx/assets/index.js但实际目录里assets在项目的下一级结果所有js、css都404。把root指到正确的一层目录后瞬间恢复。这种问题光看配置不一定看得出问题一定要结合浏览器开发者工具里“Network”标签页看看具体哪些文件404了路径结构一目了然。4.3 端口占用与被忽略的监听冲突80端口被占用的典型报错是nginx: [emerg] bind() to 0.0.0.0:80 failed。最常见的原因是Apache或者其他Web服务先占用了端口。排查命令ss -lntp | grep :80看到占用进程后要么停掉旧服务要么改Nginx的监听端口。还有一种是重复监听nginx.conf里本身配置了listen 80 default_serversites-enabled里又配置了一个listen 80虽然Nginx会启动但可能行为不符合预期排查时也要检查一下是不是有多个文件都对同一个端口做了监听配置。4.4 修改配置后不生效的真相这个问题出现频率极高。现象是改了配置文件reload也执行了但访问结果还是旧样子。原因绝大多数是浏览器缓存。静态文件如果配置了强缓存浏览器在缓存过期前根本不会去服务器请求。排查时开浏览器无痕窗口或者用curl直接请求看响应头比如curl -I http://your-domain.com/index.html看响应头里的Cache-Control和Last-Modified字段。如果缓存时间很长而你又确定了Nginx配置没问题那就是缓存策略需要调整。在静态站点场景下合理的做法是对html文件禁止缓存或设置短缓存对带hash的静态资源css、js设置长缓存。4.5 实测排查速查表我把静态站点部署中常见的问题整理成一张速查表方便你遇到问题时快速定位现象排查顺序常用命令输入IP无法访问安全组 → 防火墙 → Nginx状态systemctl status nginx / ss -lntp能访问但全部404文件路径 → root配置 → index配置ls -l /var/www/... / nginx -T403 Forbidden文件权限 → SELinux → index是否存在ls -la /var/www/... / getenforce页面样式丢失静态资源路径 → alias配置 → 构建产物路径浏览器Network面板 / curl -I某路径反复跳首页try_files回退规则 → 前端路由配置cat nginx站点配置reload报错配置语法 → 监听端口冲突nginx -t / ss -lntp5. 性能优化与进阶扩展5.1 静态资源的高效传输gzip压缩与缓存策略静态站点优化能不引入额外复杂度就做到效果的最大提升点一个是压缩一个是缓存。gzip压缩的原理是在服务端把文本文件压缩后再传给浏览器浏览器解压后渲染。现在的浏览器基本都支持gzipNginx配置起来也简单gzip on; gzip_types text/plain text/css application/javascript application/json image/svgxml; gzip_min_length 1024;gzip_min_length 1024的意思是小于1KB的文件不压缩因为压缩本身有CPU开销小文件压缩后体积反而可能变大。图片本身已经压缩过通常不放进gzip_typesjpg、png这类格式对压缩不敏感强行gzip只会浪费CPU。缓存策略建议按文件类型区分。带hash的文件名比如app.8f3k2j.js内容一变文件名就变适合长缓存index.html这种入口文件缓存时间要短否则更新后用户还是看到老版本location /assets/ { expires 30d; add_header Cache-Control public, immutable; } location / { expires -1; add_header Cache-Control no-cache; }5.2 反向代理与HTTPS静态站点也能挂接口静态站点的局限是它只能返回文件但现实中经常遇到的前后端分离架构是前端静态页面由Nginx服务接口请求代理到后端服务。这个场景用Nginx的反向代理能力可以无缝衔接location /api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }这段配置会把所有/api/开头的请求转发到本机8080端口的后端服务。在做前端部署时浏览器可以直接请求同一个域名下的/api路径不存在跨域问题非常干净。HTTPS这块也不用跳过去。即使现在只是静态站点我也建议把HTTPS一口气配上。用Let‘s Encrypt的证书是最省事的路径但如果没有现成域名或不想依赖外部机构可以先生成自签名证书先顶上。Nginx里生成自签名证书并启用443监听我个人的做法是分两步openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /etc/nginx/ssl/nginx-selfsigned.key \ -out /etc/nginx/ssl/nginx-selfsigned.crt \ -subj /CNyour-domain.com然后在配置里加server { listen 443 ssl; server_name your-domain.com; ssl_certificate /etc/nginx/ssl/nginx-selfsigned.crt; ssl_certificate_key /etc/nginx/ssl/nginx-selfsigned.key; }这组配置网上有很多现成模板核心是证书路径别写错另外记得443端口同样需要在安全组和防火墙里放行。5.3 日志切割与意外排错access.log增长速度快得惊人尤其是站点一旦有爬虫或异常流量几天时间就能生成几个GB的日志。日志切割的常规做法是使用logrotate系统自带的logrotate每天定时处理。Nginx的日志切割原理很简单先把旧日志改名再执行nginx -s reopen让Nginx重新打开新的日志文件句柄。apt安装时Nginx已经配套了logrotate配置通常不需要额外操作。需要提的是排错时要善用error.log。我在前面几节反复提到“看日志”但很多人可能没意识到error.log是Nginx排错的第一手信息源。遇到页面异常直接tail -f /var/log/nginx/error.log它能告诉你的信息比配置文件本身还多比如文件权限问题、路径不存在的报错、上游连接被拒error.log里都会有具体的行号和原因。5.4 离线环境安装Nginx的补充方案有些生产环境的服务器不联网或者像银河麒麟这类国产系统无法直接访问官方源这时候离线安装就派得上用场。思路是在一台联网的同架构机器上把依赖包和安装包下载下来拷过去再本地安装。如果用apt可以在联网机器上执行apt download nginx nginx-common nginx-core libnginx-mod-http-geoip然后把下好的deb包拷到离线机器上执行dpkg -i *.deb安装。如果是编译安装则需要把源码包和pcre、zlib、openssl的源码包一并拷过去在离线机器上解压、configure、make。整个过程不复杂但对版本依赖关系要仔细容易漏依赖建议先在一台联网的干净的机器上把编译依赖列表理清楚。还有一种方式是把整个nginx的deb安装包连同依赖单独打包成离线仓库apt-offline工具能做适合大批量、多台机器重复部署的场景第一次准备麻烦点后续复制就能用。最后再分享一点个人的实战习惯说实话Nginx配置静态HTML这件事本身不难难的是把它放到真实环境里遇到各种边界情况时不慌。我自己经历了几次线上事故之后摸索出了一套固定的操作习惯这里做个简单分享。每次改完配置文件我一定执行nginx -t再做reload这两步中间隔了一秒都行但绝不能省。上线新站点前我会先在本地用curl -I验证响应头确认状态码是200再拿域名去访问。我习惯把每个站点的配置文件都放到sites-available然后通过软链接到sites-enabled这样即使哪天哪个站点出问题只要把软链接一删站点就立即下线而配置文件还在仓库里随时能恢复这个习惯救过我很多次。还有一个细节所有静态站点目录的权限我统一用755/644所有者设置为root也没关系关键是让Nginx的worker用户有读权限。这个方案在多个线上环境都稳定运行了很久值得你直接拿来用。最后再多说一句如果是给前端项目做部署构建产物目录里的文件、尤其是带hash的资源文件名建议保留默认构建配置不要手动改名。Nginx的缓存策略和文件名是配套设计的乱改文件名很容易踩到缓存不更新的坑到时候排查起来会非常头疼。
返回列表