4. Nginx 入门部署:安装、配置结构与静态资源代理

好,咱们进入 Nginx 实战的第一站。说实话,Nginx 这东西,你只要搞过线上服务,早晚得跟它打交道。我最早接触它的时候,还是用来解决 Apache 并发撑不住的问题。那时候 Nginx 刚火起来,配置起来感觉挺别扭——跟 Apache 的 .htaccess 思路完全不一样。但用顺手之后,你会发现它的设计其实非常优雅。

这一节,咱们把 Nginx 从安装到基本配置捋一遍。重点就三个:怎么装、配置长什么样、怎么用 Nginx 代理静态资源。

4.1 安装 Nginx:三种主流方式

安装这事儿,不同环境有不同玩法。我个人习惯在开发机用包管理器,线上机器用编译安装或者 Docker。下面列三种最常见的,你根据场景选。

安装方式 适用场景 命令 / 步骤
apt / yum 包管理器 Ubuntu / CentOS 快速安装 sudo apt install nginx 或 sudo yum install nginx
源码编译安装 需要自定义模块(如 HTTP/2、SSL) ./configure → make → make install
Docker 容器 微服务 / 容器化部署 docker run -d -p 80:80 nginx
我的建议: 如果你只是学习或者做简单的反向代理,直接用包管理器装就行。我曾经在生产环境图省事用了默认源里的旧版本,结果有个安全漏洞打了补丁才搞定。从那以后,我线上机器一律用官方源或者编译安装。

4.2 Nginx 配置结构:http、server、location

Nginx 的配置,说白了就是一棵树。根是 http,下面挂 server,server 下面挂 location。你想想看,这跟咱们写代码的命名空间、类、方法是不是有点像?

咱们先看一个最简配置,感受一下:

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

    server {
        listen       80;
        server_name  example.com;

        location / {
            root   /var/www/html;
            index  index.html index.htm;
        }

        location /api/ {
            proxy_pass http://127.0.0.1:8080;
        }
    }
}

这个结构,我拆开给你讲:

  • http 块:全局配置,影响所有虚拟主机。比如超时时间、日志格式、gzip 开关,都放这里。
  • server 块:一个虚拟主机。你可以配多个 server,监听不同端口或域名。我记得有一次帮客户排查问题,发现他配了三个 server 块,但 server_name 写重了,结果请求全跑到第一个去了。嗯,这种坑很常见。
  • location 块:匹配 URI 路径。它支持前缀匹配、正则匹配、精确匹配。匹配优先级是个容易搞混的点,我后面会专门说。
核心原则: Nginx 配置是“继承 + 覆盖”的。location 里没写的参数,会从 server 继承;server 没写的,从 http 继承。但有些指令(比如 proxy_pass)不会自动继承,必须显式写。

4.3 location 匹配规则:别在这上面翻车

location 的匹配规则,我见过太多人搞错了。你记住这张表就行:

写法 匹配类型 优先级 示例
= /path 精确匹配 最高 = /login 只匹配 /login
^~ /path/ 前缀匹配(不检查正则) 次高 ^~ /static/ 匹配 /static/ 开头的所有路径
~ pattern 正则匹配(区分大小写) 第三 ~ \.(jpg|png)$
~* pattern 正则匹配(不区分大小写) 第三 ~* \.(jpg|png)$
/path 普通前缀匹配 最低 / 匹配所有

匹配流程是这样的:先检查精确匹配,有就直接返回。然后看前缀匹配,如果找到 ^~ 的,也直接返回。否则把所有正则匹配跑一遍,命中第一个就停。最后才用普通前缀匹配。

我曾经踩过的坑: 有一次配了一个 location /images/,又配了一个 location ~ \.(jpg|png)$。我以为前者会优先,结果正则先匹配了,导致 /images/ 下的请求全走了正则,缓存策略全乱了。后来我加了个 ^~ /images/ 才搞定。所以,如果你确定某个路径不需要正则,记得用 ^~ 锁死。

4.4 静态资源代理:最常用的场景

静态资源代理,说白了就是让 Nginx 直接返回文件,不经过后端应用。这能大幅减轻应用服务器的压力。我见过一个项目,图片全走 Tomcat 返回,结果 Tomcat 线程池经常被打满。后来把静态资源切到 Nginx,CPU 占用直接降了 60%。

一个典型的静态资源代理配置长这样:

server {
    listen 80;
    server_name static.example.com;

    # 图片、CSS、JS 等静态资源
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg)$ {
        root /data/static;
        expires 30d;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # 字体文件(跨域问题)
    location ~* \.(woff|woff2|ttf|eot)$ {
        root /data/static;
        expires 365d;
        add_header Access-Control-Allow-Origin "*";
    }

    # 其他请求
    location / {
        root /data/static;
        try_files $uri $uri/ /index.html;
    }
}

这里面有几个关键点:

  • root 指令:指定文件在磁盘上的根目录。注意,它是把 URI 拼到 root 后面去找文件。比如请求 /img/logo.png,实际路径是 /data/static/img/logo.png。
  • expires:设置浏览器缓存时间。30d 就是 30 天。对于不常变的资源,设长一点,能省很多带宽。
  • Cache-Control:public 表示允许中间缓存(比如 CDN)缓存;immutable 告诉浏览器,这个文件永远不会变,连条件请求都不用发。
  • access_log off:静态资源的访问日志一般关掉,不然日志文件会疯长。我见过一个案例,日志把磁盘写满了,服务直接挂掉。
一个小技巧: 如果你用 alias 而不是 root,路径拼接逻辑会不一样。alias 会替换掉 location 匹配的部分。比如 location /static/ { alias /data/files/; },请求 /static/logo.png 实际找的是 /data/files/logo.png。很多人在这上面搞混,我建议你统一用 root,除非你明确知道需要 alias。

4.5 本章知识体系:一张图看懂

下面这张 SVG 图,把 Nginx 配置的核心结构、匹配流程和静态资源代理的要点串起来了。你多看几遍,心里就有谱了。

Nginx 配置核心结构图 Nginx 配置核心结构 http 块(全局配置:超时、日志、gzip、MIME 类型) server 块(虚拟主机:listen、server_name) location / 根路径匹配 location /api/ 反向代理到后端 location ~* \.(jpg|css)$ 静态资源代理 try_files / index.html proxy_pass 到后端 root + expires + cache 💡 匹配优先级: = 精确匹配 → ^~ 前缀匹配(不检查正则)→ ~ / ~* 正则匹配 → 普通前缀匹配 静态资源代理建议用 ^~ 或正则 + expires 缓存,避免走反向代理

4.6 验证配置与常见问题

配置写完了,别急着重启。先检查语法:

# 检查配置文件语法
nginx -t

# 如果输出类似下面,说明没问题
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful

# 重新加载配置(不中断服务)
nginx -s reload

我见过有人直接 systemctl restart nginx,结果配置有错,服务起不来,线上直接挂了。所以,nginx -t 这个习惯一定要养成。

注意: 如果你改了监听端口(比如从 80 改成 8080),记得检查防火墙和 SELinux。我曾经在 CentOS 上折腾了半天,最后发现是 SELinux 把 Nginx 的 8080 端口给拦了。用 setsebool -P httpd_can_network_connect 1 解决。